aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJason Macnak <natsu@google.com>2021-09-08 17:34:26 +0000
committerAutomerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>2021-09-08 17:34:26 +0000
commit15721e363ddf230eb45281365a43d0235a28950d (patch)
tree3c7a84d825c70fcf8bfe8d1d0d29be91c32bd737
parentd7fde7d22818ce4ba369b5da19ba9953b76cce48 (diff)
parentbadf994436f0a0dcd313d61988172ecac5ad4acc (diff)
downloadvulkano-15721e363ddf230eb45281365a43d0235a28950d.tar.gz
Import vulkano rust crate (attempt #2) am: 08bdde554c am: 7f5097d6a2 am: badf994436
Original change: https://android-review.googlesource.com/c/platform/external/rust/crates/vulkano/+/1818913 Change-Id: Iee62c85b489f55475d4ad6d30f9cc58eb864779e
-rw-r--r--Android.bp75
-rw-r--r--Cargo.toml61
-rw-r--r--Cargo.toml.orig32
l---------LICENSE1
-rw-r--r--LICENSE-APACHE201
-rw-r--r--LICENSE-MIT25
-rw-r--r--METADATA20
-rw-r--r--MODULE_LICENSE_APACHE20
-rw-r--r--OWNERS1
-rw-r--r--TEST_MAPPING10
-rw-r--r--autogen/extensions.rs399
-rw-r--r--autogen/features.rs393
-rw-r--r--autogen/fns.rs79
-rw-r--r--autogen/mod.rs215
-rw-r--r--autogen/properties.rs357
-rw-r--r--build.rs34
-rw-r--r--cargo2android.json7
-rw-r--r--out/autogen.rs9611
-rw-r--r--patches/Android.bp.patch16
-rw-r--r--patches/build.rs.patch13
-rw-r--r--patches/device_memory.rs.patch40
-rw-r--r--patches/instance.rs.patch38
-rw-r--r--patches/properties.rs.patch13
-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.rs102
-rw-r--r--src/buffer/slice.rs315
-rw-r--r--src/buffer/sys.rs591
-rw-r--r--src/buffer/traits.rs243
-rw-r--r--src/buffer/usage.rs231
-rw-r--r--src/buffer/view.rs458
-rw-r--r--src/command_buffer/auto.rs2867
-rw-r--r--src/command_buffer/mod.rs326
-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/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.rs748
-rw-r--r--src/command_buffer/synced/commands.rs3123
-rw-r--r--src/command_buffer/synced/mod.rs766
-rw-r--r--src/command_buffer/synced/tests.rs52
-rw-r--r--src/command_buffer/sys.rs1972
-rw-r--r--src/command_buffer/traits.rs528
-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/collection.rs71
-rw-r--r--src/descriptor_set/fixed_size_pool.rs604
-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.rs287
-rw-r--r--src/descriptor_set/persistent.rs1304
-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.rs588
-rw-r--r--src/device/extensions.rs174
-rw-r--r--src/device/features.rs290
-rw-r--r--src/device/mod.rs1036
-rw-r--r--src/device/physical.rs936
-rw-r--r--src/device/properties.rs316
-rw-r--r--src/extensions.rs271
-rw-r--r--src/fns.rs33
-rw-r--r--src/format.rs759
-rw-r--r--src/image/aspect.rs145
-rw-r--r--src/image/attachment.rs659
-rw-r--r--src/image/immutable.rs703
-rw-r--r--src/image/layout.rs60
-rw-r--r--src/image/mod.rs701
-rw-r--r--src/image/storage.rs336
-rw-r--r--src/image/swapchain.rs189
-rw-r--r--src/image/sys.rs1349
-rw-r--r--src/image/traits.rs438
-rw-r--r--src/image/usage.rs222
-rw-r--r--src/image/view.rs621
-rw-r--r--src/instance/debug.rs461
-rw-r--r--src/instance/extensions.rs153
-rw-r--r--src/instance/instance.rs693
-rw-r--r--src/instance/layers.rs262
-rw-r--r--src/instance/loader.rs316
-rw-r--r--src/instance/mod.rs72
-rw-r--r--src/lib.rs243
-rw-r--r--src/memory/device_memory.rs1162
-rw-r--r--src/memory/external_memory_handle_type.rs168
-rw-r--r--src/memory/mod.rs225
-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/pipeline/blend.rs291
-rw-r--r--src/pipeline/cache.rs452
-rw-r--r--src/pipeline/compute_pipeline.rs523
-rw-r--r--src/pipeline/depth_stencil.rs263
-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/graphics_pipeline/tests.rs395
-rw-r--r--src/pipeline/input_assembly.rs136
-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.rs113
-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/pipeline/viewport.rs202
-rw-r--r--src/query.rs688
-rw-r--r--src/render_pass/attachments_list.rs82
-rw-r--r--src/render_pass/compat_atch.rs263
-rw-r--r--src/render_pass/desc.rs434
-rw-r--r--src/render_pass/framebuffer.rs990
-rw-r--r--src/render_pass/macros.rs237
-rw-r--r--src/render_pass/mod.rs56
-rw-r--r--src/render_pass/render_pass.rs911
-rw-r--r--src/sampler.rs1051
-rw-r--r--src/swapchain/capabilities.rs664
-rw-r--r--src/swapchain/display.rs430
-rw-r--r--src/swapchain/mod.rs342
-rw-r--r--src/swapchain/present_region.rs69
-rw-r--r--src/swapchain/surface.rs856
-rw-r--r--src/swapchain/swapchain.rs1724
-rw-r--r--src/sync/event.rs245
-rw-r--r--src/sync/fence.rs501
-rw-r--r--src/sync/future/fence_signal.rs516
-rw-r--r--src/sync/future/join.rs268
-rw-r--r--src/sync/future/mod.rs555
-rw-r--r--src/sync/future/now.rs90
-rw-r--r--src/sync/future/semaphore_signal.rs198
-rw-r--r--src/sync/mod.rs173
-rw-r--r--src/sync/pipeline.rs271
-rw-r--r--src/sync/semaphore/external_semaphore_handle_type.rs101
-rw-r--r--src/sync/semaphore/mod.rs15
-rw-r--r--src/sync/semaphore/semaphore.rs355
-rw-r--r--src/tests.rs101
-rw-r--r--src/version.rs145
-rw-r--r--vk.xml17283
164 files changed, 88641 insertions, 0 deletions
diff --git a/Android.bp b/Android.bp
new file mode 100644
index 0000000..a156cb8
--- /dev/null
+++ b/Android.bp
@@ -0,0 +1,75 @@
+// This file is generated by cargo2android.py --config cargo2android.json.
+// Do not modify this file as changes will be overridden on upgrade.
+
+
+
+genrule {
+ name: "copy_vulkano_build_out",
+ srcs: ["out/*"],
+ cmd: "cp $(in) $(genDir)",
+ out: ["autogen.rs"],
+}
+
+rust_library {
+ name: "libvulkano",
+ // 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",
+ ],
+ edition: "2018",
+ rustlibs: [
+ "libash_rust",
+ "libcrossbeam_queue",
+ "libfnv",
+ "libhalf",
+ "liblazy_static",
+ "libparking_lot",
+ "libshared_library",
+ "libsmallvec",
+ ],
+}
+
+rust_defaults {
+ name: "vulkano_test_defaults",
+ crate_name: "vulkano",
+ // has rustc warnings
+ srcs: [
+ "src/lib.rs",
+ ":copy_vulkano_build_out",
+ ],
+ cargo_env_compat: true,
+ cargo_pkg_version: "0.25.0",
+ test_suites: ["general-tests"],
+ auto_gen_config: true,
+ edition: "2018",
+ rustlibs: [
+ "libash_rust",
+ "libcrossbeam_queue",
+ "libfnv",
+ "libhalf",
+ "liblazy_static",
+ "libparking_lot",
+ "libshared_library",
+ "libsmallvec",
+ ],
+}
+
+rust_test_host {
+ name: "vulkano_host_test_src_lib",
+ defaults: ["vulkano_test_defaults"],
+ // Manually disabled as these tests depend on specific graphics libraries
+ // being available on the machine running the tests.
+ test_options: {
+ unit_test: false,
+ },
+}
+
+rust_test {
+ name: "vulkano_device_test_src_lib",
+ defaults: ["vulkano_test_defaults"],
+}
diff --git a/Cargo.toml b/Cargo.toml
new file mode 100644
index 0000000..d18af58
--- /dev/null
+++ b/Cargo.toml
@@ -0,0 +1,61 @@
+# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
+#
+# 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
+#
+# 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)
+
+[package]
+edition = "2018"
+name = "vulkano"
+version = "0.25.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"]
+categories = ["rendering::graphics-api"]
+license = "MIT/Apache-2.0"
+repository = "https://github.com/vulkano-rs/vulkano"
+[dependencies.ash]
+version = "0.33.0"
+
+[dependencies.crossbeam-queue]
+version = "0.3"
+
+[dependencies.fnv]
+version = "1.0"
+
+[dependencies.half]
+version = "1.7"
+
+[dependencies.lazy_static]
+version = "1.4"
+
+[dependencies.parking_lot]
+version = "0.11.1"
+features = ["send_guard"]
+
+[dependencies.shared_library]
+version = "0.1"
+
+[dependencies.smallvec]
+version = "1.6"
+[build-dependencies.heck]
+version = "0.3"
+
+[build-dependencies.indexmap]
+version = "1.7"
+
+[build-dependencies.regex]
+version = "1.5"
+
+[build-dependencies.vk-parse]
+version = "0.6"
diff --git a/Cargo.toml.orig b/Cargo.toml.orig
new file mode 100644
index 0000000..99c9a33
--- /dev/null
+++ b/Cargo.toml.orig
@@ -0,0 +1,32 @@
+[package]
+name = "vulkano"
+version = "0.25.0"
+edition = "2018"
+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"
+documentation = "https://docs.rs/vulkano"
+homepage = "https://vulkano.rs"
+keywords = ["vulkan", "bindings", "graphics", "gpu", "rendering"]
+categories = ["rendering::graphics-api"]
+readme = "../README.md"
+build = "build.rs"
+
+[dependencies]
+# 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"
+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"
+
+[build-dependencies]
+heck = "0.3"
+indexmap = "1.7"
+regex = "1.5"
+vk-parse = "0.6"
diff --git a/LICENSE b/LICENSE
new file mode 120000
index 0000000..6b579aa
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1 @@
+LICENSE-APACHE \ No newline at end of file
diff --git a/LICENSE-APACHE b/LICENSE-APACHE
new file mode 100644
index 0000000..11069ed
--- /dev/null
+++ b/LICENSE-APACHE
@@ -0,0 +1,201 @@
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+END OF TERMS AND CONDITIONS
+
+APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+Copyright [yyyy] [name of copyright owner]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
diff --git a/LICENSE-MIT b/LICENSE-MIT
new file mode 100644
index 0000000..d9e1b8f
--- /dev/null
+++ b/LICENSE-MIT
@@ -0,0 +1,25 @@
+Copyright (c) 2016 The Vulkano Developers
+
+Permission is hereby granted, free of charge, to any
+person obtaining a copy of this software and associated
+documentation files (the "Software"), to deal in the
+Software without restriction, including without
+limitation the rights to use, copy, modify, merge,
+publish, distribute, sublicense, and/or sell copies of
+the Software, and to permit persons to whom the Software
+is 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 Software.
+
+THE SOFTWARE IS 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 SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE. \ No newline at end of file
diff --git a/METADATA b/METADATA
new file mode 100644
index 0000000..fe0bbcc
--- /dev/null
+++ b/METADATA
@@ -0,0 +1,20 @@
+name: "vulkano"
+description: "Safe wrapper for the Vulkan graphics API"
+third_party {
+ url {
+ type: HOMEPAGE
+ value: "https://crates.io/crates/vulkano"
+ }
+ url {
+ type: ARCHIVE
+ value: "https://static.crates.io/crates/vulkano/vulkano-0.25.0.crate"
+ }
+ version: "0.25.0"
+ # Dual-licensed, using the least restrictive per go/thirdpartylicenses#same.
+ license_type: NOTICE
+ last_upgrade_date {
+ year: 2021
+ month: 8
+ day: 30
+ }
+}
diff --git a/MODULE_LICENSE_APACHE2 b/MODULE_LICENSE_APACHE2
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/MODULE_LICENSE_APACHE2
diff --git a/OWNERS b/OWNERS
new file mode 100644
index 0000000..45dc4dd
--- /dev/null
+++ b/OWNERS
@@ -0,0 +1 @@
+include platform/prebuilts/rust:master:/OWNERS
diff --git a/TEST_MAPPING b/TEST_MAPPING
new file mode 100644
index 0000000..b205cd1
--- /dev/null
+++ b/TEST_MAPPING
@@ -0,0 +1,10 @@
+// Generated by update_crate_tests.py for tests that depend on this crate.
+{
+ "presubmit": [
+ // Manually disabled as these tests depend on specific graphics libraries
+ // being available on the machine running the tests.
+ //{
+ // "name": "vulkano_device_test_src_lib"
+ //}
+ ]
+}
diff --git a/autogen/extensions.rs b/autogen/extensions.rs
new file mode 100644
index 0000000..b303da1
--- /dev/null
+++ b/autogen/extensions.rs
@@ -0,0 +1,399 @@
+// 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 heck::SnakeCase;
+use indexmap::IndexMap;
+use std::io::Write;
+use vk_parse::Extension;
+
+// This is not included in vk.xml, so it's added here manually
+fn required_if_supported(name: &str) -> bool {
+ match name {
+ "VK_KHR_portability_subset" => true,
+ _ => false,
+ }
+}
+
+fn conflicts_extensions(name: &str) -> &'static [&'static str] {
+ match name {
+ "VK_KHR_buffer_device_address" => &["VK_EXT_buffer_device_address"],
+ "VK_EXT_buffer_device_address" => &["VK_KHR_buffer_device_address"],
+ _ => &[],
+ }
+}
+
+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));
+}
+
+#[derive(Clone, Debug)]
+struct VulkanoExtension {
+ member: 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>,
+ status: Option<ExtensionStatus>,
+}
+
+#[derive(Clone, Debug)]
+enum Replacement {
+ Core((u16, u16)),
+ DeviceExtension(String),
+ InstanceExtension(String),
+}
+
+#[derive(Clone, Debug)]
+enum ExtensionStatus {
+ Promoted(Replacement),
+ Deprecated(Option<Replacement>),
+}
+
+fn make_vulkano_extensions(
+ ty: &str,
+ extensions: &IndexMap<&str, &Extension>,
+) -> Vec<VulkanoExtension> {
+ 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 conflicts_extensions = conflicts_extensions(&ext.name);
+
+ VulkanoExtension {
+ member: member.clone(),
+ 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()),
+ 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())
+ .collect(),
+ status: ext
+ .promotedto
+ .as_ref()
+ .map(|s| s.as_str())
+ .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(),
+ ))))
+ } 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),
+ )),
+ "instance" => Some(ExtensionStatus::Promoted(
+ Replacement::InstanceExtension(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!(),
+ }
+ }
+ })
+ }),
+ }
+ })
+ .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();
+ }
+
+ 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(", ")
+ )
+ .unwrap();
+ }
+
+ if let Some(status) = ext.status.as_ref() {
+ match status {
+ ExtensionStatus::Promoted(replacement) => {
+ write!(writer, "\n\t\t\t- Promoted to ",).unwrap();
+
+ match replacement {
+ Replacement::Core(version) => {
+ write!(writer, "Vulkan {}.{}", version.0, version.1).unwrap();
+ }
+ Replacement::DeviceExtension(ext) => {
+ write!(writer, "[`{}`](crate::device::DeviceExtensions::{0})", ext)
+ .unwrap();
+ }
+ Replacement::InstanceExtension(ext) => {
+ write!(
+ writer,
+ "[`{}`](crate::instance::InstanceExtensions::{0})",
+ ext
+ )
+ .unwrap();
+ }
+ }
+ }
+ ExtensionStatus::Deprecated(replacement) => {
+ write!(writer, "\n\t\t\t- Deprecated ",).unwrap();
+
+ match replacement {
+ Some(Replacement::Core(version)) => {
+ write!(writer, "by Vulkan {}.{}", version.0, version.1).unwrap();
+ }
+ Some(Replacement::DeviceExtension(ext)) => {
+ write!(
+ writer,
+ "by [`{}`](crate::device::DeviceExtensions::{0})",
+ ext
+ )
+ .unwrap();
+ }
+ Some(Replacement::InstanceExtension(ext)) => {
+ write!(
+ writer,
+ "by [`{}`](crate::instance::InstanceExtensions::{0})",
+ ext
+ )
+ .unwrap();
+ }
+ None => {
+ write!(writer, "without a replacement").unwrap();
+ }
+ }
+ }
+ }
+ }
+
+ write!(writer, "\n\t\t\",").unwrap();
+}
diff --git a/autogen/features.rs b/autogen/features.rs
new file mode 100644
index 0000000..4c49747
--- /dev/null
+++ b/autogen/features.rs
@@ -0,0 +1,393 @@
+// 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 heck::SnakeCase;
+use indexmap::IndexMap;
+use regex::Regex;
+use std::{
+ collections::{hash_map::Entry, HashMap},
+ io::Write,
+};
+use vk_parse::{Extension, Type, TypeMember, TypeMemberMarkup, TypeSpec};
+
+// This is not included in vk.xml, so it's added here manually
+fn requires_features(name: &str) -> &'static [&'static str] {
+ match name {
+ "sparseImageInt64Atomics" => &["shaderImageInt64Atomics"],
+ "sparseImageFloat32Atomics" => &["shaderImageFloat32Atomics"],
+ "sparseImageFloat32AtomicAdd" => &["shaderImageFloat32AtomicAdd"],
+ _ => &[],
+ }
+}
+
+fn conflicts_features(name: &str) -> &'static [&'static str] {
+ match name {
+ "shadingRateImage" => &[
+ "pipelineFragmentShadingRate",
+ "primitiveFragmentShadingRate",
+ "attachmentFragmentShadingRate",
+ ],
+ "fragmentDensityMap" => &[
+ "pipelineFragmentShadingRate",
+ "primitiveFragmentShadingRate",
+ "attachmentFragmentShadingRate",
+ ],
+ "pipelineFragmentShadingRate" => &["shadingRateImage", "fragmentDensityMap"],
+ "primitiveFragmentShadingRate" => &["shadingRateImage", "fragmentDensityMap"],
+ "attachmentFragmentShadingRate" => &["shadingRateImage", "fragmentDensityMap"],
+ _ => &[],
+ }
+}
+
+fn required_by_extensions(name: &str) -> &'static [&'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"],
+ _ => &[],
+ }
+}
+
+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();
+ }
+
+ write!(
+ writer,
+ "\n}}\n\ncrate::device::features::features_ffi! {{\n\tapi_version,\n\tdevice_extensions,\n\tinstance_extensions,"
+ )
+ .unwrap();
+
+ 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();
+ }
+
+ write!(writer, "\n}}").unwrap();
+}
+
+#[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>,
+}
+
+fn make_vulkano_features(types: &HashMap<&str, (&Type, Vec<&str>)>) -> Vec<VulkanoFeature> {
+ let mut features = HashMap::new();
+ 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())
+ == 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()
+ } else {
+ ffi_member(vulkan_ty_name)
+ };
+
+ members(ty).into_iter().for_each(|name| {
+ let member = name.to_snake_case();
+ match features.entry(member.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()],
+ requires_features: requires_features
+ .into_iter()
+ .map(|&s| s.to_snake_case())
+ .collect(),
+ conflicts_features: conflicts_features
+ .into_iter()
+ .map(|&s| s.to_snake_case())
+ .collect(),
+ required_by_extensions: required_by_extensions
+ .iter()
+ .map(|vk_name| vk_name.strip_prefix("VK_").unwrap().to_snake_case())
+ .collect(),
+ });
+ }
+ Entry::Occupied(entry) => {
+ entry.into_mut().ffi_members.push(ty_name.to_owned());
+ }
+ };
+ });
+ });
+
+ let mut names: Vec<_> = features.values().map(|feat| feat.member.clone()).collect();
+ names.sort_unstable();
+ names
+ .into_iter()
+ .map(|name| features.remove(&name).unwrap())
+ .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();
+
+ if !feat.requires_features.is_empty() {
+ let links: Vec<_> = feat
+ .requires_features
+ .iter()
+ .map(|ext| format!("[`{}`](crate::device::Features::{0})", ext))
+ .collect();
+ write!(
+ writer,
+ "\n\t\t\t- Requires feature{}: {}",
+ if feat.requires_features.len() > 1 {
+ "s"
+ } else {
+ ""
+ },
+ links.join(", ")
+ )
+ .unwrap();
+ }
+
+ if !feat.required_by_extensions.is_empty() {
+ let links: Vec<_> = feat
+ .required_by_extensions
+ .iter()
+ .map(|ext| format!("[`{}`](crate::device::DeviceExtensions::{0})", ext))
+ .collect();
+ write!(
+ writer,
+ "\n\t\t\t- Required by device extension{}: {}",
+ if feat.required_by_extensions.len() > 1 {
+ "s"
+ } else {
+ ""
+ },
+ links.join(", ")
+ )
+ .unwrap();
+ }
+
+ if !feat.conflicts_features.is_empty() {
+ let links: Vec<_> = feat
+ .conflicts_features
+ .iter()
+ .map(|ext| format!("[`{}`](crate::device::Features::{0})", ext))
+ .collect();
+ write!(
+ writer,
+ "\n\t\t\t- Conflicts with feature{}: {}",
+ if feat.conflicts_features.len() > 1 {
+ "s"
+ } else {
+ ""
+ },
+ links.join(", ")
+ )
+ .unwrap();
+ }
+
+ write!(writer, "\n\t\t\",").unwrap();
+}
+
+#[derive(Clone, Debug)]
+struct VulkanoFeatureFfi {
+ member: String,
+ ty: String,
+ provided_by: Vec<String>,
+ conflicts: Vec<String>,
+}
+
+fn make_vulkano_features_ffi<'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();
+ sorted_structs(types)
+ .into_iter()
+ .map(|(ty, provided_by)| {
+ let 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)
+ } else {
+ format!(
+ "{}_extensions.{}",
+ extensions[provided_by].ext_type.as_ref().unwrap().as_str(),
+ provided_by
+ .strip_prefix("VK_")
+ .unwrap()
+ .to_ascii_lowercase()
+ )
+ }
+ })
+ .collect();
+ let mut conflicts = vec![];
+ members(ty)
+ .into_iter()
+ .for_each(|member| match feature_included_in.entry(member) {
+ Entry::Vacant(entry) => {
+ entry.insert(vec![name]);
+ }
+ Entry::Occupied(entry) => {
+ let conflicters = entry.into_mut();
+ conflicters.iter().for_each(|conflicter| {
+ let conflicter = ffi_member(conflicter);
+ if !conflicts.contains(&conflicter) {
+ conflicts.push(conflicter);
+ }
+ });
+ conflicters.push(name);
+ }
+ });
+
+ VulkanoFeatureFfi {
+ member: ffi_member(name),
+ ty: name.strip_prefix("Vk").unwrap().to_owned(),
+ provided_by,
+ conflicts,
+ }
+ })
+ .collect()
+}
+
+fn sorted_structs<'a>(
+ types: &'a HashMap<&str, (&'a Type, Vec<&'a str>)>,
+) -> 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("VkPhysicalDeviceFeatures2,VkDeviceCreateInfo")
+ })
+ .collect();
+ let regex = Regex::new(r"^VkPhysicalDeviceVulkan\d+Features$").unwrap();
+ structs.sort_unstable_by_key(|&(ty, provided_by)| {
+ let name = ty.name.as_ref().unwrap();
+ (
+ !regex.is_match(name),
+ if let Some(version) = provided_by
+ .iter()
+ .find_map(|s| s.strip_prefix("VK_VERSION_"))
+ {
+ 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()
+ {
+ i32::MAX - 2
+ } else if provided_by
+ .iter()
+ .find(|s| s.starts_with("VK_EXT_"))
+ .is_some()
+ {
+ i32::MAX - 1
+ } else {
+ i32::MAX
+ },
+ name,
+ )
+ });
+
+ structs
+}
+
+fn ffi_member(ty_name: &str) -> String {
+ let ty_name = ty_name
+ .strip_prefix("VkPhysicalDevice")
+ .unwrap()
+ .to_snake_case();
+ let (base, suffix) = ty_name.rsplit_once("_features").unwrap();
+ format!("features_{}{}", base, suffix)
+}
+
+fn members(ty: &Type) -> Vec<&str> {
+ if let TypeSpec::Members(members) = &ty.spec {
+ members
+ .iter()
+ .filter_map(|member| {
+ if let TypeMember::Definition(def) = member {
+ let name = def.markup.iter().find_map(|markup| match markup {
+ TypeMemberMarkup::Name(name) => Some(name.as_str()),
+ _ => None,
+ });
+ if name != Some("sType") && name != Some("pNext") {
+ return name;
+ }
+ }
+ None
+ })
+ .collect()
+ } else {
+ vec![]
+ }
+}
diff --git a/autogen/fns.rs b/autogen/fns.rs
new file mode 100644
index 0000000..da25938
--- /dev/null
+++ b/autogen/fns.rs
@@ -0,0 +1,79 @@
+// 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 heck::{CamelCase, SnakeCase};
+use indexmap::IndexMap;
+use std::io::Write;
+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),
+ "Instance",
+ );
+ write!(writer, "\n\n").unwrap();
+ write_fns(
+ writer,
+ make_vulkano_extension_fns("device", &extensions),
+ "Device",
+ );
+}
+
+#[derive(Clone, Debug)]
+struct VulkanoFns {
+ member: String,
+ fn_struct: String,
+}
+
+fn make_vulkano_extension_fns(
+ ty: &str,
+ extensions: &IndexMap<&str, &Extension>,
+) -> Vec<VulkanoFns> {
+ extensions
+ .values()
+ .filter(|ext| ext.ext_type.as_ref().unwrap() == ty)
+ // Filter only extensions that have functions
+ .filter(|ext| {
+ ext.children.iter().any(|ch| {
+ if let ExtensionChild::Require { items, .. } = ch {
+ items
+ .iter()
+ .any(|i| matches!(i, InterfaceItem::Command { .. }))
+ } else {
+ false
+ }
+ })
+ })
+ .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 }
+ })
+ .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();
+}
diff --git a/autogen/mod.rs b/autogen/mod.rs
new file mode 100644
index 0000000..dde09ea
--- /dev/null
+++ b/autogen/mod.rs
@@ -0,0 +1,215 @@
+// 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 indexmap::IndexMap;
+use std::{collections::HashMap, io::Write, path::Path};
+use vk_parse::{
+ Extension, ExtensionChild, Feature, InterfaceItem, Registry, RegistryChild, Type,
+ TypeCodeMarkup, TypeSpec, TypesChild,
+};
+
+mod extensions;
+mod features;
+mod fns;
+mod properties;
+
+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);
+
+ 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
+ )
+ .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();
+}
+
+fn get_registry<P: AsRef<Path> + ?Sized>(path: &P) -> Registry {
+ let (registry, errors) = vk_parse::parse_file(path.as_ref()).unwrap();
+
+ if !errors.is_empty() {
+ eprintln!("The following errors were found while parsing the file:");
+
+ for error in errors {
+ eprintln!("{:?}", error);
+ }
+ }
+
+ 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()
+}
+
+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())
+ }
+ });
+
+ names.iter().map(|&name| (name, extensions[name])).collect()
+}
+
+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_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| {
+ 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();
+
+ 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()
+}
+
+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());
+ }
+ }
+ }
+
+ None
+ });
+ }
+
+ None
+ })
+ .unwrap()
+}
diff --git a/autogen/properties.rs b/autogen/properties.rs
new file mode 100644
index 0000000..1dfb695
--- /dev/null
+++ b/autogen/properties.rs
@@ -0,0 +1,357 @@
+// 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 heck::SnakeCase;
+use indexmap::IndexMap;
+use regex::Regex;
+use std::{
+ collections::{hash_map::Entry, HashMap},
+ io::Write,
+};
+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();
+ }
+
+ write!(
+ writer,
+ "\n}}\n\ncrate::device::properties::properties_ffi! {{\n\tapi_version,\n\tdevice_extensions,\n\tinstance_extensions,"
+ )
+ .unwrap();
+
+ 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();
+ }
+
+ write!(writer, "\n}}").unwrap();
+}
+
+#[derive(Clone, Debug)]
+struct VulkanoProperty {
+ member: String,
+ ty: String,
+ vulkan_doc: String,
+ ffi_name: String,
+ ffi_members: Vec<String>,
+ required: bool,
+}
+
+fn make_vulkano_properties(types: &HashMap<&str, (&Type, Vec<&str>)>) -> Vec<VulkanoProperty> {
+ let mut properties = HashMap::new();
+ std::array::IntoIter::new([
+ &types["VkPhysicalDeviceProperties"],
+ &types["VkPhysicalDeviceLimits"],
+ &types["VkPhysicalDeviceSparseProperties"],
+ ])
+ .chain(sorted_structs(types).into_iter())
+ .filter(|(ty, _)| {
+ let name = ty.name.as_ref().map(|s| s.as_str());
+ name == Some("VkPhysicalDeviceProperties")
+ || name == Some("VkPhysicalDeviceLimits")
+ || name == Some("VkPhysicalDeviceSparseProperties")
+ || ty.structextends.as_ref().map(|s| s.as_str()) == 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()
+ } else if vulkan_ty_name == "VkPhysicalDeviceLimits" {
+ "properties_vulkan10.properties.limits".to_owned()
+ } else if vulkan_ty_name == "VkPhysicalDeviceSparseProperties" {
+ "properties_vulkan10.properties.sparse_properties".to_owned()
+ } else {
+ ffi_member(vulkan_ty_name)
+ };
+
+ members(ty)
+ .into_iter()
+ .for_each(|Member { name, ty, len }| {
+ if ty == "VkPhysicalDeviceLimits" || ty == "VkPhysicalDeviceSparseProperties" {
+ return;
+ }
+
+ let vulkano_member = name.to_snake_case();
+ let vulkano_ty = match name {
+ "apiVersion" => "crate::Version",
+ _ => 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,
+ });
+ }
+ Entry::Occupied(entry) => {
+ entry.into_mut().ffi_members.push(ty_name.to_owned());
+ }
+ };
+ });
+ });
+
+ let mut names: Vec<_> = properties
+ .values()
+ .map(|feat| feat.member.clone())
+ .collect();
+ names.sort_unstable();
+ names
+ .into_iter()
+ .map(|name| properties.remove(&name).unwrap())
+ .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();
+}
+
+#[derive(Clone, Debug)]
+struct VulkanoPropertyFfi {
+ member: String,
+ ty: String,
+ provided_by: Vec<String>,
+ conflicts: Vec<String>,
+}
+
+fn make_vulkano_properties_ffi<'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();
+ sorted_structs(types)
+ .into_iter()
+ .map(|(ty, provided_by)| {
+ 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)
+ } else {
+ format!(
+ "{}_extensions.{}",
+ extensions[provided_by].ext_type.as_ref().unwrap().as_str(),
+ provided_by
+ .strip_prefix("VK_")
+ .unwrap()
+ .to_ascii_lowercase()
+ )
+ }
+ })
+ .collect();
+ let mut conflicts = vec![];
+ members(ty).into_iter().for_each(|Member { name, .. }| {
+ match property_included_in.entry(name) {
+ Entry::Vacant(entry) => {
+ entry.insert(vec![ty_name]);
+ }
+ Entry::Occupied(entry) => {
+ let conflicters = entry.into_mut();
+ conflicters.iter().for_each(|conflicter| {
+ let conflicter = ffi_member(conflicter);
+ if !conflicts.contains(&conflicter) {
+ conflicts.push(conflicter);
+ }
+ });
+ conflicters.push(ty_name);
+ }
+ }
+ });
+
+ VulkanoPropertyFfi {
+ member: ffi_member(ty_name),
+ ty: ty_name.strip_prefix("Vk").unwrap().to_owned(),
+ provided_by,
+ conflicts,
+ }
+ })
+ .collect()
+}
+
+fn sorted_structs<'a>(
+ types: &'a HashMap<&str, (&'a Type, Vec<&'a str>)>,
+) -> 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")
+ })
+ .collect();
+ let regex = Regex::new(r"^VkPhysicalDeviceVulkan\d+Properties$").unwrap();
+ structs.sort_unstable_by_key(|&(ty, provided_by)| {
+ let name = ty.name.as_ref().unwrap();
+ (
+ !regex.is_match(name),
+ if let Some(version) = provided_by
+ .iter()
+ .find_map(|s| s.strip_prefix("VK_VERSION_"))
+ {
+ 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()
+ {
+ i32::MAX - 2
+ } else if provided_by
+ .iter()
+ .find(|s| s.starts_with("VK_EXT_"))
+ .is_some()
+ {
+ i32::MAX - 1
+ } else {
+ i32::MAX
+ },
+ name,
+ )
+ });
+
+ structs
+}
+
+fn ffi_member(ty_name: &str) -> String {
+ let ty_name = ty_name
+ .strip_prefix("VkPhysicalDevice")
+ .unwrap()
+ .to_snake_case();
+ let (base, suffix) = ty_name.rsplit_once("_properties").unwrap();
+ format!("properties_{}{}", base, suffix)
+}
+
+struct Member<'a> {
+ name: &'a str,
+ ty: &'a str,
+ len: Option<&'a str>,
+}
+
+fn members(ty: &Type) -> Vec<Member> {
+ let regex = Regex::new(r"\[([A-Za-z0-9_]+)\]\s*$").unwrap();
+ if let TypeSpec::Members(members) = &ty.spec {
+ members
+ .iter()
+ .filter_map(|member| {
+ if let TypeMember::Definition(def) = member {
+ let name = def.markup.iter().find_map(|markup| match markup {
+ TypeMemberMarkup::Name(name) => Some(name.as_str()),
+ _ => None,
+ });
+ let ty = def.markup.iter().find_map(|markup| match markup {
+ TypeMemberMarkup::Type(ty) => Some(ty.as_str()),
+ _ => None,
+ });
+ let len = def
+ .markup
+ .iter()
+ .find_map(|markup| match markup {
+ TypeMemberMarkup::Enum(len) => Some(len.as_str()),
+ _ => None,
+ })
+ .or_else(|| {
+ regex
+ .captures(&def.code)
+ .and_then(|cap| cap.get(1))
+ .map(|m| m.as_str())
+ });
+ if name != Some("sType") && name != Some("pNext") {
+ return name.map(|name| Member {
+ name,
+ ty: ty.unwrap(),
+ len,
+ });
+ }
+ }
+ None
+ })
+ .collect()
+ } else {
+ vec![]
+ }
+}
+
+fn vulkano_type(ty: &str, len: Option<&str>) -> &'static str {
+ 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]",
+ _ => 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",
+ _ => unimplemented!("{}", ty),
+ }
+ }
+}
diff --git a/build.rs b/build.rs
new file mode 100644
index 0000000..4da24a1
--- /dev/null
+++ b/build.rs
@@ -0,0 +1,34 @@
+// 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.
+
+#![feature(str_split_once)]
+
+use std::{env, fs::File, io::BufWriter, path::Path};
+
+mod autogen;
+
+fn main() {
+ let target = env::var("TARGET").unwrap();
+ if target.contains("apple-ios") {
+ println!("cargo:rustc-link-search=framework=/Library/Frameworks/");
+ println!("cargo:rustc-link-lib=c++");
+ println!("cargo:rustc-link-lib=framework=MoltenVK");
+ println!("cargo:rustc-link-lib=framework=Metal");
+ println!("cargo:rustc-link-lib=framework=IOSurface");
+ println!("cargo:rustc-link-lib=framework=QuartzCore");
+ println!("cargo:rustc-link-lib=framework=UIKit");
+ println!("cargo:rustc-link-lib=framework=Foundation");
+ }
+
+ // Write autogen.rs
+ 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);
+}
diff --git a/cargo2android.json b/cargo2android.json
new file mode 100644
index 0000000..4d9f28e
--- /dev/null
+++ b/cargo2android.json
@@ -0,0 +1,7 @@
+{
+ "copy-out": true,
+ "device": true,
+ "run": true,
+ "tests": true,
+ "patch": "patches/Android.bp.patch"
+} \ No newline at end of file
diff --git a/out/autogen.rs b/out/autogen.rs
new file mode 100644
index 0000000..4158e48
--- /dev/null
+++ b/out/autogen.rs
@@ -0,0 +1,9611 @@
+// 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/patches/Android.bp.patch b/patches/Android.bp.patch
new file mode 100644
index 0000000..97e8d62
--- /dev/null
+++ b/patches/Android.bp.patch
@@ -0,0 +1,16 @@
+diff --git a/Android.bp b/Android.bp
+index 8e11707..a156cb8 100644
+--- a/Android.bp
++++ b/Android.bp
+@@ -62,8 +62,10 @@ rust_defaults {
+ rust_test_host {
+ name: "vulkano_host_test_src_lib",
+ defaults: ["vulkano_test_defaults"],
++ // Manually disabled as these tests depend on specific graphics libraries
++ // being available on the machine running the tests.
+ test_options: {
+- unit_test: true,
++ unit_test: false,
+ },
+ }
+
diff --git a/patches/build.rs.patch b/patches/build.rs.patch
new file mode 100644
index 0000000..4af564f
--- /dev/null
+++ b/patches/build.rs.patch
@@ -0,0 +1,13 @@
+diff --git a/build.rs b/build.rs
+index 1f2b2bf5..4da24a10 100644
+--- a/build.rs
++++ b/build.rs
+@@ -7,6 +7,8 @@
+ // notice may not be copied, modified, or distributed except
+ // according to those terms.
+
++#![feature(str_split_once)]
++
+ use std::{env, fs::File, io::BufWriter, path::Path};
+
+ mod autogen;
diff --git a/patches/device_memory.rs.patch b/patches/device_memory.rs.patch
new file mode 100644
index 0000000..becf2c2
--- /dev/null
+++ b/patches/device_memory.rs.patch
@@ -0,0 +1,40 @@
+diff --git a/src/memory/device_memory.rs b/src/memory/device_memory.rs
+index 7f6bc8ff..be1eed9f 100644
+--- a/src/memory/device_memory.rs
++++ b/src/memory/device_memory.rs
+@@ -19,7 +19,7 @@ use crate::OomError;
+ use crate::VulkanObject;
+ use std::error;
+ use std::fmt;
+-#[cfg(target_os = "linux")]
++#[cfg(any(target_os = "android", target_os = "linux"))]
+ use std::fs::File;
+ use std::marker::PhantomData;
+ use std::mem::MaybeUninit;
+@@ -27,7 +27,7 @@ use std::ops::Deref;
+ use std::ops::DerefMut;
+ use std::ops::Range;
+ use std::os::raw::c_void;
+-#[cfg(target_os = "linux")]
++#[cfg(any(target_os = "android", target_os = "linux"))]
+ use std::os::unix::io::{FromRawFd, IntoRawFd};
+ use std::ptr;
+ use std::sync::Arc;
+@@ -178,7 +178,7 @@ impl<'a> DeviceMemoryBuilder<'a> {
+ /// # Panic
+ ///
+ /// - Panics if the import info has already been set.
+- #[cfg(target_os = "linux")]
++ #[cfg(any(target_os = "android", target_os = "linux"))]
+ pub fn import_info(
+ mut self,
+ fd: File,
+@@ -572,7 +572,7 @@ impl DeviceMemory {
+ ///
+ /// - Panics if the user requests an invalid handle type for this device memory object.
+ #[inline]
+- #[cfg(target_os = "linux")]
++ #[cfg(any(target_os = "android", target_os = "linux"))]
+ pub fn export_fd(
+ &self,
+ handle_type: ExternalMemoryHandleType,
diff --git a/patches/instance.rs.patch b/patches/instance.rs.patch
new file mode 100644
index 0000000..e3409fd
--- /dev/null
+++ b/patches/instance.rs.patch
@@ -0,0 +1,38 @@
+diff --git a/src/instance/instance.rs b/src/instance/instance.rs
+index b887f1e2..d9f02276 100644
+--- a/src/instance/instance.rs
++++ b/src/instance/instance.rs
+@@ -541,12 +541,12 @@ impl<'a> ApplicationInfo<'a> {
+ #[deprecated(note = "Please use the `app_info_from_cargo_toml!` macro instead")]
+ pub fn from_cargo_toml() -> ApplicationInfo<'a> {
+ let 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(),
++ major: 0,
++ minor: 0,
++ patch: 0,
+ };
+
+- let name = env!("CARGO_PKG_NAME");
++ let name = "";
+
+ ApplicationInfo {
+ application_name: Some(name.into()),
+@@ -568,12 +568,12 @@ impl<'a> ApplicationInfo<'a> {
+ macro_rules! app_info_from_cargo_toml {
+ () => {{
+ let version = $crate::instance::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(),
++ major: 0,
++ minor: 0,
++ patch: 0,
+ };
+
+- let name = env!("CARGO_PKG_NAME");
++ let name = "";
+
+ $crate::instance::ApplicationInfo {
+ application_name: Some(name.into()),
diff --git a/patches/properties.rs.patch b/patches/properties.rs.patch
new file mode 100644
index 0000000..69d5b09
--- /dev/null
+++ b/patches/properties.rs.patch
@@ -0,0 +1,13 @@
+diff --git a/src/device/properties.rs b/src/device/properties.rs
+index be1c36d..8628cb0 100644
+--- a/src/device/properties.rs
++++ b/src/device/properties.rs
+@@ -212,7 +212,7 @@ impl<const N: usize> FromVulkan<[f32; N]> for [f32; N] {
+
+ impl<const N: usize> FromVulkan<[std::os::raw::c_char; N]> for String {
+ #[inline]
+- fn from_vulkan(val: [i8; N]) -> Option<Self> {
++ fn from_vulkan(val: [std::os::raw::c_char; N]) -> Option<Self> {
+ Some(unsafe { CStr::from_ptr(val.as_ptr()).to_string_lossy().into_owned() })
+ }
+ }
diff --git a/src/buffer/cpu_access.rs b/src/buffer/cpu_access.rs
new file mode 100644
index 0000000..5c9bc19
--- /dev/null
+++ b/src/buffer/cpu_access.rs
@@ -0,0 +1,659 @@
+// 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
new file mode 100644
index 0000000..2475961
--- /dev/null
+++ b/src/buffer/cpu_pool.rs
@@ -0,0 +1,945 @@
+// 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
new file mode 100644
index 0000000..51eaf31
--- /dev/null
+++ b/src/buffer/device_local.rs
@@ -0,0 +1,398 @@
+// 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
new file mode 100644
index 0000000..bb9c8e5
--- /dev/null
+++ b/src/buffer/immutable.rs
@@ -0,0 +1,728 @@
+// 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
new file mode 100644
index 0000000..1f203a9
--- /dev/null
+++ b/src/buffer/mod.rs
@@ -0,0 +1,102 @@
+// 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.
+
+//! Location in memory that contains data.
+//!
+//! A Vulkan buffer is very similar to a buffer that you would use in programming languages in
+//! general, in the sense that it is a location in memory that contains data. The difference
+//! 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
+//! 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.
+//!
+//! You can use buffers for the following purposes:
+//!
+//! - Can contain arbitrary data that can be transferred from/to other buffers and images.
+//! - Can be read and modified from a shader.
+//! - Can be used as a source of vertices and indices.
+//! - Can be used as a source of list of models for draw indirect commands.
+//!
+//! Accessing a buffer from a shader can be done in the following ways:
+//!
+//! - 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 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
+//! for how to create a buffer view.
+//!
+
+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 sys;
+pub mod view;
+
+mod slice;
+mod traits;
+mod usage;
diff --git a/src/buffer/slice.rs b/src/buffer/slice.rs
new file mode 100644
index 0000000..03995d5
--- /dev/null
+++ b/src/buffer/slice.rs
@@ -0,0 +1,315 @@
+// 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/sys.rs b/src/buffer/sys.rs
new file mode 100644
index 0000000..f462e00
--- /dev/null
+++ b/src/buffer/sys.rs
@@ -0,0 +1,591 @@
+// 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 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;
+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,
+ device: Arc<Device>,
+ size: DeviceSize,
+ usage: BufferUsage,
+}
+
+impl UnsafeBuffer {
+ /// Creates a new buffer of the given size.
+ ///
+ /// See the module's documentation for information about safety.
+ ///
+ /// # Panic
+ ///
+ /// - 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>(
+ 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
+ };
+
+ // Checking sparse features.
+ let flags = if let Some(sparse_level) = sparse {
+ if !device.enabled_features().sparse_binding {
+ return Err(BufferCreationError::SparseBindingFeatureNotEnabled);
+ }
+
+ if sparse_level.sparse_residency && !device.enabled_features().sparse_residency_buffer {
+ return Err(BufferCreationError::SparseResidencyBufferFeatureNotEnabled);
+ }
+
+ if sparse_level.sparse_aliased && !device.enabled_features().sparse_residency_aliased {
+ return Err(BufferCreationError::SparseResidencyAliasedFeatureNotEnabled);
+ }
+
+ sparse_level.into()
+ } else {
+ ash::vk::BufferCreateFlags::empty()
+ };
+
+ 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);
+ }
+ }
+
+ 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(),
+ ..Default::default()
+ };
+
+ let mut output = MaybeUninit::uninit();
+ check_errors(fns.v1_0.create_buffer(
+ device.internal_object(),
+ &infos,
+ ptr::null(),
+ output.as_mut_ptr(),
+ ))?;
+ output.assume_init()
+ };
+
+ let mem_reqs = {
+ #[inline]
+ fn align(val: DeviceSize, al: DeviceSize) -> DeviceSize {
+ al * (1 + (val - 1) / al)
+ }
+
+ 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()
+ };
+
+ 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 device.api_version() >= Version::V1_1 {
+ fns.v1_1.get_buffer_memory_requirements2(
+ device.internal_object(),
+ &infos,
+ &mut output,
+ );
+ } 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;
+ }
+ 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,
+ );
+ }
+
+ if usage.uniform_buffer {
+ output.alignment = align(
+ output.alignment,
+ properties.min_uniform_buffer_offset_alignment,
+ );
+ }
+
+ output
+ };
+
+ let obj = UnsafeBuffer {
+ buffer,
+ device: device.clone(),
+ size,
+ usage,
+ };
+
+ Ok((obj, mem_reqs))
+ }
+
+ /// Binds device memory to this buffer.
+ pub unsafe fn bind_memory(
+ &self,
+ memory: &DeviceMemory,
+ offset: DeviceSize,
+ ) -> Result<(), OomError> {
+ let fns = self.device.fns();
+
+ // 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(),
+ );
+
+ 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
+ });
+
+ // 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 self.usage().storage_buffer {
+ debug_assert!(offset % properties.min_storage_buffer_offset_alignment == 0);
+ }
+ if self.usage().uniform_buffer {
+ debug_assert!(offset % properties.min_uniform_buffer_offset_alignment == 0);
+ }
+ }
+
+ check_errors(fns.v1_0.bind_buffer_memory(
+ self.device.internal_object(),
+ self.buffer,
+ memory.internal_object(),
+ offset,
+ ))?;
+ Ok(())
+ }
+
+ /// Returns the size of the buffer in bytes.
+ #[inline]
+ pub fn size(&self) -> DeviceSize {
+ self.size
+ }
+
+ /// Returns the buffer the image was created with.
+ #[inline]
+ pub fn usage(&self) -> BufferUsage {
+ self.usage
+ }
+
+ /// Returns a key unique to each `UnsafeBuffer`. Can be used for the `conflicts_key` method.
+ #[inline]
+ pub fn key(&self) -> u64 {
+ self.buffer.as_raw()
+ }
+}
+
+unsafe impl VulkanObject for UnsafeBuffer {
+ type Object = ash::vk::Buffer;
+
+ #[inline]
+ fn internal_object(&self) -> ash::vk::Buffer {
+ self.buffer
+ }
+}
+
+unsafe impl DeviceOwned for UnsafeBuffer {
+ #[inline]
+ fn device(&self) -> &Arc<Device> {
+ &self.device
+ }
+}
+
+impl fmt::Debug for UnsafeBuffer {
+ #[inline]
+ fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
+ write!(fmt, "<Vulkan buffer {:?}>", self.buffer)
+ }
+}
+
+impl Drop for UnsafeBuffer {
+ #[inline]
+ fn drop(&mut self) {
+ unsafe {
+ let fns = self.device.fns();
+ fns.v1_0
+ .destroy_buffer(self.device.internal_object(), self.buffer, 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 {}
+
+impl Hash for UnsafeBuffer {
+ #[inline]
+ fn hash<H: Hasher>(&self, state: &mut H) {
+ self.buffer.hash(state);
+ self.device.hash(state);
+ }
+}
+
+/// 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 {
+ #[inline]
+ pub fn none() -> SparseLevel {
+ SparseLevel {
+ sparse_residency: false,
+ sparse_aliased: false,
+ }
+ }
+}
+
+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
+ }
+}
+
+/// 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")
+ }
+}
+
+/// 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,
+}
+
+impl error::Error for BufferCreationError {
+ #[inline]
+ fn source(&self) -> Option<&(dyn error::Error + 'static)> {
+ match *self {
+ BufferCreationError::AllocError(ref err) => Some(err),
+ _ => None,
+ }
+ }
+}
+
+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"
+ }
+ }
+ )
+ }
+}
+
+impl From<OomError> for BufferCreationError {
+ #[inline]
+ fn from(err: OomError) -> BufferCreationError {
+ BufferCreationError::AllocError(err.into())
+ }
+}
+
+impl From<Error> for BufferCreationError {
+ #[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),
+ }
+ }
+}
+
+#[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;
+
+ #[test]
+ fn create() {
+ let (device, _) = gfx_dev_and_queue!();
+ let (buf, reqs) = unsafe {
+ UnsafeBuffer::new(
+ device.clone(),
+ 128,
+ BufferUsage::all(),
+ Sharing::Exclusive::<Empty<_>>,
+ None,
+ )
+ }
+ .unwrap();
+
+ assert!(reqs.size >= 128);
+ assert_eq!(buf.size(), 128);
+ assert_eq!(&**buf.device() as *const Device, &*device as *const Device);
+ }
+
+ #[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!(),
+ }
+ };
+ }
+
+ #[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!(),
+ }
+ };
+ }
+
+ #[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!(),
+ }
+ };
+ }
+
+ #[test]
+ fn create_empty_buffer() {
+ let (device, _) = gfx_dev_and_queue!();
+
+ unsafe {
+ let _ = UnsafeBuffer::new(
+ device,
+ 0,
+ BufferUsage::all(),
+ Sharing::Exclusive::<Empty<_>>,
+ None,
+ );
+ };
+ }
+}
diff --git a/src/buffer/traits.rs b/src/buffer/traits.rs
new file mode 100644
index 0000000..9b76b21
--- /dev/null
+++ b/src/buffer/traits.rs
@@ -0,0 +1,243 @@
+// 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
new file mode 100644
index 0000000..7566012
--- /dev/null
+++ b/src/buffer/usage.rs
@@ -0,0 +1,231 @@
+// 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::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,
+ }
+ }
+}
diff --git a/src/buffer/view.rs b/src/buffer/view.rs
new file mode 100644
index 0000000..bf885c2
--- /dev/null
+++ b/src/buffer/view.rs
@@ -0,0 +1,458 @@
+// 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.
+
+//! View of a buffer, in order to use it as a uniform texel buffer or storage texel buffer.
+//!
+//! In order to use a buffer as a uniform texel buffer or a storage texel buffer, you have to
+//! create a `BufferView`, which indicates which format the data is in.
+//!
+//! 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
+//!
+//! ```
+//! # use std::sync::Arc;
+//! use vulkano::buffer::immutable::ImmutableBuffer;
+//! use vulkano::buffer::BufferUsage;
+//! use vulkano::buffer::BufferView;
+//! use vulkano::format::Format;
+//!
+//! # let device: Arc<vulkano::device::Device> = return;
+//! # let queue: Arc<vulkano::device::Queue> = return;
+//! let usage = BufferUsage {
+//! storage_texel_buffer: true,
+//! .. BufferUsage::none()
+//! };
+//!
+//! let (buffer, _future) = ImmutableBuffer::<[u32]>::from_iter((0..128).map(|n| n), usage,
+//! queue.clone()).unwrap();
+//! let _view = BufferView::new(buffer, Format::R32Uint).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;
+
+/// 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,
+}
+
+impl<B> BufferView<B>
+where
+ B: BufferAccess,
+{
+ /// Builds a new buffer view.
+ #[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) }
+ }
+
+ /// 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);
+ }
+
+ if !buffer.usage().uniform_texel_buffer && !buffer.usage().storage_texel_buffer {
+ return Err(BufferViewCreationError::WrongBufferUsage);
+ }
+
+ {
+ 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);
+ }
+ }
+
+ 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);
+ }
+ }
+
+ if buffer.usage().storage_texel_buffer {
+ if (format_props & ash::vk::FormatFeatureFlags::STORAGE_TEXEL_BUFFER).is_empty() {
+ return Err(BufferViewCreationError::UnsupportedFormat);
+ }
+ }
+
+ let infos = ash::vk::BufferViewCreateInfo {
+ flags: ash::vk::BufferViewCreateFlags::empty(),
+ buffer: buffer.internal_object(),
+ format: format.into(),
+ offset,
+ range: size,
+ ..Default::default()
+ };
+
+ let fns = device.fns();
+ let mut output = MaybeUninit::uninit();
+ check_errors(fns.v1_0.create_buffer_view(
+ device.internal_object(),
+ &infos,
+ ptr::null(),
+ output.as_mut_ptr(),
+ ))?;
+ (output.assume_init(), format_props)
+ };
+
+ Ok(BufferView {
+ view,
+ buffer: org_buffer,
+ atomic_accesses: !(format_props
+ & ash::vk::FormatFeatureFlags::STORAGE_TEXEL_BUFFER_ATOMIC)
+ .is_empty(),
+ })
+ }
+
+ /// 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
+ }
+
+ /// Returns true if the buffer view can be used as a storage texel buffer with atomic accesses.
+ #[inline]
+ pub fn storage_texel_buffer_atomic(&self) -> bool {
+ self.atomic_accesses && self.storage_texel_buffer()
+ }
+}
+
+unsafe impl<B> VulkanObject for BufferView<B>
+where
+ B: BufferAccess,
+{
+ type Object = ash::vk::BufferView;
+
+ #[inline]
+ fn internal_object(&self) -> ash::vk::BufferView {
+ self.view
+ }
+}
+
+unsafe impl<B> DeviceOwned for BufferView<B>
+where
+ B: BufferAccess,
+{
+ #[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()
+ }
+}
+
+impl<B> Drop for BufferView<B>
+where
+ B: BufferAccess,
+{
+ #[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,
+ ptr::null(),
+ );
+ }
+ }
+}
+
+pub unsafe trait BufferViewRef {
+ type BufferAccess: BufferAccess;
+
+ fn view(&self) -> &BufferView<Self::BufferAccess>;
+}
+
+unsafe impl<B> BufferViewRef for BufferView<B>
+where
+ B: BufferAccess,
+{
+ type BufferAccess = B;
+
+ #[inline]
+ fn view(&self) -> &BufferView<B> {
+ self
+ }
+}
+
+unsafe impl<T, B> BufferViewRef for T
+where
+ T: SafeDeref<Target = BufferView<B>>,
+ B: BufferAccess,
+{
+ type BufferAccess = B;
+
+ #[inline]
+ fn view(&self) -> &BufferView<B> {
+ &**self
+ }
+}
+
+/// Error that can happen when creating a buffer view.
+#[derive(Debug, Copy, Clone)]
+pub enum BufferViewCreationError {
+ /// Out of memory.
+ OomError(OomError),
+
+ /// The buffer was not creating with one of the `storage_texel_buffer` or
+ /// `uniform_texel_buffer` usages.
+ WrongBufferUsage,
+
+ /// The offset within the buffer is not a multiple of the `min_texel_buffer_offset_alignment`
+ /// limit.
+ WrongBufferAlignment,
+
+ /// The requested format is not supported for this usage.
+ UnsupportedFormat,
+
+ /// The maximum number of elements in the buffer view 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),
+ _ => 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 From<OomError> for BufferViewCreationError {
+ #[inline]
+ fn from(err: OomError) -> BufferViewCreationError {
+ BufferViewCreationError::OomError(err)
+ }
+}
+
+impl From<Error> for BufferViewCreationError {
+ #[inline]
+ fn from(err: Error) -> BufferViewCreationError {
+ OomError::from(err).into()
+ }
+}
+
+#[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;
+
+ #[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 (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());
+ }
+
+ #[test]
+ fn create_storage() {
+ // `VK_FORMAT_R8G8B8A8_UNORM` guaranteed to be a supported format
+ let (device, queue) = gfx_dev_and_queue!();
+
+ 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());
+ }
+
+ #[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();
+
+ assert!(view.storage_texel_buffer());
+ assert!(view.storage_texel_buffer_atomic());
+ }
+
+ #[test]
+ fn wrong_usage() {
+ // `VK_FORMAT_R8G8B8A8_UNORM` guaranteed to be a supported format
+ let (device, queue) = gfx_dev_and_queue!();
+
+ let (buffer, _) = ImmutableBuffer::<[[u8; 4]]>::from_iter(
+ (0..128).map(|_| [0; 4]),
+ BufferUsage::none(),
+ queue.clone(),
+ )
+ .unwrap();
+
+ match BufferView::new(buffer, Format::R8G8B8A8Unorm) {
+ Err(BufferViewCreationError::WrongBufferUsage) => (),
+ _ => 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 (buffer, _) = ImmutableBuffer::<[[f64; 4]]>::from_iter(
+ (0..128).map(|_| [0.0; 4]),
+ usage,
+ queue.clone(),
+ )
+ .unwrap();
+
+ // TODO: what if R64G64B64A64Sfloat is supported?
+ match BufferView::new(buffer, Format::R64G64B64A64Sfloat) {
+ Err(BufferViewCreationError::UnsupportedFormat) => (),
+ _ => panic!(),
+ }
+ }
+}
diff --git a/src/command_buffer/auto.rs b/src/command_buffer/auto.rs
new file mode 100644
index 0000000..64d0d2d
--- /dev/null
+++ b/src/command_buffer/auto.rs
@@ -0,0 +1,2867 @@
+// 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::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,
+
+ // The inheritance for secondary command buffers.
+ inheritance: Option<CommandBufferInheritance<Box<dyn FramebufferAbstract + Send + Sync>>>,
+
+ // Usage flags passed when creating the command buffer.
+ usage: CommandBufferUsage,
+
+ // If we're inside a render pass, contains the render pass state.
+ render_pass_state: Option<RenderPassState>,
+
+ // If any queries are active, this hashmap contains their state.
+ query_state: FnvHashMap<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 an active query.
+struct QueryState {
+ query_pool: ash::vk::QueryPool,
+ query: u32,
+ ty: QueryType,
+ flags: QueryControlFlags,
+ in_subpass: bool,
+}
+
+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<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,
+ })
+ }
+ }
+}
+
+#[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,
+}
+
+impl error::Error for BeginError {
+ #[inline]
+ fn source(&self) -> Option<&(dyn error::Error + 'static)> {
+ match *self {
+ Self::OomError(ref err) => Some(err),
+ _ => None,
+ }
+ }
+}
+
+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"
+ }
+ }
+ )
+ }
+}
+
+impl From<OomError> for BeginError {
+ #[inline]
+ fn from(err: OomError) -> Self {
+ Self::OomError(err)
+ }
+}
+
+impl<P> AutoCommandBufferBuilder<PrimaryAutoCommandBuffer<P::Alloc>, P>
+where
+ P: CommandPoolBuilderAlloc,
+{
+ /// Builds the 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());
+ }
+
+ 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>
+where
+ P: CommandPoolBuilderAlloc,
+{
+ /// 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(())
+ }
+
+ #[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,
+ {
+ 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()
+ },
+ 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());
+ }
+
+ 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()
+ }
+ } 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());
+ }
+
+ 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)
+ }
+
+ /// 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);
+ }
+
+ Ok(self)
+ }
+
+ /// 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)
+ }
+
+ /// 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());
+ }
+
+ check_debug_marker_color(color)?;
+
+ unsafe {
+ self.inner.debug_marker_insert(name.into(), color);
+ }
+
+ Ok(self)
+ }
+
+ /// 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();
+
+ unsafe {
+ if !self.queue_family().supports_compute() {
+ return Err(AutoCommandBufferBuilderContextError::NotSupportedByQueueFamily.into());
+ }
+
+ 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 StateCacherOutcome::NeedChange =
+ self.state_cacher.bind_compute_pipeline(&pipeline)
+ {
+ self.inner.bind_pipeline_compute(pipeline.clone());
+ }
+
+ 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)
+ }
+ }
+
+ /// 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();
+
+ unsafe {
+ if !self.queue_family().supports_compute() {
+ return Err(AutoCommandBufferBuilderContextError::NotSupportedByQueueFamily.into());
+ }
+
+ 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 StateCacherOutcome::NeedChange =
+ self.state_cacher.bind_compute_pipeline(&pipeline)
+ {
+ self.inner.bind_pipeline_compute(pipeline.clone());
+ }
+
+ 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
+
+ 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)
+ {
+ 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(
+ vb_infos.vertex_count as u32,
+ vb_infos.instance_count as u32,
+ 0,
+ 0,
+ );
+ Ok(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`](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)
+ }
+ }
+
+ /// 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)
+ }
+ }
+
+ /// 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();
+
+ 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(),
+ );
+ }
+
+ 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,
+ )?;
+
+ debug_assert!(self.queue_family().supports_graphics());
+
+ self.inner.draw_indexed_indirect(
+ indirect_buffer,
+ requested,
+ mem::size_of::<DrawIndexedIndirectCommand>() as u32,
+ )?;
+ Ok(self)
+ }
+ }
+
+ /// 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)
+ }
+ }
+
+ /// 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);
+ }
+
+ Ok(self)
+ }
+ }
+
+ /// 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(),
+ );
+ }
+ }
+ 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.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());
+ }
+
+ // 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)
+ }
+
+ /// 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());
+ }
+
+ // 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>
+where
+ P: CommandPoolBuilderAlloc,
+{
+ /// 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)?;
+ }
+
+ 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()?;
+ }
+
+ // 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)
+ }
+
+ // 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()?;
+ }
+
+ 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);
+ }
+ }
+ _ => (),
+ }
+ }
+
+ Ok(())
+ }
+
+ #[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);
+ }
+
+ // Subpasses must be the same.
+ if render_pass.subpass.index() != render_pass_state.subpass.1 {
+ return Err(AutoCommandBufferBuilderContextError::WrongSubpassIndex);
+ }
+
+ // 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);
+ }
+
+ // 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);
+ }
+ }
+
+ 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);
+ }
+
+ debug_assert!(self.queue_family().supports_graphics());
+
+ self.inner.next_subpass(contents);
+ Ok(self)
+ }
+ }
+}
+
+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,
+ );
+ }
+}
+
+// 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);
+ }
+
+ if let Some(reference) = dynamic.reference {
+ destination.set_stencil_reference(StencilFaces::Front, reference.front);
+ destination.set_stencil_reference(StencilFaces::Back, reference.back);
+ }
+}
+
+// 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);
+ }
+ sets_binder.submit(pipeline_bind_point, pipeline_layout.clone(), first_binding)?;
+ Ok(())
+}
+
+pub struct PrimaryAutoCommandBuffer<P = StandardCommandPoolAlloc> {
+ inner: SyncCommandBuffer,
+ pool_alloc: P, // Safety: must be dropped after `inner`
+
+ // Tracks usage of the command buffer on the GPU.
+ submit_state: SubmitState,
+}
+
+unsafe impl<P> DeviceOwned for PrimaryAutoCommandBuffer<P> {
+ #[inline]
+ 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 => (),
+ };
+
+ Err(err)
+ }
+
+ #[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 => (),
+ };
+ }
+
+ #[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)
+ }
+
+ #[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)
+ }
+}
+
+pub struct SecondaryAutoCommandBuffer<P = StandardCommandPoolAlloc> {
+ inner: SyncCommandBuffer,
+ pool_alloc: P, // Safety: must be dropped after `inner`
+ inheritance: CommandBufferInheritance<Box<dyn FramebufferAbstract + Send + Sync>>,
+
+ // Tracks usage of the command buffer on the GPU.
+ submit_state: SubmitState,
+}
+
+unsafe impl<P> DeviceOwned for SecondaryAutoCommandBuffer<P> {
+ #[inline]
+ fn device(&self) -> &Arc<Device> {
+ self.inner.device()
+ }
+}
+
+unsafe impl<P> SecondaryCommandBuffer for SecondaryAutoCommandBuffer<P> {
+ #[inline]
+ fn inner(&self) -> &UnsafeCommandBuffer {
+ self.inner.as_ref()
+ }
+
+ #[inline]
+ fn lock_record(&self) -> 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 => (),
+ };
+
+ Ok(())
+ }
+
+ #[inline]
+ unsafe fn unlock(&self) {
+ 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 => (),
+ };
+ }
+
+ 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)
+ }
+}
+
+// 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,
+ },
+}
+
+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;
+
+ #[test]
+ fn copy_buffer_dimensions() {
+ 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 (device, mut queues) = Device::new(
+ phys,
+ &Features::none(),
+ &DeviceExtensions::none(),
+ std::iter::once((queue_family, 0.5)),
+ )
+ .unwrap();
+
+ let queue = queues.next().unwrap();
+
+ let source = CpuAccessibleBuffer::from_iter(
+ device.clone(),
+ BufferUsage::all(),
+ true,
+ [1_u32, 2].iter().copied(),
+ )
+ .unwrap();
+
+ let destination = CpuAccessibleBuffer::from_iter(
+ device.clone(),
+ BufferUsage::all(),
+ true,
+ [0_u32, 10, 20, 3, 4].iter().copied(),
+ )
+ .unwrap();
+
+ let mut cbb = AutoCommandBufferBuilder::primary(
+ device.clone(),
+ queue.family(),
+ CommandBufferUsage::OneTimeSubmit,
+ )
+ .unwrap();
+
+ cbb.copy_buffer_dimensions(source.clone(), 0, destination.clone(), 1, 2)
+ .unwrap();
+
+ let cb = cbb.build().unwrap();
+
+ let future = cb
+ .execute(queue.clone())
+ .unwrap()
+ .then_signal_fence_and_flush()
+ .unwrap();
+ future.wait(None).unwrap();
+
+ let result = destination.read().unwrap();
+
+ assert_eq!(*result, [0_u32, 1, 2, 3, 4]);
+ }
+
+ #[test]
+ fn secondary_nonconcurrent_conflict() {
+ let (device, queue) = gfx_dev_and_queue!();
+
+ // Make a secondary CB that doesn't support simultaneous use.
+ let builder = AutoCommandBufferBuilder::secondary_compute(
+ device.clone(),
+ queue.family(),
+ CommandBufferUsage::MultipleSubmit,
+ )
+ .unwrap();
+ let secondary = Arc::new(builder.build().unwrap());
+
+ {
+ let mut builder = AutoCommandBufferBuilder::primary(
+ device.clone(),
+ queue.family(),
+ CommandBufferUsage::SimultaneousUse,
+ )
+ .unwrap();
+
+ // Add the secondary a first time
+ builder.execute_commands(secondary.clone()).unwrap();
+
+ // Recording the same non-concurrent secondary command buffer twice into the same
+ // primary is an error.
+ assert!(matches!(
+ builder.execute_commands(secondary.clone()),
+ Err(ExecuteCommandsError::SyncCommandBufferBuilderError(
+ SyncCommandBufferBuilderError::ExecError(
+ CommandBufferExecError::ExclusiveAlreadyInUse
+ )
+ ))
+ ));
+ }
+
+ {
+ let mut builder = AutoCommandBufferBuilder::primary(
+ device.clone(),
+ queue.family(),
+ CommandBufferUsage::SimultaneousUse,
+ )
+ .unwrap();
+ builder.execute_commands(secondary.clone()).unwrap();
+ let cb1 = builder.build().unwrap();
+
+ let mut builder = AutoCommandBufferBuilder::primary(
+ device.clone(),
+ queue.family(),
+ CommandBufferUsage::SimultaneousUse,
+ )
+ .unwrap();
+
+ // Recording the same non-concurrent secondary command buffer into multiple
+ // primaries is an error.
+ assert!(matches!(
+ builder.execute_commands(secondary.clone()),
+ Err(ExecuteCommandsError::SyncCommandBufferBuilderError(
+ SyncCommandBufferBuilderError::ExecError(
+ CommandBufferExecError::ExclusiveAlreadyInUse
+ )
+ ))
+ ));
+
+ std::mem::drop(cb1);
+
+ // Now that the first cb is dropped, we should be able to record.
+ builder.execute_commands(secondary.clone()).unwrap();
+ }
+ }
+}
diff --git a/src/command_buffer/mod.rs b/src/command_buffer/mod.rs
new file mode 100644
index 0000000..b439a4d
--- /dev/null
+++ b/src/command_buffer/mod.rs
@@ -0,0 +1,326 @@
+// 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.
+
+//! Commands that the GPU will execute (includes draw commands).
+//!
+//! 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.
+//!
+//! # Primary and secondary command buffers.
+//!
+//! There are three types of command buffers:
+//!
+//! - **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.
+//!
+//! Using secondary command buffers leads to slightly lower performance on the GPU, but they have
+//! two advantages on the CPU side:
+//!
+//! - 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.
+//!
+//! # The `AutoCommandBufferBuilder`
+//!
+//! 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`.
+//!
+//! 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.
+//!
+//! ```
+//! use vulkano::command_buffer::AutoCommandBufferBuilder;
+//! use vulkano::command_buffer::CommandBufferUsage;
+//! use vulkano::command_buffer::PrimaryCommandBuffer;
+//!
+//! # let device: std::sync::Arc<vulkano::device::Device> = return;
+//! # let queue: std::sync::Arc<vulkano::device::Queue> = return;
+//! let cb = AutoCommandBufferBuilder::primary(
+//! device.clone(),
+//! queue.family(),
+//! CommandBufferUsage::MultipleSubmit
+//! ).unwrap()
+//! // TODO: add an actual command to this example
+//! .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;
+
+mod auto;
+pub mod pool;
+mod state_cacher;
+pub mod submit;
+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)]
+pub struct DrawIndirectCommand {
+ pub vertex_count: u32,
+ pub instance_count: u32,
+ pub first_vertex: u32,
+ pub first_instance: u32,
+}
+
+#[repr(C)]
+#[derive(Debug, Copy, Clone, PartialEq, Eq)]
+pub struct DrawIndexedIndirectCommand {
+ pub index_count: u32,
+ pub instance_count: u32,
+ pub first_index: u32,
+ pub vertex_offset: u32,
+ pub first_instance: u32,
+}
+
+#[repr(C)]
+#[derive(Debug, Copy, Clone, 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>,
+}
+
+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.
+#[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(),
+ /// The subpass will only contain secondary command buffers invocations.
+ SecondaryCommandBuffers = ash::vk::SubpassContents::SECONDARY_COMMAND_BUFFERS.as_raw(),
+}
+
+impl From<SubpassContents> for ash::vk::SubpassContents {
+ #[inline]
+ fn from(val: SubpassContents) -> Self {
+ Self::from_raw(val as i32)
+ }
+}
+
+/// Determines the kind of command buffer to create.
+#[derive(Debug, Clone)]
+pub enum CommandBufferLevel<F> {
+ /// 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,
+
+ /// 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>),
+}
+
+/// 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>>,
+
+ /// 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
+ /// active occlusion is allowed to have enabled.
+ /// If `None`, the primary command buffer cannot have an occlusion query active when this
+ /// secondary command buffer is executed.
+ ///
+ /// The `inherited_queries` feature must be enabled if this is `Some`.
+ 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,
+}
+
+/// The render pass context that a secondary command buffer is created for.
+#[derive(Debug, Clone)]
+pub struct CommandBufferInheritanceRenderPass<F> {
+ /// The render subpass that this secondary command buffer must be executed within.
+ 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>,
+}
+
+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.
+ #[inline]
+ pub fn primary() -> CommandBufferLevel<Arc<Framebuffer<()>>> {
+ CommandBufferLevel::Primary
+ }
+
+ /// Equivalent to `Kind::Secondary`.
+ ///
+ /// > **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.
+ #[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,
+ })
+ }
+}
+
+/// Usage flags to pass when creating a command buffer.
+///
+/// The safest option is `SimultaneousUse`, but it may be slower than the other two.
+// NOTE: The ordering is important: the variants are listed from least to most permissive!
+#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
+#[repr(u32)]
+pub enum CommandBufferUsage {
+ /// The command buffer can only be submitted once before being destroyed. Any further submit is
+ /// forbidden. This makes it possible for the implementation to perform additional
+ /// optimizations.
+ OneTimeSubmit = ash::vk::CommandBufferUsageFlags::ONE_TIME_SUBMIT.as_raw(),
+
+ /// The command buffer can be used multiple times, but must not execute or record more than once
+ /// simultaneously. In other words, it is as if executing the command buffer borrows it mutably.
+ MultipleSubmit = 0,
+
+ /// The command buffer can be executed multiple times in parallel on different queues.
+ /// If it's a secondary command buffer, it can be recorded to multiple primary command buffers
+ /// at once.
+ SimultaneousUse = ash::vk::CommandBufferUsageFlags::SIMULTANEOUS_USE.as_raw(),
+}
+
+impl From<CommandBufferUsage> for ash::vk::CommandBufferUsageFlags {
+ #[inline]
+ fn from(val: CommandBufferUsage) -> Self {
+ Self::from_raw(val as u32)
+ }
+}
diff --git a/src/command_buffer/pool/mod.rs b/src/command_buffer/pool/mod.rs
new file mode 100644
index 0000000..e7a6fb6
--- /dev/null
+++ b/src/command_buffer/pool/mod.rs
@@ -0,0 +1,103 @@
+// 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
new file mode 100644
index 0000000..3bf105a
--- /dev/null
+++ b/src/command_buffer/pool/standard.rs
@@ -0,0 +1,313 @@
+// 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
new file mode 100644
index 0000000..8432182
--- /dev/null
+++ b/src/command_buffer/pool/sys.rs
@@ -0,0 +1,421 @@
+// 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/state_cacher.rs b/src/command_buffer/state_cacher.rs
new file mode 100644
index 0000000..63bfc3d
--- /dev/null
+++ b/src/command_buffer/state_cacher.rs
@@ -0,0 +1,484 @@
+// 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
new file mode 100644
index 0000000..313a09c
--- /dev/null
+++ b/src/command_buffer/submit/bind_sparse.rs
@@ -0,0 +1,511 @@
+// 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
new file mode 100644
index 0000000..53c0d4b
--- /dev/null
+++ b/src/command_buffer/submit/mod.rs
@@ -0,0 +1,52 @@
+// 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
new file mode 100644
index 0000000..28f4229
--- /dev/null
+++ b/src/command_buffer/submit/queue_present.rs
@@ -0,0 +1,279 @@
+// 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
new file mode 100644
index 0000000..8ffa129
--- /dev/null
+++ b/src/command_buffer/submit/queue_submit.rs
@@ -0,0 +1,359 @@
+// 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
new file mode 100644
index 0000000..2ebcfed
--- /dev/null
+++ b/src/command_buffer/submit/semaphores_wait.rs
@@ -0,0 +1,81 @@
+// 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
new file mode 100644
index 0000000..541ccbb
--- /dev/null
+++ b/src/command_buffer/synced/builder.rs
@@ -0,0 +1,748 @@
+// 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::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;
+
+/// Wrapper around `UnsafeCommandBufferBuilder` that handles synchronization for you.
+///
+/// Each method of the `UnsafeCommandBufferBuilder` has an equivalent in this wrapper, except
+/// 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.
+/// Note that all methods are still unsafe, because this builder doesn't check the validity of
+/// 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,
+
+ // 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>>,
+
+ // Prototype for the pipeline barrier that must be submitted before flushing the commands
+ // in `commands`.
+ pending_barrier: UnsafeCommandBufferBuilderPipelineBarrier,
+
+ // Locations within commands that pipeline barriers were inserted. For debugging purposes.
+ // TODO: present only in cfg(debug_assertions)?
+ barriers: Vec<usize>,
+
+ // Only the commands before `first_unflushed` have already been sent to the inner
+ // `UnsafeCommandBufferBuilder`.
+ first_unflushed: usize,
+
+ // If we're currently inside a render pass, contains the index of the `CmdBeginRenderPass`
+ // command.
+ 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>,
+
+ // 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,
+}
+
+impl SyncCommandBufferBuilder {
+ /// Builds a new `SyncCommandBufferBuilder`. The parameters are the same as the
+ /// `UnsafeCommandBufferBuilder::new` function.
+ ///
+ /// # 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())
+ }
+ };
+
+ let cmd = UnsafeCommandBufferBuilder::new(pool_alloc, level, usage)?;
+ Ok(SyncCommandBufferBuilder::from_unsafe_cmd(
+ cmd,
+ is_secondary,
+ inside_render_pass,
+ ))
+ }
+
+ /// Builds a `SyncCommandBufferBuilder` from an existing `UnsafeCommandBufferBuilder`.
+ ///
+ /// # Safety
+ ///
+ /// See `UnsafeCommandBufferBuilder::new()`.
+ ///
+ /// In addition to this, the `UnsafeCommandBufferBuilder` should be empty. If it isn't, then
+ /// you must take into account the fact that the `SyncCommandBufferBuilder` won't be aware of
+ /// any existing resource usage.
+ #[inline]
+ pub unsafe fn from_unsafe_cmd(
+ cmd: UnsafeCommandBufferBuilder,
+ is_secondary: bool,
+ inside_render_pass: bool,
+ ) -> SyncCommandBufferBuilder {
+ let latest_render_pass_enter = if inside_render_pass { Some(0) } else { None };
+
+ SyncCommandBufferBuilder {
+ inner: cmd,
+ commands: Vec::new(),
+ pending_barrier: UnsafeCommandBufferBuilderPipelineBarrier::new(),
+ 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,
+ }
+ }
+
+ // 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.
+ #[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;
+
+ for &(resource_ty, resource) in resources {
+ if let Some((memory, start_layout, end_layout, image_uninitialized_safe)) = resource {
+ // Anti-dumbness checks.
+ 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);
+
+ 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)
+ }
+ };
+
+ 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));
+
+ let entry_key_resource_index = entry.get().resource_index;
+
+ // 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
+ {
+ 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;
+ }
+ }
+ }
+
+ entry.get_mut().command_ids.push(latest_command_id);
+ let entry = entry.into_mut();
+
+ // Modify the pipeline barrier to handle the collision.
+ 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(),
+ );
+ }
+
+ 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,
+ );
+ }
+ };
+ }
+
+ // 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;
+ }
+ } 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;
+ }
+ }
+
+ // 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
+ {
+ 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();
+ }
+ }
+ }
+
+ 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,
+ });
+ }
+ }
+
+ // 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;
+ }
+ }
+ }
+ }
+
+ 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);
+ 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 {
+ 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;
+ }
+
+ 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);
+ }
+ }
+
+ // Build the final resources states.
+ let final_resources_states: FnvHashMap<_, _> = {
+ self.resources
+ .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)
+ })
+ .collect()
+ };
+
+ Ok(SyncCommandBuffer {
+ inner: self.inner.build()?,
+ buffers: self.buffers,
+ images: self.images,
+ resources: final_resources_states,
+ 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 {
+ #[inline]
+ fn device(&self) -> &Arc<Device> {
+ self.inner.device()
+ }
+}
+
+impl fmt::Debug for SyncCommandBufferBuilder {
+ #[inline]
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ fmt::Debug::fmt(&self.inner, f)
+ }
+}
+
+/// Error returned if the builder detects that there's an unsolvable conflict.
+#[derive(Debug, Clone)]
+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,
+ },
+
+ ExecError(CommandBufferExecError),
+}
+
+impl error::Error for SyncCommandBufferBuilderError {}
+
+impl fmt::Display for SyncCommandBufferBuilderError {
+ #[inline]
+ fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
+ match self {
+ SyncCommandBufferBuilderError::Conflict { .. } => write!(fmt, "unsolvable conflict"),
+ SyncCommandBufferBuilderError::ExecError(err) => err.fmt(fmt),
+ }
+ }
+}
+
+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(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,
+
+ // 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,
+
+ // Layout at the first use of the resource by the command buffer. 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,
+}
+
+/// 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>>,
+}
diff --git a/src/command_buffer/synced/commands.rs b/src/command_buffer/synced/commands.rs
new file mode 100644
index 0000000..6b49a5a
--- /dev/null
+++ b/src/command_buffer/synced/commands.rs
@@ -0,0 +1,3123 @@
+// 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
new file mode 100644
index 0000000..4c65dda
--- /dev/null
+++ b/src/command_buffer/synced/mod.rs
@@ -0,0 +1,766 @@
+// 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.
+
+//! Contains `SyncCommandBufferBuilder` and `SyncCommandBuffer`.
+//!
+//! # How pipeline stages work in Vulkan
+//!
+//! Imagine you create a command buffer that contains 10 dispatch commands, and submit that command
+//! buffer. According to the Vulkan specs, the implementation is free to execute the 10 commands
+//! simultaneously.
+//!
+//! Now imagine that the command buffer contains 10 draw commands instead. Contrary to the dispatch
+//! commands, the draw pipeline contains multiple stages: draw indirect, vertex input, vertex shader,
+//! ..., fragment shader, late fragment test, color output. When there are multiple stages, the
+//! implementations must start and end the stages in order. In other words it can start the draw
+//! indirect stage of all 10 commands, then start the vertex input stage of all 10 commands, and so
+//! on. But it can't for example start the fragment shader stage of a command before starting the
+//! vertex shader stage of another command. Same thing for ending the stages in the right order.
+//!
+//! Depending on the type of the command, the pipeline stages are different. Compute shaders use the
+//! compute stage, while transfer commands use the transfer stage. The compute and transfer stages
+//! aren't ordered.
+//!
+//! When you submit multiple command buffers to a queue, the implementation doesn't do anything in
+//! particular and behaves as if the command buffers were appended to one another. Therefore if you
+//! submit a command buffer with 10 dispatch commands, followed with another command buffer with 5
+//! dispatch commands, then the implementation can perform the 15 commands simultaneously.
+//!
+//! ## Introducing barriers
+//!
+//! In some situations this is not the desired behaviour. If you add a command that writes to a
+//! buffer followed with another command that reads that buffer, you don't want them to execute
+//! simultaneously. Instead you want the second one to wait until the first one is finished. This
+//! is done by adding a pipeline barrier between the two commands.
+//!
+//! A pipeline barriers has a source stage and a destination stage (plus various other things).
+//! A barrier represents a split in the list of commands. When you add it, the stages of the commands
+//! before the barrier corresponding to the source stage of the barrier, must finish before the
+//! stages of the commands after the barrier corresponding to the destination stage of the barrier
+//! can start.
+//!
+//! For example if you add a barrier that transitions from the compute stage to the compute stage,
+//! then the compute stage of all the commands before the barrier must end before the compute stage
+//! of all the commands after the barrier can start. This is appropriate for the example about
+//! writing then reading the same buffer.
+//!
+//! ## Batching barriers
+//!
+//! Since barriers are "expensive" (as the queue must block), vulkano attempts to group as many
+//! pipeline barriers as possible into one.
+//!
+//! Adding a command to a sync command buffer builder does not immediately add it to the underlying
+//! command buffer builder. Instead the command is added to a queue, and the builder keeps a
+//! prototype of a barrier that must be added before the commands in the queue are flushed.
+//!
+//! Whenever you add a command, the builder will find out whether a barrier is needed before the
+//! command. If so, it will try to merge this barrier with the prototype and add the command to the
+//! 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;
+
+mod builder;
+
+/// Command buffer built from a `SyncCommandBufferBuilder` that provides utilities to handle
+/// synchronization.
+pub struct SyncCommandBuffer {
+ // The actual Vulkan command buffer.
+ inner: UnsafeCommandBuffer,
+
+ // 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>>,
+
+ // Locations within commands that pipeline barriers were inserted. For debugging purposes.
+ // TODO: present only in cfg(debug_assertions)?
+ barriers: Vec<usize>,
+
+ // State of all the resources used by this command buffer.
+ resources: FnvHashMap<ResourceKey, ResourceFinalState>,
+
+ // Resources and their accesses. Used for executing secondary command buffers in a primary.
+ buffers: Vec<(ResourceLocation, PipelineMemoryAccess)>,
+ images: Vec<(
+ ResourceLocation,
+ PipelineMemoryAccess,
+ ImageLayout,
+ ImageLayout,
+ ImageUninitializedSafe,
+ )>,
+}
+
+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)
+ })
+ }
+
+ #[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,
+ )
+ },
+ )
+ }
+}
+
+impl AsRef<UnsafeCommandBuffer> for SyncCommandBuffer {
+ #[inline]
+ fn as_ref(&self) -> &UnsafeCommandBuffer {
+ &self.inner
+ }
+}
+
+unsafe impl DeviceOwned for SyncCommandBuffer {
+ #[inline]
+ fn device(&self) -> &Arc<Device> {
+ self.inner.device()
+ }
+}
+
+// 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,
+}
+
+// Trait for single commands within the list of commands.
+trait Command {
+ // 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 {
+ 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;
+
+ #[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 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,
+ )
+ .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 { .. })
+ ));
+ }
+ }
+
+ #[test]
+ fn secondary_conflicting_writes() {
+ unsafe {
+ let (device, queue) = gfx_dev_and_queue!();
+
+ // Create a tiny test buffer
+ let (buf, future) = ImmutableBuffer::from_data(
+ 0u32,
+ BufferUsage::transfer_destination(),
+ queue.clone(),
+ )
+ .unwrap();
+ future
+ .then_signal_fence_and_flush()
+ .unwrap()
+ .wait(None)
+ .unwrap();
+
+ // 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(),
+ CommandBufferUsage::SimultaneousUse,
+ )
+ .unwrap();
+ builder.fill_buffer(buf.clone(), 42u32).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 mut builder = SyncCommandBufferBuilder::new(
+ allocs[0].inner(),
+ CommandBufferLevel::primary(),
+ CommandBufferUsage::SimultaneousUse,
+ )
+ .unwrap();
+
+ // Add both secondary command buffers using separate execute_commands calls.
+ secondary.iter().cloned().for_each(|secondary| {
+ let mut ec = builder.execute_commands();
+ ec.add(secondary);
+ ec.submit().unwrap();
+ });
+
+ let primary = builder.build().unwrap();
+ let names = primary
+ .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]);
+ }
+
+ {
+ let mut builder = SyncCommandBufferBuilder::new(
+ allocs[1].inner(),
+ CommandBufferLevel::primary(),
+ CommandBufferUsage::SimultaneousUse,
+ )
+ .unwrap();
+
+ // Add a single execute_commands for all secondary command buffers at once
+ let mut ec = builder.execute_commands();
+ 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 { .. })
+ ));
+ }
+ }
+ }
+
+ #[test]
+ fn vertex_buffer_binding() {
+ 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(),
+ CommandBufferLevel::primary(),
+ CommandBufferUsage::MultipleSubmit,
+ )
+ .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();
+
+ assert!(sync.bound_vertex_buffer(0).is_none());
+ assert!(sync.bound_vertex_buffer(1).is_some());
+ assert!(sync.bound_vertex_buffer(2).is_none());
+ }
+ }
+
+ #[test]
+ fn descriptor_set_binding() {
+ 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(),
+ CommandBufferLevel::primary(),
+ CommandBufferUsage::MultipleSubmit,
+ )
+ .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();
+
+ assert!(sync
+ .bound_descriptor_set(PipelineBindPoint::Compute, 0)
+ .is_none());
+ assert!(sync
+ .bound_descriptor_set(PipelineBindPoint::Graphics, 0)
+ .is_none());
+ assert!(sync
+ .bound_descriptor_set(PipelineBindPoint::Graphics, 1)
+ .is_some());
+ assert!(sync
+ .bound_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();
+
+ assert!(sync
+ .bound_descriptor_set(PipelineBindPoint::Graphics, 0)
+ .is_some());
+ assert!(sync
+ .bound_descriptor_set(PipelineBindPoint::Graphics, 1)
+ .is_none());
+ }
+ }
+}
diff --git a/src/command_buffer/synced/tests.rs b/src/command_buffer/synced/tests.rs
new file mode 100644
index 0000000..d40654b
--- /dev/null
+++ b/src/command_buffer/synced/tests.rs
@@ -0,0 +1,52 @@
+// 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
new file mode 100644
index 0000000..0fb8b58
--- /dev/null
+++ b/src/command_buffer/sys.rs
@@ -0,0 +1,1972 @@
+// 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::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;
+use smallvec::SmallVec;
+use std::ffi::CStr;
+use std::fmt;
+use std::mem;
+use std::ops::Range;
+use std::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.
+///
+/// When you are finished adding commands, you can use the `CommandBufferBuild` trait to turn this
+/// builder into an `UnsafeCommandBuffer`.
+pub struct UnsafeCommandBufferBuilder {
+ command_buffer: ash::vk::CommandBuffer,
+ 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.
+ ///
+ /// # Safety
+ ///
+ /// - `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,
+ };
+
+ let device = pool_alloc.device().clone();
+ let fns = device.fns();
+
+ 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(),
+ };
+
+ a | b
+ };
+
+ 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()
+ }
+ 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)
+ }
+ 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 infos = ash::vk::CommandBufferBeginInfo {
+ flags: vk_flags,
+ p_inheritance_info: &inheritance,
+ ..Default::default()
+ };
+
+ check_errors(
+ fns.v1_0
+ .begin_command_buffer(pool_alloc.internal_object(), &infos),
+ )?;
+
+ Ok(UnsafeCommandBufferBuilder {
+ command_buffer: pool_alloc.internal_object(),
+ device: device.clone(),
+ usage,
+ })
+ }
+
+ /// Turns the builder into an actual command buffer.
+ #[inline]
+ pub fn build(self) -> Result<UnsafeCommandBuffer, OomError> {
+ unsafe {
+ let fns = self.device.fns();
+ check_errors(fns.v1_0.end_command_buffer(self.command_buffer))?;
+
+ Ok(UnsafeCommandBuffer {
+ command_buffer: self.command_buffer,
+ 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);
+ }
+
+ /// 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);
+ }
+}
+
+unsafe impl DeviceOwned for UnsafeCommandBufferBuilder {
+ #[inline]
+ fn device(&self) -> &Arc<Device> {
+ &self.device
+ }
+}
+
+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.
+ ///
+ #[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();
+ }
+
+ 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`.
+ ///
+ /// # 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);
+
+ 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)
+ };
+
+ if image.format().ty() == FormatTy::Ycbcr {
+ unimplemented!();
+ }
+
+ // 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()
+ });
+ }
+}
+
+/// Command buffer that has been built.
+///
+/// # Safety
+///
+/// The command buffer must not outlive the command pool that it was created from,
+/// nor the resources used by the recorded commands.
+pub struct UnsafeCommandBuffer {
+ command_buffer: ash::vk::CommandBuffer,
+ device: Arc<Device>,
+ usage: CommandBufferUsage,
+}
+
+impl UnsafeCommandBuffer {
+ #[inline]
+ pub fn usage(&self) -> CommandBufferUsage {
+ self.usage
+ }
+}
+
+unsafe impl DeviceOwned for UnsafeCommandBuffer {
+ #[inline]
+ fn device(&self) -> &Arc<Device> {
+ &self.device
+ }
+}
+
+unsafe impl VulkanObject for UnsafeCommandBuffer {
+ type Object = ash::vk::CommandBuffer;
+
+ #[inline]
+ fn internal_object(&self) -> ash::vk::CommandBuffer {
+ self.command_buffer
+ }
+}
diff --git a/src/command_buffer/traits.rs b/src/command_buffer/traits.rs
new file mode 100644
index 0000000..5252073
--- /dev/null
+++ b/src/command_buffer/traits.rs
@@ -0,0 +1,528 @@
+// 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::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>;
+
+ /// 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);
+
+ /// 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.
+ ///
+ /// 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.
+ ///
+ /// > **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 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>
+ where
+ Self: Sized + 'static,
+ {
+ let device = queue.device().clone();
+ self.execute_after(now(device), queue)
+ }
+
+ /// 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.
+ ///
+ /// 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.
+ ///
+ /// > **Note**: In the future this function may return `-> impl GpuFuture` instead of a
+ /// > concrete type.
+ ///
+ /// This function requires the `'static` lifetime to be on the command buffer. This is because
+ /// this function returns a `CommandBufferExecFuture` whose job is to lock resources and keep
+ /// them alive while they are in use by the GPU. If `'static` wasn't required, you could call
+ /// `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 if the device of the command buffer is not the same as the device of the future.
+ #[inline]
+ fn execute_after<F>(
+ self,
+ future: F,
+ queue: Arc<Queue>,
+ ) -> Result<CommandBufferExecFuture<F, Self>, CommandBufferExecError>
+ where
+ Self: Sized + 'static,
+ F: GpuFuture,
+ {
+ assert_eq!(
+ self.device().internal_object(),
+ future.device().internal_object()
+ );
+
+ if !future.queue_change_allowed() {
+ assert!(future.queue().unwrap().is_same(&queue));
+ }
+
+ self.lock_submit(&future, &queue)?;
+
+ Ok(CommandBufferExecFuture {
+ previous: future,
+ command_buffer: 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>;
+
+ fn check_image_access(
+ &self,
+ image: &dyn ImageAccess,
+ layout: ImageLayout,
+ exclusive: bool,
+ queue: &Queue,
+ ) -> Result<Option<(PipelineStages, AccessFlags)>, AccessCheckError>;
+}
+
+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)
+ }
+
+ #[inline]
+ unsafe fn unlock(&self) {
+ (**self).unlock();
+ }
+
+ #[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)
+ }
+
+ #[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)
+ }
+}
+
+pub unsafe trait SecondaryCommandBuffer: DeviceOwned {
+ /// Returns the underlying `UnsafeCommandBuffer` of this command buffer.
+ fn inner(&self) -> &UnsafeCommandBuffer;
+
+ /// Checks whether this command buffer is allowed to be recorded to a command buffer,
+ /// and if so locks it.
+ ///
+ /// If you call this function, then you should call `unlock` afterwards.
+ fn lock_record(&self) -> Result<(), CommandBufferExecError>;
+
+ /// Unlocks the command buffer. Should be called once for each call to `lock_record`.
+ ///
+ /// # Safety
+ ///
+ /// 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,
+ )>;
+}
+
+unsafe impl<T> SecondaryCommandBuffer for T
+where
+ T: SafeDeref,
+ T::Target: SecondaryCommandBuffer,
+{
+ #[inline]
+ fn inner(&self) -> &UnsafeCommandBuffer {
+ (**self).inner()
+ }
+
+ #[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)
+ }
+}
+
+/// Represents a command buffer being executed by the GPU and the moment when the execution
+/// finishes.
+#[must_use = "Dropping this object will immediately block the thread until the GPU has finished processing the submission"]
+pub struct CommandBufferExecFuture<F, Cb>
+where
+ F: GpuFuture,
+ Cb: PrimaryCommandBuffer,
+{
+ previous: F,
+ command_buffer: Cb,
+ 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.
+ // Therefore we use a `Mutex<bool>` and not an `AtomicBool`.
+ submitted: Mutex<bool>,
+ finished: AtomicBool,
+}
+
+unsafe impl<F, Cb> GpuFuture for CommandBufferExecFuture<F, Cb>
+where
+ F: GpuFuture,
+ Cb: PrimaryCommandBuffer,
+{
+ #[inline]
+ fn cleanup_finished(&mut self) {
+ self.previous.cleanup_finished();
+ }
+
+ unsafe fn build_submission(&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::SemaphoresWait(sem) => {
+ let mut builder: SubmitCommandBufferBuilder = sem.into();
+ builder.add_command_buffer(self.command_buffer.inner());
+ SubmitAnyBuilder::CommandBuffer(builder)
+ }
+ SubmitAnyBuilder::CommandBuffer(mut builder) => {
+ // FIXME: add pipeline barrier
+ builder.add_command_buffer(self.command_buffer.inner());
+ SubmitAnyBuilder::CommandBuffer(builder)
+ }
+ SubmitAnyBuilder::QueuePresent(_) | SubmitAnyBuilder::BindSparse(_) => {
+ unimplemented!() // TODO:
+ /*present.submit(); // TODO: wrong
+ let mut builder = SubmitCommandBufferBuilder::new();
+ builder.add_command_buffer(self.command_buffer.inner());
+ SubmitAnyBuilder::CommandBuffer(builder)*/
+ }
+ })
+ }
+
+ #[inline]
+ fn flush(&self) -> Result<(), FlushError> {
+ unsafe {
+ let mut submitted = self.submitted.lock().unwrap();
+ if *submitted {
+ return Ok(());
+ }
+
+ let queue = self.queue.clone();
+
+ match self.build_submission()? {
+ SubmitAnyBuilder::Empty => {}
+ SubmitAnyBuilder::CommandBuffer(builder) => {
+ builder.submit(&queue)?;
+ }
+ _ => unreachable!(),
+ };
+
+ // Only write `true` here in order to try again next time if we failed to submit.
+ *submitted = true;
+ Ok(())
+ }
+ }
+
+ #[inline]
+ unsafe fn signal_finished(&self) {
+ if self.finished.swap(true, Ordering::SeqCst) == false {
+ self.command_buffer.unlock();
+ }
+
+ 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,
+ exclusive: bool,
+ queue: &Queue,
+ ) -> Result<Option<(PipelineStages, AccessFlags)>, AccessCheckError> {
+ match self
+ .command_buffer
+ .check_buffer_access(buffer, exclusive, queue)
+ {
+ Ok(v) => Ok(v),
+ Err(AccessCheckError::Denied(err)) => Err(AccessCheckError::Denied(err)),
+ Err(AccessCheckError::Unknown) => {
+ self.previous.check_buffer_access(buffer, exclusive, queue)
+ }
+ }
+ }
+
+ #[inline]
+ fn check_image_access(
+ &self,
+ image: &dyn ImageAccess,
+ layout: ImageLayout,
+ exclusive: bool,
+ queue: &Queue,
+ ) -> Result<Option<(PipelineStages, AccessFlags)>, AccessCheckError> {
+ match self
+ .command_buffer
+ .check_image_access(image, layout, exclusive, queue)
+ {
+ Ok(v) => Ok(v),
+ Err(AccessCheckError::Denied(err)) => Err(AccessCheckError::Denied(err)),
+ Err(AccessCheckError::Unknown) => self
+ .previous
+ .check_image_access(image, layout, exclusive, queue),
+ }
+ }
+}
+
+unsafe impl<F, Cb> DeviceOwned for CommandBufferExecFuture<F, Cb>
+where
+ F: GpuFuture,
+ Cb: PrimaryCommandBuffer,
+{
+ #[inline]
+ fn device(&self) -> &Arc<Device> {
+ self.command_buffer.device()
+ }
+}
+
+impl<F, Cb> Drop for CommandBufferExecFuture<F, Cb>
+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();
+ }
+ }
+ }
+}
+
+/// Error that can happen when attempting to execute a command buffer.
+#[derive(Clone, Debug, PartialEq, Eq)]
+pub enum CommandBufferExecError {
+ /// Access to a resource has been denied.
+ AccessError {
+ error: AccessError,
+ command_name: Cow<'static, str>,
+ command_param: Cow<'static, str>,
+ command_offset: usize,
+ },
+
+ /// 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,
+ // 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),
+ _ => None,
+ }
+ }
+}
+
+impl fmt::Display for CommandBufferExecError {
+ #[inline]
+ fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
+ write!(
+ fmt,
+ "{}",
+ 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"
+ }
+ 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"
+ }
+ }
+ )
+ }
+}
diff --git a/src/command_buffer/validity/blit_image.rs b/src/command_buffer/validity/blit_image.rs
new file mode 100644
index 0000000..aae58f6
--- /dev/null
+++ b/src/command_buffer/validity/blit_image.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.
+
+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
new file mode 100644
index 0000000..6ecb68f
--- /dev/null
+++ b/src/command_buffer/validity/clear_color_image.rs
@@ -0,0 +1,81 @@
+// 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
new file mode 100644
index 0000000..3691860
--- /dev/null
+++ b/src/command_buffer/validity/copy_buffer.rs
@@ -0,0 +1,103 @@
+// 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
new file mode 100644
index 0000000..b55e73d
--- /dev/null
+++ b/src/command_buffer/validity/copy_image.rs
@@ -0,0 +1,243 @@
+// 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
new file mode 100644
index 0000000..77224b1
--- /dev/null
+++ b/src/command_buffer/validity/copy_image_buffer.rs
@@ -0,0 +1,266 @@
+// 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
new file mode 100644
index 0000000..9a80e7f
--- /dev/null
+++ b/src/command_buffer/validity/debug_marker.rs
@@ -0,0 +1,32 @@
+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
new file mode 100644
index 0000000..227101b
--- /dev/null
+++ b/src/command_buffer/validity/descriptor_sets.rs
@@ -0,0 +1,109 @@
+// 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
new file mode 100644
index 0000000..297c1f6
--- /dev/null
+++ b/src/command_buffer/validity/dispatch.rs
@@ -0,0 +1,88 @@
+// 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
new file mode 100644
index 0000000..f9a65ad
--- /dev/null
+++ b/src/command_buffer/validity/dynamic_state.rs
@@ -0,0 +1,215 @@
+// 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
new file mode 100644
index 0000000..a02f47d
--- /dev/null
+++ b/src/command_buffer/validity/fill_buffer.rs
@@ -0,0 +1,105 @@
+// 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
new file mode 100644
index 0000000..52f2bdc
--- /dev/null
+++ b/src/command_buffer/validity/index_buffer.rs
@@ -0,0 +1,148 @@
+// 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
new file mode 100644
index 0000000..3acd4b2
--- /dev/null
+++ b/src/command_buffer/validity/indirect_buffer.rs
@@ -0,0 +1,72 @@
+// 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
new file mode 100644
index 0000000..d4c7a9e
--- /dev/null
+++ b/src/command_buffer/validity/mod.rs
@@ -0,0 +1,50 @@
+// 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
new file mode 100644
index 0000000..65b749e
--- /dev/null
+++ b/src/command_buffer/validity/push_constants.rs
@@ -0,0 +1,52 @@
+// 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
new file mode 100644
index 0000000..52781f4
--- /dev/null
+++ b/src/command_buffer/validity/query.rs
@@ -0,0 +1,391 @@
+// 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
new file mode 100644
index 0000000..39f60be
--- /dev/null
+++ b/src/command_buffer/validity/update_buffer.rs
@@ -0,0 +1,181 @@
+// 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
new file mode 100644
index 0000000..9031498
--- /dev/null
+++ b/src/command_buffer/validity/vertex_buffers.rs
@@ -0,0 +1,118 @@
+// 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/collection.rs b/src/descriptor_set/collection.rs
new file mode 100644
index 0000000..d62c15a
--- /dev/null
+++ b/src/descriptor_set/collection.rs
@@ -0,0 +1,71 @@
+// 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::DescriptorSetWithOffsets;
+
+/// A collection of descriptor set objects.
+pub unsafe trait DescriptorSetsCollection {
+ fn into_vec(self) -> Vec<DescriptorSetWithOffsets>;
+}
+
+unsafe impl DescriptorSetsCollection for () {
+ #[inline]
+ fn into_vec(self) -> Vec<DescriptorSetWithOffsets> {
+ vec![]
+ }
+}
+
+unsafe impl<T> DescriptorSetsCollection for T
+where
+ T: Into<DescriptorSetWithOffsets>,
+{
+ #[inline]
+ fn into_vec(self) -> Vec<DescriptorSetWithOffsets> {
+ vec![self.into()]
+ }
+}
+
+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()
+ }
+}
+
+macro_rules! impl_collection {
+ ($first:ident $(, $others:ident)+) => (
+ unsafe impl<$first$(, $others)+> DescriptorSetsCollection for ($first, $($others),+)
+ where $first: Into<DescriptorSetWithOffsets>
+ $(, $others: Into<DescriptorSetWithOffsets>)*
+ {
+ #[inline]
+ 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
+ }
+ }
+
+ impl_collection!($($others),+);
+ );
+
+ ($i:ident) => ();
+}
+
+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/descriptor_set/fixed_size_pool.rs b/src/descriptor_set/fixed_size_pool.rs
new file mode 100644
index 0000000..248f794
--- /dev/null
+++ b/src/descriptor_set/fixed_size_pool.rs
@@ -0,0 +1,604 @@
+// 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/desc.rs b/src/descriptor_set/layout/desc.rs
new file mode 100644
index 0000000..1516861
--- /dev/null
+++ b/src/descriptor_set/layout/desc.rs
@@ -0,0 +1,889 @@
+// 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
new file mode 100644
index 0000000..272e480
--- /dev/null
+++ b/src/descriptor_set/layout/mod.rs
@@ -0,0 +1,29 @@
+// 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
new file mode 100644
index 0000000..656f767
--- /dev/null
+++ b/src/descriptor_set/layout/sys.rs
@@ -0,0 +1,202 @@
+// 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
new file mode 100644
index 0000000..b69deee
--- /dev/null
+++ b/src/descriptor_set/mod.rs
@@ -0,0 +1,287 @@
+// 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.
+
+//! Bindings between shaders and the resources they access.
+//!
+//! # Overview
+//!
+//! In order to access a buffer or an image from a shader, that buffer or image must be put in a
+//! *descriptor*. Each descriptor contains one buffer or one image alongside with the way that it
+//! can be accessed. A descriptor can also be an array, in which case it contains multiple buffers
+//! or images that all have the same layout.
+//!
+//! Descriptors are grouped in what is called *descriptor sets*. In Vulkan you don't bind
+//! individual descriptors one by one, but you create then bind descriptor sets one by one. As
+//! binding a descriptor set has (small but non-null) a cost, you are encouraged to put descriptors
+//! that are often used together in the same set so that you can keep the same set binding through
+//! multiple draws.
+//!
+//! # Example
+//!
+//! > **Note**: This section describes the simple way to bind resources. There are more optimized
+//! > ways.
+//!
+//! There are two steps to give access to a resource in a shader: creating the descriptor set, and
+//! passing the descriptor sets when drawing.
+//!
+//! ## Creating a descriptor set
+//!
+//! TODO: write example for: PersistentDescriptorSet::start(layout.clone()).add_buffer(data_buffer.clone())
+//!
+//! ## Passing the descriptor set when drawing
+//!
+//! TODO: write
+//!
+//! # When drawing
+//!
+//! When you call a function that adds a draw command to a command buffer, one of the parameters
+//! corresponds to the list of descriptor sets to use. Vulkano will check that what you passed is
+//! compatible with the layout of the pipeline.
+//!
+//! TODO: talk about perfs of changing sets
+//!
+//! # Descriptor sets creation and management
+//!
+//! There are three concepts in Vulkan related to descriptor sets:
+//!
+//! - 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
+//! 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.
+//! - A `DescriptorSet` contains the bindings to resources and is allocated from a pool. This is
+//! 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
+//! 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;
+
+mod collection;
+pub mod fixed_size_pool;
+pub mod layout;
+pub mod persistent;
+pub mod pool;
+pub mod sys;
+
+/// 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 {
+ /// Returns the inner `UnsafeDescriptorSet`.
+ fn inner(&self) -> &UnsafeDescriptorSet;
+
+ /// Returns the layout of this descriptor set.
+ fn layout(&self) -> &Arc<DescriptorSetLayout>;
+
+ /// Creates a [`DescriptorSetWithOffsets`] with the given dynamic offsets.
+ fn offsets<I>(self, dynamic_offsets: I) -> DescriptorSetWithOffsets
+ where
+ Self: Sized + Send + Sync + 'static,
+ I: IntoIterator<Item = u32>,
+ {
+ DescriptorSetWithOffsets::new(self, dynamic_offsets)
+ }
+
+ /// Returns the number of buffers within this descriptor set.
+ fn num_buffers(&self) -> usize;
+
+ /// 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)>;
+
+ /// Returns the number of images within this descriptor set.
+ fn num_images(&self) -> usize;
+
+ /// 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)>;
+}
+
+unsafe impl<T> DescriptorSet for T
+where
+ T: SafeDeref,
+ T::Target: DescriptorSet,
+{
+ #[inline]
+ fn inner(&self) -> &UnsafeDescriptorSet {
+ (**self).inner()
+ }
+
+ #[inline]
+ fn layout(&self) -> &Arc<DescriptorSetLayout> {
+ (**self).layout()
+ }
+
+ #[inline]
+ fn num_buffers(&self) -> usize {
+ (**self).num_buffers()
+ }
+
+ #[inline]
+ fn buffer(&self, index: usize) -> Option<(&dyn BufferAccess, u32)> {
+ (**self).buffer(index)
+ }
+
+ #[inline]
+ fn num_images(&self) -> usize {
+ (**self).num_images()
+ }
+
+ #[inline]
+ fn image(&self, index: usize) -> Option<(&dyn ImageViewAbstract, u32)> {
+ (**self).image(index)
+ }
+}
+
+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()
+ }
+}
+
+impl Eq for dyn DescriptorSet + Send + Sync {}
+
+impl Hash for dyn DescriptorSet + Send + Sync {
+ #[inline]
+ fn hash<H: Hasher>(&self, state: &mut H) {
+ self.inner().internal_object().hash(state);
+ self.device().hash(state);
+ }
+}
+
+pub struct DescriptorSetWithOffsets {
+ descriptor_set: Box<dyn DescriptorSet + Send + Sync>,
+ 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,
+ }
+ }
+
+ #[inline]
+ pub fn as_ref(&self) -> (&dyn DescriptorSet, &[u32]) {
+ (&self.descriptor_set, &self.dynamic_offsets)
+ }
+
+ #[inline]
+ pub fn into_tuple(
+ self,
+ ) -> (
+ Box<dyn DescriptorSet + Send + Sync>,
+ impl ExactSizeIterator<Item = u32>,
+ ) {
+ (self.descriptor_set, self.dynamic_offsets.into_iter())
+ }
+}
+
+impl<S> From<S> for DescriptorSetWithOffsets
+where
+ S: DescriptorSet + Send + Sync + 'static,
+{
+ #[inline]
+ fn from(descriptor_set: S) -> Self {
+ Self::new(descriptor_set, std::iter::empty())
+ }
+}
diff --git a/src/descriptor_set/persistent.rs b/src/descriptor_set/persistent.rs
new file mode 100644
index 0000000..c949f88
--- /dev/null
+++ b/src/descriptor_set/persistent.rs
@@ -0,0 +1,1304 @@
+// 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 simple, immutable descriptor set that is expected to be long-lived.
+//!
+//! Creating a persistent descriptor set allocates from a pool, and can't be modified once created.
+//! You are therefore encouraged to create them at initialization and not the during
+//! performance-critical paths.
+//!
+//! > **Note**: You can control of the pool that is used to create the descriptor set, if you wish
+//! > so. By creating a implementation of the `DescriptorPool` trait that doesn't perform any
+//! > 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
+//! 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;
+
+/// 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()
+ }
+}
+
+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.
+ ///
+ #[inline]
+ pub fn add_image<T>(
+ self,
+ image_view: T,
+ ) -> Result<
+ PersistentDescriptorSetBuilder<(R, PersistentDescriptorSetImg<T>)>,
+ PersistentDescriptorSetError,
+ >
+ where
+ T: ImageViewAbstract,
+ {
+ self.enter_array()?.add_image(image_view)?.leave_array()
+ }
+
+ /// 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<
+ PersistentDescriptorSetBuilder<(
+ (R, PersistentDescriptorSetImg<T>),
+ PersistentDescriptorSetSampler,
+ )>,
+ PersistentDescriptorSetError,
+ >
+ where
+ T: ImageViewAbstract,
+ {
+ 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()
+ );
+
+ 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,
+ ));
+ }
+
+ 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()
+ );
+
+ 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
+ }
+
+ #[inline]
+ fn image(&self, _: usize) -> Option<(&dyn ImageViewAbstract, u32)> {
+ None
+ }
+}
+
+/// 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>)
+where
+ R: PersistentDescriptorSetResources,
+ B: BufferAccess,
+{
+ #[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.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)
+ }
+}
+
+/// Internal object related to the `PersistentDescriptorSet` system.
+pub struct PersistentDescriptorSetBufView<V>
+where
+ V: BufferViewRef,
+{
+ 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)
+ }
+}
+
+/// 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>)
+where
+ R: PersistentDescriptorSetResources,
+ I: ImageViewAbstract,
+{
+ #[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
+ }
+ }
+}
+
+/// Internal object related to the `PersistentDescriptorSet` system.
+pub struct PersistentDescriptorSetSampler {
+ sampler: Arc<Sampler>,
+}
+
+unsafe impl<R> PersistentDescriptorSetResources for (R, PersistentDescriptorSetSampler)
+where
+ R: PersistentDescriptorSetResources,
+{
+ #[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",
+ }
+ )
+ }
+}
diff --git a/src/descriptor_set/pool/mod.rs b/src/descriptor_set/pool/mod.rs
new file mode 100644
index 0000000..e29209c
--- /dev/null
+++ b/src/descriptor_set/pool/mod.rs
@@ -0,0 +1,220 @@
+// 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
new file mode 100644
index 0000000..287cac1
--- /dev/null
+++ b/src/descriptor_set/pool/standard.rs
@@ -0,0 +1,213 @@
+// 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
new file mode 100644
index 0000000..134ddc7
--- /dev/null
+++ b/src/descriptor_set/pool/sys.rs
@@ -0,0 +1,503 @@
+// 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
new file mode 100644
index 0000000..d1c7cc1
--- /dev/null
+++ b/src/descriptor_set/sys.rs
@@ -0,0 +1,588 @@
+// 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 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 smallvec::SmallVec;
+use std::fmt;
+use std::ptr;
+use std::sync::Arc;
+
+/// 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`.
+pub struct UnsafeDescriptorSet {
+ pub(super) set: ash::vk::DescriptorSet,
+}
+
+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
+
+ /// 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());
+
+ // 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()
+ });
+
+ 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);
+ }
+ 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);
+ }
+ 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()));
+ }
+ }
+
+ 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);
+ }
+ }
+ }
+ }
+
+ // 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(),
+ };
+
+ 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(),
+ );
+ }
+ }
+}
+
+unsafe impl VulkanObject for UnsafeDescriptorSet {
+ type Object = ash::vk::DescriptorSet;
+
+ #[inline]
+ fn internal_object(&self) -> ash::vk::DescriptorSet {
+ self.set
+ }
+}
+
+impl fmt::Debug for UnsafeDescriptorSet {
+ fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
+ write!(fmt, "<Vulkan descriptor set {:?}>", self.set)
+ }
+}
+
+/// 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,
+ }
+ }
+}
diff --git a/src/device/extensions.rs b/src/device/extensions.rs
new file mode 100644
index 0000000..b6d0c44
--- /dev/null
+++ b/src/device/extensions.rs
@@ -0,0 +1,174 @@
+// 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::PhysicalDevice;
+pub use crate::extensions::{
+ ExtensionRestriction, ExtensionRestrictionError, SupportedExtensionsError,
+};
+
+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(());
+
+#[cfg(test)]
+mod tests {
+ use crate::device::DeviceExtensions;
+ use std::ffi::CString;
+
+ #[test]
+ fn empty_extensions() {
+ let d: Vec<CString> = (&DeviceExtensions::none()).into();
+ assert!(d.iter().next().is_none());
+ }
+
+ #[test]
+ fn required_if_supported_extensions() {
+ assert_eq!(
+ DeviceExtensions::required_if_supported_extensions(),
+ DeviceExtensions {
+ khr_portability_subset: true,
+ ..DeviceExtensions::none()
+ }
+ )
+ }
+}
diff --git a/src/device/features.rs b/src/device/features.rs
new file mode 100644
index 0000000..1d83545
--- /dev/null
+++ b/src/device/features.rs
@@ -0,0 +1,290 @@
+// 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;
+
+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;
+
+/// An error that can happen when enabling a feature on a device.
+#[derive(Clone, Copy, Debug)]
+pub struct FeatureRestrictionError {
+ /// The feature in question.
+ pub feature: &'static str,
+ /// The restriction that was not met.
+ pub restriction: FeatureRestriction,
+}
+
+impl error::Error for FeatureRestrictionError {}
+
+impl fmt::Display for FeatureRestrictionError {
+ #[inline]
+ fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
+ write!(
+ fmt,
+ "a restriction for the feature {} was not met: {}",
+ self.feature, self.restriction,
+ )
+ }
+}
+
+#[derive(Clone, Copy, Debug)]
+pub enum FeatureRestriction {
+ /// Not supported by the physical device.
+ NotSupported,
+ /// Requires a feature to be enabled.
+ RequiresFeature(&'static str),
+ /// Requires a feature to be disabled.
+ ConflictsFeature(&'static str),
+ /// An extension requires this feature to be enabled.
+ RequiredByExtension(&'static str),
+}
+
+impl fmt::Display for FeatureRestriction {
+ #[inline]
+ fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
+ match *self {
+ FeatureRestriction::NotSupported => {
+ write!(fmt, "not supported by the physical device")
+ }
+ FeatureRestriction::RequiresFeature(feat) => {
+ write!(fmt, "requires feature {} to be enabled", feat)
+ }
+ FeatureRestriction::ConflictsFeature(feat) => {
+ write!(fmt, "requires feature {} to be disabled", feat)
+ }
+ FeatureRestriction::RequiredByExtension(ext) => {
+ write!(fmt, "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()
+ }
+ }
+ };
+}
+
+pub(crate) use {crate::autogen::FeaturesFfi, features_ffi};
diff --git a/src/device/mod.rs b/src/device/mod.rs
new file mode 100644
index 0000000..036ef5d
--- /dev/null
+++ b/src/device/mod.rs
@@ -0,0 +1,1036 @@
+// 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.
+
+//! Communication channel with a physical device.
+//!
+//! The `Device` is one of the most important objects of Vulkan. Creating a `Device` is required
+//! before you can create buffers, textures, shaders, etc.
+//!
+//! 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;
+//!
+//! // 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)
+//! };
+//!
+//! // 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");
+//!
+//! // 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();
+//!
+//! match Device::new(physical_device, &features, &ext, Some((queue_family, 1.0))) {
+//! Ok(d) => d,
+//! Err(err) => panic!("Couldn't build device: {:?}", err)
+//! }
+//! };
+//! ```
+//!
+//! # Features and extensions
+//!
+//! Two of the parameters that you pass to `Device::new` are the list of the features and the list
+//! of extensions to enable on the newly-created device.
+//!
+//! > **Note**: Device extensions are the same as instance extensions, except for the device.
+//! > Features are similar to extensions, except that they are part of the core Vulkan
+//! > specifications instead of being separate documents.
+//!
+//! Some Vulkan capabilities, such as swapchains (that allow you to render on the screen) or
+//! geometry shaders for example, require that you enable a certain feature or extension when you
+//! create the device. Contrary to OpenGL, you can't use the functions provided by a feature or an
+//! extension if you didn't explicitly enable it when creating the device.
+//!
+//! Not all physical devices support all possible features and extensions. For example mobile
+//! devices tend to not support geometry shaders, because their hardware is not capable of it. You
+//! can query what is supported with respectively `PhysicalDevice::supported_features` and
+//! `DeviceExtensions::supported_by_device`.
+//!
+//! > **Note**: The fact that you need to manually enable features at initialization also means
+//! > that you don't need to worry about a capability not being supported later on in your code.
+//!
+//! # Queues
+//!
+//! Each physical device proposes one or more *queues* that are divided in *queue families*. A
+//! queue is a thread of execution to which you can submit commands that the GPU will execute.
+//!
+//! > **Note**: You can think of a queue like a CPU thread. Each queue executes its commands one
+//! > after the other, and queues run concurrently. A GPU behaves similarly to the hyper-threading
+//! > technology, in the sense that queues will only run partially in parallel.
+//!
+//! The Vulkan API requires that you specify the list of queues that you are going to use at the
+//! same time as when you create the device. This is done in vulkano by passing an iterator where
+//! each element is a tuple containing a queue family and a number between 0.0 and 1.0 indicating
+//! the priority of execution of the queue relative to the others.
+//!
+//! TODO: write better doc here
+//!
+//! The `Device::new` function returns the newly-created device, but also the list of queues.
+//!
+//! # Extended example
+//!
+//! 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 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 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;
+
+pub(crate) mod extensions;
+pub(crate) mod features;
+pub mod physical;
+pub(crate) mod properties;
+
+/// Represents a Vulkan context.
+pub struct Device {
+ instance: Arc<Instance>,
+ physical_device: usize,
+ device: ash::vk::Device,
+
+ // 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>,
+ 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.
+ ///
+ /// - 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.
+ ///
+ // 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)>,
+ {
+ 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(),
+ api_version,
+ instance.enabled_extensions(),
+ )?;
+
+ let mut requested_features = requested_features.clone();
+
+ // 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
+ // to use a shader that can perform out-of-bounds operations without having
+ // `robust_buffer_access` enabled, an error is returned.
+ //
+ // However for the moment this verification isn't performed. In order to be safe,
+ // we always enable the `robust_buffer_access` feature as it is guaranteed to be
+ // supported everywhere.
+ //
+ // The only alternative (while waiting for shaders introspection to work) is to
+ // make all shaders depend on `robust_buffer_access`. But since usually the
+ // majority of shaders don't need this feature, it would be very annoying to have
+ // to enable it manually when you don't need it.
+ //
+ // 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(
+ physical_device.supported_features(),
+ api_version,
+ requested_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));
+ }
+
+ // 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()
+ };
+
+ let mut output = MaybeUninit::uninit();
+ check_errors(fns_i.v1_0.create_device(
+ physical_device.internal_object(),
+ &infos,
+ ptr::null(),
+ output.as_mut_ptr(),
+ ))?;
+
+ (output.assume_init(), output_queues)
+ };
+
+ // 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()))
+ });
+
+ 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,
+ 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),
+ 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,
+ };
+
+ Ok((device, queues))
+ }
+
+ /// 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).
+ #[inline]
+ pub fn api_version(&self) -> Version {
+ self.api_version
+ }
+
+ /// Grants access to the 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 instance used to create this device.
+ #[inline]
+ pub fn instance(&self) -> &Arc<Instance> {
+ &self.instance
+ }
+
+ /// Returns the physical device that was used to create this device.
+ #[inline]
+ pub fn physical_device(&self) -> PhysicalDevice {
+ PhysicalDevice::from_index(&self.instance, self.physical_device).unwrap()
+ }
+
+ /// Returns an iterator to the list of queues families that this device uses.
+ ///
+ /// > **Note**: Will return `-> impl ExactSizeIterator<Item = QueueFamily>` in the future.
+ // TODO: ^
+ #[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()),
+ )
+ }
+
+ /// Returns the features that have been enabled on the device.
+ #[inline]
+ pub fn enabled_features(&self) -> &Features {
+ &self.features
+ }
+
+ /// Returns the extensions that have been enabled on the device.
+ #[inline]
+ pub fn enabled_extensions(&self) -> &DeviceExtensions {
+ &self.extensions
+ }
+
+ /// 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
+ }
+
+ /// 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;
+ }
+
+ // 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
+ }
+
+ /// Returns the standard command buffer pool used by default if you don't provide any other
+ /// pool.
+ ///
+ /// # Panic
+ ///
+ /// - Panics if the device and the queue family don't belong to the same physical device.
+ ///
+ 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
+ }
+ }
+ }
+
+ /// 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
+ }
+
+ pub(crate) fn fence_pool(&self) -> &Mutex<Vec<ash::vk::Fence>> {
+ &self.fence_pool
+ }
+
+ pub(crate) fn semaphore_pool(&self) -> &Mutex<Vec<ash::vk::Semaphore>> {
+ &self.semaphore_pool
+ }
+
+ pub(crate) fn event_pool(&self) -> &Mutex<Vec<ash::vk::Event>> {
+ &self.event_pool
+ }
+
+ /// Assigns a human-readable name to `object` for debugging purposes.
+ ///
+ /// # Panics
+ /// * If `object` is not owned by this device.
+ pub fn set_object_name<T: VulkanObject + DeviceOwned>(
+ &self,
+ object: &T,
+ name: &CStr,
+ ) -> 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)
+ }
+ }
+
+ /// 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 info = ash::vk::DebugUtilsObjectNameInfoEXT {
+ object_type: ty,
+ object_handle: object,
+ p_object_name: 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
+ )))
+ }
+ }
+ }
+ }
+}
+
+impl fmt::Debug for Device {
+ #[inline]
+ fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
+ write!(fmt, "<Vulkan device {:?}>", self.device)
+ }
+}
+
+unsafe impl VulkanObject for Device {
+ type Object = ash::vk::Device;
+
+ #[inline]
+ fn internal_object(&self) -> ash::vk::Device {
+ self.device
+ }
+}
+
+impl Drop for Device {
+ #[inline]
+ fn drop(&mut self) {
+ 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_sem in self.semaphore_pool.lock().unwrap().iter() {
+ self.fns
+ .v1_0
+ .destroy_semaphore(self.device, 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());
+ }
+ self.fns.v1_0.destroy_device(self.device, 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,
+ }))
+ }
+ }
+
+ #[inline]
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ let len = self.families_and_ids.len().saturating_sub(self.next_queue);
+ (len, Some(len))
+ }
+}
+
+impl ExactSizeIterator for QueuesIter {}
+
+/// Error that can be returned when creating a device.
+#[derive(Copy, Clone, Debug)]
+pub enum DeviceCreationError {
+ /// Failed to create the device for an implementation-specific reason.
+ InitializationFailed,
+ /// You have reached the limit to the number of devices that can be created from the same
+ /// physical device.
+ TooManyObjects,
+ /// Failed to connect to the device.
+ DeviceLost,
+ /// Some of the requested features are unsupported by the physical device.
+ FeatureNotPresent,
+ /// Some of the requested device extensions are not supported by the physical device.
+ ExtensionNotPresent,
+ /// Tried to create too many queues for a given family.
+ TooManyQueuesForFamily,
+ /// The priority of one of the queues is out of the [0.0; 1.0] range.
+ PriorityOutOfRange,
+ /// 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,
+ /// A restriction for an extension was not met.
+ ExtensionRestrictionNotMet(ExtensionRestrictionError),
+ /// A restriction for a feature was not met.
+ 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"
+ )
+ }
+ DeviceCreationError::PriorityOutOfRange => {
+ write!(
+ fmt,
+ "the priority of one of the queues is out of the [0.0; 1.0] range"
+ )
+ }
+ 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),
+ }
+ }
+}
+
+impl From<Error> for DeviceCreationError {
+ #[inline]
+ fn from(err: Error) -> DeviceCreationError {
+ 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),
+ }
+ }
+}
+
+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
+}
+
+impl Queue {
+ /// Returns the device this queue belongs to.
+ #[inline]
+ pub fn device(&self) -> &Arc<Device> {
+ &self.device
+ }
+
+ /// 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()
+ }
+
+ /// Returns the family this queue belongs to.
+ #[inline]
+ pub fn family(&self) -> QueueFamily {
+ self.device
+ .physical_device()
+ .queue_family_by_id(self.family)
+ .unwrap()
+ }
+
+ /// Returns the index of this queue within its family.
+ #[inline]
+ pub fn id_within_family(&self) -> u32 {
+ self.id
+ }
+
+ /// Waits until all work on this queue has finished.
+ ///
+ /// Just like `Device::wait()`, you shouldn't have to call this function in a typical program.
+ #[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(())
+ }
+ }
+}
+
+impl PartialEq for Queue {
+ fn eq(&self, other: &Self) -> bool {
+ self.is_same(other)
+ }
+}
+
+impl Eq for Queue {}
+
+unsafe impl DeviceOwned for Queue {
+ fn device(&self) -> &Arc<Device> {
+ &self.device
+ }
+}
+
+unsafe impl SynchronizedVulkanObject for Queue {
+ type Object = ash::vk::Queue;
+
+ #[inline]
+ fn internal_object_guard(&self) -> MutexGuard<ash::vk::Queue> {
+ self.queue.lock().unwrap()
+ }
+}
+
+#[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 std::sync::Arc;
+
+ #[test]
+ fn one_ref() {
+ let (mut device, _) = gfx_dev_and_queue!();
+ assert!(Arc::get_mut(&mut device).is_some());
+ }
+
+ #[test]
+ fn too_many_queues() {
+ let instance = instance!();
+ let physical = match PhysicalDevice::enumerate(&instance).next() {
+ Some(p) => p,
+ None => return,
+ };
+
+ let family = physical.queue_families().next().unwrap();
+ let queues = (0..family.queues_count() + 1).map(|_| (family, 1.0));
+
+ match Device::new(
+ physical,
+ &Features::none(),
+ &DeviceExtensions::none(),
+ queues,
+ ) {
+ Err(DeviceCreationError::TooManyQueuesForFamily) => return, // Success
+ _ => panic!(),
+ };
+ }
+
+ #[test]
+ fn unsupposed_features() {
+ let instance = instance!();
+ let physical = match PhysicalDevice::enumerate(&instance).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) {
+ return;
+ }
+
+ match Device::new(
+ physical,
+ &features,
+ &DeviceExtensions::none(),
+ Some((family, 1.0)),
+ ) {
+ Err(DeviceCreationError::FeatureRestrictionNotMet(FeatureRestrictionError {
+ restriction: FeatureRestriction::NotSupported,
+ ..
+ })) => return, // Success
+ _ => panic!(),
+ };
+ }
+
+ #[test]
+ fn priority_out_of_range() {
+ let instance = instance!();
+ let physical = match PhysicalDevice::enumerate(&instance).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!(),
+ };
+
+ match Device::new(
+ physical,
+ &Features::none(),
+ &DeviceExtensions::none(),
+ Some((family, -0.2)),
+ ) {
+ Err(DeviceCreationError::PriorityOutOfRange) => (), // Success
+ _ => panic!(),
+ };
+ }
+}
diff --git a/src/device/physical.rs b/src/device/physical.rs
new file mode 100644
index 0000000..feaea4b
--- /dev/null
+++ b/src/device/physical.rs
@@ -0,0 +1,936 @@
+// 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::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 {
+ handle: ash::vk::PhysicalDevice,
+ 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>,
+}
+
+pub(crate) fn init_physical_devices(
+ instance: &Instance,
+) -> Result<Vec<PhysicalDeviceInfo>, InstanceCreationError> {
+ let fns = instance.fns();
+ let instance_extensions = instance.enabled_extensions();
+
+ 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(),
+ ))?;
+
+ 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)
+ };
+
+ 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
+ };
+
+ let supported_extensions = DeviceExtensions::from(
+ extension_properties
+ .iter()
+ .map(|property| unsafe { CStr::from_ptr(property.extension_name.as_ptr()) }),
+ );
+
+ let required_extensions = supported_extensions
+ .intersection(&DeviceExtensions::required_if_supported_extensions());
+
+ 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)
+}
+
+/// Initialize all physical devices
+fn init_physical_devices_inner(instance: &Instance, infos: &mut [PhysicalDeviceInfo]) {
+ let fns = instance.fns();
+
+ 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)
+ };
+
+ 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)
+ };
+
+ 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()
+ };
+
+ info.queue_families = unsafe {
+ let mut num = 0;
+ fns.v1_0.get_physical_device_queue_family_properties(
+ info.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,
+ &mut num,
+ families.as_mut_ptr(),
+ );
+ 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(),
+ );
+
+ 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());
+ }
+
+ Features::from(&output)
+ };
+
+ info.properties = unsafe {
+ let mut output = PropertiesFfi::default();
+ output.make_chain(
+ info.api_version,
+ &info.supported_extensions,
+ instance.enabled_extensions(),
+ );
+
+ 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());
+ }
+
+ Properties::from(&output)
+ };
+
+ info.memory_properties = unsafe {
+ let mut output = ash::vk::PhysicalDeviceMemoryProperties2KHR::default();
+
+ 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);
+ }
+
+ output.memory_properties
+ };
+
+ info.queue_families = unsafe {
+ let mut num = 0;
+
+ 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(),
+ );
+ }
+
+ let mut families = vec![ash::vk::QueueFamilyProperties2::default(); num as usize];
+
+ 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(),
+ );
+ }
+
+ families
+ .into_iter()
+ .map(|family| family.queue_family_properties)
+ .collect()
+ };
+ }
+}
+
+/// 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,
+}
+
+impl<'a> PhysicalDevice<'a> {
+ /// Returns an iterator that enumerates the physical devices available.
+ ///
+ /// # 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) {
+ /// println!("Available device: {}", physical_device.properties().device_name);
+ /// }
+ /// ```
+ #[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,
+ })
+ }
+
+ /// 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();
+ /// ```
+ #[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,
+ })
+ }
+
+ /// Returns the instance corresponding to this physical device.
+ ///
+ /// # Example
+ ///
+ /// ```no_run
+ /// use vulkano::device::physical::PhysicalDevice;
+ ///
+ /// fn do_something(physical_device: PhysicalDevice) {
+ /// let _loaded_extensions = physical_device.instance().enabled_extensions();
+ /// // ...
+ /// }
+ /// ```
+ #[inline]
+ pub fn instance(&self) -> &'a Arc<Instance> {
+ &self.instance
+ }
+
+ /// 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
+ }
+
+ /// 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`.
+ #[inline]
+ pub fn api_version(&self) -> Version {
+ self.info.api_version
+ }
+
+ /// Returns the extensions that are supported by this physical device.
+ #[inline]
+ pub fn supported_extensions(&self) -> &'a DeviceExtensions {
+ &self.info.supported_extensions
+ }
+
+ /// 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
+ }
+
+ /// Returns the properties reported by the device.
+ #[inline]
+ pub fn properties(&self) -> &'a Properties {
+ &self.info.properties
+ }
+
+ /// Returns the features that are supported by this physical device.
+ #[inline]
+ pub fn supported_features(&self) -> &'a Features {
+ &self.info.supported_features
+ }
+
+ /// Builds an iterator that enumerates all the memory types on this physical device.
+ #[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,
+ })
+ }
+
+ /// Returns the memory type with the given index, or `None` if out of range.
+ #[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],
+ })
+ } else {
+ None
+ }
+ }
+
+ /// Builds an iterator that enumerates all the memory heaps on this physical device.
+ #[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,
+ })
+ }
+
+ /// 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
+ }
+ }
+
+ /// Builds an iterator that enumerates all the queue families on this physical device.
+ #[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,
+ })
+ }
+
+ /// Returns the queue family with the given index, or `None` if out of range.
+ #[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],
+ })
+ } else {
+ None
+ }
+ }
+}
+
+unsafe impl<'a> VulkanObject for PhysicalDevice<'a> {
+ type Object = ash::vk::PhysicalDevice;
+
+ #[inline]
+ fn internal_object(&self) -> ash::vk::PhysicalDevice {
+ self.info.handle
+ }
+}
+
+/// 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(),
+}
+
+/// VkPhysicalDeviceType::Other is represented as 0
+impl Default for PhysicalDeviceType {
+ fn default() -> Self {
+ PhysicalDeviceType::Other
+ }
+}
+
+impl TryFrom<ash::vk::PhysicalDeviceType> for PhysicalDeviceType {
+ type Error = ();
+
+ #[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(()),
+ }
+ }
+}
+
+/// 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,
+}
+
+impl<'a> MemoryType<'a> {
+ /// Returns the physical device associated to this memory type.
+ #[inline]
+ pub fn physical_device(&self) -> PhysicalDevice<'a> {
+ self.physical_device
+ }
+
+ /// Returns the identifier of this memory type within the physical device.
+ #[inline]
+ pub fn id(&self) -> u32 {
+ self.id
+ }
+
+ /// 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 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()
+ }
+
+ /// 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()
+ }
+
+ /// 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.
+ ///
+ /// You don't need to worry about this, as this library handles that for you.
+ #[inline]
+ pub fn is_host_coherent(&self) -> bool {
+ !(self.info.property_flags & ash::vk::MemoryPropertyFlags::HOST_COHERENT).is_empty()
+ }
+
+ /// 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()
+ }
+
+ /// Returns true if allocations made to this memory type is lazy.
+ ///
+ /// This means that no actual allocation is performed. Instead memory is automatically
+ /// allocated by the Vulkan implementation.
+ ///
+ /// Memory of this type can only be used on images created with a certain flag. Memory of this
+ /// type is never host-visible.
+ #[inline]
+ pub fn is_lazily_allocated(&self) -> bool {
+ !(self.info.property_flags & ash::vk::MemoryPropertyFlags::LAZILY_ALLOCATED).is_empty()
+ }
+}
+
+/// 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,
+}
+
+impl<'a> MemoryHeap<'a> {
+ /// Returns the physical device associated to this memory heap.
+ #[inline]
+ pub fn physical_device(&self) -> PhysicalDevice<'a> {
+ self.physical_device
+ }
+
+ /// Returns the identifier of this memory heap within the physical device.
+ #[inline]
+ pub fn id(&self) -> u32 {
+ self.id
+ }
+
+ /// Returns the size in bytes on this heap.
+ #[inline]
+ pub fn size(&self) -> DeviceSize {
+ self.info.size
+ }
+
+ /// 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()
+ }
+
+ /// 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.
+ #[inline]
+ pub fn is_multi_instance(&self) -> bool {
+ !(self.info.flags & ash::vk::MemoryHeapFlags::MULTI_INSTANCE).is_empty()
+ }
+}
+
+/// 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,
+}
+
+impl<'a> QueueFamily<'a> {
+ /// Returns the physical device associated to this queue family.
+ #[inline]
+ pub fn physical_device(&self) -> PhysicalDevice<'a> {
+ self.physical_device
+ }
+
+ /// Returns the identifier of this queue family within the physical device.
+ #[inline]
+ pub fn id(&self) -> u32 {
+ self.id
+ }
+
+ /// Returns the number of queues that belong to this 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
+ }
+
+ /// 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)
+ }
+ }
+
+ /// 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]
+ }
+
+ /// 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()
+ }
+
+ /// 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()
+ }
+
+ /// 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()
+ }
+
+ /// 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()
+ }
+
+ /// 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()
+ }
+}
+
+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<'a> Eq for QueueFamily<'a> {}
+
+/// The version of the Vulkan conformance test that a driver is conformant against.
+#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
+pub struct ConformanceVersion {
+ pub major: u8,
+ pub minor: u8,
+ pub subminor: u8,
+ pub patch: u8,
+}
+
+impl From<ash::vk::ConformanceVersion> for ConformanceVersion {
+ #[inline]
+ fn from(val: ash::vk::ConformanceVersion) -> Self {
+ ConformanceVersion {
+ major: val.major,
+ minor: val.minor,
+ subminor: val.subminor,
+ patch: val.patch,
+ }
+ }
+}
+
+impl fmt::Debug for ConformanceVersion {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ write!(formatter, "{}.{}.{}", 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)
+ }
+}
+
+/// 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(),
+}
+
+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(()),
+ }
+ }
+}
+
+/// 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,
+}
+
+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),
+ }
+ }
+}
+
+/// Specifies how the device clips single point primitives.
+#[derive(Clone, Copy, Debug, PartialEq, Eq)]
+#[repr(i32)]
+pub enum PointClippingBehavior {
+ /// 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(),
+ /// Points are clipped only if they lie outside a user-defined clip plane.
+ UserClipPlanesOnly = ash::vk::PointClippingBehavior::USER_CLIP_PLANES_ONLY.as_raw(),
+}
+
+impl TryFrom<ash::vk::PointClippingBehavior> for PointClippingBehavior {
+ type Error = ();
+
+ #[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.
+#[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(),
+}
+
+impl TryFrom<ash::vk::ShaderFloatControlsIndependence> for ShaderFloatControlsIndependence {
+ type Error = ();
+
+ #[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(()),
+ }
+ }
+}
+
+/// Specifies shader core properties.
+#[derive(Clone, Copy, Debug)]
+pub struct ShaderCoreProperties {}
+
+impl From<ash::vk::ShaderCorePropertiesFlagsAMD> for ShaderCoreProperties {
+ #[inline]
+ fn from(val: ash::vk::ShaderCorePropertiesFlagsAMD) -> Self {
+ Self {}
+ }
+}
diff --git a/src/device/properties.rs b/src/device/properties.rs
new file mode 100644
index 0000000..8628cb0
--- /dev/null
+++ b/src/device/properties.rs
@@ -0,0 +1,316 @@
+use crate::device::physical::{
+ ConformanceVersion, DriverId, PhysicalDeviceType, PointClippingBehavior, 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};
+
+// A bit of a hack...
+pub(crate) trait FromVulkan<F>
+where
+ Self: Sized,
+{
+ fn from_vulkan(val: F) -> Option<Self>;
+}
+
+impl FromVulkan<u8> for u8 {
+ #[inline]
+ fn from_vulkan(val: u8) -> Option<Self> {
+ Some(val)
+ }
+}
+
+impl<const N: usize> FromVulkan<[u8; N]> for [u8; N] {
+ #[inline]
+ fn from_vulkan(val: [u8; N]) -> Option<Self> {
+ Some(val)
+ }
+}
+
+impl FromVulkan<u32> for u32 {
+ #[inline]
+ fn from_vulkan(val: u32) -> Option<Self> {
+ Some(val)
+ }
+}
+
+impl<const N: usize> FromVulkan<[u32; N]> for [u32; N] {
+ #[inline]
+ fn from_vulkan(val: [u32; N]) -> Option<Self> {
+ Some(val)
+ }
+}
+
+impl FromVulkan<u64> for u64 {
+ #[inline]
+ fn from_vulkan(val: u64) -> Option<Self> {
+ Some(val)
+ }
+}
+
+impl FromVulkan<usize> for usize {
+ #[inline]
+ fn from_vulkan(val: usize) -> Option<Self> {
+ Some(val)
+ }
+}
+
+impl FromVulkan<i32> for i32 {
+ #[inline]
+ fn from_vulkan(val: i32) -> Option<Self> {
+ Some(val)
+ }
+}
+
+impl FromVulkan<i64> for i64 {
+ #[inline]
+ fn from_vulkan(val: i64) -> Option<Self> {
+ Some(val)
+ }
+}
+
+impl FromVulkan<f32> for f32 {
+ #[inline]
+ fn from_vulkan(val: f32) -> Option<Self> {
+ Some(val)
+ }
+}
+
+impl<const N: usize> FromVulkan<[f32; N]> for [f32; N] {
+ #[inline]
+ fn from_vulkan(val: [f32; N]) -> Option<Self> {
+ Some(val)
+ }
+}
+
+impl<const N: usize> FromVulkan<[std::os::raw::c_char; N]> for String {
+ #[inline]
+ fn from_vulkan(val: [std::os::raw::c_char; N]) -> Option<Self> {
+ Some(unsafe { CStr::from_ptr(val.as_ptr()).to_string_lossy().into_owned() })
+ }
+}
+
+impl FromVulkan<u32> for Version {
+ #[inline]
+ fn from_vulkan(val: u32) -> Option<Self> {
+ val.try_into().ok()
+ }
+}
+
+impl FromVulkan<ash::vk::Bool32> for bool {
+ #[inline]
+ fn from_vulkan(val: ash::vk::Bool32) -> Option<Self> {
+ Some(val != 0)
+ }
+}
+
+impl FromVulkan<ash::vk::ConformanceVersion> for ConformanceVersion {
+ #[inline]
+ fn from_vulkan(val: ash::vk::ConformanceVersion) -> Option<Self> {
+ Some(val.into())
+ }
+}
+
+impl FromVulkan<ash::vk::DriverId> for DriverId {
+ #[inline]
+ fn from_vulkan(val: ash::vk::DriverId) -> Option<Self> {
+ val.try_into().ok()
+ }
+}
+
+impl FromVulkan<ash::vk::Extent2D> for [u32; 2] {
+ #[inline]
+ fn from_vulkan(val: ash::vk::Extent2D) -> Option<Self> {
+ Some([val.width, val.height])
+ }
+}
+
+impl FromVulkan<ash::vk::PhysicalDeviceType> for PhysicalDeviceType {
+ #[inline]
+ fn from_vulkan(val: ash::vk::PhysicalDeviceType) -> Option<Self> {
+ val.try_into().ok()
+ }
+}
+
+impl FromVulkan<ash::vk::PointClippingBehavior> for PointClippingBehavior {
+ #[inline]
+ fn from_vulkan(val: ash::vk::PointClippingBehavior) -> Option<Self> {
+ val.try_into().ok()
+ }
+}
+
+impl FromVulkan<ash::vk::ResolveModeFlags> for ResolveModes {
+ #[inline]
+ fn from_vulkan(val: ash::vk::ResolveModeFlags) -> Option<Self> {
+ Some(val.into())
+ }
+}
+
+impl FromVulkan<ash::vk::SampleCountFlags> for SampleCounts {
+ #[inline]
+ fn from_vulkan(val: ash::vk::SampleCountFlags) -> Option<Self> {
+ Some(val.into())
+ }
+}
+
+impl FromVulkan<ash::vk::SampleCountFlags> for SampleCount {
+ #[inline]
+ fn from_vulkan(val: ash::vk::SampleCountFlags) -> Option<Self> {
+ val.try_into().ok()
+ }
+}
+
+impl FromVulkan<ash::vk::ShaderCorePropertiesFlagsAMD> for ShaderCoreProperties {
+ #[inline]
+ fn from_vulkan(val: ash::vk::ShaderCorePropertiesFlagsAMD) -> Option<Self> {
+ Some(val.into())
+ }
+}
+
+impl FromVulkan<ash::vk::ShaderFloatControlsIndependence> for ShaderFloatControlsIndependence {
+ #[inline]
+ fn from_vulkan(val: ash::vk::ShaderFloatControlsIndependence) -> Option<Self> {
+ val.try_into().ok()
+ }
+}
+
+impl FromVulkan<ash::vk::ShaderStageFlags> for ShaderStages {
+ #[inline]
+ fn from_vulkan(val: ash::vk::ShaderStageFlags) -> Option<Self> {
+ Some(val.into())
+ }
+}
+
+impl FromVulkan<ash::vk::SubgroupFeatureFlags> for SubgroupFeatures {
+ #[inline]
+ fn from_vulkan(val: ash::vk::SubgroupFeatureFlags) -> Option<Self> {
+ Some(val.into())
+ }
+}
diff --git a/src/extensions.rs b/src/extensions.rs
new file mode 100644
index 0000000..822eb67
--- /dev/null
+++ b/src/extensions.rs
@@ -0,0 +1,271 @@
+// 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::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.
+#[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),
+ }
+ }
+}
+
+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",
+ }
+ )
+ }
+}
+
+impl From<OomError> for SupportedExtensionsError {
+ #[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),
+ }
+ }
+}
+
+/// An error that can happen when enabling an extension on an instance or device.
+#[derive(Clone, Copy, Debug)]
+pub struct ExtensionRestrictionError {
+ /// The extension in question.
+ pub extension: &'static str,
+ /// The restriction that was not met.
+ pub restriction: ExtensionRestriction,
+}
+
+impl error::Error for ExtensionRestrictionError {}
+
+impl fmt::Display for ExtensionRestrictionError {
+ #[inline]
+ fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
+ write!(
+ fmt,
+ "a restriction for the extension {} was not met: {}",
+ self.extension, self.restriction,
+ )
+ }
+}
+
+#[derive(Clone, Copy, Debug)]
+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 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> {
+ 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)
+ }
+ ExtensionRestriction::RequiredIfSupported => {
+ write!(fmt, "required to be enabled by the physical device")
+ }
+ ExtensionRestriction::ConflictsDeviceExtension(ext) => {
+ write!(fmt, "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
new file mode 100644
index 0000000..88a8354
--- /dev/null
+++ b/src/fns.rs
@@ -0,0 +1,33 @@
+// 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.
+
+macro_rules! fns {
+ ($struct_name:ident, { $($member:ident => $fn_struct:ident,)+ }) => {
+ pub struct $struct_name {
+ $(
+ pub $member: ash::vk::$fn_struct,
+ )+
+ }
+
+ 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;
diff --git a/src/format.rs b/src/format.rs
new file mode 100644
index 0000000..679eaf9
--- /dev/null
+++ b/src/format.rs
@@ -0,0 +1,759 @@
+// 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.
+
+//! All the formats of images supported by Vulkan.
+//!
+//! # Formats
+//!
+//! List of suffixes:
+//!
+//! - `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`.
+//!
+//! - `Snorm` is the same as `Unorm`, but the integers are signed and the range is from `-1.0` to
+//! `1.0` instead.
+//!
+//! - `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`.
+//!
+//! - `Sscaled` is the same as `Uscaled` expect that the integers are signed.
+//!
+//! - `Uint` means that the values are unsigned integers. No conversion is performed.
+//!
+//! - `Sint` means that the values are signed integers. No conversion is performed.
+//!
+//! - `Ufloat` means that the values are unsigned floating points. No conversion is performed. This
+//! format is very unusual.
+//!
+//! - `Sfloat` means that the values are regular floating points. No conversion is performed.
+//!
+//! - `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.
+//!
+//! # Choosing a format
+//!
+//! 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:
+//!
+//! - B4G4R4A4UnormPack16
+//! - R5G6B5UnormPack16
+//! - A1R5G5B5UnormPack16
+//! - R8Unorm
+//! - R8Snorm
+//! - R8G8Unorm
+//! - R8G8Snorm
+//! - R8G8B8A8Unorm
+//! - R8G8B8A8Snorm
+//! - R8G8B8A8Srgb
+//! - B8G8R8A8Unorm
+//! - B8G8R8A8Srgb
+//! - A8B8G8R8UnormPack32
+//! - A8B8G8R8SnormPack32
+//! - A8B8G8R8SrgbPack32
+//! - A2B10G10R10UnormPack32
+//! - R16Sfloat
+//! - R16G16Sfloat
+//! - R16G16B16A16Sfloat
+//! - B10G11R11UfloatPack32
+//! - E5B9G9R9UfloatPack32
+//!
+//! 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):
+//!
+//! - R5G6B5UnormPack16
+//! - A1R5G5B5UnormPack16
+//! - R8Unorm
+//! - R8G8Unorm
+//! - R8G8B8A8Unorm
+//! - R8G8B8A8Srgb
+//! - B8G8R8A8Unorm
+//! - B8G8R8A8Srgb
+//! - A8B8G8R8UnormPack32
+//! - A8B8G8R8SrgbPack32
+//! - A2B10G10R10UnormPack32
+//! - R16Sfloat
+//! - R16G16Sfloat
+//! - R16G16B16A16Sfloat
+//!
+//! 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,
+ )+
+ }
+ }
+
+ /// 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(()),
+ }
+ }
+ }
+
+ 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},
+}
+
+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.
+ #[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(),
+ }
+ }
+
+ #[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"),
+ }
+ }
+}
+
+#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
+pub enum FormatTy {
+ Float,
+ Uint,
+ Sint,
+ Depth,
+ Stencil,
+ DepthStencil,
+ Compressed,
+ Ycbcr,
+}
+
+/// 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;
+}
+
+#[derive(Debug, Copy, Clone, PartialEq, Eq)]
+pub struct IncompatiblePixelsType;
+
+impl error::Error for IncompatiblePixelsType {}
+
+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"
+ )
+ }
+}
+
+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)
+ }
+ }
+
+ fn rate(format: Format) -> u32 {
+ (format.size().expect("this format cannot accept pixels") / mem::size_of::<$ty>() as DeviceSize) as u32
+ }
+ }
+ }
+}
+
+impl_pixel! {
+ u8; i8; u16; i16; u32; i32; u64; i64; f16; f32; f64;
+}
+
+/// 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)]
+pub enum ClearValue {
+ /// Entry for attachments that aren't cleared.
+ None,
+ /// Value for floating-point attachments, including `Unorm`, `Snorm`, `Sfloat`.
+ Float([f32; 4]),
+ /// Value for integer attachments, including `Int`.
+ Int([i32; 4]),
+ /// 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<[f32; 1]> for ClearValue {
+ #[inline]
+ fn from(val: [f32; 1]) -> ClearValue {
+ ClearValue::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])
+ }
+}
+
+impl From<[f32; 3]> for ClearValue {
+ #[inline]
+ fn from(val: [f32; 3]) -> ClearValue {
+ ClearValue::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)
+ }
+}
+
+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?
+ }
+}
+
+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?
+ }
+}
+
+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?
+ }
+}
+
+impl From<[u32; 4]> for ClearValue {
+ #[inline]
+ fn from(val: [u32; 4]) -> ClearValue {
+ ClearValue::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?
+ }
+}
+
+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?
+ }
+}
+
+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?
+ }
+}
+
+impl From<[i32; 4]> for ClearValue {
+ #[inline]
+ fn from(val: [i32; 4]) -> ClearValue {
+ ClearValue::Int(val)
+ }
+}
+
+impl From<f32> for ClearValue {
+ #[inline]
+ fn from(val: f32) -> ClearValue {
+ ClearValue::Depth(val)
+ }
+}
+
+impl From<u32> for ClearValue {
+ #[inline]
+ fn from(val: u32) -> ClearValue {
+ ClearValue::Stencil(val)
+ }
+}
+
+impl From<(f32, u32)> for ClearValue {
+ #[inline]
+ fn from(val: (f32, u32)) -> ClearValue {
+ ClearValue::DepthStencil(val)
+ }
+}
+
+// TODO: remove once no longer needed
+pub unsafe trait ClearValuesTuple {
+ type Iter: Iterator<Item = ClearValue>;
+ fn iter(self) -> Self::Iter;
+}
+
+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_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_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);
+
+/// The properties of an image format that are supported by a physical device.
+#[derive(Debug, Clone, PartialEq, Eq, Hash, Default)]
+pub struct FormatProperties {
+ /// Features available for images with linear tiling.
+ pub linear_tiling_features: FormatFeatures,
+
+ /// Features available for images with optimal tiling.
+ pub optimal_tiling_features: FormatFeatures,
+
+ /// Features available for buffers.
+ pub buffer_features: FormatFeatures,
+}
+
+/// 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 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(),
+ }
+ }
+}
diff --git a/src/image/aspect.rs b/src/image/aspect.rs
new file mode 100644
index 0000000..41d834e
--- /dev/null
+++ b/src/image/aspect.rs
@@ -0,0 +1,145 @@
+// 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;
+
+/// 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(),
+}
+
+impl From<ImageAspect> for ash::vk::ImageAspectFlags {
+ #[inline]
+ fn from(val: ImageAspect) -> Self {
+ Self::from_raw(val as u32)
+ }
+}
+
+/// 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,
+}
+
+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,
+ }
+ }
+}
+
+impl BitOr for ImageAspects {
+ type Output = Self;
+
+ #[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,
+ }
+ }
+}
+
+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
+ }
+}
+
+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(),
+ }
+ }
+}
diff --git a/src/image/attachment.rs b/src/image/attachment.rs
new file mode 100644
index 0000000..5892d3c
--- /dev/null
+++ b/src/image/attachment.rs
@@ -0,0 +1,659 @@
+// 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::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;
+
+/// ImageAccess whose purpose is to be used as a framebuffer attachment.
+///
+/// The image is always two-dimensional and has only one mipmap, but it can have any kind of
+/// format. Trying to use a format that the backend doesn't support for rendering will result in
+/// an error being returned when creating the image. Once you have an `AttachmentImage`, you are
+/// guaranteed that you will be able to draw on it.
+///
+/// The template parameter of `AttachmentImage` is a type that describes the format of the image.
+///
+/// # Regular vs transient
+///
+/// Calling `AttachmentImage::new` will create a regular image, while calling
+/// `AttachmentImage::transient` will create a *transient* image. Transient image are only
+/// relevant for images that serve as attachments, so `AttachmentImage` is the only type of
+/// image in vulkano that provides a shortcut for this.
+///
+/// A transient image is a special kind of image whose content is undefined outside of render
+/// passes. Once you finish drawing, reading from it will returned undefined data (which can be
+/// either valid or garbage, depending on the implementation).
+///
+/// This gives a hint to the Vulkan implementation that it is possible for the image's content to
+/// live exclusively in some cache memory, and that no real memory has to be allocated for it.
+///
+/// In other words, if you are going to read from the image after drawing to it, use a regular
+/// image. If you don't need to read from it (for example if it's some kind of intermediary color,
+/// or a depth buffer that is only used once) then use a transient image as it may improve
+/// performance.
+///
+// 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,
+
+ // Layout to use when the image is used as a framebuffer attachment.
+ // Must be either "depth-stencil optimal" or "color optimal".
+ attachment_layout: ImageLayout,
+
+ // 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,
+}
+
+impl AttachmentImage {
+ /// Creates a new image with the given dimensions and format.
+ ///
+ /// Returns an error if the dimensions are too large or if the backend doesn't support this
+ /// format as a framebuffer attachment.
+ #[inline]
+ pub fn new(
+ device: Arc<Device>,
+ dimensions: [u32; 2],
+ format: Format,
+ ) -> Result<Arc<AttachmentImage>, ImageCreationError> {
+ AttachmentImage::new_impl(
+ device,
+ dimensions,
+ 1,
+ format,
+ ImageUsage::none(),
+ SampleCount::Sample1,
+ )
+ }
+
+ /// Same as `new`, but creates an image that can be used as an input attachment.
+ ///
+ /// > **Note**: This function is just a convenient shortcut for `with_usage`.
+ #[inline]
+ pub fn input_attachment(
+ device: Arc<Device>,
+ dimensions: [u32; 2],
+ format: Format,
+ ) -> Result<Arc<AttachmentImage>, ImageCreationError> {
+ let base_usage = ImageUsage {
+ input_attachment: true,
+ ..ImageUsage::none()
+ };
+
+ AttachmentImage::new_impl(
+ device,
+ dimensions,
+ 1,
+ format,
+ base_usage,
+ SampleCount::Sample1,
+ )
+ }
+
+ /// Same as `new`, but creates a multisampled image.
+ ///
+ /// > **Note**: You can also use this function and pass `1` for the number of samples if you
+ /// > want a regular image.
+ #[inline]
+ pub fn multisampled(
+ device: Arc<Device>,
+ dimensions: [u32; 2],
+ samples: SampleCount,
+ format: Format,
+ ) -> Result<Arc<AttachmentImage>, ImageCreationError> {
+ AttachmentImage::new_impl(device, dimensions, 1, format, ImageUsage::none(), samples)
+ }
+
+ /// Same as `multisampled`, but creates an image that can be used as an input attachment.
+ ///
+ /// > **Note**: This function is just a convenient shortcut for `multisampled_with_usage`.
+ #[inline]
+ pub fn multisampled_input_attachment(
+ device: Arc<Device>,
+ dimensions: [u32; 2],
+ samples: SampleCount,
+ format: Format,
+ ) -> Result<Arc<AttachmentImage>, ImageCreationError> {
+ let base_usage = ImageUsage {
+ input_attachment: true,
+ ..ImageUsage::none()
+ };
+
+ AttachmentImage::new_impl(device, dimensions, 1, format, base_usage, samples)
+ }
+
+ /// Same as `new`, but lets you specify additional usages.
+ ///
+ /// The `color_attachment` or `depth_stencil_attachment` usages are automatically added based
+ /// on the format of the usage. Therefore the `usage` parameter allows you specify usages in
+ /// addition to these two.
+ #[inline]
+ pub fn with_usage(
+ device: Arc<Device>,
+ dimensions: [u32; 2],
+ format: Format,
+ usage: ImageUsage,
+ ) -> Result<Arc<AttachmentImage>, ImageCreationError> {
+ AttachmentImage::new_impl(device, dimensions, 1, format, usage, SampleCount::Sample1)
+ }
+
+ /// Same as `with_usage`, but creates a multisampled image.
+ ///
+ /// > **Note**: You can also use this function and pass `1` for the number of samples if you
+ /// > want a regular image.
+ #[inline]
+ pub fn multisampled_with_usage(
+ device: Arc<Device>,
+ dimensions: [u32; 2],
+ samples: SampleCount,
+ format: Format,
+ usage: ImageUsage,
+ ) -> Result<Arc<AttachmentImage>, ImageCreationError> {
+ AttachmentImage::new_impl(device, dimensions, 1, format, usage, samples)
+ }
+
+ /// Same as `multisampled_with_usage`, but creates an image with multiple layers.
+ ///
+ /// > **Note**: You can also use this function and pass `1` for the number of layers if you
+ /// > want a regular image.
+ #[inline]
+ pub fn multisampled_with_usage_with_layers(
+ device: Arc<Device>,
+ 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)
+ }
+
+ /// Same as `new`, except that the image can later be sampled.
+ ///
+ /// > **Note**: This function is just a convenient shortcut for `with_usage`.
+ #[inline]
+ pub fn sampled(
+ device: Arc<Device>,
+ dimensions: [u32; 2],
+ format: Format,
+ ) -> Result<Arc<AttachmentImage>, ImageCreationError> {
+ let base_usage = ImageUsage {
+ sampled: true,
+ ..ImageUsage::none()
+ };
+
+ AttachmentImage::new_impl(
+ device,
+ dimensions,
+ 1,
+ format,
+ base_usage,
+ SampleCount::Sample1,
+ )
+ }
+
+ /// Same as `sampled`, except that the image can be used as an input attachment.
+ ///
+ /// > **Note**: This function is just a convenient shortcut for `with_usage`.
+ #[inline]
+ pub fn sampled_input_attachment(
+ device: Arc<Device>,
+ dimensions: [u32; 2],
+ format: Format,
+ ) -> Result<Arc<AttachmentImage>, ImageCreationError> {
+ let base_usage = ImageUsage {
+ sampled: true,
+ input_attachment: true,
+ ..ImageUsage::none()
+ };
+
+ AttachmentImage::new_impl(
+ device,
+ dimensions,
+ 1,
+ format,
+ base_usage,
+ SampleCount::Sample1,
+ )
+ }
+
+ /// Same as `sampled`, but creates a multisampled image.
+ ///
+ /// > **Note**: You can also use this function and pass `1` for the number of samples if you
+ /// > want a regular image.
+ ///
+ /// > **Note**: This function is just a convenient shortcut for `multisampled_with_usage`.
+ #[inline]
+ pub fn sampled_multisampled(
+ device: Arc<Device>,
+ dimensions: [u32; 2],
+ samples: SampleCount,
+ format: Format,
+ ) -> Result<Arc<AttachmentImage>, ImageCreationError> {
+ let base_usage = ImageUsage {
+ sampled: true,
+ ..ImageUsage::none()
+ };
+
+ AttachmentImage::new_impl(device, dimensions, 1, format, base_usage, samples)
+ }
+
+ /// Same as `sampled_multisampled`, but creates an image that can be used as an input
+ /// attachment.
+ ///
+ /// > **Note**: This function is just a convenient shortcut for `multisampled_with_usage`.
+ #[inline]
+ pub fn sampled_multisampled_input_attachment(
+ device: Arc<Device>,
+ dimensions: [u32; 2],
+ samples: SampleCount,
+ format: Format,
+ ) -> Result<Arc<AttachmentImage>, ImageCreationError> {
+ let base_usage = ImageUsage {
+ sampled: true,
+ input_attachment: true,
+ ..ImageUsage::none()
+ };
+
+ AttachmentImage::new_impl(device, dimensions, 1, format, base_usage, samples)
+ }
+
+ /// Same as `new`, except that the image will be transient.
+ ///
+ /// A transient image is special because its content is undefined outside of a render pass.
+ /// This means that the implementation has the possibility to not allocate any memory for it.
+ ///
+ /// > **Note**: This function is just a convenient shortcut for `with_usage`.
+ #[inline]
+ pub fn transient(
+ device: Arc<Device>,
+ dimensions: [u32; 2],
+ format: Format,
+ ) -> Result<Arc<AttachmentImage>, ImageCreationError> {
+ let base_usage = ImageUsage {
+ transient_attachment: true,
+ ..ImageUsage::none()
+ };
+
+ AttachmentImage::new_impl(
+ device,
+ dimensions,
+ 1,
+ format,
+ base_usage,
+ SampleCount::Sample1,
+ )
+ }
+
+ /// Same as `transient`, except that the image can be used as an input attachment.
+ ///
+ /// > **Note**: This function is just a convenient shortcut for `with_usage`.
+ #[inline]
+ pub fn transient_input_attachment(
+ device: Arc<Device>,
+ dimensions: [u32; 2],
+ format: Format,
+ ) -> Result<Arc<AttachmentImage>, ImageCreationError> {
+ let base_usage = ImageUsage {
+ transient_attachment: true,
+ input_attachment: true,
+ ..ImageUsage::none()
+ };
+
+ AttachmentImage::new_impl(
+ device,
+ dimensions,
+ 1,
+ format,
+ base_usage,
+ SampleCount::Sample1,
+ )
+ }
+
+ /// Same as `transient`, but creates a multisampled image.
+ ///
+ /// > **Note**: You can also use this function and pass `1` for the number of samples if you
+ /// > want a regular image.
+ ///
+ /// > **Note**: This function is just a convenient shortcut for `multisampled_with_usage`.
+ #[inline]
+ pub fn transient_multisampled(
+ device: Arc<Device>,
+ dimensions: [u32; 2],
+ samples: SampleCount,
+ format: Format,
+ ) -> Result<Arc<AttachmentImage>, ImageCreationError> {
+ let base_usage = ImageUsage {
+ transient_attachment: true,
+ ..ImageUsage::none()
+ };
+
+ AttachmentImage::new_impl(device, dimensions, 1, format, base_usage, samples)
+ }
+
+ /// Same as `transient_multisampled`, but creates an image that can be used as an input
+ /// attachment.
+ ///
+ /// > **Note**: This function is just a convenient shortcut for `multisampled_with_usage`.
+ #[inline]
+ pub fn transient_multisampled_input_attachment(
+ device: Arc<Device>,
+ dimensions: [u32; 2],
+ samples: SampleCount,
+ format: Format,
+ ) -> Result<Arc<AttachmentImage>, ImageCreationError> {
+ let base_usage = ImageUsage {
+ transient_attachment: true,
+ input_attachment: true,
+ ..ImageUsage::none()
+ };
+
+ AttachmentImage::new_impl(device, dimensions, 1, format, base_usage, samples)
+ }
+
+ // All constructors dispatch to this one.
+ fn new_impl(
+ device: Arc<Device>,
+ dimensions: [u32; 2],
+ array_layers: u32,
+ format: Format,
+ base_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,
+ };
+
+ let usage = ImageUsage {
+ color_attachment: !is_depth,
+ depth_stencil_attachment: is_depth,
+ ..base_usage
+ };
+
+ let (image, mem_reqs) = unsafe {
+ let dims = ImageDimensions::Dim2d {
+ width: dimensions[0],
+ height: dimensions[1],
+ array_layers,
+ };
+
+ UnsafeImage::new(
+ device.clone(),
+ usage,
+ format,
+ ImageCreateFlags::none(),
+ dims,
+ samples,
+ 1,
+ Sharing::Exclusive::<Empty<u32>>,
+ 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
+ } else {
+ AllocFromRequirementsFilter::Allowed
+ }
+ },
+ )?;
+ debug_assert!((memory.offset() % mem_reqs.alignment) == 0);
+ unsafe {
+ image.bind_memory(memory.memory(), memory.offset())?;
+ }
+
+ 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),
+ }))
+ }
+}
+
+impl<A> AttachmentImage<A> {
+ /// Returns the dimensions of the image.
+ #[inline]
+ pub fn dimensions(&self) -> [u32; 2] {
+ let dims = self.image.dimensions();
+ [dims.width(), dims.height()]
+ }
+}
+
+unsafe impl<A> ImageAccess for AttachmentImage<A> {
+ #[inline]
+ fn inner(&self) -> ImageInner {
+ ImageInner {
+ image: &self.image,
+ first_layer: 0,
+ num_layers: self.image.dimensions().array_layers() as usize,
+ first_mipmap_level: 0,
+ num_mipmap_levels: 1,
+ }
+ }
+
+ #[inline]
+ fn initial_layout_requirement(&self) -> ImageLayout {
+ self.attachment_layout
+ }
+
+ #[inline]
+ fn final_layout_requirement(&self) -> ImageLayout {
+ self.attachment_layout
+ }
+
+ #[inline]
+ fn descriptor_layouts(&self) -> Option<ImageDescriptorLayouts> {
+ Some(ImageDescriptorLayouts {
+ storage_image: ImageLayout::ShaderReadOnlyOptimal,
+ combined_image_sampler: ImageLayout::ShaderReadOnlyOptimal,
+ sampled_image: ImageLayout::ShaderReadOnlyOptimal,
+ input_attachment: ImageLayout::ShaderReadOnlyOptimal,
+ })
+ }
+
+ #[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);
+ }
+
+ #[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
+ }
+}
+
+unsafe impl<A> ImageClearValue<ClearValue> for Arc<AttachmentImage<A>> {
+ #[inline]
+ fn decode(&self, value: ClearValue) -> Option<ClearValue> {
+ Some(self.format.decode_clear_value(value))
+ }
+}
+
+unsafe impl<P, A> ImageContent<P> for Arc<AttachmentImage<A>> {
+ #[inline]
+ fn matches_format(&self) -> bool {
+ true // FIXME:
+ }
+}
+
+impl<A> PartialEq for AttachmentImage<A> {
+ #[inline]
+ fn eq(&self, other: &Self) -> bool {
+ ImageAccess::inner(self) == ImageAccess::inner(other)
+ }
+}
+
+impl<A> Eq for AttachmentImage<A> {}
+
+impl<A> Hash for AttachmentImage<A> {
+ #[inline]
+ fn hash<H: Hasher>(&self, state: &mut H) {
+ ImageAccess::inner(self).hash(state);
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use super::AttachmentImage;
+ use crate::format::Format;
+
+ #[test]
+ fn create_regular() {
+ let (device, _) = gfx_dev_and_queue!();
+ let _img = AttachmentImage::new(device, [32, 32], Format::R8G8B8A8Unorm).unwrap();
+ }
+
+ #[test]
+ fn create_transient() {
+ let (device, _) = gfx_dev_and_queue!();
+ let _img = AttachmentImage::transient(device, [32, 32], Format::R8G8B8A8Unorm).unwrap();
+ }
+
+ #[test]
+ fn d16_unorm_always_supported() {
+ let (device, _) = gfx_dev_and_queue!();
+ let _img = AttachmentImage::new(device, [32, 32], Format::D16Unorm).unwrap();
+ }
+}
diff --git a/src/image/immutable.rs b/src/image/immutable.rs
new file mode 100644
index 0000000..6a6e093
--- /dev/null
+++ b/src/image/immutable.rs
@@ -0,0 +1,703 @@
+// 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::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;
+
+/// 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>,
+ 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,
+ MipmapsCount::Log2 => true,
+ MipmapsCount::Specific(x) => x > 1,
+ }
+}
+
+fn generate_mipmaps<L, Img>(
+ cbb: &mut AutoCommandBufferBuilder<L>,
+ image: Arc<Img>,
+ dimensions: ImageDimensions,
+ layout: ImageLayout,
+) where
+ Img: ImageAccess + Send + Sync + 'static,
+{
+ for level in 1..image.mipmap_levels() {
+ let [xs, ys, ds] = dimensions
+ .mipmap_dimensions(level - 1)
+ .unwrap()
+ .width_height_depth();
+ let [xd, yd, dd] = dimensions
+ .mipmap_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
+ )
+ .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>,
+ dimensions: ImageDimensions,
+ format: Format,
+ mipmaps: M,
+ usage: ImageUsage,
+ flags: ImageCreateFlags,
+ layout: ImageLayout,
+ queue_families: I,
+ ) -> Result<(Arc<ImmutableImage>, ImmutableImageInitialization), ImageCreationError>
+ where
+ I: IntoIterator<Item = QueueFamily<'a>>,
+ M: Into<MipmapsCount>,
+ {
+ 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,
+ 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
+ } else {
+ AllocFromRequirementsFilter::Allowed
+ }
+ },
+ )?;
+ debug_assert!((memory.offset() % mem_reqs.alignment) == 0);
+ unsafe {
+ image.bind_memory(memory.memory(), memory.offset())?;
+ }
+
+ let image = Arc::new(ImmutableImage {
+ image,
+ memory,
+ dimensions,
+ format,
+ initialized: AtomicBool::new(false),
+ layout,
+ });
+
+ 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(),
+ };
+
+ Ok((image, init))
+ }
+
+ /// Construct an ImmutableImage from the contents of `iter`.
+ #[inline]
+ pub fn from_iter<Px, I>(
+ iter: I,
+ dimensions: ImageDimensions,
+ mipmaps: MipmapsCount,
+ format: Format,
+ queue: Arc<Queue>,
+ ) -> Result<
+ (
+ Arc<Self>,
+ CommandBufferExecFuture<NowFuture, PrimaryAutoCommandBuffer>,
+ ),
+ ImageCreationError,
+ >
+ where
+ Px: Pixel + Send + Sync + Clone + 'static,
+ I: ExactSizeIterator<Item = Px>,
+ {
+ let source = CpuAccessibleBuffer::from_iter(
+ queue.device().clone(),
+ BufferUsage::transfer_source(),
+ false,
+ iter,
+ )?;
+ ImmutableImage::from_buffer(source, dimensions, mipmaps, format, queue)
+ }
+
+ /// Construct an ImmutableImage containing a copy of the data in `source`.
+ pub fn from_buffer<B, Px>(
+ source: B,
+ dimensions: ImageDimensions,
+ mipmaps: MipmapsCount,
+ format: Format,
+ queue: Arc<Queue>,
+ ) -> Result<
+ (
+ Arc<Self>,
+ CommandBufferExecFuture<NowFuture, PrimaryAutoCommandBuffer>,
+ ),
+ ImageCreationError,
+ >
+ where
+ B: BufferAccess + TypedBufferAccess<Content = [Px]> + 'static + Clone + Send + Sync,
+ Px: Pixel + Send + Sync + Clone + 'static,
+ {
+ 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 flags = ImageCreateFlags::none();
+ let layout = ImageLayout::ShaderReadOnlyOptimal;
+
+ let (image, initializer) = ImmutableImage::uninitialized(
+ source.device().clone(),
+ dimensions,
+ format,
+ mipmaps,
+ usage,
+ flags,
+ layout,
+ source.device().active_queue_families(),
+ )?;
+
+ 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();
+
+ if need_to_generate_mipmaps {
+ generate_mipmaps(
+ &mut cbb,
+ image.clone(),
+ image.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))
+ }
+}
+
+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.
+ #[inline]
+ pub fn mipmap_levels(&self) -> u32 {
+ self.image.mipmap_levels()
+ }
+}
+
+unsafe impl<A> ImageAccess for ImmutableImage<A> {
+ #[inline]
+ fn inner(&self) -> ImageInner {
+ ImageInner {
+ image: &self.image,
+ first_layer: 0,
+ num_layers: self.image.dimensions().array_layers() as usize,
+ first_mipmap_level: 0,
+ num_mipmap_levels: self.image.mipmap_levels() as usize,
+ }
+ }
+
+ #[inline]
+ fn initial_layout_requirement(&self) -> ImageLayout {
+ self.layout
+ }
+
+ #[inline]
+ fn final_layout_requirement(&self) -> ImageLayout {
+ self.layout
+ }
+
+ #[inline]
+ fn descriptor_layouts(&self) -> Option<ImageDescriptorLayouts> {
+ Some(ImageDescriptorLayouts {
+ storage_image: self.layout,
+ combined_image_sampler: self.layout,
+ sampled_image: self.layout,
+ input_attachment: self.layout,
+ })
+ }
+
+ #[inline]
+ fn conflict_key(&self) -> u64 {
+ self.image.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,
+ });
+ }
+
+ 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, new_layout: Option<ImageLayout>) {
+ debug_assert!(new_layout.is_none());
+ }
+
+ #[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<P, A> ImageContent<P> for ImmutableImage<A> {
+ #[inline]
+ fn matches_format(&self) -> bool {
+ true // FIXME:
+ }
+}
+
+unsafe impl ImageAccess for SubImage {
+ #[inline]
+ fn inner(&self) -> ImageInner {
+ self.image.inner()
+ }
+
+ #[inline]
+ fn initial_layout_requirement(&self) -> ImageLayout {
+ self.image.initial_layout_requirement()
+ }
+
+ #[inline]
+ fn final_layout_requirement(&self) -> ImageLayout {
+ self.image.final_layout_requirement()
+ }
+
+ #[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> {
+ #[inline]
+ fn eq(&self, other: &Self) -> bool {
+ ImageAccess::inner(self) == ImageAccess::inner(other)
+ }
+}
+
+impl<A> Eq for ImmutableImage<A> {}
+
+impl<A> Hash for ImmutableImage<A> {
+ #[inline]
+ fn hash<H: Hasher>(&self, state: &mut H) {
+ ImageAccess::inner(self).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);
+ }
+
+ // 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)
+ }
+ }
+
+ #[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);
+ }
+
+ #[inline]
+ fn current_miplevels_access(&self) -> std::ops::Range<u32> {
+ self.mip_levels_access.clone()
+ }
+
+ #[inline]
+ fn current_layer_levels_access(&self) -> std::ops::Range<u32> {
+ self.layer_levels_access.clone()
+ }
+}
+
+impl<A> PartialEq for ImmutableImageInitialization<A> {
+ #[inline]
+ fn eq(&self, other: &Self) -> bool {
+ ImageAccess::inner(self) == ImageAccess::inner(other)
+ }
+}
+
+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);
+ }
+}
diff --git a/src/image/layout.rs b/src/image/layout.rs
new file mode 100644
index 0000000..2e29f58
--- /dev/null
+++ b/src/image/layout.rs
@@ -0,0 +1,60 @@
+// 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.
+
+/// 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(),
+}
+
+impl From<ImageLayout> for ash::vk::ImageLayout {
+ #[inline]
+ fn from(val: ImageLayout) -> Self {
+ Self::from_raw(val as i32)
+ }
+}
+
+/// The set of layouts to use for an image when used in descriptor of various kinds.
+#[derive(Clone, Copy, Debug, PartialEq, Eq)]
+pub struct ImageDescriptorLayouts {
+ /// The image layout to use in a descriptor as a storage image.
+ pub storage_image: ImageLayout,
+ /// The image layout to use in a descriptor as a combined image sampler.
+ pub combined_image_sampler: ImageLayout,
+ /// The image layout to use in a descriptor as a sampled image.
+ pub sampled_image: ImageLayout,
+ /// The image layout to use in a descriptor as an input attachment.
+ pub input_attachment: ImageLayout,
+}
diff --git a/src/image/mod.rs b/src/image/mod.rs
new file mode 100644
index 0000000..4e7f4af
--- /dev/null
+++ b/src/image/mod.rs
@@ -0,0 +1,701 @@
+// 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.
+
+//! Image storage (1D, 2D, 3D, arrays, etc.) and image views.
+//!
+//! An *image* is a region of memory whose purpose is to store multi-dimensional data. Its
+//! most common use is to store a 2D array of color pixels (in other words an *image* in
+//! everyday language), but it can also be used to store arbitrary data.
+//!
+//! The advantage of using an image compared to a buffer is that the memory layout is optimized
+//! for locality. When reading a specific pixel of an image, reading the nearby pixels is really
+//! fast. Most implementations have hardware dedicated to reading from images if you access them
+//! through a sampler.
+//!
+//! # Properties of an image
+//!
+//! # Images and image views
+//!
+//! There is a distinction between *images* and *image views*. As its name suggests, an image
+//! view describes how the GPU must interpret the image.
+//!
+//! Transfer and memory operations operate on images themselves, while reading/writing an image
+//! operates on image views. You can create multiple image views from the same image.
+//!
+//! # High-level wrappers
+//!
+//! In the vulkano library, an image is any object that implements the [`ImageAccess`] trait. You
+//! can create a view by wrapping them in an [`ImageView`](crate::image::view::ImageView).
+//!
+//! Since the `ImageAccess` trait is low-level, you are encouraged to not implement it yourself but
+//! instead use one of the provided implementations that are specialized depending on the way you
+//! are going to use the image:
+//!
+//! - An `AttachmentImage` can be used when you want to draw to an image.
+//! - An `ImmutableImage` stores data which never need be changed after the initial upload,
+//! like a texture.
+//!
+//! # Low-level information
+//!
+//! 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;
+
+mod aspect;
+pub mod attachment; // TODO: make private
+pub mod immutable; // TODO: make private
+mod layout;
+mod storage;
+pub mod swapchain; // TODO: make private
+pub mod sys;
+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(),
+}
+
+impl From<SampleCount> for ash::vk::SampleCountFlags {
+ #[inline]
+ fn from(val: SampleCount) -> Self {
+ Self::from_raw(val as u32)
+ }
+}
+
+impl TryFrom<ash::vk::SampleCountFlags> for SampleCount {
+ type Error = ();
+
+ #[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(()),
+ }
+ }
+}
+
+impl TryFrom<u32> for SampleCount {
+ type Error = ();
+
+ #[inline]
+ fn try_from(val: u32) -> Result<Self, Self::Error> {
+ match val {
+ 1 => Ok(Self::Sample1),
+ 2 => Ok(Self::Sample2),
+ 4 => Ok(Self::Sample4),
+ 8 => Ok(Self::Sample8),
+ 16 => Ok(Self::Sample16),
+ 32 => Ok(Self::Sample32),
+ 64 => Ok(Self::Sample64),
+ _ => Err(()),
+ }
+ }
+}
+
+/// 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)]
+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.
+ ///
+ /// Note that this is not necessarily the maximum number of mipmaps, as the Vulkan
+ /// implementation may report that it supports a greater value.
+ Log2,
+
+ /// Allocate one mipmap (ie. just the main level). Always supported.
+ One,
+
+ /// Allocate the given number of mipmaps. May result in an error if the value is out of range
+ /// of what the implementation supports.
+ Specific(u32),
+}
+
+impl From<u32> for MipmapsCount {
+ #[inline]
+ fn from(num: u32) -> MipmapsCount {
+ MipmapsCount::Specific(num)
+ }
+}
+
+/// Helper type for creating extents
+#[derive(Debug, Copy, Clone)]
+pub enum Extent {
+ E1D([u32; 1]),
+ E2D([u32; 2]),
+ E3D([u32; 3]),
+}
+
+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 = ();
+
+ 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(()),
+ }
+ }
+}
+
+impl TryFrom<Extent> for ash::vk::Extent3D {
+ type Error = ();
+
+ 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(()),
+ }
+ }
+}
+
+/// 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,
+}
+
+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,
+ }
+ }
+}
+
+#[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,
+}
+
+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,
+ }
+ }
+
+ 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)
+ }
+}
+
+/// The dimensions of an image.
+#[derive(Copy, Clone, Debug, PartialEq, Eq)]
+pub enum ImageDimensions {
+ Dim1d {
+ width: u32,
+ array_layers: u32,
+ },
+ Dim2d {
+ width: u32,
+ height: u32,
+ array_layers: u32,
+ },
+ Dim3d {
+ width: u32,
+ height: u32,
+ depth: u32,
+ },
+}
+
+impl ImageDimensions {
+ #[inline]
+ pub fn width(&self) -> u32 {
+ match *self {
+ ImageDimensions::Dim1d { width, .. } => width,
+ ImageDimensions::Dim2d { width, .. } => width,
+ ImageDimensions::Dim3d { width, .. } => width,
+ }
+ }
+
+ #[inline]
+ pub fn height(&self) -> u32 {
+ match *self {
+ ImageDimensions::Dim1d { .. } => 1,
+ ImageDimensions::Dim2d { height, .. } => height,
+ ImageDimensions::Dim3d { height, .. } => height,
+ }
+ }
+
+ #[inline]
+ pub fn width_height(&self) -> [u32; 2] {
+ [self.width(), self.height()]
+ }
+
+ #[inline]
+ pub fn depth(&self) -> u32 {
+ match *self {
+ ImageDimensions::Dim1d { .. } => 1,
+ ImageDimensions::Dim2d { .. } => 1,
+ ImageDimensions::Dim3d { depth, .. } => depth,
+ }
+ }
+
+ #[inline]
+ pub fn width_height_depth(&self) -> [u32; 3] {
+ [self.width(), self.height(), self.depth()]
+ }
+
+ #[inline]
+ pub fn array_layers(&self) -> u32 {
+ match *self {
+ ImageDimensions::Dim1d { array_layers, .. } => array_layers,
+ ImageDimensions::Dim2d { array_layers, .. } => array_layers,
+ ImageDimensions::Dim3d { .. } => 1,
+ }
+ }
+
+ /// Returns the total number of texels for an image of these dimensions.
+ #[inline]
+ pub fn num_texels(&self) -> u32 {
+ self.width() * self.height() * self.depth() * self.array_layers()
+ }
+
+ /// Returns the maximum number of mipmaps for these image dimensions.
+ ///
+ /// The returned value is always at least superior or equal to 1.
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// use vulkano::image::ImageDimensions;
+ ///
+ /// let dims = ImageDimensions::Dim2d {
+ /// width: 32,
+ /// height: 50,
+ /// array_layers: 1,
+ /// };
+ ///
+ /// assert_eq!(dims.max_mipmaps(), 6);
+ /// ```
+ ///
+ pub fn max_mipmaps(&self) -> u32 {
+ 32 - (self.width() | self.height() | self.depth()).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()`.
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// use vulkano::image::ImageDimensions;
+ ///
+ /// let dims = ImageDimensions::Dim2d {
+ /// width: 963,
+ /// height: 256,
+ /// array_layers: 1,
+ /// };
+ ///
+ /// assert_eq!(dims.mipmap_dimensions(0), Some(dims));
+ /// assert_eq!(dims.mipmap_dimensions(1), Some(ImageDimensions::Dim2d {
+ /// width: 481,
+ /// height: 128,
+ /// array_layers: 1,
+ /// }));
+ /// assert_eq!(dims.mipmap_dimensions(6), Some(ImageDimensions::Dim2d {
+ /// width: 15,
+ /// height: 4,
+ /// array_layers: 1,
+ /// }));
+ /// assert_eq!(dims.mipmap_dimensions(9), Some(ImageDimensions::Dim2d {
+ /// width: 1,
+ /// height: 1,
+ /// array_layers: 1,
+ /// }));
+ /// assert_eq!(dims.mipmap_dimensions(11), None);
+ /// ```
+ ///
+ /// # Panic
+ ///
+ /// In debug mode, Panics if `width`, `height` or `depth` is equal to 0. In release, returns
+ /// an unspecified value.
+ ///
+ pub fn mipmap_dimensions(&self, level: u32) -> Option<ImageDimensions> {
+ if level == 0 {
+ return Some(*self);
+ }
+
+ if level >= self.max_mipmaps() {
+ return None;
+ }
+
+ Some(match *self {
+ ImageDimensions::Dim1d {
+ width,
+ array_layers,
+ } => {
+ debug_assert_ne!(width, 0);
+ ImageDimensions::Dim1d {
+ array_layers,
+ width: cmp::max(1, width >> level),
+ }
+ }
+
+ ImageDimensions::Dim2d {
+ width,
+ height,
+ array_layers,
+ } => {
+ debug_assert_ne!(width, 0);
+ debug_assert_ne!(height, 0);
+ ImageDimensions::Dim2d {
+ width: cmp::max(1, width >> level),
+ height: cmp::max(1, height >> level),
+ array_layers,
+ }
+ }
+
+ ImageDimensions::Dim3d {
+ width,
+ height,
+ depth,
+ } => {
+ debug_assert_ne!(width, 0);
+ debug_assert_ne!(height, 0);
+ ImageDimensions::Dim3d {
+ width: cmp::max(1, width >> level),
+ height: cmp::max(1, height >> level),
+ depth: cmp::max(1, depth >> level),
+ }
+ }
+ })
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use crate::format::Format;
+ use crate::image::ImageDimensions;
+ use crate::image::ImmutableImage;
+ use crate::image::MipmapsCount;
+
+ #[test]
+ fn max_mipmaps() {
+ let dims = ImageDimensions::Dim2d {
+ width: 2,
+ height: 1,
+ array_layers: 1,
+ };
+ assert_eq!(dims.max_mipmaps(), 2);
+
+ let dims = ImageDimensions::Dim2d {
+ width: 2,
+ height: 3,
+ array_layers: 1,
+ };
+ assert_eq!(dims.max_mipmaps(), 2);
+
+ let dims = ImageDimensions::Dim2d {
+ width: 512,
+ height: 512,
+ array_layers: 1,
+ };
+ assert_eq!(dims.max_mipmaps(), 10);
+ }
+
+ #[test]
+ fn mipmap_dimensions() {
+ let dims = ImageDimensions::Dim2d {
+ width: 283,
+ height: 175,
+ array_layers: 1,
+ };
+ assert_eq!(dims.mipmap_dimensions(0), Some(dims));
+ assert_eq!(
+ dims.mipmap_dimensions(1),
+ Some(ImageDimensions::Dim2d {
+ width: 141,
+ height: 87,
+ array_layers: 1,
+ })
+ );
+ assert_eq!(
+ dims.mipmap_dimensions(2),
+ Some(ImageDimensions::Dim2d {
+ width: 70,
+ height: 43,
+ array_layers: 1,
+ })
+ );
+ assert_eq!(
+ dims.mipmap_dimensions(3),
+ Some(ImageDimensions::Dim2d {
+ width: 35,
+ height: 21,
+ array_layers: 1,
+ })
+ );
+
+ assert_eq!(
+ dims.mipmap_dimensions(4),
+ Some(ImageDimensions::Dim2d {
+ width: 17,
+ height: 10,
+ array_layers: 1,
+ })
+ );
+ assert_eq!(
+ dims.mipmap_dimensions(5),
+ Some(ImageDimensions::Dim2d {
+ width: 8,
+ height: 5,
+ array_layers: 1,
+ })
+ );
+ assert_eq!(
+ dims.mipmap_dimensions(6),
+ Some(ImageDimensions::Dim2d {
+ width: 4,
+ height: 2,
+ array_layers: 1,
+ })
+ );
+ assert_eq!(
+ dims.mipmap_dimensions(7),
+ Some(ImageDimensions::Dim2d {
+ width: 2,
+ height: 1,
+ array_layers: 1,
+ })
+ );
+ assert_eq!(
+ dims.mipmap_dimensions(8),
+ Some(ImageDimensions::Dim2d {
+ width: 1,
+ height: 1,
+ array_layers: 1,
+ })
+ );
+ assert_eq!(dims.mipmap_dimensions(9), None);
+ }
+
+ #[test]
+ fn mipmap_working_immutable_image() {
+ let (device, queue) = gfx_dev_and_queue!();
+
+ let dimensions = ImageDimensions::Dim2d {
+ width: 512,
+ height: 512,
+ array_layers: 1,
+ };
+ {
+ let mut vec = Vec::new();
+
+ vec.resize(512 * 512, 0u8);
+
+ let (image, _) = ImmutableImage::from_iter(
+ vec.into_iter(),
+ dimensions,
+ MipmapsCount::One,
+ Format::R8Unorm,
+ queue.clone(),
+ )
+ .unwrap();
+ assert_eq!(image.mipmap_levels(), 1);
+ }
+ {
+ let mut vec = Vec::new();
+
+ vec.resize(512 * 512, 0u8);
+
+ let (image, _) = ImmutableImage::from_iter(
+ vec.into_iter(),
+ dimensions,
+ MipmapsCount::Log2,
+ Format::R8Unorm,
+ queue.clone(),
+ )
+ .unwrap();
+ assert_eq!(image.mipmap_levels(), 10);
+ }
+ }
+}
diff --git a/src/image/storage.rs b/src/image/storage.rs
new file mode 100644
index 0000000..627d43a
--- /dev/null
+++ b/src/image/storage.rs
@@ -0,0 +1,336 @@
+// 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::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 smallvec::SmallVec;
+use std::hash::Hash;
+use std::hash::Hasher;
+use std::sync::atomic::AtomicUsize;
+use std::sync::atomic::Ordering;
+use std::sync::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,
+
+ // 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,
+}
+
+impl StorageImage {
+ /// Creates a new image with the given dimensions and format.
+ #[inline]
+ pub fn new<'a, I>(
+ device: Arc<Device>,
+ 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,
+ };
+
+ 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();
+
+ StorageImage::with_usage(device, dimensions, format, usage, flags, queue_families)
+ }
+
+ /// Same as `new`, but allows specifying the usage.
+ pub fn with_usage<'a, I>(
+ device: Arc<Device>,
+ 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,
+ flags,
+ dimensions,
+ SampleCount::Sample1,
+ 1,
+ 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
+ } else {
+ AllocFromRequirementsFilter::Allowed
+ }
+ },
+ )?;
+ debug_assert!((memory.offset() % mem_reqs.alignment) == 0);
+ unsafe {
+ image.bind_memory(memory.memory(), memory.offset())?;
+ }
+
+ Ok(Arc::new(StorageImage {
+ image,
+ memory,
+ dimensions,
+ format,
+ queue_families,
+ gpu_lock: AtomicUsize::new(0),
+ }))
+ }
+}
+
+impl<A> StorageImage<A>
+where
+ A: MemoryPool,
+{
+ /// Returns the dimensions of the image.
+ #[inline]
+ pub fn dimensions(&self) -> ImageDimensions {
+ self.dimensions
+ }
+}
+
+unsafe impl<A> ImageAccess for StorageImage<A>
+where
+ A: MemoryPool,
+{
+ #[inline]
+ fn inner(&self) -> ImageInner {
+ ImageInner {
+ image: &self.image,
+ first_layer: 0,
+ num_layers: self.dimensions.array_layers() as usize,
+ first_mipmap_level: 0,
+ num_mipmap_levels: 1,
+ }
+ }
+
+ #[inline]
+ fn initial_layout_requirement(&self) -> ImageLayout {
+ ImageLayout::General
+ }
+
+ #[inline]
+ fn final_layout_requirement(&self) -> ImageLayout {
+ ImageLayout::General
+ }
+
+ #[inline]
+ fn descriptor_layouts(&self) -> Option<ImageDescriptorLayouts> {
+ Some(ImageDescriptorLayouts {
+ storage_image: ImageLayout::General,
+ combined_image_sampler: ImageLayout::General,
+ sampled_image: ImageLayout::General,
+ 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]
+ fn matches_format(&self) -> bool {
+ true // FIXME:
+ }
+}
+
+impl<A> PartialEq for StorageImage<A>
+where
+ A: MemoryPool,
+{
+ #[inline]
+ fn eq(&self, other: &Self) -> bool {
+ ImageAccess::inner(self) == ImageAccess::inner(other)
+ }
+}
+
+impl<A> Eq for StorageImage<A> where A: MemoryPool {}
+
+impl<A> Hash for StorageImage<A>
+where
+ A: MemoryPool,
+{
+ #[inline]
+ fn hash<H: Hasher>(&self, state: &mut H) {
+ ImageAccess::inner(self).hash(state);
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use super::StorageImage;
+ use crate::format::Format;
+ use crate::image::ImageDimensions;
+
+ #[test]
+ fn create() {
+ let (device, queue) = gfx_dev_and_queue!();
+ let _img = StorageImage::new(
+ device,
+ ImageDimensions::Dim2d {
+ width: 32,
+ height: 32,
+ array_layers: 1,
+ },
+ Format::R8G8B8A8Unorm,
+ Some(queue.family()),
+ )
+ .unwrap();
+ }
+}
diff --git a/src/image/swapchain.rs b/src/image/swapchain.rs
new file mode 100644
index 0000000..9cd3fe5
--- /dev/null
+++ b/src/image/swapchain.rs
@@ -0,0 +1,189 @@
+// 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::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;
+
+/// An image that is part of a swapchain.
+///
+/// Creating a `SwapchainImage` is automatically done when creating a swapchain.
+///
+/// A swapchain image is special in the sense that it can only be used after being acquired by
+/// calling the `acquire` method on the swapchain. You have no way to know in advance which
+/// swapchain image is going to be acquired, so you should keep all of them alive.
+///
+/// After a swapchain image has been acquired, you are free to perform all the usual operations
+/// on it. When you are done you can then *present* the image (by calling the corresponding
+/// 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,
+}
+
+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();
+
+ Ok(Arc::new(SwapchainImage {
+ swapchain: swapchain.clone(),
+ image_offset: id,
+ }))
+ }
+
+ /// 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);
+ }
+
+ #[inline]
+ fn is_layout_initialized(&self) -> bool {
+ self.swapchain
+ .is_image_layout_initialized(self.image_offset)
+ }
+}
+
+unsafe impl<W> ImageAccess for SwapchainImage<W> {
+ #[inline]
+ fn inner(&self) -> ImageInner {
+ self.my_image()
+ }
+
+ #[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,
+ 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();
+ }
+
+ #[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))
+ }
+}
+
+unsafe impl<P, W> ImageContent<P> for SwapchainImage<W> {
+ #[inline]
+ fn matches_format(&self) -> bool {
+ true // FIXME:
+ }
+}
+
+impl<W> PartialEq for SwapchainImage<W> {
+ #[inline]
+ fn eq(&self, other: &Self) -> bool {
+ ImageAccess::inner(self) == ImageAccess::inner(other)
+ }
+}
+
+impl<W> Eq for SwapchainImage<W> {}
+
+impl<W> Hash for SwapchainImage<W> {
+ #[inline]
+ fn hash<H: Hasher>(&self, state: &mut H) {
+ ImageAccess::inner(self).hash(state);
+ }
+}
diff --git a/src/image/sys.rs b/src/image/sys.rs
new file mode 100644
index 0000000..c810478
--- /dev/null
+++ b/src/image/sys.rs
@@ -0,0 +1,1349 @@
+// 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 implementation of images.
+//!
+//! This module contains low-level wrappers around the Vulkan image types. All
+//! 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.
+///
+pub struct UnsafeImage {
+ image: ash::vk::Image,
+ device: Arc<Device>,
+ usage: ImageUsage,
+ format: Format,
+ flags: ImageCreateFlags,
+
+ dimensions: ImageDimensions,
+ samples: SampleCount,
+ mipmaps: u32,
+
+ // Features that are supported for this particular format.
+ format_features: FormatFeatures,
+
+ // `vkDestroyImage` is called only if `needs_destruction` is true.
+ needs_destruction: bool,
+ preinitialized_layout: bool,
+}
+
+impl UnsafeImage {
+ /// Creates a new image and allocates memory for it.
+ ///
+ /// # Panic
+ ///
+ /// - Panics if one of the dimensions is 0.
+ /// - Panics if the number of mipmaps is 0.
+ /// - Panics if the number of samples is 0.
+ ///
+ #[inline]
+ pub unsafe fn new<'a, Mi, I>(
+ 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()),
+ };
+
+ UnsafeImage::new_impl(
+ device,
+ usage,
+ format,
+ flags,
+ dimensions,
+ num_samples,
+ mipmaps.into(),
+ sharing,
+ linear_tiling,
+ preinitialized_layout,
+ )
+ }
+
+ // 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
+ {
+ unimplemented!();
+ }
+
+ let fns = device.fns();
+ let fns_i = device.instance().fns();
+
+ // Checking if image usage conforms to what is supported.
+ let format_features = {
+ let format_properties = format.properties(device.physical_device());
+
+ let features = if linear_tiling {
+ format_properties.linear_tiling_features
+ } else {
+ format_properties.optimal_tiling_features
+ };
+
+ if features == FormatFeatures::default() {
+ return Err(ImageCreationError::FormatNotSupported);
+ }
+
+ if usage.sampled && !features.sampled_image {
+ return Err(ImageCreationError::UnsupportedUsage);
+ }
+ if usage.storage && !features.storage_image {
+ return Err(ImageCreationError::UnsupportedUsage);
+ }
+ if usage.color_attachment && !features.color_attachment {
+ return Err(ImageCreationError::UnsupportedUsage);
+ }
+ if usage.depth_stencil_attachment && !features.depth_stencil_attachment {
+ return Err(ImageCreationError::UnsupportedUsage);
+ }
+ if usage.input_attachment
+ && !(features.color_attachment || features.depth_stencil_attachment)
+ {
+ return Err(ImageCreationError::UnsupportedUsage);
+ }
+ if device.api_version() >= Version::V1_1 || device.enabled_extensions().khr_maintenance1
+ {
+ if usage.transfer_source && !features.transfer_src {
+ return Err(ImageCreationError::UnsupportedUsage);
+ }
+ if usage.transfer_destination && !features.transfer_dst {
+ return Err(ImageCreationError::UnsupportedUsage);
+ }
+ }
+
+ features
+ };
+
+ // VUID-VkImageCreateInfo-usage-requiredbitmask: usage must not be 0
+ if usage == ImageUsage::none() {
+ return Err(ImageCreationError::UnsupportedUsage);
+ }
+
+ // 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 u != ImageUsage::none() {
+ return Err(ImageCreationError::UnsupportedUsage);
+ }
+ }
+
+ // 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;
+
+ // 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,
+ });
+ }
+
+ num
+ }
+ 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 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.storage {
+ supported_samples &= device
+ .physical_device()
+ .properties()
+ .storage_image_sample_counts
+ .into();
+ }
+
+ if usage.color_attachment
+ || usage.depth_stencil_attachment
+ || usage.input_attachment
+ || usage.transient_attachment
+ {
+ 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();
+ }
+ FormatTy::DepthStencil => {
+ supported_samples &= device
+ .physical_device()
+ .properties()
+ .framebuffer_depth_sample_counts
+ .into();
+ supported_samples &= device
+ .physical_device()
+ .properties()
+ .framebuffer_stencil_sample_counts
+ .into();
+ }
+ FormatTy::Ycbcr => {
+ /*
+ * It's generally not possible to use a Ycbcr image as a framebuffer color
+ * attachment.
+ */
+ return Err(ImageCreationError::UnsupportedUsage);
+ }
+ }
+ }
+
+ if (ash::vk::SampleCountFlags::from(num_samples) & supported_samples).is_empty() {
+ let err = ImageCreationError::UnsupportedSamplesCount {
+ obtained: num_samples,
+ };
+ capabilities_error = Some(err);
+ }
+ }
+
+ // 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);
+ }
+ }
+
+ // Decoding the dimensions.
+ let (ty, 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)
+ }
+ 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)
+ }
+ 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)
+ }
+ };
+
+ // 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);
+ }
+ }
+
+ if flags.array_2d_compatible {
+ if !(ty == ash::vk::ImageType::TYPE_3D) {
+ return Err(ImageCreationError::CreationFlagRequirementsNotMet);
+ }
+ }
+
+ // Checking the dimensions against the limits.
+ if array_layers
+ > device
+ .physical_device()
+ .properties()
+ .max_image_array_layers
+ {
+ let err = ImageCreationError::UnsupportedDimensions { dimensions };
+ capabilities_error = Some(err);
+ }
+ 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);
+ }
+ }
+ }
+ 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);
+ }
+ }
+ _ => unreachable!(),
+ };
+
+ let usage_bits = usage.into();
+
+ // 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 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(),
+ );
+
+ match check_errors(r) {
+ Ok(_) => (),
+ Err(Error::FormatNotSupported) => {
+ return Err(ImageCreationError::FormatNotSupported)
+ }
+ Err(err) => return Err(err.into()),
+ }
+
+ let output = output.assume_init();
+
+ 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()
+ {
+ 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
+ } else {
+ ash::vk::ImageLayout::UNDEFINED
+ },
+ ..Default::default()
+ };
+
+ 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 mem_reqs = if device.api_version() >= Version::V1_1
+ || device.enabled_extensions().khr_get_memory_requirements2
+ {
+ let infos = ash::vk::ImageMemoryRequirementsInfo2 {
+ image,
+ ..Default::default()
+ };
+
+ let mut output2 = if device.api_version() >= Version::V1_1
+ || device.enabled_extensions().khr_dedicated_allocation
+ {
+ Some(ash::vk::MemoryDedicatedRequirements::default())
+ } else {
+ None
+ };
+
+ 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()
+ };
+
+ if device.api_version() >= Version::V1_1 {
+ fns.v1_1.get_image_memory_requirements2(
+ device.internal_object(),
+ &infos,
+ &mut output,
+ );
+ } else {
+ fns.khr_get_memory_requirements2
+ .get_image_memory_requirements2_khr(
+ device.internal_object(),
+ &infos,
+ &mut output,
+ );
+ }
+
+ 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;
+ }
+ 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)
+ };
+
+ let image = UnsafeImage {
+ device: device.clone(),
+ image,
+ usage,
+ format,
+ flags,
+ dimensions,
+ samples: num_samples,
+ mipmaps,
+ format_features,
+ needs_destruction: true,
+ preinitialized_layout,
+ };
+
+ Ok((image, mem_reqs))
+ }
+
+ /// 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());
+
+ // TODO: check that usage is correct in regard to `output`?
+
+ 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?
+ }
+ }
+
+ pub unsafe fn bind_memory(
+ &self,
+ memory: &DeviceMemory,
+ offset: DeviceSize,
+ ) -> Result<(), OomError> {
+ 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 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
+ });
+
+ check_errors(fns.v1_0.bind_image_memory(
+ self.device.internal_object(),
+ self.image,
+ memory.internal_object(),
+ offset,
+ ))?;
+ Ok(())
+ }
+
+ #[inline]
+ pub fn device(&self) -> &Arc<Device> {
+ &self.device
+ }
+
+ #[inline]
+ pub fn format(&self) -> Format {
+ self.format
+ }
+
+ pub fn create_flags(&self) -> ImageCreateFlags {
+ self.flags
+ }
+
+ #[inline]
+ pub fn mipmap_levels(&self) -> u32 {
+ self.mipmaps
+ }
+
+ #[inline]
+ pub fn dimensions(&self) -> ImageDimensions {
+ self.dimensions
+ }
+
+ #[inline]
+ pub fn samples(&self) -> SampleCount {
+ self.samples
+ }
+
+ /// Returns a key unique to each `UnsafeImage`. Can be used for the `conflicts_key` method.
+ #[inline]
+ pub fn key(&self) -> u64 {
+ self.image.as_raw()
+ }
+
+ /// Queries the layout of an image in memory. Only valid for images with linear tiling.
+ ///
+ /// This function is only valid for images with a color format. See the other similar functions
+ /// for the other aspects.
+ ///
+ /// 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.
+ ///
+ /// 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.
+ ///
+ /// # Panic
+ ///
+ /// - Panics if the mipmap level is out of range.
+ ///
+ /// # Safety
+ ///
+ /// - The image must *not* have a depth, stencil or depth-stencil format.
+ /// - The image must have been created with linear tiling.
+ ///
+ #[inline]
+ pub unsafe fn color_linear_layout(&self, mip_level: u32) -> LinearLayout {
+ self.linear_layout_impl(mip_level, ImageAspect::Color)
+ }
+
+ /// Same as `color_linear_layout`, except that it retrieves the depth component of the image.
+ ///
+ /// # Panic
+ ///
+ /// - Panics if the mipmap level is out of range.
+ ///
+ /// # Safety
+ ///
+ /// - The image must have a depth or depth-stencil format.
+ /// - The image must have been created with linear tiling.
+ ///
+ #[inline]
+ pub unsafe fn depth_linear_layout(&self, mip_level: u32) -> LinearLayout {
+ self.linear_layout_impl(mip_level, ImageAspect::Depth)
+ }
+
+ /// Same as `color_linear_layout`, except that it retrieves the stencil component of the image.
+ ///
+ /// # Panic
+ ///
+ /// - Panics if the mipmap level is out of range.
+ ///
+ /// # Safety
+ ///
+ /// - The image must have a stencil or depth-stencil format.
+ /// - The image must have been created with linear tiling.
+ ///
+ #[inline]
+ pub unsafe fn stencil_linear_layout(&self, mip_level: u32) -> LinearLayout {
+ self.linear_layout_impl(mip_level, ImageAspect::Stencil)
+ }
+
+ /// Same as `color_linear_layout`, except that it retrieves layout for the requested ycbcr
+ /// component too if the format is a YcbCr format.
+ ///
+ /// # Panic
+ ///
+ /// - 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);
+
+ 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);
+ }
+ }
+
+ self.linear_layout_impl(0, aspect)
+ }
+
+ // 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,
+ };
+
+ let mut out = MaybeUninit::uninit();
+ fns.v1_0.get_image_subresource_layout(
+ self.device.internal_object(),
+ self.image,
+ &subresource,
+ out.as_mut_ptr(),
+ );
+
+ 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 flags the image was created with.
+ #[inline]
+ pub fn 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 usage the image was created with.
+ #[inline]
+ pub fn usage(&self) -> ImageUsage {
+ self.usage
+ }
+
+ #[inline]
+ pub fn preinitialized_layout(&self) -> bool {
+ self.preinitialized_layout
+ }
+}
+
+unsafe impl VulkanObject for UnsafeImage {
+ type Object = ash::vk::Image;
+
+ #[inline]
+ fn internal_object(&self) -> ash::vk::Image {
+ self.image
+ }
+}
+
+impl fmt::Debug for UnsafeImage {
+ #[inline]
+ fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
+ write!(fmt, "<Vulkan image {:?}>", self.image)
+ }
+}
+
+impl Drop for UnsafeImage {
+ #[inline]
+ fn drop(&mut self) {
+ if !self.needs_destruction {
+ return;
+ }
+
+ unsafe {
+ let fns = self.device.fns();
+ fns.v1_0
+ .destroy_image(self.device.internal_object(), self.image, ptr::null());
+ }
+ }
+}
+
+impl PartialEq for UnsafeImage {
+ #[inline]
+ fn eq(&self, other: &Self) -> bool {
+ self.image == other.image && self.device == other.device
+ }
+}
+
+impl Eq for UnsafeImage {}
+
+impl Hash for UnsafeImage {
+ #[inline]
+ fn hash<H: Hasher>(&self, state: &mut H) {
+ self.image.hash(state);
+ self.device.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,
+}
+
+impl error::Error for ImageCreationError {
+ #[inline]
+ fn source(&self) -> Option<&(dyn error::Error + 'static)> {
+ match *self {
+ ImageCreationError::AllocError(ref err) => Some(err),
+ _ => None,
+ }
+ }
+}
+
+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"
+ }
+ ImageCreationError::UnsupportedSamplesCount { .. } => {
+ "the requested number of samples is not supported, or is 0"
+ }
+ ImageCreationError::UnsupportedDimensions { .. } => {
+ "the dimensions are too large, or one of the dimensions is 0"
+ }
+ ImageCreationError::UnsupportedUsage => {
+ "the format is supported, but at least one of the requested usages is not \
+ supported"
+ }
+ ImageCreationError::ShaderStorageImageMultisampleFeatureNotEnabled => {
+ "the `shader_storage_image_multisample` feature must be enabled to create such \
+ an image"
+ }
+ }
+ )
+ }
+}
+
+impl From<OomError> for ImageCreationError {
+ #[inline]
+ fn from(err: OomError) -> ImageCreationError {
+ ImageCreationError::AllocError(DeviceMemoryAllocError::OomError(err))
+ }
+}
+
+impl From<DeviceMemoryAllocError> for ImageCreationError {
+ #[inline]
+ fn from(err: DeviceMemoryAllocError) -> ImageCreationError {
+ ImageCreationError::AllocError(err)
+ }
+}
+
+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),
+ }
+ }
+}
+
+/// Describes the memory layout of an image with linear tiling.
+///
+/// Obtained by calling `*_linear_layout` on the 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.
+ pub offset: DeviceSize,
+ /// Total number of bytes for the queried subresource. Can be used for a safety check.
+ pub size: DeviceSize,
+ /// 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,
+}
+
+#[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;
+
+ #[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 {
+ width: 32,
+ height: 32,
+ array_layers: 1,
+ },
+ SampleCount::Sample1,
+ 1,
+ Sharing::Exclusive::<Empty<_>>,
+ false,
+ false,
+ )
+ }
+ .unwrap();
+ }
+
+ #[test]
+ 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 {
+ width: 32,
+ height: 32,
+ array_layers: 1,
+ },
+ SampleCount::Sample1,
+ 1,
+ Sharing::Exclusive::<Empty<_>>,
+ false,
+ false,
+ )
+ }
+ .unwrap();
+ }
+
+ #[test]
+ fn zero_mipmap() {
+ 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 {
+ width: 32,
+ height: 32,
+ array_layers: 1,
+ },
+ 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 {
+ width: 32,
+ height: 32,
+ array_layers: 1,
+ },
+ SampleCount::Sample1,
+ u32::MAX,
+ Sharing::Exclusive::<Empty<_>>,
+ false,
+ false,
+ )
+ };
+
+ match res {
+ Err(ImageCreationError::InvalidMipmapsCount {
+ obtained,
+ valid_range,
+ }) => {
+ assert_eq!(obtained, u32::MAX);
+ assert_eq!(valid_range.start, 1);
+ }
+ _ => panic!(),
+ };
+ }
+
+ #[test]
+ 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 {
+ width: 32,
+ height: 32,
+ array_layers: 1,
+ },
+ SampleCount::Sample2,
+ 1,
+ Sharing::Exclusive::<Empty<_>>,
+ false,
+ false,
+ )
+ };
+
+ match res {
+ Err(ImageCreationError::ShaderStorageImageMultisampleFeatureNotEnabled) => (),
+ Err(ImageCreationError::UnsupportedSamplesCount { .. }) => (), // unlikely but possible
+ _ => panic!(),
+ };
+ }
+
+ #[test]
+ 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 {
+ width: 32,
+ height: 32,
+ array_layers: 1,
+ },
+ SampleCount::Sample1,
+ u32::MAX,
+ Sharing::Exclusive::<Empty<_>>,
+ false,
+ false,
+ )
+ };
+
+ match res {
+ Err(ImageCreationError::FormatNotSupported) => (),
+ Err(ImageCreationError::UnsupportedUsage) => (),
+ _ => panic!(),
+ };
+ }
+
+ #[test]
+ 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(
+ device,
+ usage,
+ Format::R8G8B8A8Unorm,
+ ImageCreateFlags::none(),
+ ImageDimensions::Dim2d {
+ width: 32,
+ height: 32,
+ array_layers: 1,
+ },
+ 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 {
+ width: 32,
+ height: 64,
+ array_layers: 1,
+ },
+ SampleCount::Sample1,
+ 1,
+ Sharing::Exclusive::<Empty<_>>,
+ false,
+ false,
+ )
+ };
+
+ match res {
+ Err(ImageCreationError::CreationFlagRequirementsNotMet) => (),
+ _ => panic!(),
+ };
+ }
+}
diff --git a/src/image/traits.rs b/src/image/traits.rs
new file mode 100644
index 0000000..4c6a5c8
--- /dev/null
+++ b/src/image/traits.rs
@@ -0,0 +1,438 @@
+// 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::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;
+
+/// Trait for types that represent the way a GPU can access an image.
+pub unsafe trait ImageAccess {
+ /// Returns the inner unsafe image object used by this image.
+ 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.
+ #[inline]
+ fn has_color(&self) -> bool {
+ matches!(
+ self.format().ty(),
+ FormatTy::Float | FormatTy::Uint | FormatTy::Sint | FormatTy::Compressed
+ )
+ }
+
+ /// Returns true if the image has a depth component. In other words, if it is a depth or a
+ /// depth-stencil format.
+ #[inline]
+ fn has_depth(&self) -> bool {
+ matches!(self.format().ty(), FormatTy::Depth | FormatTy::DepthStencil)
+ }
+
+ /// Returns true if the image has a stencil component. In other words, if it is a stencil or a
+ /// depth-stencil format.
+ #[inline]
+ fn has_stencil(&self) -> bool {
+ matches!(
+ self.format().ty(),
+ FormatTy::Stencil | FormatTy::DepthStencil
+ )
+ }
+
+ /// 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()
+ }
+
+ /// Returns the number of samples of this image.
+ #[inline]
+ fn samples(&self) -> SampleCount {
+ self.inner().image.samples()
+ }
+
+ /// Returns the dimensions of the image.
+ #[inline]
+ fn dimensions(&self) -> ImageDimensions {
+ // TODO: not necessarily correct because of the new inner() design?
+ self.inner().image.dimensions()
+ }
+
+ /// Returns true if the image can be used as a source for blits.
+ #[inline]
+ fn supports_blit_source(&self) -> bool {
+ self.inner().image.format_features().blit_src
+ }
+
+ /// Returns true if the image can be used as a destination for blits.
+ #[inline]
+ fn supports_blit_destination(&self) -> bool {
+ self.inner().image.format_features().blit_dst
+ }
+
+ /// When images are created their memory layout is initially `Undefined` or `Preinitialized`.
+ /// This method allows the image memory barrier creation process to signal when an image
+ /// has been transitioned out of its initial `Undefined` or `Preinitialized` state. This
+ /// allows vulkano to avoid creating unnecessary image memory barriers between future
+ /// uses of the image.
+ ///
+ /// ## Unsafe
+ ///
+ /// If a user calls this method outside of the intended context and signals that the layout
+ /// is no longer `Undefined` or `Preinitialized` when it is still in an `Undefined` or
+ /// `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.
+ unsafe fn layout_initialized(&self) {}
+
+ fn is_layout_initialized(&self) -> bool {
+ false
+ }
+
+ unsafe fn preinitialized_layout(&self) -> bool {
+ self.inner().image.preinitialized_layout()
+ }
+
+ /// Returns the layout that the image has when it is first used in a primary command buffer.
+ ///
+ /// The first time you use an image in an `AutoCommandBufferBuilder`, vulkano will suppose that
+ /// the image is in the layout returned by this function. Later when the command buffer is
+ /// submitted vulkano will check whether the image is actually in this layout, and if it is not
+ /// the case then an error will be returned.
+ /// TODO: ^ that check is not yet implemented
+ fn initial_layout_requirement(&self) -> ImageLayout;
+
+ /// Returns the layout that the image must be returned to before the end of the command buffer.
+ ///
+ /// When an image is used in an `AutoCommandBufferBuilder` vulkano will automatically
+ /// transition this image to the layout returned by this function at the end of the command
+ /// buffer, if necessary.
+ ///
+ /// Except for special cases, this value should likely be the same as the one returned by
+ /// `initial_layout_requirement` so that the user can submit multiple command buffers that use
+ /// this image one after the other.
+ fn final_layout_requirement(&self) -> ImageLayout;
+
+ /// Wraps around this `ImageAccess` and returns an identical `ImageAccess` but whose initial
+ /// layout requirement is either `Undefined` or `Preinitialized`.
+ #[inline]
+ unsafe fn forced_undefined_initial_layout(
+ self,
+ preinitialized: bool,
+ ) -> ImageAccessFromUndefinedLayout<Self>
+ where
+ Self: Sized,
+ {
+ ImageAccessFromUndefinedLayout {
+ image: self,
+ preinitialized,
+ }
+ }
+
+ /// Returns an [`ImageDescriptorLayouts`] structure specifying the image layout to use
+ /// in descriptors of various kinds.
+ ///
+ /// 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,
+
+ /// The first layer of `image` to consider.
+ pub first_layer: usize,
+
+ /// The number of layers of `image` to consider.
+ pub num_layers: usize,
+
+ /// The first mipmap level of `image` to consider.
+ pub first_mipmap_level: usize,
+
+ /// The number of mipmap levels of `image` to consider.
+ pub num_mipmap_levels: usize,
+}
+
+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 PartialEq for dyn ImageAccess + Send + Sync {
+ #[inline]
+ fn eq(&self, other: &Self) -> bool {
+ self.inner() == other.inner()
+ }
+}
+
+impl Eq for dyn ImageAccess + Send + Sync {}
+
+impl Hash for dyn ImageAccess + Send + Sync {
+ #[inline]
+ fn hash<H: Hasher>(&self, state: &mut H) {
+ self.inner().hash(state);
+ }
+}
+
+/// Wraps around an object that implements `ImageAccess` and modifies the initial layout
+/// requirement to be either `Undefined` or `Preinitialized`.
+#[derive(Debug, Copy, Clone)]
+pub struct ImageAccessFromUndefinedLayout<I> {
+ image: I,
+ preinitialized: bool,
+}
+
+unsafe impl<I> ImageAccess for ImageAccessFromUndefinedLayout<I>
+where
+ I: ImageAccess,
+{
+ #[inline]
+ fn inner(&self) -> ImageInner {
+ self.image.inner()
+ }
+
+ #[inline]
+ fn initial_layout_requirement(&self) -> ImageLayout {
+ if self.preinitialized {
+ ImageLayout::Preinitialized
+ } else {
+ ImageLayout::Undefined
+ }
+ }
+
+ #[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()
+ }
+}
+
+impl<I> Eq for ImageAccessFromUndefinedLayout<I> where I: ImageAccess {}
+
+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;
+}
diff --git a/src/image/usage.rs b/src/image/usage.rs
new file mode 100644
index 0000000..da64809
--- /dev/null
+++ b/src/image/usage.rs
@@ -0,0 +1,222 @@
+// 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::ops::BitOr;
+
+/// 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,
+
+ /// Can be used as a destination for transfers. Includes blits.
+ pub transfer_destination: bool,
+
+ /// Can be sampled from a shader.
+ pub sampled: bool,
+
+ /// Can be used as an image storage in a shader.
+ pub storage: bool,
+
+ /// Can be attached as a color attachment to a framebuffer.
+ pub color_attachment: bool,
+
+ /// Can be attached as a depth, stencil or depth-stencil attachment to a framebuffer.
+ pub depth_stencil_attachment: bool,
+
+ /// Indicates that this image will only ever be used as a temporary framebuffer attachment.
+ /// 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,
+ }
+ }
+}
diff --git a/src/image/view.rs b/src/image/view.rs
new file mode 100644
index 0000000..894a343
--- /dev/null
+++ b/src/image/view.rs
@@ -0,0 +1,621 @@
+// 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.
+
+//! Image views.
+//!
+//! This module contains types related to image views. An image view wraps around
+//! 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.
+pub struct ImageView<I>
+where
+ I: ImageAccess,
+{
+ image: I,
+ inner: UnsafeImageView,
+ format: Format,
+
+ ty: ImageViewType,
+ component_mapping: ComponentMapping,
+ array_layers: Range<u32>,
+}
+
+impl<I> ImageView<I>
+where
+ I: ImageAccess,
+{
+ /// 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();
+
+ ImageViewBuilder {
+ image,
+ ty,
+ component_mapping: ComponentMapping::default(),
+ mipmap_levels,
+ array_layers,
+ }
+ }
+
+ /// Returns the wrapped image that this image view was created from.
+ pub fn image(&self) -> &I {
+ &self.image
+ }
+}
+
+#[derive(Debug)]
+pub struct ImageViewBuilder<I> {
+ image: I,
+ ty: ImageViewType,
+ component_mapping: ComponentMapping,
+ mipmap_levels: Range<u32>,
+ array_layers: Range<u32>,
+}
+
+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
+ }
+
+ /// 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
+ }
+
+ /// 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
+ }
+
+ /// 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
+ }
+
+ /// 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();
+
+ if self.mipmap_levels.end <= self.mipmap_levels.start
+ || self.mipmap_levels.end > image_inner.mipmap_levels()
+ {
+ return Err(ImageViewCreationError::MipMapLevelsOutOfRange);
+ }
+
+ if self.array_layers.end <= self.array_layers.start
+ || self.array_layers.end > dimensions.array_layers()
+ {
+ return Err(ImageViewCreationError::ArrayLayersOutOfRange);
+ }
+
+ if !(usage.sampled
+ || usage.storage
+ || usage.color_attachment
+ || usage.depth_stencil_attachment
+ || usage.input_attachment
+ || usage.transient_attachment)
+ {
+ return Err(ImageViewCreationError::InvalidImageUsage);
+ }
+
+ // 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 =>
+ {
+ ()
+ }
+ (ImageViewType::CubemapArray, ImageDimensions::Dim2d { .. }, n, _)
+ if flags.cube_compatible && n % 6 == 0 =>
+ {
+ ()
+ }
+ (ImageViewType::Dim3d, ImageDimensions::Dim3d { .. }, 1, _) => (),
+ (ImageViewType::Dim2d, ImageDimensions::Dim3d { .. }, 1, 1)
+ if flags.array_2d_compatible =>
+ {
+ ()
+ }
+ (ImageViewType::Dim2dArray, ImageDimensions::Dim3d { .. }, _, 1)
+ if flags.array_2d_compatible =>
+ {
+ ()
+ }
+ _ => 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,
+ }))
+ }
+}
+
+/// 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,
+}
+
+impl error::Error for ImageViewCreationError {
+ #[inline]
+ fn source(&self) -> Option<&(dyn error::Error + 'static)> {
+ match *self {
+ ImageViewCreationError::AllocError(ref err) => Some(err),
+ _ => None,
+ }
+ }
+}
+
+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",
+ }
+ )
+ }
+}
+
+impl From<OomError> for ImageViewCreationError {
+ #[inline]
+ fn from(err: OomError) -> ImageViewCreationError {
+ ImageViewCreationError::AllocError(DeviceMemoryAllocError::OomError(err))
+ }
+}
+
+/// A low-level wrapper around a `vkImageView`.
+pub struct UnsafeImageView {
+ view: ash::vk::ImageView,
+ device: Arc<Device>,
+}
+
+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,
+ },
+ ..Default::default()
+ };
+
+ let mut output = MaybeUninit::uninit();
+ check_errors(fns.v1_0.create_image_view(
+ image.device().internal_object(),
+ &infos,
+ ptr::null(),
+ output.as_mut_ptr(),
+ ))?;
+ output.assume_init()
+ };
+
+ Ok(UnsafeImageView {
+ view,
+ device: image.device().clone(),
+ })
+ }
+}
+
+unsafe impl VulkanObject for UnsafeImageView {
+ type Object = ash::vk::ImageView;
+
+ #[inline]
+ fn internal_object(&self) -> ash::vk::ImageView {
+ self.view
+ }
+}
+
+impl fmt::Debug for UnsafeImageView {
+ #[inline]
+ fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
+ write!(fmt, "<Vulkan image view {:?}>", self.view)
+ }
+}
+
+impl Drop for UnsafeImageView {
+ #[inline]
+ fn drop(&mut self) {
+ unsafe {
+ let fns = self.device.fns();
+ fns.v1_0
+ .destroy_image_view(self.device.internal_object(), self.view, ptr::null());
+ }
+ }
+}
+
+impl PartialEq for UnsafeImageView {
+ #[inline]
+ fn eq(&self, other: &Self) -> bool {
+ self.view == other.view && self.device == other.device
+ }
+}
+
+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);
+ }
+}
+
+/// 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 From<ImageViewType> for ash::vk::ImageViewType {
+ fn from(val: ImageViewType) -> Self {
+ Self::from_raw(val as i32)
+ }
+}
+
+/// 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 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
+ }
+}
+
+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(),
+ }
+ }
+}
+
+/// 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<ComponentSwizzle> for ash::vk::ComponentSwizzle {
+ #[inline]
+ fn from(val: ComponentSwizzle) -> Self {
+ Self::from_raw(val as i32)
+ }
+}
+
+impl Default for ComponentSwizzle {
+ #[inline]
+ fn default() -> ComponentSwizzle {
+ ComponentSwizzle::Identity
+ }
+}
+
+/// Trait for types that represent the GPU can access an image view.
+pub unsafe trait ImageViewAbstract {
+ /// Returns the wrapped image that this image view was created from.
+ fn image(&self) -> &dyn ImageAccess;
+
+ /// Returns the inner unsafe image view object used by this image view.
+ fn inner(&self) -> &UnsafeImageView;
+
+ /// Returns the range of array layers of the wrapped image that this view exposes.
+ fn array_layers(&self) -> Range<u32>;
+
+ /// Returns the format of this view. This can be different from the parent's format.
+ fn format(&self) -> Format;
+
+ /// Returns the component mapping of this view.
+ fn component_mapping(&self) -> ComponentMapping;
+
+ /// Returns the [`ImageViewType`] of this image view.
+ fn ty(&self) -> ImageViewType;
+
+ /// 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 */
+ }
+}
+
+unsafe impl<I> ImageViewAbstract for ImageView<I>
+where
+ I: ImageAccess,
+{
+ #[inline]
+ fn image(&self) -> &dyn ImageAccess {
+ &self.image
+ }
+
+ #[inline]
+ fn inner(&self) -> &UnsafeImageView {
+ &self.inner
+ }
+
+ #[inline]
+ fn array_layers(&self) -> Range<u32> {
+ self.array_layers.clone()
+ }
+
+ #[inline]
+ fn format(&self) -> Format {
+ // TODO: remove this default impl
+ self.format
+ }
+
+ #[inline]
+ fn component_mapping(&self) -> ComponentMapping {
+ self.component_mapping
+ }
+
+ #[inline]
+ fn ty(&self) -> ImageViewType {
+ self.ty
+ }
+}
+
+unsafe impl<T> ImageViewAbstract for T
+where
+ T: SafeDeref,
+ T::Target: ImageViewAbstract,
+{
+ #[inline]
+ fn image(&self) -> &dyn ImageAccess {
+ (**self).image()
+ }
+
+ #[inline]
+ fn inner(&self) -> &UnsafeImageView {
+ (**self).inner()
+ }
+
+ #[inline]
+ fn array_layers(&self) -> Range<u32> {
+ (**self).array_layers()
+ }
+
+ #[inline]
+ fn format(&self) -> Format {
+ (**self).format()
+ }
+
+ #[inline]
+ fn component_mapping(&self) -> ComponentMapping {
+ (**self).component_mapping()
+ }
+
+ #[inline]
+ fn ty(&self) -> ImageViewType {
+ (**self).ty()
+ }
+
+ #[inline]
+ fn can_be_sampled(&self, sampler: &Sampler) -> bool {
+ (**self).can_be_sampled(sampler)
+ }
+}
+
+impl PartialEq for dyn ImageViewAbstract + Send + Sync {
+ #[inline]
+ fn eq(&self, other: &Self) -> bool {
+ self.inner() == other.inner()
+ }
+}
+
+impl Eq for dyn ImageViewAbstract + Send + Sync {}
+
+impl Hash for dyn ImageViewAbstract + Send + Sync {
+ #[inline]
+ fn hash<H: Hasher>(&self, state: &mut H) {
+ self.inner().hash(state);
+ }
+}
diff --git a/src/instance/debug.rs b/src/instance/debug.rs
new file mode 100644
index 0000000..2bc0615
--- /dev/null
+++ b/src/instance/debug.rs
@@ -0,0 +1,461 @@
+// 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.
+
+//! Debug callback called by intermediate layers or by the driver.
+//!
+//! When working on an application, it is recommended to register a debug callback. 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.
+//!
+//! 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
+//!
+//! ```
+//! # use vulkano::instance::Instance;
+//! # use std::sync::Arc;
+//! # let instance: Arc<Instance> = return;
+//! use vulkano::instance::debug::DebugCallback;
+//!
+//! let _callback = DebugCallback::errors_and_warnings(&instance, |msg| {
+//! println!("Debug callback: {:?}", msg.description);
+//! }).ok();
+//! ```
+//!
+//! The type of `msg` in the callback is [`Message`](struct.Message.html).
+//!
+//! 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
+//! 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;
+
+/// 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 {
+ instance: Arc<Instance>,
+ debug_report_callback: ash::vk::DebugUtilsMessengerEXT,
+ user_callback: Box<Box<dyn Fn(&Message) + Send>>,
+}
+
+impl DebugCallback {
+ /// 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,
+ {
+ if !instance.enabled_extensions().ext_debug_utils {
+ return Err(DebugCallbackCreationError::MissingExtension);
+ }
+
+ // 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,
+ };
+
+ // 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);
+ }));
+
+ ash::vk::FALSE
+ }
+
+ 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
+ };
+
+ 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
+ };
+
+ let infos = 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 _,
+ ..Default::default()
+ };
+
+ let fns = instance.fns();
+
+ let debug_report_callback = unsafe {
+ let mut output = MaybeUninit::uninit();
+ check_errors(fns.ext_debug_utils.create_debug_utils_messenger_ext(
+ instance.internal_object(),
+ &infos,
+ ptr::null(),
+ output.as_mut_ptr(),
+ ))?;
+ 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,
+ )
+ }
+}
+
+impl Drop for DebugCallback {
+ #[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,
+ 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,
+}
+
+/// 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,
+}
+
+impl MessageSeverity {
+ /// Builds a `MessageSeverity` with all fields set to `false` expect `error`.
+ #[inline]
+ pub const fn errors() -> MessageSeverity {
+ MessageSeverity {
+ error: true,
+ ..MessageSeverity::none()
+ }
+ }
+
+ /// Builds a `MessageSeverity` with all fields set to `false` expect `warning`.
+ #[inline]
+ pub const fn warnings() -> MessageSeverity {
+ MessageSeverity {
+ warning: true,
+ ..MessageSeverity::none()
+ }
+ }
+
+ /// Builds a `MessageSeverity` with all fields set to `false` expect `information`.
+ #[inline]
+ pub const fn information() -> MessageSeverity {
+ MessageSeverity {
+ information: true,
+ ..MessageSeverity::none()
+ }
+ }
+
+ /// Builds a `MessageSeverity` with all fields set to `false` expect `verbose`.
+ #[inline]
+ pub const fn verbose() -> MessageSeverity {
+ MessageSeverity {
+ verbose: true,
+ ..MessageSeverity::none()
+ }
+ }
+
+ /// 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()
+ }
+ }
+
+ /// Builds a `MessageSeverity` with all fields set to `false`.
+ #[inline]
+ pub const fn none() -> MessageSeverity {
+ MessageSeverity {
+ error: false,
+ warning: false,
+ information: false,
+ verbose: false,
+ }
+ }
+
+ /// Builds a `MessageSeverity` with all fields set to `true`.
+ #[inline]
+ pub const fn all() -> MessageSeverity {
+ MessageSeverity {
+ error: true,
+ warning: true,
+ information: true,
+ verbose: true,
+ }
+ }
+}
+
+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,
+ }
+ }
+}
+
+/// Type of message.
+#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
+pub struct MessageType {
+ /// Specifies that some general event has occurred.
+ pub general: bool,
+ /// Specifies that something has occurred during validation against the vulkan specification
+ pub validation: bool,
+ /// Specifies a potentially non-optimal use of Vulkan
+ pub performance: bool,
+}
+
+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,
+ }
+ }
+
+ /// Builds a `MessageType` with performance field set to `true`.
+ #[inline]
+ pub const fn performance() -> MessageType {
+ MessageType {
+ general: false,
+ validation: false,
+ performance: true,
+ }
+ }
+
+ /// Builds a `MessageType` with all fields set to `true`.
+ #[inline]
+ pub const fn all() -> MessageType {
+ MessageType {
+ general: true,
+ validation: true,
+ performance: true,
+ }
+ }
+
+ /// Builds a `MessageType` with all fields set to `false`.
+ #[inline]
+ pub const fn none() -> MessageType {
+ MessageType {
+ general: false,
+ validation: false,
+ performance: false,
+ }
+ }
+}
+
+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,
+ }
+ }
+}
+
+/// 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,
+}
+
+impl error::Error for DebugCallbackCreationError {}
+
+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"
+ }
+ }
+ )
+ }
+}
+
+impl From<Error> for DebugCallbackCreationError {
+ #[inline]
+ fn from(err: Error) -> DebugCallbackCreationError {
+ panic!("unexpected error: {:?}", err)
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+ use std::thread;
+ #[test]
+ fn ensure_sendable() {
+ // It's useful to be able to initialize a DebugCallback 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, |_| {});
+ thread::spawn(move || {
+ let _ = callback;
+ });
+ }
+}
diff --git a/src/instance/extensions.rs b/src/instance/extensions.rs
new file mode 100644
index 0000000..dab0b12
--- /dev/null
+++ b/src/instance/extensions.rs
@@ -0,0 +1,153 @@
+// 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;
+pub use crate::extensions::{
+ ExtensionRestriction, ExtensionRestrictionError, SupportedExtensionsError,
+};
+use crate::instance::loader;
+use crate::instance::loader::LoadingError;
+use std::ffi::CStr;
+use std::ptr;
+
+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())
+ })))
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use crate::instance::InstanceExtensions;
+ use std::ffi::CString;
+
+ #[test]
+ fn empty_extensions() {
+ let i: Vec<CString> = (&InstanceExtensions::none()).into();
+ assert!(i.iter().next().is_none());
+ }
+}
diff --git a/src/instance/instance.rs b/src/instance/instance.rs
new file mode 100644
index 0000000..50712d2
--- /dev/null
+++ b/src/instance/instance.rs
@@ -0,0 +1,693 @@
+// 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
new file mode 100644
index 0000000..6c56090
--- /dev/null
+++ b/src/instance/layers.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.
+
+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(),
+ })
+ }
+}
+
+/// Properties of a layer.
+#[derive(Clone)]
+pub struct LayerProperties {
+ props: ash::vk::LayerProperties,
+}
+
+impl LayerProperties {
+ /// Returns the name of the layer.
+ ///
+ /// If you want to enable this layer on an instance, you need to pass this value to
+ /// `Instance::new`.
+ ///
+ /// # Example
+ ///
+ /// ```no_run
+ /// use vulkano::instance;
+ ///
+ /// for layer in instance::layers_list().unwrap() {
+ /// println!("Layer name: {}", layer.name());
+ /// }
+ /// ```
+ #[inline]
+ pub fn name(&self) -> &str {
+ unsafe {
+ CStr::from_ptr(self.props.layer_name.as_ptr())
+ .to_str()
+ .unwrap()
+ }
+ }
+
+ /// Returns a description of the layer.
+ ///
+ /// This description is chosen by the layer itself.
+ ///
+ /// # Example
+ ///
+ /// ```no_run
+ /// use vulkano::instance;
+ ///
+ /// for layer in instance::layers_list().unwrap() {
+ /// println!("Layer description: {}", layer.description());
+ /// }
+ /// ```
+ #[inline]
+ pub fn description(&self) -> &str {
+ unsafe {
+ CStr::from_ptr(self.props.description.as_ptr())
+ .to_str()
+ .unwrap()
+ }
+ }
+
+ /// Returns the version of Vulkan supported by this layer.
+ ///
+ /// # Example
+ ///
+ /// ```no_run
+ /// use vulkano::instance;
+ /// use vulkano::instance::Version;
+ ///
+ /// for layer in instance::layers_list().unwrap() {
+ /// if layer.vulkan_version() >= Version::major_minor(2, 0) {
+ /// println!("Layer {} requires Vulkan 2.0", layer.name());
+ /// }
+ /// }
+ /// ```
+ #[inline]
+ pub fn vulkan_version(&self) -> Version {
+ Version::from(self.props.spec_version)
+ }
+
+ /// Returns an implementation-specific version number for this layer.
+ ///
+ /// The number is chosen by the layer itself. It can be used for bug reports for example.
+ ///
+ /// # Example
+ ///
+ /// ```no_run
+ /// use vulkano::instance;
+ ///
+ /// for layer in instance::layers_list().unwrap() {
+ /// println!("Layer {} - Version: {}", layer.name(), layer.implementation_version());
+ /// }
+ /// ```
+ #[inline]
+ pub fn implementation_version(&self) -> u32 {
+ self.props.implementation_version
+ }
+}
+
+/// 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;
+
+ #[test]
+ fn layers_list() {
+ let mut list = match instance::layers_list() {
+ Ok(l) => l,
+ Err(_) => return,
+ };
+
+ while let Some(_) = list.next() {}
+ }
+}
diff --git a/src/instance/loader.rs b/src/instance/loader.rs
new file mode 100644
index 0000000..7714fd2
--- /dev/null
+++ b/src/instance/loader.rs
@@ -0,0 +1,316 @@
+// 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
new file mode 100644
index 0000000..5e85e7f
--- /dev/null
+++ b/src/instance/mod.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.
+
+//! API entry point.
+//!
+//! The first thing to do before you start using Vulkan 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)
+//! };
+//! ```
+//!
+//! 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::device::physical::PhysicalDevice;
+//!
+//! # 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);
+//! }
+//! ```
+//!
+//! # 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).
+//!
+//! 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
+//! to draw at all. See the `swapchain` module for more information about surfaces.
+//!
+//! Once you have chosen a physical device, you can create a `Device` object from it. See the
+//! `device` module for more info.
+
+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,
+};
+pub use crate::version::Version;
+
+pub mod debug;
+pub(crate) mod extensions;
+mod instance;
+mod layers;
+pub mod loader;
diff --git a/src/lib.rs b/src/lib.rs
new file mode 100644
index 0000000..8c8e7b2
--- /dev/null
+++ b/src/lib.rs
@@ -0,0 +1,243 @@
+// 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.
+
+#![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.
+//!
+
+//#![warn(missing_docs)] // TODO: activate
+#![allow(dead_code)] // TODO: remove
+#![allow(unused_variables)] // TODO: remove
+
+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;
+
+#[macro_use]
+mod tests;
+#[macro_use]
+mod extensions;
+pub mod buffer;
+pub mod command_buffer;
+pub mod descriptor_set;
+pub mod device;
+pub mod format;
+mod version;
+#[macro_use]
+pub mod render_pass;
+mod fns;
+pub mod image;
+pub mod instance;
+pub mod memory;
+pub mod pipeline;
+pub mod query;
+pub mod sampler;
+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;
+
+/// 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 {}
+unsafe impl<T: ?Sized> SafeDeref for Arc<T> {}
+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;
+
+ /// Returns a reference to the object.
+ fn internal_object(&self) -> Self::Object;
+}
+
+/// 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;
+
+ /// Returns a reference to the object.
+ fn internal_object_guard(&self) -> MutexGuard<Self::Object>;
+}
+
+/// Error type returned by most Vulkan functions.
+#[derive(Copy, Clone, Debug, PartialEq, Eq)]
+pub enum OomError {
+ /// 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,
+}
+
+impl error::Error for OomError {}
+
+impl fmt::Display for OomError {
+ #[inline]
+ fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
+ write!(
+ fmt,
+ "{}",
+ match *self {
+ OomError::OutOfHostMemory => "no memory available on the host",
+ OomError::OutOfDeviceMemory => "no memory available on the graphical device",
+ }
+ )
+ }
+}
+
+impl From<Error> for OomError {
+ #[inline]
+ fn from(err: Error) -> OomError {
+ match err {
+ Error::OutOfHostMemory => OomError::OutOfHostMemory,
+ Error::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(),
+}
+
+/// 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(),
+}
+
+/// 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)
+ }
+ 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),
+ }
+}
diff --git a/src/memory/device_memory.rs b/src/memory/device_memory.rs
new file mode 100644
index 0000000..5f2bf0e
--- /dev/null
+++ b/src/memory/device_memory.rs
@@ -0,0 +1,1162 @@
+// 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::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.
+///
+/// The destructor of `DeviceMemory` automatically frees the memory.
+///
+/// # Example
+///
+/// ```
+/// use vulkano::memory::DeviceMemory;
+///
+/// # 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 = DeviceMemory::alloc(device.clone(), mem_ty, 1024).unwrap();
+/// ```
+pub struct DeviceMemory {
+ memory: ash::vk::DeviceMemory,
+ device: Arc<Device>,
+ size: DeviceSize,
+ memory_type_index: u32,
+ handle_types: ExternalMemoryHandleType,
+ mapped: Mutex<bool>,
+}
+
+/// 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 ()>,
+}
+
+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(
+ 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()
+ };
+
+ DeviceMemoryBuilder {
+ device,
+ allocate,
+ dedicated_info: None,
+ export_info: None,
+ import_info: None,
+ marker: PhantomData,
+ }
+ }
+
+ /// 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.
+ ///
+ /// # Panic
+ ///
+ /// - 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;
+ }
+
+ 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`.
+ ///
+ /// # Panic
+ ///
+ /// - 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`.
+ ///
+ /// # Panic
+ ///
+ /// - 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()
+ };
+
+ self = self.push_next(&mut import_info);
+ self.import_info = Some(import_info);
+ self
+ }
+
+ // 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;
+ }
+
+ 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)?;
+ }
+
+ // 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))?;
+
+ if self.device.physical_device().internal_object()
+ != memory_type.physical_device().internal_object()
+ {
+ return Err(DeviceMemoryAllocError::SpecViolation(1714));
+ }
+
+ // 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));
+ }
+
+ 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 !(export_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 !(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",
+ ));
+ }
+ }
+
+ 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 !(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",
+ ));
+ }
+ }
+ }
+
+ 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);
+ }
+ let fns = self.device.fns();
+
+ let mut output = MaybeUninit::uninit();
+ check_errors(fns.v1_0.allocate_memory(
+ self.device.internal_object(),
+ &self.allocate,
+ ptr::null(),
+ output.as_mut_ptr(),
+ ))?;
+ *allocation_count += 1;
+ 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),
+ }))
+ }
+}
+
+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`.
+ ///
+ #[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())
+ }
+
+ /// 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.
+ #[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())
+ }
+
+ /// 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.
+ ///
+ #[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)
+ }
+
+ /// 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)
+ }
+
+ /// Same as `alloc`, but allows exportable file descriptor on Linux.
+ #[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())
+ }
+
+ /// Same as `dedicated_alloc`, but allows exportable file descriptor on Linux.
+ #[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())
+ }
+
+ /// Same as `alloc_and_map`, but allows exportable file descriptor on Linux.
+ #[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,
+ )
+ }
+
+ /// Same as `dedicated_alloc_and_map`, but allows exportable file descriptor on Linux.
+ #[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,
+ )?;
+
+ Self::map_allocation(device.clone(), mem)
+ }
+
+ 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()
+ };
+
+ Ok(MappedDeviceMemory {
+ memory: mem,
+ pointer: ptr,
+ coherent,
+ })
+ }
+
+ /// 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()
+ }
+
+ /// Returns the size in bytes of that memory chunk.
+ #[inline]
+ pub fn size(&self) -> DeviceSize {
+ self.size
+ }
+
+ /// Exports the device memory into a Unix file descriptor. The caller retains ownership of the
+ /// file, as per the Vulkan spec.
+ ///
+ /// # Panic
+ ///
+ /// - 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();
+
+ // 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
+ {
+ return Err(DeviceMemoryAllocError::SpecViolation(672))?;
+ }
+
+ // 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))?;
+ }
+
+ let fd = unsafe {
+ let info = ash::vk::MemoryGetFdInfoKHR {
+ memory: self.memory,
+ handle_type: handle_type.into(),
+ ..Default::default()
+ };
+
+ 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 { File::from_raw_fd(fd) };
+ Ok(file)
+ }
+}
+
+unsafe impl DeviceOwned for DeviceMemory {
+ #[inline]
+ fn device(&self) -> &Arc<Device> {
+ &self.device
+ }
+}
+
+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()
+ }
+}
+
+unsafe impl VulkanObject for DeviceMemory {
+ type Object = ash::vk::DeviceMemory;
+
+ #[inline]
+ fn internal_object(&self) -> ash::vk::DeviceMemory {
+ self.memory
+ }
+}
+
+impl Drop for DeviceMemory {
+ #[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;
+ }
+ }
+}
+
+/// 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.
+///
+/// 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.
+///
+/// # Example
+///
+/// ```
+/// use vulkano::memory::DeviceMemory;
+///
+/// # 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
+///
+/// // Allocates 1KB of memory.
+/// let memory = DeviceMemory::alloc_and_map(device.clone(), mem_ty, 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.
+/// unsafe {
+/// let mut content = memory.read_write::<[u8]>(0 .. 1024);
+/// content[12] = 54; // `content` derefs to a `&[u8]` or a `&mut [u8]`
+/// }
+/// ```
+pub struct MappedDeviceMemory {
+ memory: DeviceMemory,
+ pointer: *mut c_void,
+ coherent: bool,
+}
+
+// Note that `MappedDeviceMemory` doesn't implement `Drop`, as we don't need to unmap memory before
+// freeing it.
+//
+// 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.
+ ///
+ /// 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.
+ ///
+ /// # Safety
+ ///
+ /// - 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`.
+ ///
+ #[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
+
+ if !self.coherent {
+ let range = ash::vk::MappedMemoryRange {
+ memory: self.memory.internal_object(),
+ offset: range.start,
+ size: range.end - range.start,
+ ..Default::default()
+ };
+
+ // TODO: return result instead?
+ check_errors(fns.v1_0.invalidate_mapped_memory_ranges(
+ self.memory.device().internal_object(),
+ 1,
+ &range,
+ ))
+ .unwrap();
+ }
+
+ CpuAccess {
+ pointer: pointer,
+ mem: self,
+ coherent: self.coherent,
+ range,
+ }
+ }
+}
+
+impl AsRef<DeviceMemory> for MappedDeviceMemory {
+ #[inline]
+ fn as_ref(&self) -> &DeviceMemory {
+ &self.memory
+ }
+}
+
+impl AsMut<DeviceMemory> for MappedDeviceMemory {
+ #[inline]
+ fn as_mut(&mut self) -> &mut DeviceMemory {
+ &mut self.memory
+ }
+}
+
+unsafe impl DeviceOwned for MappedDeviceMemory {
+ #[inline]
+ fn device(&self) -> &Arc<Device> {
+ self.memory.device()
+ }
+}
+
+unsafe impl Send for MappedDeviceMemory {}
+unsafe impl Sync for MappedDeviceMemory {}
+
+impl fmt::Debug for MappedDeviceMemory {
+ fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+ fmt.debug_tuple("MappedDeviceMemory")
+ .field(&self.memory)
+ .finish()
+ }
+}
+
+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));
+ }
+
+ // 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));
+ }
+
+ // 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-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));
+ }
+
+ // 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));
+ }
+
+ // VUID-vkMapMemory-memory-00683: "memory must not have been allocated with multiple instances".
+ // Confused about this one, so not implemented.
+
+ // 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",
+ ));
+ }
+
+ // VUID-vkMapMemory-flags-zerobitmask: "flags must be 0".
+ if flags != 0 {
+ return Err(DeviceMemoryAllocError::ImplicitSpecViolation(
+ "VUID-vkMapMemory-flags-zerobitmask",
+ ));
+ }
+
+ // VUID-vkMapMemory-device-parameter, VUID-vkMapMemory-memory-parameter and
+ // VUID-vkMapMemory-ppData-parameter satisfied via Vulkano internally.
+
+ 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()
+ };
+
+ *mapped = true;
+
+ Ok(DeviceMemoryMapping {
+ device: device.clone(),
+ memory: memory.clone(),
+ pointer: ptr,
+ coherent,
+ })
+ }
+
+ /// Returns the raw pointer associated with the `DeviceMemoryMapping`.
+ ///
+ /// # 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
+ }
+}
+
+impl Drop for DeviceMemoryMapping {
+ #[inline]
+ fn drop(&mut self) {
+ let mut mapped = self.memory.mapped.lock().expect("Poisoned mutex");
+
+ unsafe {
+ let fns = self.device.fns();
+ fns.v1_0
+ .unmap_memory(self.device.internal_object(), self.memory.memory);
+ }
+
+ *mapped = false;
+ }
+}
+
+/// 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: ?
+ }
+ }
+}
+
+unsafe impl<'a, T: ?Sized + 'a> Send for CpuAccess<'a, T> {}
+unsafe impl<'a, T: ?Sized + 'a> Sync for CpuAccess<'a, T> {}
+
+impl<'a, T: ?Sized + 'a> Deref for CpuAccess<'a, T> {
+ type Target = T;
+
+ #[inline]
+ fn deref(&self) -> &T {
+ unsafe { &*self.pointer }
+ }
+}
+
+impl<'a, T: ?Sized + 'a> DerefMut for CpuAccess<'a, T> {
+ #[inline]
+ fn deref_mut(&mut self) -> &mut T {
+ unsafe { &mut *self.pointer }
+ }
+}
+
+impl<'a, T: ?Sized + 'a> Drop for CpuAccess<'a, T> {
+ #[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();
+ }
+ }
+ }
+}
+
+/// Error type returned by functions related to `DeviceMemory`.
+#[derive(Copy, Clone, Debug, PartialEq, Eq)]
+pub enum DeviceMemoryAllocError {
+ /// 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,
+}
+
+impl error::Error for DeviceMemoryAllocError {
+ #[inline]
+ fn source(&self) -> Option<&(dyn error::Error + 'static)> {
+ match *self {
+ DeviceMemoryAllocError::OomError(ref 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)
+ }
+ 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"),
+ }
+ }
+}
+
+impl From<Error> for DeviceMemoryAllocError {
+ #[inline]
+ fn from(err: Error) -> DeviceMemoryAllocError {
+ match err {
+ e @ Error::OutOfHostMemory | e @ Error::OutOfDeviceMemory => {
+ DeviceMemoryAllocError::OomError(e.into())
+ }
+ Error::TooManyObjects => DeviceMemoryAllocError::TooManyObjects,
+ Error::MemoryMapFailed => DeviceMemoryAllocError::MemoryMapFailed,
+ _ => panic!("unexpected error: {:?}", err),
+ }
+ }
+}
+
+impl From<OomError> for DeviceMemoryAllocError {
+ #[inline]
+ fn from(err: OomError) -> DeviceMemoryAllocError {
+ DeviceMemoryAllocError::OomError(err)
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use crate::memory::DeviceMemory;
+ use crate::memory::DeviceMemoryAllocError;
+ use crate::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();
+ }
+
+ #[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();
+ });
+ }
+
+ #[test]
+ #[cfg(target_pointer_width = "64")]
+ fn oom_single() {
+ let (device, _) = gfx_dev_and_queue!();
+ let mem_ty = device
+ .physical_device()
+ .memory_types()
+ .filter(|m| !m.is_lazily_allocated())
+ .next()
+ .unwrap();
+
+ match DeviceMemory::alloc(device.clone(), mem_ty, 0xffffffffffffffff) {
+ Err(DeviceMemoryAllocError::SpecViolation(u)) => (),
+ _ => panic!(),
+ }
+ }
+
+ #[test]
+ #[ignore] // TODO: test fails for now on Mesa+Intel
+ fn oom_multi() {
+ let (device, _) = gfx_dev_and_queue!();
+ let mem_ty = device
+ .physical_device()
+ .memory_types()
+ .filter(|m| !m.is_lazily_allocated())
+ .next()
+ .unwrap();
+ let heap_size = mem_ty.heap().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
+ Ok(a) => allocs.push(a),
+ _ => (),
+ }
+ }
+
+ panic!()
+ }
+
+ #[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);
+ {
+ let mem2 = DeviceMemory::alloc(device.clone(), mem_ty, 256).unwrap();
+ assert_eq!(*device.allocation_count().lock().unwrap(), 2);
+ }
+ assert_eq!(*device.allocation_count().lock().unwrap(), 1);
+ }
+}
diff --git a/src/memory/external_memory_handle_type.rs b/src/memory/external_memory_handle_type.rs
new file mode 100644
index 0000000..39dee03
--- /dev/null
+++ b/src/memory/external_memory_handle_type.rs
@@ -0,0 +1,168 @@
+// 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
new file mode 100644
index 0000000..8797d38
--- /dev/null
+++ b/src/memory/mod.rs
@@ -0,0 +1,225 @@
+// 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.
+
+//! Device memory allocation and memory pools.
+//!
+//! By default, memory allocation is automatically handled by the vulkano library when you create
+//! a buffer or an image. But if you want more control, you have the possibility to customise the
+//! memory allocation strategy.
+//!
+//! # Memory types and heaps
+//!
+//! A physical device is composed of one or more **memory heaps**. A memory heap is a pool of
+//! memory that can be allocated.
+//!
+//! ```
+//! // 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());
+//! }
+//! ```
+//!
+//! However you can't allocate directly from a memory heap. A memory heap is shared amongst one or
+//! multiple **memory types**, which you can allocate memory from. Each memory type has different
+//! characteristics.
+//!
+//! A memory type may or may not be visible to the host. In other words, it may or may not be
+//! directly writable by the CPU. A memory type may or may not be device-local. A device-local
+//! memory type has a much quicker access time from the GPU than a non-device-local type. Note
+//! that non-device-local memory types are still accessible by the device, they are just slower.
+//!
+//! ```
+//! // 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());
+//! }
+//! ```
+//!
+//! Memory types are order from "best" to "worse". In other words, the implementation prefers that
+//! you use the memory types that are earlier in the list. This means that selecting a memory type
+//! should always be done by enumerating them and taking the first one that matches our criteria.
+//!
+//! ## In practice
+//!
+//! In practice, desktop machines usually have two memory heaps: one that represents the RAM of
+//! the CPU, and one that represents the RAM of the GPU. The CPU's RAM is host-accessible but not
+//! device-local, while the GPU's RAM is not host-accessible but is device-local.
+//!
+//! Mobile machines usually have a single memory heap that is "equally local" to both the CPU and
+//! the GPU. It is both host-accessible and device-local.
+//!
+//! # Allocating memory and memory pools
+//!
+//! Allocating memory can be done by calling `DeviceMemory::alloc()`.
+//!
+//! Here is an example:
+//!
+//! ```
+//! use vulkano::memory::DeviceMemory;
+//!
+//! # 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 alloc = DeviceMemory::alloc(device.clone(), ty, 1024).expect("Failed to allocate memory");
+//!
+//! // The memory is automatically free'd when `alloc` is destroyed.
+//! ```
+//!
+//! However allocating and freeing memory is very slow (up to several hundred milliseconds
+//! sometimes). Instead you are strongly encouraged to use a memory pool. A memory pool is not
+//! a Vulkan concept but a vulkano concept.
+//!
+//! 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.
+
+use std::mem;
+use std::os::raw::c_void;
+use std::slice;
+
+use crate::buffer::sys::UnsafeBuffer;
+use crate::image::sys::UnsafeImage;
+
+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;
+
+mod device_memory;
+mod external_memory_handle_type;
+pub mod pool;
+
+/// Represents requirements expressed by the Vulkan implementation when it comes to binding memory
+/// to a resource.
+#[derive(Debug, Copy, Clone)]
+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,
+
+ /// 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,
+}
+
+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,
+ }
+ }
+}
+
+/// Indicates whether we want to allocate memory for a specific resource, or in a generic way.
+///
+/// Using dedicated allocations can yield better performance, but requires the
+/// `VK_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
+/// one that was passed with the enumeration.
+#[derive(Debug, Copy, Clone)]
+pub enum DedicatedAlloc<'a> {
+ /// Generic allocation.
+ None,
+ /// Allocation dedicated to a buffer.
+ Buffer(&'a UnsafeBuffer),
+ /// Allocation dedicated to an image.
+ Image(&'a UnsafeImage),
+}
+
+/// 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>;
+
+ /// Returns true if the size is suitable to store a type like this.
+ fn is_size_suitable(size: DeviceSize) -> bool;
+
+ /// Returns the size of an individual element.
+ fn indiv_size() -> DeviceSize;
+}
+
+unsafe impl<T> Content for T {
+ #[inline]
+ fn ref_from_ptr<'a>(ptr: *mut c_void, size: usize) -> Option<*mut T> {
+ if size < mem::size_of::<T>() {
+ return None;
+ }
+
+ Some(ptr as *mut T)
+ }
+
+ #[inline]
+ fn is_size_suitable(size: DeviceSize) -> bool {
+ size == mem::size_of::<T>() as DeviceSize
+ }
+
+ #[inline]
+ fn indiv_size() -> DeviceSize {
+ mem::size_of::<T>() as DeviceSize
+ }
+}
+
+unsafe impl<T> Content for [T] {
+ #[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] })
+ }
+
+ #[inline]
+ fn is_size_suitable(size: DeviceSize) -> bool {
+ size % mem::size_of::<T>() as DeviceSize == 0
+ }
+
+ #[inline]
+ fn indiv_size() -> DeviceSize {
+ mem::size_of::<T>() as DeviceSize
+ }
+}
+
+/*
+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> {}
+
+*/
diff --git a/src/memory/pool/host_visible.rs b/src/memory/pool/host_visible.rs
new file mode 100644
index 0000000..0060618
--- /dev/null
+++ b/src/memory/pool/host_visible.rs
@@ -0,0 +1,252 @@
+// 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
new file mode 100644
index 0000000..4c5ad7c
--- /dev/null
+++ b/src/memory/pool/mod.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.
+
+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
new file mode 100644
index 0000000..e9cf12e
--- /dev/null
+++ b/src/memory/pool/non_host_visible.rs
@@ -0,0 +1,251 @@
+// 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
new file mode 100644
index 0000000..0681716
--- /dev/null
+++ b/src/memory/pool/pool.rs
@@ -0,0 +1,273 @@
+// 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/pipeline/blend.rs b/src/pipeline/blend.rs
new file mode 100644
index 0000000..7863b8a
--- /dev/null
+++ b/src/pipeline/blend.rs
@@ -0,0 +1,291 @@
+// 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
new file mode 100644
index 0000000..9b3ac77
--- /dev/null
+++ b/src/pipeline/cache.rs
@@ -0,0 +1,452 @@
+// 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.
+
+//! Cache the pipeline objects to disk for faster reloads.
+//!
+//! A pipeline cache is an opaque type that allow you to cache your graphics and compute
+//! pipelines on the disk.
+//!
+//! You can create either an empty cache or a cache from some initial data. Whenever you create a
+//! graphics or compute pipeline, you have the possibility to pass a reference to that cache.
+//! The Vulkan implementation will then look in the cache for an existing entry, or add one if it
+//! 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.
+
+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;
+
+/// Opaque cache that contains pipeline objects.
+///
+/// See [the documentation of the module](index.html) for more info.
+pub struct PipelineCache {
+ device: Arc<Device>,
+ cache: ash::vk::PipelineCache,
+}
+
+impl PipelineCache {
+ /// Builds a new pipeline cache from existing data. The data must have been previously obtained
+ /// with [`get_data`](#method.get_data).
+ ///
+ /// The data passed to this function will most likely be blindly trusted by the Vulkan
+ /// implementation. Therefore you can easily crash your application or the system by passing
+ /// wrong data. Hence why this function is unsafe.
+ ///
+ /// # Example
+ ///
+ /// 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.
+ /// TODO: there's a header in the cached data that must be checked ; talk about this
+ ///
+ /// ```
+ /// # use std::sync::Arc;
+ /// # use vulkano::device::Device;
+ /// use std::fs::File;
+ /// use std::io::Read;
+ /// use vulkano::pipeline::cache::PipelineCache;
+ /// # let device: Arc<Device> = return;
+ ///
+ /// let data = {
+ /// let file = File::open("pipeline_cache.bin");
+ /// if let Ok(mut file) = file {
+ /// let mut data = Vec::new();
+ /// if let Ok(_) = file.read_to_end(&mut data) {
+ /// Some(data)
+ /// } else { None }
+ /// } else { None }
+ /// };
+ ///
+ /// let cache = if let Some(data) = data {
+ /// // This is unsafe because there is no way to be sure that the file contains valid data.
+ /// unsafe { PipelineCache::with_data(device.clone(), &data).unwrap() }
+ /// } else {
+ /// PipelineCache::empty(device.clone()).unwrap()
+ /// };
+ /// ```
+ #[inline]
+ pub unsafe fn with_data(
+ device: Arc<Device>,
+ initial_data: &[u8],
+ ) -> Result<Arc<PipelineCache>, OomError> {
+ PipelineCache::new_impl(device, Some(initial_data))
+ }
+
+ /// Builds a new empty pipeline cache.
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// # use std::sync::Arc;
+ /// # use vulkano::device::Device;
+ /// use vulkano::pipeline::cache::PipelineCache;
+ /// # let device: Arc<Device> = return;
+ /// let cache = PipelineCache::empty(device.clone()).unwrap();
+ /// ```
+ #[inline]
+ pub fn empty(device: Arc<Device>) -> Result<Arc<PipelineCache>, OomError> {
+ unsafe { PipelineCache::new_impl(device, None) }
+ }
+
+ // Actual implementation of the constructor.
+ unsafe fn new_impl(
+ device: Arc<Device>,
+ initial_data: Option<&[u8]>,
+ ) -> Result<Arc<PipelineCache>, OomError> {
+ let fns = device.fns();
+
+ let cache = {
+ let infos = ash::vk::PipelineCacheCreateInfo {
+ flags: ash::vk::PipelineCacheCreateFlags::empty(),
+ initial_data_size: initial_data.map(|d| d.len()).unwrap_or(0),
+ p_initial_data: initial_data
+ .map(|d| d.as_ptr() as *const _)
+ .unwrap_or(ptr::null()),
+ ..Default::default()
+ };
+
+ let mut output = MaybeUninit::uninit();
+ check_errors(fns.v1_0.create_pipeline_cache(
+ device.internal_object(),
+ &infos,
+ ptr::null(),
+ output.as_mut_ptr(),
+ ))?;
+ output.assume_init()
+ };
+
+ Ok(Arc::new(PipelineCache {
+ device: device.clone(),
+ cache: cache,
+ }))
+ }
+
+ /// Merges other pipeline caches into this one.
+ ///
+ /// It is `self` that is modified here. The pipeline caches passed as parameter are untouched.
+ ///
+ /// # Panic
+ ///
+ /// - 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>>,
+ {
+ unsafe {
+ let fns = self.device.fns();
+
+ let pipelines = pipelines
+ .into_iter()
+ .map(|pipeline| {
+ assert!(&***pipeline as *const _ != &*self as *const _);
+ pipeline.cache
+ })
+ .collect::<Vec<_>>();
+
+ check_errors(fns.v1_0.merge_pipeline_caches(
+ self.device.internal_object(),
+ self.cache,
+ pipelines.len() as u32,
+ pipelines.as_ptr(),
+ ))?;
+
+ Ok(())
+ }
+ }
+
+ /// Obtains the data from the cache.
+ ///
+ /// This data can be stored and then reloaded and passed to `PipelineCache::with_data`.
+ ///
+ /// # Example
+ ///
+ /// This example stores the data of a pipeline cache on the disk.
+ /// See [`with_data`](#method.with_data) for how to reload it.
+ ///
+ /// ```
+ /// use std::fs;
+ /// use std::fs::File;
+ /// use std::io::Write;
+ /// # use std::sync::Arc;
+ /// # use vulkano::pipeline::cache::PipelineCache;
+ ///
+ /// # let cache: Arc<PipelineCache> = return;
+ /// // If an error happens (eg. no permission for the file) we simply skip storing the cache.
+ /// if let Ok(data) = cache.get_data() {
+ /// if let Ok(mut file) = File::create("pipeline_cache.bin.tmp") {
+ /// if let Ok(_) = file.write_all(&data) {
+ /// let _ = fs::rename("pipeline_cache.bin.tmp", "pipeline_cache.bin");
+ /// } else {
+ /// let _ = fs::remove_file("pipeline_cache.bin.tmp");
+ /// }
+ /// }
+ /// }
+ /// ```
+ 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);
+
+ Ok(data)
+ }
+ }
+}
+
+unsafe impl VulkanObject for PipelineCache {
+ type Object = ash::vk::PipelineCache;
+
+ #[inline]
+ fn internal_object(&self) -> ash::vk::PipelineCache {
+ self.cache
+ }
+}
+
+impl Drop for PipelineCache {
+ #[inline]
+ fn drop(&mut self) {
+ unsafe {
+ let fns = self.device.fns();
+ fns.v1_0
+ .destroy_pipeline_cache(self.device.internal_object(), 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};
+
+ #[test]
+ fn merge_self_forbidden() {
+ let (device, queue) = gfx_dev_and_queue!();
+ let pipeline = PipelineCache::empty(device).unwrap();
+ assert_should_panic!({
+ pipeline.merge(&[&pipeline]).unwrap();
+ });
+ }
+
+ #[test]
+ fn cache_returns_same_data() {
+ let (device, queue) = gfx_dev_and_queue!();
+
+ let cache = PipelineCache::empty(device.clone()).unwrap();
+
+ let module = unsafe {
+ /*
+ * #version 450
+ * void main() {
+ * }
+ */
+ const MODULE: [u8; 192] = [
+ 3, 2, 35, 7, 0, 0, 1, 0, 10, 0, 8, 0, 6, 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, 19, 0, 2, 0, 2, 0, 0, 0, 33, 0, 3, 0, 3, 0, 0, 0, 2,
+ 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(),
+ )
+ };
+
+ let pipeline = Arc::new(
+ ComputePipeline::new(device.clone(), &shader, &(), Some(cache.clone())).unwrap(),
+ );
+
+ let cache_data = cache.get_data().unwrap();
+ let second_data = cache.get_data().unwrap();
+
+ assert_eq!(cache_data, second_data);
+ }
+
+ #[test]
+ fn cache_returns_different_data() {
+ let (device, queue) = gfx_dev_and_queue!();
+
+ let cache = PipelineCache::empty(device.clone()).unwrap();
+
+ let first_module = unsafe {
+ /*
+ * #version 450
+ * void main() {
+ * }
+ */
+ const MODULE: [u8; 192] = [
+ 3, 2, 35, 7, 0, 0, 1, 0, 10, 0, 8, 0, 6, 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, 19, 0, 2, 0, 2, 0, 0, 0, 33, 0, 3, 0, 3, 0, 0, 0, 2,
+ 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(),
+ )
+ };
+
+ let second_module = unsafe {
+ /*
+ * #version 450
+ *
+ * void main() {
+ * uint idx = gl_GlobalInvocationID.x;
+ * }
+ */
+ const SECOND_MODULE: [u8; 432] = [
+ 3, 2, 35, 7, 0, 0, 1, 0, 10, 0, 8, 0, 16, 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, 6, 0, 5, 0, 0, 0, 4, 0, 0,
+ 0, 109, 97, 105, 110, 0, 0, 0, 0, 11, 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, 3, 0, 8, 0, 0, 0, 105, 100,
+ 120, 0, 5, 0, 8, 0, 11, 0, 0, 0, 103, 108, 95, 71, 108, 111, 98, 97, 108, 73, 110,
+ 118, 111, 99, 97, 116, 105, 111, 110, 73, 68, 0, 0, 0, 71, 0, 4, 0, 11, 0, 0, 0,
+ 11, 0, 0, 0, 28, 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, 0, 0, 0, 0, 32, 0, 4, 0, 7, 0, 0, 0, 7,
+ 0, 0, 0, 6, 0, 0, 0, 23, 0, 4, 0, 9, 0, 0, 0, 6, 0, 0, 0, 3, 0, 0, 0, 32, 0, 4, 0,
+ 10, 0, 0, 0, 1, 0, 0, 0, 9, 0, 0, 0, 59, 0, 4, 0, 10, 0, 0, 0, 11, 0, 0, 0, 1, 0,
+ 0, 0, 43, 0, 4, 0, 6, 0, 0, 0, 12, 0, 0, 0, 0, 0, 0, 0, 32, 0, 4, 0, 13, 0, 0, 0,
+ 1, 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, 59, 0, 4, 0, 7, 0, 0, 0, 8, 0, 0, 0, 7, 0, 0, 0, 65,
+ 0, 5, 0, 13, 0, 0, 0, 14, 0, 0, 0, 11, 0, 0, 0, 12, 0, 0, 0, 61, 0, 4, 0, 6, 0, 0,
+ 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()
+ };
+
+ 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 cache_data = cache.get_data().unwrap();
+
+ let second_pipeline = Arc::new(
+ ComputePipeline::new(device.clone(), &second_shader, &(), Some(cache.clone())).unwrap(),
+ );
+
+ let second_data = cache.get_data().unwrap();
+
+ if cache_data.is_empty() {
+ assert_eq!(cache_data, second_data);
+ } else {
+ assert_ne!(cache_data, second_data);
+ }
+ }
+
+ #[test]
+ fn cache_data_does_not_change() {
+ let (device, queue) = gfx_dev_and_queue!();
+
+ let cache = PipelineCache::empty(device.clone()).unwrap();
+
+ let module = unsafe {
+ /*
+ * #version 450
+ * void main() {
+ * }
+ */
+ const MODULE: [u8; 192] = [
+ 3, 2, 35, 7, 0, 0, 1, 0, 10, 0, 8, 0, 6, 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, 19, 0, 2, 0, 2, 0, 0, 0, 33, 0, 3, 0, 3, 0, 0, 0, 2,
+ 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(),
+ )
+ };
+
+ let pipeline = Arc::new(
+ ComputePipeline::new(device.clone(), &shader, &(), 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_data = cache.get_data().unwrap();
+
+ assert_eq!(cache_data, second_data);
+ }
+}
diff --git a/src/pipeline/compute_pipeline.rs b/src/pipeline/compute_pipeline.rs
new file mode 100644
index 0000000..0601374
--- /dev/null
+++ b/src/pipeline/compute_pipeline.rs
@@ -0,0 +1,523 @@
+// 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
new file mode 100644
index 0000000..84d1e03
--- /dev/null
+++ b/src/pipeline/depth_stencil.rs
@@ -0,0 +1,263 @@
+// 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_pipeline/builder.rs b/src/pipeline/graphics_pipeline/builder.rs
new file mode 100644
index 0000000..5f9a770
--- /dev/null
+++ b/src/pipeline/graphics_pipeline/builder.rs
@@ -0,0 +1,1952 @@
+// 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
new file mode 100644
index 0000000..434426e
--- /dev/null
+++ b/src/pipeline/graphics_pipeline/creation_error.rs
@@ -0,0 +1,380 @@
+// 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
new file mode 100644
index 0000000..2082830
--- /dev/null
+++ b/src/pipeline/graphics_pipeline/mod.rs
@@ -0,0 +1,448 @@
+// 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/graphics_pipeline/tests.rs b/src/pipeline/graphics_pipeline/tests.rs
new file mode 100644
index 0000000..53ef2eb
--- /dev/null
+++ b/src/pipeline/graphics_pipeline/tests.rs
@@ -0,0 +1,395 @@
+// 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.
+
+//! This module contains the unit tests of `GraphicsPipeline`.
+
+#![cfg(test)]
+
+use format::Format;
+use framebuffer::Subpass;
+use pipeline::blend::Blend;
+use pipeline::depth_stencil::DepthStencil;
+use pipeline::input_assembly::InputAssembly;
+use pipeline::input_assembly::PrimitiveTopology;
+use pipeline::layout::PipelineLayoutDesc;
+use pipeline::multisample::Multisample;
+use pipeline::shader::ShaderInterface;
+use pipeline::shader::ShaderModule;
+use pipeline::vertex::SingleBufferDefinition;
+use pipeline::viewport::ViewportsState;
+use pipeline::GraphicsPipeline;
+use pipeline::GraphicsPipelineCreationError;
+use pipeline::GraphicsPipelineParams;
+use std::ffi::CString;
+
+#[test]
+fn create() {
+ let (device, _) = gfx_dev_and_queue!();
+
+ let vs = unsafe { ShaderModule::new(device.clone(), &BASIC_VS).unwrap() };
+ let fs = unsafe { ShaderModule::new(device.clone(), &BASIC_FS).unwrap() };
+
+ let _ = GraphicsPipeline::new(
+ &device,
+ GraphicsPipelineParams {
+ vertex_input: SingleBufferDefinition::<()>::new(),
+ vertex_shader: unsafe {
+ vs.vertex_shader_entry_point::<(), _, _, _>(
+ &CString::new("main").unwrap(),
+ ShaderInterface::empty(),
+ ShaderInterface::empty(),
+ PipelineLayoutDesc::empty(),
+ )
+ },
+ input_assembly: InputAssembly::triangle_list(),
+ tessellation: None,
+ geometry_shader: None,
+ viewport: ViewportsState::Dynamic { num: 1 },
+ raster: Default::default(),
+ multisample: Multisample::disabled(),
+ fragment_shader: unsafe {
+ fs.fragment_shader_entry_point::<(), _, _, _>(
+ &CString::new("main").unwrap(),
+ ShaderInterface::empty(),
+ ShaderInterface::empty(),
+ PipelineLayoutDesc::empty(),
+ )
+ },
+ depth_stencil: DepthStencil::disabled(),
+ blend: Blend::pass_through(),
+ render_pass: Subpass::from(
+ simple_rp::CustomRenderPass::new(&device, &{
+ simple_rp::Formats {
+ color: (Format::R8G8B8A8Unorm, 1),
+ }
+ })
+ .unwrap(),
+ 0,
+ )
+ .unwrap(),
+ },
+ )
+ .unwrap();
+}
+
+#[test]
+fn bad_primitive_restart() {
+ let (device, _) = gfx_dev_and_queue!();
+
+ let vs = unsafe { ShaderModule::new(device.clone(), &BASIC_VS).unwrap() };
+ let fs = unsafe { ShaderModule::new(device.clone(), &BASIC_FS).unwrap() };
+
+ let result = GraphicsPipeline::new(
+ &device,
+ GraphicsPipelineParams {
+ vertex_input: SingleBufferDefinition::<()>::new(),
+ vertex_shader: unsafe {
+ vs.vertex_shader_entry_point::<(), _, _, _>(
+ &CString::new("main").unwrap(),
+ ShaderInterface::empty(),
+ ShaderInterface::empty(),
+ PipelineLayoutDesc::empty(),
+ )
+ },
+ input_assembly: InputAssembly {
+ topology: PrimitiveTopology::TriangleList,
+ primitive_restart_enable: true,
+ },
+ tessellation: None,
+ geometry_shader: None,
+ viewport: ViewportsState::Dynamic { num: 1 },
+ raster: Default::default(),
+ multisample: Multisample::disabled(),
+ fragment_shader: unsafe {
+ fs.fragment_shader_entry_point::<(), _, _, _>(
+ &CString::new("main").unwrap(),
+ ShaderInterface::empty(),
+ ShaderInterface::empty(),
+ PipelineLayoutDesc::empty(),
+ )
+ },
+ depth_stencil: DepthStencil::disabled(),
+ blend: Blend::pass_through(),
+ render_pass: Subpass::from(
+ simple_rp::CustomRenderPass::new(&device, &{
+ simple_rp::Formats {
+ color: (Format::R8G8B8A8Unorm, 1),
+ }
+ })
+ .unwrap(),
+ 0,
+ )
+ .unwrap(),
+ },
+ );
+
+ match result {
+ Err(GraphicsPipelineCreationError::PrimitiveDoesntSupportPrimitiveRestart { .. }) => (),
+ _ => panic!(),
+ }
+}
+
+#[test]
+fn multi_viewport_feature() {
+ let (device, _) = gfx_dev_and_queue!();
+
+ let vs = unsafe { ShaderModule::new(device.clone(), &BASIC_VS).unwrap() };
+ let fs = unsafe { ShaderModule::new(device.clone(), &BASIC_FS).unwrap() };
+
+ let result = GraphicsPipeline::new(
+ &device,
+ GraphicsPipelineParams {
+ vertex_input: SingleBufferDefinition::<()>::new(),
+ vertex_shader: unsafe {
+ vs.vertex_shader_entry_point::<(), _, _, _>(
+ &CString::new("main").unwrap(),
+ ShaderInterface::empty(),
+ ShaderInterface::empty(),
+ PipelineLayoutDesc::empty(),
+ )
+ },
+ input_assembly: InputAssembly::triangle_list(),
+ tessellation: None,
+ geometry_shader: None,
+ viewport: ViewportsState::Dynamic { num: 2 },
+ raster: Default::default(),
+ multisample: Multisample::disabled(),
+ fragment_shader: unsafe {
+ fs.fragment_shader_entry_point::<(), _, _, _>(
+ &CString::new("main").unwrap(),
+ ShaderInterface::empty(),
+ ShaderInterface::empty(),
+ PipelineLayoutDesc::empty(),
+ )
+ },
+ depth_stencil: DepthStencil::disabled(),
+ blend: Blend::pass_through(),
+ render_pass: Subpass::from(
+ simple_rp::CustomRenderPass::new(&device, &{
+ simple_rp::Formats {
+ color: (Format::R8G8B8A8Unorm, 1),
+ }
+ })
+ .unwrap(),
+ 0,
+ )
+ .unwrap(),
+ },
+ );
+
+ match result {
+ Err(GraphicsPipelineCreationError::MultiViewportFeatureNotEnabled) => (),
+ _ => panic!(),
+ }
+}
+
+#[test]
+fn max_viewports() {
+ let (device, _) = gfx_dev_and_queue!(multi_viewport);
+
+ let vs = unsafe { ShaderModule::new(device.clone(), &BASIC_VS).unwrap() };
+ let fs = unsafe { ShaderModule::new(device.clone(), &BASIC_FS).unwrap() };
+
+ let result = GraphicsPipeline::new(
+ &device,
+ GraphicsPipelineParams {
+ vertex_input: SingleBufferDefinition::<()>::new(),
+ vertex_shader: unsafe {
+ vs.vertex_shader_entry_point::<(), _, _, _>(
+ &CString::new("main").unwrap(),
+ ShaderInterface::empty(),
+ ShaderInterface::empty(),
+ PipelineLayoutDesc::empty(),
+ )
+ },
+ input_assembly: InputAssembly::triangle_list(),
+ tessellation: None,
+ geometry_shader: None,
+ viewport: ViewportsState::Dynamic { num: !0 },
+ raster: Default::default(),
+ multisample: Multisample::disabled(),
+ fragment_shader: unsafe {
+ fs.fragment_shader_entry_point::<(), _, _, _>(
+ &CString::new("main").unwrap(),
+ ShaderInterface::empty(),
+ ShaderInterface::empty(),
+ PipelineLayoutDesc::empty(),
+ )
+ },
+ depth_stencil: DepthStencil::disabled(),
+ blend: Blend::pass_through(),
+ render_pass: Subpass::from(
+ simple_rp::CustomRenderPass::new(&device, &{
+ simple_rp::Formats {
+ color: (Format::R8G8B8A8Unorm, 1),
+ }
+ })
+ .unwrap(),
+ 0,
+ )
+ .unwrap(),
+ },
+ );
+
+ match result {
+ Err(GraphicsPipelineCreationError::MaxViewportsExceeded { .. }) => (),
+ _ => panic!(),
+ }
+}
+
+#[test]
+fn no_depth_attachment() {
+ let (device, _) = gfx_dev_and_queue!();
+
+ let vs = unsafe { ShaderModule::new(device.clone(), &BASIC_VS).unwrap() };
+ let fs = unsafe { ShaderModule::new(device.clone(), &BASIC_FS).unwrap() };
+
+ let result = GraphicsPipeline::new(
+ &device,
+ GraphicsPipelineParams {
+ vertex_input: SingleBufferDefinition::<()>::new(),
+ vertex_shader: unsafe {
+ vs.vertex_shader_entry_point::<(), _, _, _>(
+ &CString::new("main").unwrap(),
+ ShaderInterface::empty(),
+ ShaderInterface::empty(),
+ PipelineLayoutDesc::empty(),
+ )
+ },
+ input_assembly: InputAssembly::triangle_list(),
+ tessellation: None,
+ geometry_shader: None,
+ viewport: ViewportsState::Dynamic { num: 1 },
+ raster: Default::default(),
+ multisample: Multisample::disabled(),
+ fragment_shader: unsafe {
+ fs.fragment_shader_entry_point::<(), _, _, _>(
+ &CString::new("main").unwrap(),
+ ShaderInterface::empty(),
+ ShaderInterface::empty(),
+ PipelineLayoutDesc::empty(),
+ )
+ },
+ depth_stencil: DepthStencil::simple_depth_test(),
+ blend: Blend::pass_through(),
+ render_pass: Subpass::from(
+ simple_rp::CustomRenderPass::new(&device, &{
+ simple_rp::Formats {
+ color: (Format::R8G8B8A8Unorm, 1),
+ }
+ })
+ .unwrap(),
+ 0,
+ )
+ .unwrap(),
+ },
+ );
+
+ match result {
+ Err(GraphicsPipelineCreationError::NoDepthAttachment) => (),
+ _ => panic!(),
+ }
+}
+
+mod simple_rp {
+ use format::Format;
+
+ single_pass_renderpass! {
+ attachments: {
+ color: {
+ load: Clear,
+ store: Store,
+ format: Format,
+ }
+ },
+ pass: {
+ color: [color],
+ depth_stencil: {}
+ }
+ }
+}
+
+/*
+ #version 450
+
+ #extension GL_ARB_separate_shader_objects : enable
+ #extension GL_ARB_shading_language_420pack : enable
+
+ layout(location = 0) in vec2 position;
+
+ void main() {
+ gl_Position = vec4(position, 0.0, 1.0);
+ }
+*/
+const BASIC_VS: [u8; 912] = [
+ 3, 2, 35, 7, 0, 0, 1, 0, 1, 0, 8, 0, 27, 0, 0, 0, 0, 0, 0, 0, 17, 0, 2, 0, 1, 0, 0, 0, 17, 0,
+ 2, 0, 32, 0, 0, 0, 17, 0, 2, 0, 33, 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, 7, 0, 0, 0,
+ 0, 0, 4, 0, 0, 0, 109, 97, 105, 110, 0, 0, 0, 0, 13, 0, 0, 0, 18, 0, 0, 0, 3, 0, 3, 0, 2, 0, 0,
+ 0, 194, 1, 0, 0, 4, 0, 9, 0, 71, 76, 95, 65, 82, 66, 95, 115, 101, 112, 97, 114, 97, 116, 101,
+ 95, 115, 104, 97, 100, 101, 114, 95, 111, 98, 106, 101, 99, 116, 115, 0, 0, 4, 0, 9, 0, 71, 76,
+ 95, 65, 82, 66, 95, 115, 104, 97, 100, 105, 110, 103, 95, 108, 97, 110, 103, 117, 97, 103, 101,
+ 95, 52, 50, 48, 112, 97, 99, 107, 0, 5, 0, 4, 0, 4, 0, 0, 0, 109, 97, 105, 110, 0, 0, 0, 0, 5,
+ 0, 6, 0, 11, 0, 0, 0, 103, 108, 95, 80, 101, 114, 86, 101, 114, 116, 101, 120, 0, 0, 0, 0, 6,
+ 0, 6, 0, 11, 0, 0, 0, 0, 0, 0, 0, 103, 108, 95, 80, 111, 115, 105, 116, 105, 111, 110, 0, 6, 0,
+ 7, 0, 11, 0, 0, 0, 1, 0, 0, 0, 103, 108, 95, 80, 111, 105, 110, 116, 83, 105, 122, 101, 0, 0,
+ 0, 0, 6, 0, 7, 0, 11, 0, 0, 0, 2, 0, 0, 0, 103, 108, 95, 67, 108, 105, 112, 68, 105, 115, 116,
+ 97, 110, 99, 101, 0, 6, 0, 7, 0, 11, 0, 0, 0, 3, 0, 0, 0, 103, 108, 95, 67, 117, 108, 108, 68,
+ 105, 115, 116, 97, 110, 99, 101, 0, 5, 0, 3, 0, 13, 0, 0, 0, 0, 0, 0, 0, 5, 0, 5, 0, 18, 0, 0,
+ 0, 112, 111, 115, 105, 116, 105, 111, 110, 0, 0, 0, 0, 72, 0, 5, 0, 11, 0, 0, 0, 0, 0, 0, 0,
+ 11, 0, 0, 0, 0, 0, 0, 0, 72, 0, 5, 0, 11, 0, 0, 0, 1, 0, 0, 0, 11, 0, 0, 0, 1, 0, 0, 0, 72, 0,
+ 5, 0, 11, 0, 0, 0, 2, 0, 0, 0, 11, 0, 0, 0, 3, 0, 0, 0, 72, 0, 5, 0, 11, 0, 0, 0, 3, 0, 0, 0,
+ 11, 0, 0, 0, 4, 0, 0, 0, 71, 0, 3, 0, 11, 0, 0, 0, 2, 0, 0, 0, 71, 0, 4, 0, 18, 0, 0, 0, 30, 0,
+ 0, 0, 0, 0, 0, 0, 19, 0, 2, 0, 2, 0, 0, 0, 33, 0, 3, 0, 3, 0, 0, 0, 2, 0, 0, 0, 22, 0, 3, 0, 6,
+ 0, 0, 0, 32, 0, 0, 0, 23, 0, 4, 0, 7, 0, 0, 0, 6, 0, 0, 0, 4, 0, 0, 0, 21, 0, 4, 0, 8, 0, 0, 0,
+ 32, 0, 0, 0, 0, 0, 0, 0, 43, 0, 4, 0, 8, 0, 0, 0, 9, 0, 0, 0, 1, 0, 0, 0, 28, 0, 4, 0, 10, 0,
+ 0, 0, 6, 0, 0, 0, 9, 0, 0, 0, 30, 0, 6, 0, 11, 0, 0, 0, 7, 0, 0, 0, 6, 0, 0, 0, 10, 0, 0, 0,
+ 10, 0, 0, 0, 32, 0, 4, 0, 12, 0, 0, 0, 3, 0, 0, 0, 11, 0, 0, 0, 59, 0, 4, 0, 12, 0, 0, 0, 13,
+ 0, 0, 0, 3, 0, 0, 0, 21, 0, 4, 0, 14, 0, 0, 0, 32, 0, 0, 0, 1, 0, 0, 0, 43, 0, 4, 0, 14, 0, 0,
+ 0, 15, 0, 0, 0, 0, 0, 0, 0, 23, 0, 4, 0, 16, 0, 0, 0, 6, 0, 0, 0, 2, 0, 0, 0, 32, 0, 4, 0, 17,
+ 0, 0, 0, 1, 0, 0, 0, 16, 0, 0, 0, 59, 0, 4, 0, 17, 0, 0, 0, 18, 0, 0, 0, 1, 0, 0, 0, 43, 0, 4,
+ 0, 6, 0, 0, 0, 20, 0, 0, 0, 0, 0, 0, 0, 43, 0, 4, 0, 6, 0, 0, 0, 21, 0, 0, 0, 0, 0, 128, 63,
+ 32, 0, 4, 0, 25, 0, 0, 0, 3, 0, 0, 0, 7, 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, 61, 0, 4, 0, 16, 0, 0, 0, 19, 0, 0, 0, 18, 0, 0, 0,
+ 81, 0, 5, 0, 6, 0, 0, 0, 22, 0, 0, 0, 19, 0, 0, 0, 0, 0, 0, 0, 81, 0, 5, 0, 6, 0, 0, 0, 23, 0,
+ 0, 0, 19, 0, 0, 0, 1, 0, 0, 0, 80, 0, 7, 0, 7, 0, 0, 0, 24, 0, 0, 0, 22, 0, 0, 0, 23, 0, 0, 0,
+ 20, 0, 0, 0, 21, 0, 0, 0, 65, 0, 5, 0, 25, 0, 0, 0, 26, 0, 0, 0, 13, 0, 0, 0, 15, 0, 0, 0, 62,
+ 0, 3, 0, 26, 0, 0, 0, 24, 0, 0, 0, 253, 0, 1, 0, 56, 0, 1, 0,
+];
+
+/*
+ #version 450
+
+ #extension GL_ARB_separate_shader_objects : enable
+ #extension GL_ARB_shading_language_420pack : enable
+
+ layout(location = 0) out vec4 f_color;
+
+ void main() {
+ f_color = vec4(1.0, 0.0, 0.0, 1.0);
+ }
+*/
+const BASIC_FS: [u8; 420] = [
+ 3, 2, 35, 7, 0, 0, 1, 0, 1, 0, 8, 0, 13, 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, 6, 0, 4, 0, 0, 0, 4, 0, 0, 0, 109, 97, 105, 110, 0, 0, 0, 0, 9,
+ 0, 0, 0, 16, 0, 3, 0, 4, 0, 0, 0, 7, 0, 0, 0, 3, 0, 3, 0, 2, 0, 0, 0, 194, 1, 0, 0, 4, 0, 9, 0,
+ 71, 76, 95, 65, 82, 66, 95, 115, 101, 112, 97, 114, 97, 116, 101, 95, 115, 104, 97, 100, 101,
+ 114, 95, 111, 98, 106, 101, 99, 116, 115, 0, 0, 4, 0, 9, 0, 71, 76, 95, 65, 82, 66, 95, 115,
+ 104, 97, 100, 105, 110, 103, 95, 108, 97, 110, 103, 117, 97, 103, 101, 95, 52, 50, 48, 112, 97,
+ 99, 107, 0, 5, 0, 4, 0, 4, 0, 0, 0, 109, 97, 105, 110, 0, 0, 0, 0, 5, 0, 4, 0, 9, 0, 0, 0, 102,
+ 95, 99, 111, 108, 111, 114, 0, 71, 0, 4, 0, 9, 0, 0, 0, 30, 0, 0, 0, 0, 0, 0, 0, 19, 0, 2, 0,
+ 2, 0, 0, 0, 33, 0, 3, 0, 3, 0, 0, 0, 2, 0, 0, 0, 22, 0, 3, 0, 6, 0, 0, 0, 32, 0, 0, 0, 23, 0,
+ 4, 0, 7, 0, 0, 0, 6, 0, 0, 0, 4, 0, 0, 0, 32, 0, 4, 0, 8, 0, 0, 0, 3, 0, 0, 0, 7, 0, 0, 0, 59,
+ 0, 4, 0, 8, 0, 0, 0, 9, 0, 0, 0, 3, 0, 0, 0, 43, 0, 4, 0, 6, 0, 0, 0, 10, 0, 0, 0, 0, 0, 128,
+ 63, 43, 0, 4, 0, 6, 0, 0, 0, 11, 0, 0, 0, 0, 0, 0, 0, 44, 0, 7, 0, 7, 0, 0, 0, 12, 0, 0, 0, 10,
+ 0, 0, 0, 11, 0, 0, 0, 11, 0, 0, 0, 10, 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, 62, 0, 3, 0, 9, 0, 0, 0, 12, 0, 0, 0, 253, 0, 1, 0,
+ 56, 0, 1, 0,
+];
diff --git a/src/pipeline/input_assembly.rs b/src/pipeline/input_assembly.rs
new file mode 100644
index 0000000..d797d0d
--- /dev/null
+++ b/src/pipeline/input_assembly.rs
@@ -0,0 +1,136 @@
+// 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/limits_check.rs b/src/pipeline/layout/limits_check.rs
new file mode 100644
index 0000000..8f98f26
--- /dev/null
+++ b/src/pipeline/layout/limits_check.rs
@@ -0,0 +1,513 @@
+// 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
new file mode 100644
index 0000000..c475d0a
--- /dev/null
+++ b/src/pipeline/layout/mod.rs
@@ -0,0 +1,47 @@
+// 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
new file mode 100644
index 0000000..7d6d33b
--- /dev/null
+++ b/src/pipeline/layout/sys.rs
@@ -0,0 +1,469 @@
+// 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
new file mode 100644
index 0000000..e87cbfd
--- /dev/null
+++ b/src/pipeline/mod.rs
@@ -0,0 +1,113 @@
+// 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.
+
+//! Describes a graphical or compute operation.
+//!
+//! 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.
+//!
+//! When you create a pipeline object, the implementation will usually generate some GPU machine
+//! 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 mod cache;
+mod compute_pipeline;
+pub mod depth_stencil;
+mod graphics_pipeline;
+pub mod input_assembly;
+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(),
+}
+
+impl From<PipelineBindPoint> for ash::vk::PipelineBindPoint {
+ #[inline]
+ fn from(val: PipelineBindPoint) -> Self {
+ Self::from_raw(val as i32)
+ }
+}
diff --git a/src/pipeline/multisample.rs b/src/pipeline/multisample.rs
new file mode 100644
index 0000000..dcb3362
--- /dev/null
+++ b/src/pipeline/multisample.rs
@@ -0,0 +1,61 @@
+// 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
new file mode 100644
index 0000000..337ef94
--- /dev/null
+++ b/src/pipeline/raster.rs
@@ -0,0 +1,166 @@
+// 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
new file mode 100644
index 0000000..c5ba1e3
--- /dev/null
+++ b/src/pipeline/shader.rs
@@ -0,0 +1,808 @@
+// 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
new file mode 100644
index 0000000..7bb8cd4
--- /dev/null
+++ b/src/pipeline/vertex/bufferless.rs
@@ -0,0 +1,67 @@
+// 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
new file mode 100644
index 0000000..1ef9d40
--- /dev/null
+++ b/src/pipeline/vertex/buffers.rs
@@ -0,0 +1,234 @@
+// 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
new file mode 100644
index 0000000..966feda
--- /dev/null
+++ b/src/pipeline/vertex/definition.rs
@@ -0,0 +1,105 @@
+// 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
new file mode 100644
index 0000000..7694b96
--- /dev/null
+++ b/src/pipeline/vertex/impl_vertex.rs
@@ -0,0 +1,199 @@
+// 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
new file mode 100644
index 0000000..a8886a8
--- /dev/null
+++ b/src/pipeline/vertex/mod.rs
@@ -0,0 +1,244 @@
+// 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
new file mode 100644
index 0000000..728fcaa
--- /dev/null
+++ b/src/pipeline/vertex/vertex.rs
@@ -0,0 +1,76 @@
+// 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/pipeline/viewport.rs b/src/pipeline/viewport.rs
new file mode 100644
index 0000000..e899369
--- /dev/null
+++ b/src/pipeline/viewport.rs
@@ -0,0 +1,202 @@
+// 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.
+
+//! Viewports and scissor boxes.
+//!
+//! 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`.
+//! - Any pixel outside of the scissor box will be discarded.
+//!
+//! 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
+//! only partially overlaps the target image.
+//!
+//! # Multiple viewports
+//!
+//! In most situations, you only need a single viewport and a single scissor box.
+//!
+//! If, however, you use a geometry shader, you can specify multiple viewports and scissor boxes.
+//! Then in your geometry shader you can specify in which viewport and scissor box the primitive
+//! should be written to. In GLSL this is done by writing to the special variable
+//! `gl_ViewportIndex`.
+//!
+//! If you don't use a geometry shader or use a geometry shader where don't set which viewport to
+//! use, then the first viewport and scissor box will be used.
+//!
+//! # Dynamic and fixed
+//!
+//! Vulkan allows four different setups:
+//!
+//! - The state of both the viewports and scissor boxes is known at pipeline creation.
+//! - The state of viewports is known at pipeline creation, but the state of scissor boxes is
+//! only known when submitting the draw command.
+//! - The state of scissor boxes is known at pipeline creation, but the state of viewports is
+//! only known when submitting the draw command.
+//! - The state of both the viewports and scissor boxes is only known when submitting the
+//! draw command.
+//!
+//! In all cases the number of viewports and scissor boxes must be the same.
+//!
+
+use std::ops::Range;
+
+/// List of viewports and scissors that are used when creating a graphics pipeline object.
+///
+/// Note that the number of viewports and scissors must be the same.
+#[derive(Debug, Clone)]
+pub enum ViewportsState {
+ /// The state is known in advance.
+ Fixed {
+ /// State of the viewports and scissors.
+ data: Vec<(Viewport, Scissor)>,
+ },
+
+ /// 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 {
+ /// 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>,
+ },
+
+ /// The state of both the viewports and scissors is dynamic and will be set when drawing.
+ Dynamic {
+ /// Number of viewports and scissors.
+ num: u32,
+ },
+}
+
+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,
+ }
+ }
+
+ /// 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,
+ }
+ }
+
+ /// 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,
+ }
+ }
+}
+
+/// State of a single viewport.
+// FIXME: check that:
+// x + width must be less than or equal to viewportBoundsRange[0]
+// y + height must be less than or equal to viewportBoundsRange[1]
+#[derive(Debug, Clone, PartialEq)]
+pub struct Viewport {
+ /// Coordinates in pixels of the top-left hand corner of the viewport.
+ pub origin: [f32; 2],
+
+ /// Dimensions in pixels of the viewport.
+ pub dimensions: [f32; 2],
+
+ /// Minimum and maximum values of the depth.
+ ///
+ /// The values `0.0` to `1.0` of each vertex's Z coordinate will be mapped to this
+ /// `depth_range` before being compared to the existing depth value.
+ ///
+ /// This is equivalents to `glDepthRange` in OpenGL, except that OpenGL uses the Z coordinate
+ /// range from `-1.0` to `1.0` instead.
+ pub depth_range: Range<f32>,
+}
+
+impl From<Viewport> for ash::vk::Viewport {
+ #[inline]
+ fn from(val: Viewport) -> Self {
+ ash::vk::Viewport {
+ x: val.origin[0],
+ y: val.origin[1],
+ width: val.dimensions[0],
+ height: val.dimensions[1],
+ min_depth: val.depth_range.start,
+ max_depth: val.depth_range.end,
+ }
+ }
+}
+
+/// State of a single scissor box.
+// FIXME: add a check:
+// Evaluation of (offset.x + extent.width) must not cause a signed integer addition overflow
+// Evaluation of (offset.y + extent.height) must not cause a signed integer addition overflow
+#[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],
+
+ /// 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.
+ #[inline]
+ pub fn irrelevant() -> Scissor {
+ Scissor {
+ origin: [0, 0],
+ dimensions: [0x7fffffff, 0x7fffffff],
+ }
+ }
+}
+
+impl Default for Scissor {
+ #[inline]
+ fn default() -> Scissor {
+ Scissor::irrelevant()
+ }
+}
+
+impl From<Scissor> for ash::vk::Rect2D {
+ #[inline]
+ fn from(val: Scissor) -> Self {
+ ash::vk::Rect2D {
+ offset: ash::vk::Offset2D {
+ x: val.origin[0],
+ y: val.origin[1],
+ },
+ extent: ash::vk::Extent2D {
+ width: val.dimensions[0],
+ height: val.dimensions[1],
+ },
+ }
+ }
+}
diff --git a/src/query.rs b/src/query.rs
new file mode 100644
index 0000000..44caada
--- /dev/null
+++ b/src/query.rs
@@ -0,0 +1,688 @@
+// 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.
+
+//! Gather information about rendering, held in query pools.
+//!
+//! In Vulkan, queries are not created individually. Instead you manipulate **query pools**, which
+//! 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;
+
+/// A collection of one or more queries of a particular type.
+#[derive(Debug)]
+pub struct QueryPool {
+ pool: ash::vk::QueryPool,
+ device: Arc<Device>,
+ num_slots: u32,
+ ty: QueryType,
+}
+
+impl QueryPool {
+ /// Builds a new query pool.
+ pub fn new(
+ device: Arc<Device>,
+ ty: QueryType,
+ num_slots: u32,
+ ) -> Result<QueryPool, QueryPoolCreationError> {
+ let statistics = match ty {
+ QueryType::PipelineStatistics(flags) => {
+ if !device.enabled_features().pipeline_statistics_query {
+ return Err(QueryPoolCreationError::PipelineStatisticsQueryFeatureNotEnabled);
+ }
+
+ flags.into()
+ }
+ QueryType::Occlusion | QueryType::Timestamp => {
+ ash::vk::QueryPipelineStatisticFlags::empty()
+ }
+ };
+
+ 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 mut output = MaybeUninit::uninit();
+ let fns = device.fns();
+ check_errors(fns.v1_0.create_query_pool(
+ device.internal_object(),
+ &infos,
+ ptr::null(),
+ output.as_mut_ptr(),
+ ))?;
+ output.assume_init()
+ };
+
+ Ok(QueryPool {
+ pool,
+ device,
+ num_slots,
+ ty,
+ })
+ }
+
+ /// Returns the [`QueryType`] that this query pool was created with.
+ #[inline]
+ pub fn ty(&self) -> QueryType {
+ self.ty
+ }
+
+ /// Returns the number of query slots of this query pool.
+ #[inline]
+ pub fn num_slots(&self) -> u32 {
+ self.num_slots
+ }
+
+ /// 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() {
+ Some(Query { pool: self, index })
+ } else {
+ None
+ }
+ }
+
+ /// Returns a reference to a range of queries, or `None` if out of range.
+ ///
+ /// # Panic
+ ///
+ /// Panics if the range is empty.
+ #[inline]
+ pub fn queries_range(&self, range: Range<u32>) -> Option<QueriesRange> {
+ assert!(!range.is_empty());
+
+ if range.end <= self.num_slots() {
+ Some(QueriesRange { pool: self, range })
+ } else {
+ None
+ }
+ }
+}
+
+unsafe impl VulkanObject for QueryPool {
+ type Object = ash::vk::QueryPool;
+
+ #[inline]
+ fn internal_object(&self) -> ash::vk::QueryPool {
+ self.pool
+ }
+}
+
+unsafe impl DeviceOwned for QueryPool {
+ #[inline]
+ fn device(&self) -> &Arc<Device> {
+ &self.device
+ }
+}
+
+impl Drop for QueryPool {
+ #[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());
+ }
+ }
+}
+
+/// Error that can happen when creating a query pool.
+#[derive(Clone, Debug, PartialEq, Eq)]
+pub enum QueryPoolCreationError {
+ /// Not enough memory.
+ OomError(OomError),
+ /// A pipeline statistics pool was requested but the corresponding feature wasn't enabled.
+ PipelineStatisticsQueryFeatureNotEnabled,
+}
+
+impl error::Error for QueryPoolCreationError {
+ #[inline]
+ fn source(&self) -> Option<&(dyn error::Error + 'static)> {
+ match *self {
+ QueryPoolCreationError::OomError(ref err) => Some(err),
+ _ => None,
+ }
+ }
+}
+
+impl fmt::Display for QueryPoolCreationError {
+ #[inline]
+ fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
+ write!(
+ fmt,
+ "{}",
+ match *self {
+ QueryPoolCreationError::OomError(_) => "not enough memory available",
+ QueryPoolCreationError::PipelineStatisticsQueryFeatureNotEnabled => {
+ "a pipeline statistics pool was requested but the corresponding feature \
+ wasn't enabled"
+ }
+ }
+ )
+ }
+}
+
+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 {
+ match err {
+ err @ Error::OutOfHostMemory => QueryPoolCreationError::OomError(OomError::from(err)),
+ err @ Error::OutOfDeviceMemory => QueryPoolCreationError::OomError(OomError::from(err)),
+ _ => panic!("unexpected error: {:?}", err),
+ }
+ }
+}
+
+/// A reference to a single query slot.
+///
+/// This is created through [`QueryPool::query`].
+#[derive(Clone, Debug)]
+pub struct Query<'a> {
+ pool: &'a QueryPool,
+ index: u32,
+}
+
+impl<'a> Query<'a> {
+ /// Returns a reference to the query pool.
+ #[inline]
+ pub fn pool(&self) -> &'a QueryPool {
+ &self.pool
+ }
+
+ /// Returns the index of the query represented.
+ #[inline]
+ pub fn index(&self) -> u32 {
+ self.index
+ }
+}
+
+/// A reference to a range of queries.
+///
+/// This is created through [`QueryPool::queries_range`].
+#[derive(Clone, Debug)]
+pub struct QueriesRange<'a> {
+ pool: &'a QueryPool,
+ range: Range<u32>,
+}
+
+impl<'a> QueriesRange<'a> {
+ /// Returns a reference to the query pool.
+ #[inline]
+ pub fn pool(&self) -> &'a QueryPool {
+ &self.pool
+ }
+
+ /// Returns the range of queries represented.
+ #[inline]
+ pub fn range(&self) -> Range<u32> {
+ self.range.clone()
+ }
+
+ /// 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.
+ ///
+ /// `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).
+ pub fn get_results<T>(
+ &self,
+ destination: &mut [T],
+ flags: QueryResultFlags,
+ ) -> Result<bool, GetResultsError>
+ where
+ T: QueryResultElement,
+ {
+ let stride = self.check_query_pool_results::<T>(
+ destination.as_ptr() as DeviceSize,
+ destination.len() as DeviceSize,
+ flags,
+ )?;
+
+ 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(),
+ self.range.start,
+ self.range.end - self.range.start,
+ std::mem::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),
+ })
+ }
+
+ pub(crate) fn check_query_pool_results<T>(
+ &self,
+ buffer_start: DeviceSize,
+ buffer_len: DeviceSize,
+ flags: QueryResultFlags,
+ ) -> Result<DeviceSize, GetResultsError>
+ where
+ T: QueryResultElement,
+ {
+ assert!(buffer_len > 0);
+ 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 required_len = per_query_len * count as DeviceSize;
+
+ if buffer_len < required_len {
+ return Err(GetResultsError::BufferTooSmall {
+ required_len: required_len as DeviceSize,
+ actual_len: buffer_len as DeviceSize,
+ });
+ }
+
+ match self.pool.ty {
+ QueryType::Occlusion => (),
+ QueryType::PipelineStatistics(_) => (),
+ QueryType::Timestamp => {
+ if flags.partial {
+ return Err(GetResultsError::InvalidFlags);
+ }
+ }
+ }
+
+ Ok(per_query_len * std::mem::size_of::<T>() as DeviceSize)
+ }
+}
+
+/// Error that can happen when calling [`QueriesRange::get_results`].
+#[derive(Clone, Debug, PartialEq, Eq)]
+pub enum GetResultsError {
+ /// The buffer is too small for the operation.
+ BufferTooSmall {
+ /// Required number of elements in the buffer.
+ required_len: DeviceSize,
+ /// 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 {
+ match err {
+ Error::OutOfHostMemory | Error::OutOfDeviceMemory => {
+ Self::OomError(OomError::from(err))
+ }
+ Error::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,
+ }
+ }
+}
+
+/// A trait for elements of buffers that can be used as a destination for query results.
+///
+/// # 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 {
+ const FLAG: ash::vk::QueryResultFlags;
+}
+
+unsafe impl QueryResultElement for u32 {
+ const FLAG: ash::vk::QueryResultFlags = ash::vk::QueryResultFlags::empty();
+}
+
+unsafe impl QueryResultElement for u64 {
+ const FLAG: ash::vk::QueryResultFlags = ash::vk::QueryResultFlags::TYPE_64;
+}
+
+/// The type of query that a query pool should perform.
+#[derive(Debug, Copy, Clone)]
+pub enum QueryType {
+ /// Tracks the number of samples that pass per-fragment tests (e.g. the depth test).
+ Occlusion,
+ /// Tracks statistics on pipeline invocations and their input data.
+ PipelineStatistics(QueryPipelineStatisticFlags),
+ /// Writes timestamps at chosen points in a command buffer.
+ Timestamp,
+}
+
+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.
+ ///
+ /// If the results are retrieved with [`QueryResultFlags::with_availability`] enabled, then
+ /// an additional element is required per query.
+ #[inline]
+ pub const fn result_size(&self) -> DeviceSize {
+ match self {
+ Self::Occlusion | Self::Timestamp => 1,
+ Self::PipelineStatistics(flags) => flags.count(),
+ }
+ }
+}
+
+impl From<QueryType> for ash::vk::QueryType {
+ #[inline]
+ fn from(value: QueryType) -> Self {
+ match value {
+ QueryType::Occlusion => ash::vk::QueryType::OCCLUSION,
+ QueryType::PipelineStatistics(_) => ash::vk::QueryType::PIPELINE_STATISTICS,
+ QueryType::Timestamp => ash::vk::QueryType::TIMESTAMP,
+ }
+ }
+}
+
+/// Flags that control how a query is to be executed.
+#[derive(Clone, Copy, Debug, Default)]
+pub struct QueryControlFlags {
+ /// 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,
+}
+
+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;
+ }
+ result
+ }
+}
+
+/// 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,
+ /// Count the number of primitives processed by the input assembly.
+ pub input_assembly_primitives: bool,
+ /// Count the number of times a vertex shader is invoked.
+ pub vertex_shader_invocations: bool,
+ /// Count the number of times a geometry shader is invoked.
+ pub geometry_shader_invocations: bool,
+ /// Count the number of primitives generated by geometry shaders.
+ pub geometry_shader_primitives: bool,
+ /// Count the number of times the clipping stage is invoked on a primitive.
+ pub clipping_invocations: bool,
+ /// Count the number of primitives that are output by the clipping stage.
+ pub clipping_primitives: bool,
+ /// Count the number of times a fragment shader is invoked.
+ pub fragment_shader_invocations: bool,
+ /// 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,
+}
+
+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,
+ }
+ }
+
+ /// 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
+ }
+
+ /// 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
+ }
+
+ /// 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
+ }
+}
+
+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
+ }
+}
+
+/// 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,
+ /// 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,
+ /// Allow writing partial results to the buffer, instead of waiting until they are fully
+ /// available.
+ pub partial: bool,
+}
+
+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
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use crate::query::QueryPipelineStatisticFlags;
+ use crate::query::QueryPool;
+ use crate::query::QueryPoolCreationError;
+ use crate::query::QueryType;
+
+ #[test]
+ fn pipeline_statistics_feature() {
+ let (device, _) = gfx_dev_and_queue!();
+
+ let ty = QueryType::PipelineStatistics(QueryPipelineStatisticFlags::none());
+ match QueryPool::new(device, ty, 256) {
+ Err(QueryPoolCreationError::PipelineStatisticsQueryFeatureNotEnabled) => (),
+ _ => panic!(),
+ };
+ }
+}
diff --git a/src/render_pass/attachments_list.rs b/src/render_pass/attachments_list.rs
new file mode 100644
index 0000000..2b1fe23
--- /dev/null
+++ b/src/render_pass/attachments_list.rs
@@ -0,0 +1,82 @@
+// 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
new file mode 100644
index 0000000..381f4f3
--- /dev/null
+++ b/src/render_pass/compat_atch.rs
@@ -0,0 +1,263 @@
+// 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/desc.rs b/src/render_pass/desc.rs
new file mode 100644
index 0000000..8d8928d
--- /dev/null
+++ b/src/render_pass/desc.rs
@@ -0,0 +1,434 @@
+// 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
new file mode 100644
index 0000000..b55be4d
--- /dev/null
+++ b/src/render_pass/framebuffer.rs
@@ -0,0 +1,990 @@
+// 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::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 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;
+
+/// 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.
+///
+/// ```
+/// # use std::sync::Arc;
+/// # use vulkano::render_pass::RenderPass;
+/// use vulkano::render_pass::Framebuffer;
+///
+/// # let render_pass: Arc<RenderPass> = return;
+/// # let view: Arc<vulkano::image::view::ImageView<Arc<vulkano::image::AttachmentImage<vulkano::format::Format>>>> = return;
+/// // let render_pass: Arc<_> = ...;
+/// let framebuffer = Framebuffer::start(render_pass.clone())
+/// .add(view).unwrap()
+/// .build().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>,
+ render_pass: Arc<RenderPass>,
+ framebuffer: ash::vk::Framebuffer,
+ dimensions: [u32; 3],
+ resources: A,
+}
+
+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: (),
+ }
+ }
+
+ /// Starts building a framebuffer.
+ pub fn with_dimensions(
+ render_pass: Arc<RenderPass>,
+ dimensions: [u32; 3],
+ ) -> FramebufferBuilder<()> {
+ FramebufferBuilder {
+ render_pass,
+ raw_ids: SmallVec::new(),
+ dimensions: FramebufferBuilderDimensions::Specific(dimensions),
+ attachments: (),
+ }
+ }
+}
+
+/// Prototype of a framebuffer.
+pub struct FramebufferBuilder<A> {
+ render_pass: Arc<RenderPass>,
+ raw_ids: SmallVec<[ash::vk::ImageView; 8]>,
+ dimensions: FramebufferBuilderDimensions,
+ attachments: A,
+}
+
+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()
+ }
+}
+
+#[derive(Debug)]
+enum FramebufferBuilderDimensions {
+ AutoIdentical(Option<[u32; 3]>),
+ AutoSmaller(Option<[u32; 3]>),
+ Specific([u32; 3]),
+}
+
+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,
+ });
+ }
+
+ match ensure_image_view_compatible(self.render_pass.desc(), self.raw_ids.len(), &attachment)
+ {
+ Ok(()) => (),
+ Err(err) => return Err(FramebufferCreationError::IncompatibleAttachment(err)),
+ };
+
+ let image_dimensions = attachment.image().dimensions();
+ let array_layers = attachment.array_layers();
+ debug_assert_eq!(image_dimensions.depth(), 1);
+
+ let view_dimensions = [
+ image_dimensions.width(),
+ image_dimensions.height(),
+ array_layers.end - array_layers.start,
+ ];
+
+ 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,
+ });
+ }
+
+ 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,
+ });
+ }
+
+ FramebufferBuilderDimensions::Specific(view_dimensions)
+ }
+ };
+
+ let mut raw_ids = self.raw_ids;
+ raw_ids.push(attachment.inner().internal_object());
+
+ Ok(FramebufferBuilder {
+ render_pass: self.render_pass,
+ raw_ids,
+ dimensions,
+ attachments: (self.attachments, attachment),
+ })
+ }
+
+ /// 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<_>,
+ }
+ }
+
+ /// Builds the framebuffer.
+ pub fn build(self) -> Result<Framebuffer<A>, FramebufferCreationError> {
+ let device = self.render_pass.device().clone();
+
+ // 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(),
+ });
+ }
+
+ // 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);
+ }
+ };
+
+ // 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-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;
+ }
+ }
+
+ 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 mut output = MaybeUninit::uninit();
+ check_errors(fns.v1_0.create_framebuffer(
+ device.internal_object(),
+ &infos,
+ ptr::null(),
+ output.as_mut_ptr(),
+ ))?;
+ 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]
+ }
+
+ /// Returns the device that was used to create this framebuffer.
+ #[inline]
+ pub fn device(&self) -> &Arc<Device> {
+ &self.device
+ }
+
+ /// 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.
+ #[inline]
+ fn height(&self) -> u32 {
+ self.dimensions()[1]
+ }
+
+ /// Returns the number of layers (or depth) of the framebuffer.
+ #[inline]
+ fn layers(&self) -> u32 {
+ self.dimensions()[2]
+ }
+}
+
+unsafe impl<T> FramebufferAbstract for T
+where
+ T: SafeDeref,
+ T::Target: FramebufferAbstract,
+{
+ #[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()
+ }
+
+ #[inline]
+ fn attached_image_view(&self, index: usize) -> Option<&dyn ImageViewAbstract> {
+ (**self).attached_image_view(index)
+ }
+}
+
+unsafe impl<A> FramebufferAbstract for Framebuffer<A>
+where
+ A: AttachmentsList,
+{
+ #[inline]
+ fn inner(&self) -> FramebufferSys {
+ FramebufferSys(self.framebuffer, PhantomData)
+ }
+
+ #[inline]
+ fn dimensions(&self) -> [u32; 3] {
+ self.dimensions
+ }
+
+ #[inline]
+ fn render_pass(&self) -> &Arc<RenderPass> {
+ &self.render_pass
+ }
+
+ #[inline]
+ fn attached_image_view(&self, index: usize) -> Option<&dyn ImageViewAbstract> {
+ self.resources.as_image_view_access(index)
+ }
+}
+
+unsafe impl<A> DeviceOwned for Framebuffer<A> {
+ #[inline]
+ fn device(&self) -> &Arc<Device> {
+ &self.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(),
+ );
+ }
+ }
+}
+
+/// Opaque object that represents the internals of a framebuffer.
+#[derive(Debug, Copy, Clone)]
+pub struct FramebufferSys<'a>(ash::vk::Framebuffer, PhantomData<&'a ()>);
+
+unsafe impl<'a> VulkanObject for FramebufferSys<'a> {
+ type Object = ash::vk::Framebuffer;
+
+ #[inline]
+ fn internal_object(&self) -> ash::vk::Framebuffer {
+ self.0
+ }
+}
+
+/// Error that can happen when creating a framebuffer object.
+#[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,
+ },
+ /// 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],
+ },
+ /// 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,
+ },
+ /// One of the images cannot be used as the requested attachment.
+ IncompatibleAttachment(IncompatibleRenderPassAttachmentError),
+ /// The framebuffer has no attachment and no dimension was specified.
+ CantDetermineDimensions,
+}
+
+impl From<OomError> for FramebufferCreationError {
+ #[inline]
+ fn from(err: OomError) -> FramebufferCreationError {
+ FramebufferCreationError::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),
+ _ => 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 From<Error> for FramebufferCreationError {
+ #[inline]
+ fn from(err: Error) -> FramebufferCreationError {
+ FramebufferCreationError::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;
+
+ #[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,
+ }
+ },
+ pass: {
+ color: [color],
+ depth_stencil: {}
+ }
+ )
+ .unwrap(),
+ );
+
+ let view = ImageView::new(
+ AttachmentImage::new(device.clone(), [1024, 768], Format::R8G8B8A8Unorm).unwrap(),
+ )
+ .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();
+ match res {
+ Err(FramebufferCreationError::DimensionsTooLarge) => (),
+ _ => panic!(),
+ }
+ }
+
+ #[test]
+ 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,
+ }
+ },
+ pass: {
+ color: [color],
+ depth_stencil: {}
+ }
+ )
+ .unwrap(),
+ );
+
+ let view = ImageView::new(
+ AttachmentImage::new(device.clone(), [1024, 768], Format::R8Unorm).unwrap(),
+ )
+ .unwrap();
+
+ match Framebuffer::start(render_pass).add(view) {
+ Err(FramebufferCreationError::IncompatibleAttachment(_)) => (),
+ _ => panic!(),
+ }
+ }
+
+ // TODO: check samples mismatch
+
+ #[test]
+ 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,
+ }
+ },
+ pass: {
+ color: [color],
+ depth_stencil: {}
+ }
+ )
+ .unwrap(),
+ );
+
+ let view = ImageView::new(
+ AttachmentImage::new(device.clone(), [600, 600], Format::R8G8B8A8Unorm).unwrap(),
+ )
+ .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(),
+ )
+ .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!(),
+ }
+ }
+
+ #[test]
+ fn multi_attachments_dims_not_identical() {
+ 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,
+ }
+ },
+ pass: {
+ color: [a, b],
+ depth_stencil: {}
+ }
+ )
+ .unwrap(),
+ );
+
+ let a = ImageView::new(
+ AttachmentImage::new(device.clone(), [512, 512], Format::R8G8B8A8Unorm).unwrap(),
+ )
+ .unwrap();
+ let b = ImageView::new(
+ AttachmentImage::new(device.clone(), [512, 513], Format::R8G8B8A8Unorm).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]);
+ }
+ _ => panic!(),
+ }
+ }
+
+ #[test]
+ 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,
+ }
+ },
+ pass: {
+ color: [a, b],
+ depth_stencil: {}
+ }
+ )
+ .unwrap(),
+ );
+
+ let a = ImageView::new(
+ AttachmentImage::new(device.clone(), [256, 512], Format::R8G8B8A8Unorm).unwrap(),
+ )
+ .unwrap();
+ let b = ImageView::new(
+ AttachmentImage::new(device.clone(), [512, 128], Format::R8G8B8A8Unorm).unwrap(),
+ )
+ .unwrap();
+
+ let fb = Framebuffer::with_intersecting_dimensions(render_pass)
+ .add(a)
+ .unwrap()
+ .add(b)
+ .unwrap()
+ .build()
+ .unwrap();
+
+ match (fb.width(), fb.height(), fb.layers()) {
+ (256, 128, 1) => (),
+ _ => panic!(),
+ }
+ }
+
+ #[test]
+ 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,
+ }
+ },
+ pass: {
+ color: [a, b],
+ depth_stencil: {}
+ }
+ )
+ .unwrap(),
+ );
+
+ let view = ImageView::new(
+ AttachmentImage::new(device.clone(), [256, 512], Format::R8G8B8A8Unorm).unwrap(),
+ )
+ .unwrap();
+
+ let res = Framebuffer::with_intersecting_dimensions(render_pass)
+ .add(view)
+ .unwrap()
+ .build();
+
+ match res {
+ Err(FramebufferCreationError::AttachmentsCountMismatch {
+ expected: 2,
+ obtained: 1,
+ }) => (),
+ _ => panic!(),
+ }
+ }
+
+ #[test]
+ 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,
+ }
+ },
+ pass: {
+ color: [a],
+ depth_stencil: {}
+ }
+ )
+ .unwrap(),
+ );
+
+ let a = ImageView::new(
+ AttachmentImage::new(device.clone(), [256, 512], Format::R8G8B8A8Unorm).unwrap(),
+ )
+ .unwrap();
+ let b = ImageView::new(
+ AttachmentImage::new(device.clone(), [256, 512], Format::R8G8B8A8Unorm).unwrap(),
+ )
+ .unwrap();
+
+ let res = Framebuffer::with_intersecting_dimensions(render_pass)
+ .add(a)
+ .unwrap()
+ .add(b);
+
+ match res {
+ Err(FramebufferCreationError::AttachmentsCountMismatch {
+ expected: 1,
+ obtained: 2,
+ }) => (),
+ _ => panic!(),
+ }
+ }
+
+ #[test]
+ 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();
+ }
+
+ #[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();
+ match res {
+ Err(FramebufferCreationError::CantDetermineDimensions) => (),
+ _ => panic!(),
+ }
+ }
+}
diff --git a/src/render_pass/macros.rs b/src/render_pass/macros.rs
new file mode 100644
index 0000000..d73a204
--- /dev/null
+++ b/src/render_pass/macros.rs
@@ -0,0 +1,237 @@
+// 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.
+
+/// Builds a `RenderPass` object whose template parameter is of indeterminate type.
+#[macro_export]
+macro_rules! single_pass_renderpass {
+ (
+ $device:expr,
+ attachments: { $($a:tt)* },
+ pass: {
+ color: [$($color_atch:ident),*],
+ depth_stencil: {$($depth_atch:ident)*}$(,)*
+ $(resolve: [$($resolve_atch:ident),*])*$(,)*
+ }
+ ) => (
+ $crate::ordered_passes_renderpass!(
+ $device,
+ attachments: { $($a)* },
+ passes: [
+ {
+ color: [$($color_atch),*],
+ depth_stencil: {$($depth_atch)*},
+ input: [],
+ resolve: [$($($resolve_atch),*)*]
+ }
+ ]
+ )
+ )
+}
+
+/// Builds a `RenderPass` object whose template parameter is of indeterminate type.
+#[macro_export]
+macro_rules! ordered_passes_renderpass {
+ (
+ $device:expr,
+ attachments: {
+ $(
+ $atch_name:ident: {
+ load: $load:ident,
+ store: $store:ident,
+ format: $format: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),*])*$(,)*
+ }
+ ),*
+ ]
+ ) => ({
+ 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 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];
+
+ let subpasses = vec![
+ $({
+ let desc = SubpassDesc {
+ color_attachments: vec![
+ $({
+ let layout = &mut layouts[$color_atch];
+ layout.0 = layout.0.or(Some(ImageLayout::ColorAttachmentOptimal));
+ layout.1 = Some(ImageLayout::ColorAttachmentOptimal);
+
+ ($color_atch, ImageLayout::ColorAttachmentOptimal)
+ }),*
+ ],
+ depth_stencil: {
+ let depth: Option<(usize, ImageLayout)> = None;
+ $(
+ let layout = &mut layouts[$depth_atch];
+ layout.1 = Some(ImageLayout::DepthStencilAttachmentOptimal);
+ layout.0 = layout.0.or(layout.1);
+
+ let depth = Some(($depth_atch, ImageLayout::DepthStencilAttachmentOptimal));
+ )*
+ depth
+ },
+ input_attachments: vec![
+ $({
+ let layout = &mut layouts[$input_atch];
+ layout.1 = Some(ImageLayout::ShaderReadOnlyOptimal);
+ layout.0 = layout.0.or(layout.1);
+
+ ($input_atch, ImageLayout::ShaderReadOnlyOptimal)
+ }),*
+ ],
+ resolve_attachments: vec![
+ $($({
+ let layout = &mut layouts[$resolve_atch];
+ layout.1 = Some(ImageLayout::TransferDstOptimal);
+ layout.0 = layout.0.or(layout.1);
+
+ ($resolve_atch, ImageLayout::TransferDstOptimal)
+ }),*)*
+ ],
+ preserve_attachments: (0 .. attachment_num).filter(|&a| {
+ $(if a == $color_atch { return false; })*
+ $(if a == $depth_atch { return false; })*
+ $(if a == $input_atch { return false; })*
+ $($(if a == $resolve_atch { return false; })*)*
+ true
+ }).collect()
+ };
+
+ assert!(desc.resolve_attachments.is_empty() ||
+ desc.resolve_attachments.len() == desc.color_attachments.len());
+ desc
+ }),*
+ ];
+
+ let dependencies = (0..subpasses.len().saturating_sub(1))
+ .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
+ }
+ })
+ .collect();
+
+ let attachments = vec![
+ $({
+ let layout = &mut layouts[$atch_name];
+ $(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,
+ initial_layout: layout.0.expect(
+ format!(
+ "Attachment {} is missing initial_layout, this is normally \
+ automatically determined but you can manually specify it for an individual \
+ attachment in the single_pass_renderpass! macro",
+ attachment_num
+ )
+ .as_ref(),
+ ),
+ final_layout: layout.1.expect(
+ format!(
+ "Attachment {} is missing final_layout, this is normally \
+ automatically determined but you can manually specify it for an individual \
+ attachment in the single_pass_renderpass! macro",
+ attachment_num
+ )
+ .as_ref(),
+ ),
+ }
+ }),*
+ ];
+
+ RenderPassDesc::new(
+ attachments,
+ subpasses,
+ dependencies,
+ )
+ };
+
+ RenderPass::new($device, desc)
+ });
+}
+
+#[cfg(test)]
+mod tests {
+ use crate::format::Format;
+
+ #[test]
+ fn single_pass_resolve() {
+ let (device, _) = gfx_dev_and_queue!();
+ let _ = single_pass_renderpass!(device.clone(),
+ attachments: {
+ a: {
+ load: Clear,
+ store: DontCare,
+ format: Format::R8G8B8A8Unorm,
+ samples: 4,
+ },
+ b: {
+ load: DontCare,
+ store: Store,
+ format: Format::R8G8B8A8Unorm,
+ samples: 1,
+ }
+ },
+ pass: {
+ color: [a],
+ depth_stencil: {},
+ resolve: [b],
+ }
+ )
+ .unwrap();
+ }
+}
diff --git a/src/render_pass/mod.rs b/src/render_pass/mod.rs
new file mode 100644
index 0000000..62fedaa
--- /dev/null
+++ b/src/render_pass/mod.rs
@@ -0,0 +1,56 @@
+// 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 the steps of the rendering process, and the images used as input or output.
+//!
+//! # Render passes and framebuffers
+//!
+//! There are two concepts in Vulkan:
+//!
+//! - A *render pass* describes the overall process of drawing a frame. It is subdivided into one
+//! or more subpasses.
+//! - A *framebuffer* contains the list of image views that are attached during the drawing of
+//! each subpass.
+//!
+//! Render passes are typically created at initialization only (for example during a loading
+//! screen) because they can be costly, while framebuffers can be created and destroyed either at
+//! initialization or during the frame.
+//!
+//! 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;
+
+#[macro_use]
+mod macros;
+mod attachments_list;
+mod compat_atch;
+mod desc;
+mod framebuffer;
+mod render_pass;
diff --git a/src/render_pass/render_pass.rs b/src/render_pass/render_pass.rs
new file mode 100644
index 0000000..629dc8e
--- /dev/null
+++ b/src/render_pass/render_pass.rs
@@ -0,0 +1,911 @@
+// 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
new file mode 100644
index 0000000..be7fc9b
--- /dev/null
+++ b/src/sampler.rs
@@ -0,0 +1,1051 @@
+// 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/swapchain/capabilities.rs b/src/swapchain/capabilities.rs
new file mode 100644
index 0000000..2a6feca
--- /dev/null
+++ b/src/swapchain/capabilities.rs
@@ -0,0 +1,664 @@
+// 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
new file mode 100644
index 0000000..67f135e
--- /dev/null
+++ b/src/swapchain/display.rs
@@ -0,0 +1,430 @@
+// 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.
+
+//! Allows you to create surfaces that fill a whole display, outside of the windowing system.
+//!
+//! **As far as the author knows, no existing device supports these features. Therefore the code
+//! here is mostly a draft and needs rework in both the API and the implementation.**
+//!
+//! The purpose of the objects in this module is to let you create a `Surface` object that
+//! represents a location on the screen. This is done in four steps:
+//!
+//! - Choose a `Display` where the surface will be located. A `Display` represents a display
+//! display, usually a monitor. The available displays can be enumerated with
+//! `Display::enumerate`.
+//! - Choose a `DisplayMode`, which is the combination of a display, a resolution and a refresh
+//! 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`
+//! 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};
+
+// TODO: extract this to a `display` module and solve the visibility problems
+
+/// ?
+// TODO: plane capabilities
+// TODO: store properties in the instance?
+pub struct DisplayPlane {
+ instance: Arc<Instance>,
+ physical_device: usize,
+ index: u32,
+ properties: ash::vk::DisplayPlanePropertiesKHR,
+ supported_displays: Vec<ash::vk::DisplayKHR>,
+}
+
+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
+ };
+
+ Ok(planes
+ .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
+ };
+
+ DisplayPlane {
+ instance: device.instance().clone(),
+ physical_device: device.index(),
+ index: index as u32,
+ properties: prop,
+ supported_displays: supported_displays,
+ }
+ })
+ .collect::<Vec<_>>()
+ .into_iter())
+ }
+
+ /// Enumerates all the display planes that are available on a given physical device.
+ ///
+ /// # Panic
+ ///
+ /// - 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()
+ }
+
+ /// 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()
+ }
+
+ /// Returns the index of the plane.
+ #[inline]
+ pub fn index(&self) -> u32 {
+ self.index
+ }
+
+ /// Returns true if this plane supports the given display.
+ #[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() {
+ return false;
+ }
+
+ self.supported_displays
+ .iter()
+ .find(|&&d| d == display.internal_object())
+ .is_some()
+ }
+}
+
+/// Represents a monitor connected to a physical device.
+// TODO: store properties in the instance?
+#[derive(Clone)]
+pub struct Display {
+ instance: Arc<Instance>,
+ physical_device: usize,
+ 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
+ };
+
+ Ok(displays
+ .into_iter()
+ .map(|prop| Display {
+ instance: device.instance().clone(),
+ physical_device: device.index(),
+ properties: Arc::new(prop),
+ })
+ .collect::<Vec<_>>()
+ .into_iter())
+ }
+
+ /// Enumerates all the displays that are available on a given physical device.
+ ///
+ /// # Panic
+ ///
+ /// - 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()
+ }
+
+ /// Returns the name of the display.
+ #[inline]
+ pub fn name(&self) -> &str {
+ unsafe {
+ CStr::from_ptr(self.properties.display_name)
+ .to_str()
+ .expect("non UTF-8 characters in display name")
+ }
+ }
+
+ /// 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()
+ }
+
+ /// Returns the physical dimensions of the display in millimeters.
+ #[inline]
+ pub fn physical_dimensions(&self) -> [u32; 2] {
+ let ref r = self.properties.physical_dimensions;
+ [r.width, r.height]
+ }
+
+ /// Returns the physical, native, or preferred resolution of the display.
+ ///
+ /// > **Note**: The display is usually still capable of displaying other resolutions. This is
+ /// > only the "best" resolution.
+ #[inline]
+ pub fn physical_resolution(&self) -> [u32; 2] {
+ let ref r = self.properties.physical_resolution;
+ [r.width, r.height]
+ }
+
+ /// Returns the transforms supported by this display.
+ #[inline]
+ pub fn supported_transforms(&self) -> SupportedSurfaceTransforms {
+ self.properties.supported_transforms.into()
+ }
+
+ /// Returns true if TODO.
+ #[inline]
+ pub fn plane_reorder_possible(&self) -> bool {
+ self.properties.plane_reorder_possible != 0
+ }
+
+ /// Returns true if TODO.
+ #[inline]
+ pub fn persistent_content(&self) -> bool {
+ self.properties.persistent_content != 0
+ }
+
+ /// 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
+ };
+
+ Ok(modes
+ .into_iter()
+ .map(|mode| DisplayMode {
+ display: self.clone(),
+ display_mode: mode.display_mode,
+ parameters: mode.parameters,
+ })
+ .collect::<Vec<_>>()
+ .into_iter())
+ }
+
+ /// Returns a list of all modes available on this display.
+ ///
+ /// # Panic
+ ///
+ /// - 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> {
+ self.display_modes_raw().unwrap()
+ }
+}
+
+unsafe impl VulkanObject for Display {
+ type Object = ash::vk::DisplayKHR;
+
+ #[inline]
+ fn internal_object(&self) -> ash::vk::DisplayKHR {
+ self.properties.display
+ }
+}
+
+/// Represents a mode on a specific display.
+///
+/// A display mode describes a supported display resolution and refresh rate.
+pub struct DisplayMode {
+ display: Display,
+ display_mode: ash::vk::DisplayModeKHR,
+ parameters: ash::vk::DisplayModeParametersKHR,
+}
+
+impl DisplayMode {
+ /*pub fn new(display: &Display) -> Result<Arc<DisplayMode>, OomError> {
+ let fns = instance.fns();
+ assert!(device.instance().enabled_extensions().khr_display); // TODO: return error instead
+
+ let parameters = ash::vk::DisplayModeParametersKHR {
+ visibleRegion: ash::vk::Extent2D { width: , height: },
+ refreshRate: ,
+ };
+
+ let display_mode = {
+ let infos = ash::vk::DisplayModeCreateInfoKHR {
+ flags: ash::vk::DisplayModeCreateFlags::empty(),
+ parameters: parameters,
+ ..Default::default()
+ };
+
+ let mut output = mem::uninitialized();
+ check_errors(fns.v1_0.CreateDisplayModeKHR(display.device.internal_object(),
+ display.display, &infos, ptr::null(),
+ &mut output))?;
+ output
+ };
+
+ Ok(Arc::new(DisplayMode {
+ instance: display.device.instance().clone(),
+ display_mode: display_mode,
+ parameters: ,
+ }))
+ }*/
+
+ /// Returns the display corresponding to this mode.
+ #[inline]
+ pub fn display(&self) -> &Display {
+ &self.display
+ }
+
+ /// 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;
+ [d.width, d.height]
+ }
+
+ /// Returns the refresh rate of this mode.
+ ///
+ /// The returned value is multiplied by 1000. As such the value is in terms of millihertz (mHz).
+ /// For example, a 60Hz display mode would have a refresh rate of 60,000 mHz.
+ #[inline]
+ pub fn refresh_rate(&self) -> u32 {
+ self.parameters.refresh_rate
+ }
+}
+
+impl fmt::Display for DisplayMode {
+ #[inline]
+ fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
+ let visible_region = self.visible_region();
+
+ write!(
+ f,
+ "{}×{}px @ {}.{:03} Hz",
+ visible_region[0],
+ visible_region[1],
+ self.refresh_rate() / 1000,
+ self.refresh_rate() % 1000
+ )
+ }
+}
+
+unsafe impl VulkanObject for DisplayMode {
+ type Object = ash::vk::DisplayModeKHR;
+
+ #[inline]
+ fn internal_object(&self) -> ash::vk::DisplayModeKHR {
+ self.display_mode
+ }
+}
diff --git a/src/swapchain/mod.rs b/src/swapchain/mod.rs
new file mode 100644
index 0000000..0434a57
--- /dev/null
+++ b/src/swapchain/mod.rs
@@ -0,0 +1,342 @@
+// 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.
+
+//! Link between Vulkan and a window and/or the screen.
+//!
+//! Before you can draw on the screen or a window, you have to create two objects:
+//!
+//! - Create a `Surface` object that represents the location where the image will show up (either
+//! a window or a monitor).
+//! - Create a `Swapchain` that uses that `Surface`.
+//!
+//! Creating a surface can be done with only an `Instance` object. However creating a swapchain
+//! requires a `Device` object.
+//!
+//! Once you have a swapchain, you can retrieve `Image` objects from it and draw to them just like
+//! you would draw on any other image.
+//!
+//! # Surfaces
+//!
+//! A surface is an object that represents a location where to render. It can be created from an
+//! instance and either a window handle (in a platform-specific way) or a monitor.
+//!
+//! In order to use surfaces, you will have to enable the `VK_KHR_surface` extension on the
+//! instance. See the `instance` module for more information about how to enable extensions.
+//!
+//! ## Creating a surface from a window
+//!
+//! There are 5 extensions that each allow you to create a surface from a type of window:
+//!
+//! - `VK_KHR_xlib_surface`
+//! - `VK_KHR_xcb_surface`
+//! - `VK_KHR_wayland_surface`
+//! - `VK_KHR_android_surface`
+//! - `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`.
+//! 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
+//! error.
+//!
+//! **Note that the `Surface` object is potentially unsafe**. It is your responsibility to
+//! keep the window alive for at least as long as the surface exists. In many cases Surface
+//! may be able to do this for you, if you pass it ownership of your Window (or a
+//! reference-counting container for it).
+//!
+//! ### Example
+//!
+//! ```no_run
+//! use std::ptr;
+//! use vulkano::instance::Instance;
+//! use vulkano::instance::InstanceExtensions;
+//! use vulkano::swapchain::Surface;
+//! use vulkano::Version;
+//!
+//! let instance = {
+//! let extensions = InstanceExtensions {
+//! khr_surface: true,
+//! khr_win32_surface: true, // If you don't enable this, `from_hwnd` will fail.
+//! .. InstanceExtensions::none()
+//! };
+//!
+//! match Instance::new(None, Version::V1_1, &extensions, None) {
+//! Ok(i) => i,
+//! Err(err) => panic!("Couldn't build instance: {:?}", err)
+//! }
+//! };
+//!
+//! # use std::sync::Arc;
+//! # struct Window(*const u32);
+//! # impl Window {
+//! # fn hwnd(&self) -> *const u32 { self.0 }
+//! # }
+//! #
+//! # fn build_window() -> Arc<Window> { Arc::new(Window(ptr::null())) }
+//! 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()
+//! };
+//! ```
+//!
+//! ## Creating a surface from a monitor
+//!
+//! Currently no system provides the `VK_KHR_display` extension that contains this feature.
+//! This feature is still a work-in-progress in vulkano and will reside in the `display` module.
+//!
+//! # Swapchains
+//!
+//! A surface represents a location on the screen and can be created from an instance. Once you
+//! have a surface, the next step is to create a swapchain. Creating a swapchain requires a device,
+//! and allocates the resources that will be used to display images on the screen.
+//!
+//! A swapchain is composed of one or multiple images. Each image of the swapchain is presented in
+//! turn on the screen, one after another. More information below.
+//!
+//! Swapchains have several properties:
+//!
+//! - The number of images that will cycle on the screen.
+//! - The format of the images.
+//! - The 2D dimensions of the images, plus a number of layers, for a total of three dimensions.
+//! - The usage of the images, similar to creating other images.
+//! - The queue families that are going to use the images, similar to creating other images.
+//! - An additional transformation (rotation or mirroring) to perform on the final output.
+//! - 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).
+//!
+//! ## Creating a swapchain
+//!
+//! In order to create a swapchain, you will first have to enable the `VK_KHR_swapchain` extension
+//! on the device (and not on the instance like `VK_KHR_surface`):
+//!
+//! ```no_run
+//! # use vulkano::device::DeviceExtensions;
+//! let ext = DeviceExtensions {
+//! khr_swapchain: true,
+//! .. DeviceExtensions::none()
+//! };
+//! ```
+//!
+//! Then, query the capabilities of the surface with
+//! [`Surface::capabilities()`](struct.Surface.html#method.capabilities)
+//! and choose which values you are going to use.
+//!
+//! ```no_run
+//! # use std::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())?;
+//!
+//! // Use the current window size or some fixed resolution.
+//! let dimensions = caps.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)
+//! };
+//!
+//! // Preserve the current surface transform.
+//! let transform = caps.current_transform;
+//!
+//! // Use the first available format.
+//! let (format, color_space) = caps.supported_formats[0];
+//! # Ok(())
+//! # }
+//! ```
+//!
+//! Then, call [`Swapchain::new()`](struct.Swapchain.html#method.new).
+//!
+//! ```no_run
+//! # use std::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};
+//! # 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()?;
+//!
+//! # Ok(())
+//! # }
+//! ```
+//!
+//! Creating a swapchain not only returns the swapchain object, but also all the images that belong
+//! to it.
+//!
+//! ## Acquiring and presenting images
+//!
+//! Once you created a swapchain and retrieved all the images that belong to it (see previous
+//! section), you can draw on it. This is done in three steps:
+//!
+//! - Call `swapchain::acquire_next_image`. This function will return the index of the image
+//! (within the list returned by `Swapchain::new`) that is available to draw, plus a future
+//! representing the moment when the GPU will gain access to that image.
+//! - Draw on that image just like you would draw to any other image (see the documentation of
+//! the `pipeline` module). You need to chain the draw after the future that was returned by
+//! `acquire_next_image`.
+//! - Call `Swapchain::present` with the same index and by chaining the futures, in order to tell
+//! the implementation that you are finished drawing to the image and that it can queue a
+//! command to present the image on the screen after the draw operations are finished.
+//!
+//! ```
+//! use vulkano::swapchain;
+//! 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, images) = Swapchain::new(...);
+//! loop {
+//! # let mut command_buffer: ::vulkano::command_buffer::PrimaryAutoCommandBuffer<()> = return;
+//! let (image_num, 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]
+//! acquire_future
+//! .then_execute(queue.clone(), command_buffer).unwrap()
+//! .then_swapchain_present(queue.clone(), swapchain.clone(), image_num)
+//! .then_signal_fence_and_flush().unwrap();
+//! }
+//! ```
+//!
+//! ## Recreating a swapchain
+//!
+//! In some situations, the swapchain will become invalid by itself. This includes for example when
+//! the window is resized (as the images of the swapchain will no longer match the window's) or,
+//! on Android, when the application went to the background and goes back to the foreground.
+//!
+//! In this situation, acquiring a swapchain image or presenting it will return an error. Rendering
+//! to an image of that swapchain will not produce any error, but may or may not work. To continue
+//! 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::sync::GpuFuture;
+//!
+//! // let mut swapchain = Swapchain::new(...);
+//! # let mut swapchain: (::std::sync::Arc<::vulkano::swapchain::Swapchain<()>>, _) = 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();
+//! recreate_swapchain = false;
+//! }
+//!
+//! let (ref swapchain, ref _images) = swapchain;
+//!
+//! let (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)
+//! };
+//!
+//! // ...
+//!
+//! let final_future = acq_future
+//! // .then_execute(...)
+//! .then_swapchain_present(queue.clone(), swapchain.clone(), index)
+//! .then_signal_fence_and_flush().unwrap(); // TODO: PresentError?
+//!
+//! if suboptimal {
+//! recreate_swapchain = true;
+//! }
+//! }
+//! ```
+//!
+
+use std::sync::atomic::AtomicBool;
+
+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;
+
+mod capabilities;
+pub mod display;
+mod present_region;
+mod surface;
+mod swapchain;
+
+/// Internal trait so that creating/destroying a swapchain can access the surface's "has_swapchain"
+/// flag.
+// TODO: use pub(crate) maybe?
+unsafe trait SurfaceSwapchainLock {
+ fn flag(&self) -> &AtomicBool;
+}
diff --git a/src/swapchain/present_region.rs b/src/swapchain/present_region.rs
new file mode 100644
index 0000000..7e5fdf4
--- /dev/null
+++ b/src/swapchain/present_region.rs
@@ -0,0 +1,69 @@
+// 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
new file mode 100644
index 0000000..9bf5fd8
--- /dev/null
+++ b/src/swapchain/surface.rs
@@ -0,0 +1,856 @@
+// 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::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;
+
+/// Represents a surface on the screen.
+///
+/// Creating a `Surface` is platform-specific.
+pub struct Surface<W> {
+ window: W,
+ instance: Arc<Instance>,
+ surface: ash::vk::SurfaceKHR,
+
+ // If true, a swapchain has been associated to this surface, and that any new swapchain
+ // creation should be forbidden.
+ has_swapchain: AtomicBool,
+}
+
+impl<W> Surface<W> {
+ /// Creates a `Surface` given the raw handler.
+ ///
+ /// Be careful when using it
+ ///
+ pub unsafe fn from_raw_surface(
+ instance: Arc<Instance>,
+ surface: ash::vk::SurfaceKHR,
+ win: W,
+ ) -> Surface<W> {
+ Surface {
+ window: win,
+ instance,
+ surface,
+ has_swapchain: AtomicBool::new(false),
+ }
+ }
+
+ /// Creates a `Surface` that covers a display mode.
+ ///
+ /// # Panic
+ ///
+ /// - 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(
+ display_mode: &DisplayMode,
+ plane: &DisplayPlane,
+ ) -> Result<Arc<Surface<()>>, SurfaceCreationError> {
+ if !display_mode
+ .display()
+ .physical_device()
+ .instance()
+ .enabled_extensions()
+ .khr_display
+ {
+ return Err(SurfaceCreationError::MissingExtension {
+ name: "VK_KHR_display",
+ });
+ }
+
+ assert_eq!(
+ display_mode.display().physical_device().internal_object(),
+ plane.physical_device().internal_object()
+ );
+ assert!(plane.supports(display_mode.display()));
+
+ 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 mut output = MaybeUninit::uninit();
+ check_errors(fns.khr_display.create_display_plane_surface_khr(
+ instance.internal_object(),
+ &infos,
+ ptr::null(),
+ output.as_mut_ptr(),
+ ))?;
+ output.assume_init()
+ };
+
+ Ok(Arc::new(Surface {
+ window: (),
+ instance: instance.clone(),
+ surface,
+ has_swapchain: AtomicBool::new(false),
+ }))
+ }
+
+ /// Creates a `Surface` from a Win32 window.
+ ///
+ /// The surface's min, max and current extent will always match the window's dimensions.
+ ///
+ /// # 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>(
+ instance: Arc<Instance>,
+ hinstance: *const T,
+ hwnd: *const U,
+ win: W,
+ ) -> Result<Arc<Surface<W>>, SurfaceCreationError> {
+ let fns = instance.fns();
+
+ if !instance.enabled_extensions().khr_win32_surface {
+ return Err(SurfaceCreationError::MissingExtension {
+ name: "VK_KHR_win32_surface",
+ });
+ }
+
+ let surface = {
+ let infos = ash::vk::Win32SurfaceCreateInfoKHR {
+ flags: ash::vk::Win32SurfaceCreateFlagsKHR::empty(),
+ hinstance: hinstance as *mut _,
+ hwnd: hwnd as *mut _,
+ ..Default::default()
+ };
+
+ let mut output = MaybeUninit::uninit();
+ check_errors(fns.khr_win32_surface.create_win32_surface_khr(
+ instance.internal_object(),
+ &infos,
+ ptr::null(),
+ output.as_mut_ptr(),
+ ))?;
+ output.assume_init()
+ };
+
+ Ok(Arc::new(Surface {
+ window: win,
+ instance: instance.clone(),
+ surface,
+ has_swapchain: AtomicBool::new(false),
+ }))
+ }
+
+ /// Creates a `Surface` from an XCB window.
+ ///
+ /// The surface's min, max and current extent will always match the window's dimensions.
+ ///
+ /// # 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>(
+ instance: Arc<Instance>,
+ connection: *const C,
+ window: u32,
+ win: W,
+ ) -> Result<Arc<Surface<W>>, SurfaceCreationError> {
+ let fns = instance.fns();
+
+ if !instance.enabled_extensions().khr_xcb_surface {
+ return Err(SurfaceCreationError::MissingExtension {
+ name: "VK_KHR_xcb_surface",
+ });
+ }
+
+ let surface = {
+ let infos = ash::vk::XcbSurfaceCreateInfoKHR {
+ flags: ash::vk::XcbSurfaceCreateFlagsKHR::empty(),
+ connection: connection as *mut _,
+ window,
+ ..Default::default()
+ };
+
+ let mut output = MaybeUninit::uninit();
+ check_errors(fns.khr_xcb_surface.create_xcb_surface_khr(
+ instance.internal_object(),
+ &infos,
+ ptr::null(),
+ output.as_mut_ptr(),
+ ))?;
+ output.assume_init()
+ };
+
+ Ok(Arc::new(Surface {
+ window: win,
+ instance: instance.clone(),
+ surface,
+ has_swapchain: AtomicBool::new(false),
+ }))
+ }
+
+ /// Creates a `Surface` from an Xlib window.
+ ///
+ /// The surface's min, max and current extent will always match the window's dimensions.
+ ///
+ /// # 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>(
+ instance: Arc<Instance>,
+ display: *const D,
+ window: c_ulong,
+ win: W,
+ ) -> Result<Arc<Surface<W>>, SurfaceCreationError> {
+ let fns = instance.fns();
+
+ if !instance.enabled_extensions().khr_xlib_surface {
+ return Err(SurfaceCreationError::MissingExtension {
+ name: "VK_KHR_xlib_surface",
+ });
+ }
+
+ let surface = {
+ let infos = ash::vk::XlibSurfaceCreateInfoKHR {
+ flags: ash::vk::XlibSurfaceCreateFlagsKHR::empty(),
+ dpy: display as *mut _,
+ window,
+ ..Default::default()
+ };
+
+ let mut output = MaybeUninit::uninit();
+ check_errors(fns.khr_xlib_surface.create_xlib_surface_khr(
+ instance.internal_object(),
+ &infos,
+ ptr::null(),
+ output.as_mut_ptr(),
+ ))?;
+ output.assume_init()
+ };
+
+ Ok(Arc::new(Surface {
+ window: win,
+ instance: instance.clone(),
+ surface,
+ has_swapchain: AtomicBool::new(false),
+ }))
+ }
+
+ /// Creates a `Surface` from a Wayland window.
+ ///
+ /// The window's dimensions will be set to the size of the swapchain.
+ ///
+ /// # 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>(
+ instance: Arc<Instance>,
+ display: *const D,
+ surface: *const S,
+ win: W,
+ ) -> Result<Arc<Surface<W>>, SurfaceCreationError> {
+ let fns = instance.fns();
+
+ if !instance.enabled_extensions().khr_wayland_surface {
+ return Err(SurfaceCreationError::MissingExtension {
+ name: "VK_KHR_wayland_surface",
+ });
+ }
+
+ let surface = {
+ let infos = ash::vk::WaylandSurfaceCreateInfoKHR {
+ flags: ash::vk::WaylandSurfaceCreateFlagsKHR::empty(),
+ display: display as *mut _,
+ surface: surface as *mut _,
+ ..Default::default()
+ };
+
+ let mut output = MaybeUninit::uninit();
+ check_errors(fns.khr_wayland_surface.create_wayland_surface_khr(
+ instance.internal_object(),
+ &infos,
+ ptr::null(),
+ output.as_mut_ptr(),
+ ))?;
+ output.assume_init()
+ };
+
+ Ok(Arc::new(Surface {
+ window: win,
+ instance: instance.clone(),
+ surface,
+ has_swapchain: AtomicBool::new(false),
+ }))
+ }
+
+ /// Creates a `Surface` from an Android window.
+ ///
+ /// # 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>(
+ instance: Arc<Instance>,
+ window: *const T,
+ win: W,
+ ) -> Result<Arc<Surface<W>>, SurfaceCreationError> {
+ let fns = instance.fns();
+
+ if !instance.enabled_extensions().khr_android_surface {
+ return Err(SurfaceCreationError::MissingExtension {
+ name: "VK_KHR_android_surface",
+ });
+ }
+
+ let surface = {
+ let infos = ash::vk::AndroidSurfaceCreateInfoKHR {
+ flags: ash::vk::AndroidSurfaceCreateFlagsKHR::empty(),
+ window: window as *mut _,
+ ..Default::default()
+ };
+
+ let mut output = MaybeUninit::uninit();
+ check_errors(fns.khr_android_surface.create_android_surface_khr(
+ instance.internal_object(),
+ &infos,
+ ptr::null(),
+ output.as_mut_ptr(),
+ ))?;
+ output.assume_init()
+ };
+
+ Ok(Arc::new(Surface {
+ window: win,
+ instance: instance.clone(),
+ surface,
+ has_swapchain: AtomicBool::new(false),
+ }))
+ }
+
+ /// Creates a `Surface` from an iOS `UIView`.
+ ///
+ /// # 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>(
+ instance: Arc<Instance>,
+ view: *const T,
+ win: W,
+ ) -> Result<Arc<Surface<W>>, SurfaceCreationError> {
+ let fns = instance.fns();
+
+ if !instance.enabled_extensions().mvk_ios_surface {
+ return Err(SurfaceCreationError::MissingExtension {
+ name: "VK_MVK_ios_surface",
+ });
+ }
+
+ let surface = {
+ let infos = ash::vk::IOSSurfaceCreateInfoMVK {
+ flags: ash::vk::IOSSurfaceCreateFlagsMVK::empty(),
+ p_view: view as *const _,
+ ..Default::default()
+ };
+
+ let mut output = MaybeUninit::uninit();
+ check_errors(fns.mvk_ios_surface.create_ios_surface_mvk(
+ instance.internal_object(),
+ &infos,
+ ptr::null(),
+ output.as_mut_ptr(),
+ ))?;
+ output.assume_init()
+ };
+
+ Ok(Arc::new(Surface {
+ window: win,
+ instance: instance.clone(),
+ surface,
+ has_swapchain: AtomicBool::new(false),
+ }))
+ }
+
+ /// Creates a `Surface` from a MacOS `NSView`.
+ ///
+ /// # 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>(
+ instance: Arc<Instance>,
+ view: *const T,
+ win: W,
+ ) -> Result<Arc<Surface<W>>, SurfaceCreationError> {
+ let fns = instance.fns();
+
+ if !instance.enabled_extensions().mvk_macos_surface {
+ return Err(SurfaceCreationError::MissingExtension {
+ name: "VK_MVK_macos_surface",
+ });
+ }
+
+ let surface = {
+ let infos = ash::vk::MacOSSurfaceCreateInfoMVK {
+ flags: ash::vk::MacOSSurfaceCreateFlagsMVK::empty(),
+ p_view: view as *const _,
+ ..Default::default()
+ };
+
+ let mut output = MaybeUninit::uninit();
+ check_errors(fns.mvk_macos_surface.create_mac_os_surface_mvk(
+ instance.internal_object(),
+ &infos,
+ ptr::null(),
+ output.as_mut_ptr(),
+ ))?;
+ output.assume_init()
+ };
+
+ Ok(Arc::new(Surface {
+ window: win,
+ instance: instance.clone(),
+ surface,
+ has_swapchain: AtomicBool::new(false),
+ }))
+ }
+
+ /// 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>(
+ instance: Arc<Instance>,
+ window: *const T,
+ win: W,
+ ) -> Result<Arc<Surface<W>>, SurfaceCreationError> {
+ let fns = instance.fns();
+
+ if !instance.enabled_extensions().nn_vi_surface {
+ return Err(SurfaceCreationError::MissingExtension {
+ name: "VK_NN_vi_surface",
+ });
+ }
+
+ let surface = {
+ let infos = ash::vk::ViSurfaceCreateInfoNN {
+ flags: ash::vk::ViSurfaceCreateFlagsNN::empty(),
+ window: window as *mut _,
+ ..Default::default()
+ };
+
+ let mut output = MaybeUninit::uninit();
+ check_errors(fns.nn_vi_surface.create_vi_surface_nn(
+ instance.internal_object(),
+ &infos,
+ ptr::null(),
+ output.as_mut_ptr(),
+ ))?;
+ output.assume_init()
+ };
+
+ Ok(Arc::new(Surface {
+ window: win,
+ instance: instance.clone(),
+ surface,
+ has_swapchain: AtomicBool::new(false),
+ }))
+ }
+
+ /// 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();
+
+ 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,
+ output.as_mut_ptr(),
+ ))?;
+ Ok(output.assume_init() != 0)
+ }
+ }
+
+ /// Retrieves the capabilities of a surface when used by a certain device.
+ ///
+ /// # Notes
+ ///
+ /// - Capabilities that are not supported in `vk-sys` are silently dropped
+ ///
+ /// # Panic
+ ///
+ /// - Panics if the device and the surface don't belong to the same instance.
+ ///
+ 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();
+
+ 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])
+ },
+ 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
+ },
+ 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,
+ })
+ }
+ }
+
+ #[inline]
+ pub fn window(&self) -> &W {
+ &self.window
+ }
+
+ /// Returns the instance this surface was created with.
+ #[inline]
+ pub fn instance(&self) -> &Arc<Instance> {
+ &self.instance
+ }
+}
+
+unsafe impl<W> SurfaceSwapchainLock for Surface<W> {
+ #[inline]
+ fn flag(&self) -> &AtomicBool {
+ &self.has_swapchain
+ }
+}
+
+unsafe impl<W> VulkanObject for Surface<W> {
+ type Object = ash::vk::SurfaceKHR;
+
+ #[inline]
+ fn internal_object(&self) -> ash::vk::SurfaceKHR {
+ self.surface
+ }
+}
+
+impl<W> fmt::Debug for Surface<W> {
+ #[inline]
+ fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
+ write!(fmt, "<Vulkan surface {:?}>", self.surface)
+ }
+}
+
+impl<W> Drop for Surface<W> {
+ #[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(),
+ );
+ }
+ }
+}
+
+/// 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,
+ },
+}
+
+impl error::Error for SurfaceCreationError {
+ #[inline]
+ fn source(&self) -> Option<&(dyn error::Error + 'static)> {
+ match *self {
+ SurfaceCreationError::OomError(ref 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 From<OomError> for SurfaceCreationError {
+ #[inline]
+ fn from(err: OomError) -> SurfaceCreationError {
+ SurfaceCreationError::OomError(err)
+ }
+}
+
+impl From<Error> for SurfaceCreationError {
+ #[inline]
+ fn from(err: Error) -> SurfaceCreationError {
+ match err {
+ err @ Error::OutOfHostMemory => SurfaceCreationError::OomError(OomError::from(err)),
+ err @ Error::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 surface is no longer accessible and must be recreated.
+ SurfaceLost,
+}
+
+impl error::Error for CapabilitiesError {
+ #[inline]
+ fn source(&self) -> Option<&(dyn error::Error + 'static)> {
+ match *self {
+ CapabilitiesError::OomError(ref err) => Some(err),
+ _ => None,
+ }
+ }
+}
+
+impl fmt::Display for CapabilitiesError {
+ #[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",
+ }
+ )
+ }
+}
+
+impl From<OomError> for CapabilitiesError {
+ #[inline]
+ fn from(err: OomError) -> CapabilitiesError {
+ CapabilitiesError::OomError(err)
+ }
+}
+
+impl From<Error> for CapabilitiesError {
+ #[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),
+ }
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use crate::swapchain::Surface;
+ use crate::swapchain::SurfaceCreationError;
+ 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 { .. }) => (),
+ _ => panic!(),
+ }
+ }
+
+ #[test]
+ fn khr_xcb_surface_ext_missing() {
+ let instance = instance!();
+ match unsafe { Surface::from_xcb(instance, ptr::null::<u8>(), 0, ()) } {
+ Err(SurfaceCreationError::MissingExtension { .. }) => (),
+ _ => panic!(),
+ }
+ }
+
+ #[test]
+ fn khr_xlib_surface_ext_missing() {
+ let instance = instance!();
+ match unsafe { Surface::from_xlib(instance, ptr::null::<u8>(), 0, ()) } {
+ Err(SurfaceCreationError::MissingExtension { .. }) => (),
+ _ => panic!(),
+ }
+ }
+
+ #[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 { .. }) => (),
+ _ => panic!(),
+ }
+ }
+
+ #[test]
+ fn khr_android_surface_ext_missing() {
+ let instance = instance!();
+ match unsafe { Surface::from_anativewindow(instance, ptr::null::<u8>(), ()) } {
+ Err(SurfaceCreationError::MissingExtension { .. }) => (),
+ _ => panic!(),
+ }
+ }
+}
diff --git a/src/swapchain/swapchain.rs b/src/swapchain/swapchain.rs
new file mode 100644
index 0000000..3eb9051
--- /dev/null
+++ b/src/swapchain/swapchain.rs
@@ -0,0 +1,1724 @@
+// 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::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(),
+}
+
+impl From<FullscreenExclusive> for ash::vk::FullScreenExclusiveEXT {
+ #[inline]
+ fn from(val: FullscreenExclusive) -> Self {
+ Self::from_raw(val as i32)
+ }
+}
+
+/// 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())?;
+
+ 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);
+ }
+
+ let acquire_result =
+ unsafe { acquire_next_image_raw(&swapchain, timeout, Some(&semaphore), Some(&fence)) };
+
+ if let &Err(AcquireError::FullscreenExclusiveLost) = &acquire_result {
+ swapchain
+ .fullscreen_exclusive_held
+ .store(false, Ordering::SeqCst);
+ }
+
+ acquire_result?
+ };
+
+ Ok((
+ id,
+ suboptimal,
+ SwapchainAcquireFuture {
+ swapchain,
+ semaphore: Some(semaphore),
+ fence: Some(fence),
+ image_id: id,
+ finished: AtomicBool::new(false),
+ },
+ ))
+}
+
+/// 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());
+
+ // 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,
+ image_id: index,
+ present_region: None,
+ flushed: AtomicBool::new(false),
+ finished: AtomicBool::new(false),
+ }
+}
+
+/// 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());
+
+ // 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,
+ image_id: index,
+ present_region: Some(present_region),
+ flushed: AtomicBool::new(false),
+ finished: AtomicBool::new(false),
+ }
+}
+
+/// 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,
+
+ // 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.
+ 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,
+}
+
+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,
+}
+
+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,
+
+ 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,
+
+ old_swapchain: None,
+ }
+ }
+
+ /// 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`.
+ #[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,
+ composite_alpha: self.composite_alpha,
+ present_mode: self.present_mode,
+ fullscreen_exclusive: self.fullscreen_exclusive,
+ clipped: self.clipped,
+
+ old_swapchain: Some(self.clone()),
+ }
+ }
+
+ /// Returns the saved Surface, from the Swapchain creation.
+ #[inline]
+ pub fn surface(&self) -> &Arc<Surface<W>> {
+ &self.surface
+ }
+
+ /// Returns of the images that belong to this 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,
+ })
+ }
+
+ /// Returns the number of images of the swapchain.
+ #[inline]
+ pub fn num_images(&self) -> u32 {
+ self.images.len() as u32
+ }
+
+ /// Returns the format of the images of the swapchain.
+ #[inline]
+ pub fn format(&self) -> Format {
+ self.format
+ }
+
+ /// Returns the dimensions of the images of the swapchain.
+ #[inline]
+ pub fn dimensions(&self) -> [u32; 2] {
+ self.dimensions
+ }
+
+ /// Returns the number of layers of the images of the swapchain.
+ #[inline]
+ pub fn layers(&self) -> u32 {
+ self.layers
+ }
+
+ /// Returns the transform that was passed when creating the swapchain.
+ #[inline]
+ pub fn transform(&self) -> SurfaceTransform {
+ self.transform
+ }
+
+ /// Returns the alpha mode that was passed when creating the swapchain.
+ #[inline]
+ pub fn composite_alpha(&self) -> CompositeAlpha {
+ self.composite_alpha
+ }
+
+ /// Returns the present mode that was passed when creating the swapchain.
+ #[inline]
+ pub fn present_mode(&self) -> PresentMode {
+ self.present_mode
+ }
+
+ /// Returns the value of `clipped` that was passed when creating the swapchain.
+ #[inline]
+ pub fn clipped(&self) -> bool {
+ self.clipped
+ }
+
+ /// Returns the value of 'fullscreen_exclusive` that was passed when creating the swapchain.
+ #[inline]
+ pub fn fullscreen_exclusive(&self) -> FullscreenExclusive {
+ self.fullscreen_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);
+ }
+
+ if self.fullscreen_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,
+ ),
+ )?;
+ }
+
+ 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);
+ }
+
+ if !self.fullscreen_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,
+ ),
+ )?;
+ }
+
+ Ok(())
+ }
+
+ /// `FullscreenExclusive::AppControlled` is not the active fullscreen 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 currently acquired.
+ pub fn is_fullscreen_exclusive(&self) -> bool {
+ if self.fullscreen_exclusive != FullscreenExclusive::AppControlled {
+ false
+ } else {
+ self.fullscreen_exclusive_held.load(Ordering::SeqCst)
+ }
+ }
+
+ // This method is necessary to allow `SwapchainImage`s to signal when they have been
+ // 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 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)
+ } else {
+ false
+ }
+ }
+}
+
+unsafe impl<W> VulkanObject for Swapchain<W> {
+ type Object = ash::vk::SwapchainKHR;
+
+ #[inline]
+ fn internal_object(&self) -> ash::vk::SwapchainKHR {
+ self.swapchain
+ }
+}
+
+unsafe impl<W> DeviceOwned for Swapchain<W> {
+ fn device(&self) -> &Arc<Device> {
+ &self.device
+ }
+}
+
+impl<W> fmt::Debug for Swapchain<W> {
+ #[inline]
+ fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
+ write!(fmt, "<Vulkan swapchain {:?}>", self.swapchain)
+ }
+}
+
+impl<W> Drop for Swapchain<W> {
+ #[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);
+ }
+ }
+}
+
+/// 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<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 {
+ device,
+ surface,
+ old_swapchain,
+
+ num_images,
+ format,
+ color_space,
+ dimensions,
+ layers,
+ usage,
+ sharing_mode,
+ transform,
+ composite_alpha,
+ present_mode,
+ fullscreen_exclusive,
+ clipped,
+ } = 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);
+ }
+ }
+
+ 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);
+ }
+ }
+ };
+
+ 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);
+ }
+
+ 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);
+ }
+ }
+
+ // 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);
+ }
+ }
+
+ if !device.enabled_extensions().khr_swapchain {
+ return Err(SwapchainCreationError::MissingExtensionKHRSwapchain);
+ }
+
+ 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()
+ });
+ }
+
+ let p_next = match surface_full_screen_exclusive_info.as_ref() {
+ Some(some) => unsafe { mem::transmute(some as *const _) },
+ None => ptr::null(),
+ };
+
+ // Required by the specs.
+ assert_ne!(usage, ImageUsage::none());
+
+ if let Some(ref old_swapchain) = old_swapchain {
+ let mut stale = old_swapchain.stale.lock().unwrap();
+
+ // 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;
+ }
+ }
+
+ let fns = device.fns();
+
+ 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(),
+ ),
+ };
+
+ 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()
+ };
+
+ 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()
+ };
+
+ 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(),
+ ))?;
+
+ 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
+ };
+
+ 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);
+
+ 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,
+ });
+
+ 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
+ };
+
+ Ok((swapchain, swapchain_images))
+ }
+
+ /// Sets the number of images that will be created.
+ ///
+ /// The default is 2.
+ #[inline]
+ pub fn num_images(mut self, num_images: u32) -> Self {
+ self.num_images = num_images;
+ self
+ }
+
+ /// 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
+ }
+
+ /// 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
+ }
+
+ /// 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
+ }
+
+ /// 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
+ }
+
+ /// 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
+ }
+
+ /// 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
+ }
+
+ /// 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
+ }
+
+ /// 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
+ }
+
+ /// 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
+ }
+
+ /// 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
+ }
+
+ /// 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.
+ ///
+ /// The default is `true`.
+ #[inline]
+ pub fn clipped(mut self, clipped: bool) -> Self {
+ self.clipped = clipped;
+ self
+ }
+}
+
+/// Error that can happen when creation a swapchain.
+#[derive(Clone, Debug, PartialEq, Eq)]
+pub enum SwapchainCreationError {
+ /// Not enough memory.
+ OomError(OomError),
+ /// The device was lost.
+ DeviceLost,
+ /// The surface was lost.
+ 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,
+}
+
+impl error::Error for SwapchainCreationError {
+ #[inline]
+ fn source(&self) -> Option<&(dyn error::Error + 'static)> {
+ match *self {
+ SwapchainCreationError::OomError(ref err) => Some(err),
+ _ => None,
+ }
+ }
+}
+
+impl fmt::Display for SwapchainCreationError {
+ #[inline]
+ fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
+ write!(
+ fmt,
+ "{}",
+ 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"
+ }
+ SwapchainCreationError::UnsupportedPresentMode => {
+ "the requested present mode is not supported by the surface"
+ }
+ SwapchainCreationError::UnsupportedImageConfiguration => {
+ "the requested image configuration is not supported by the physical device"
+ }
+ }
+ )
+ }
+}
+
+impl From<Error> for SwapchainCreationError {
+ #[inline]
+ fn from(err: Error) -> SwapchainCreationError {
+ 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,
+ _ => panic!("unexpected error: {:?}", err),
+ }
+ }
+}
+
+impl From<OomError> for SwapchainCreationError {
+ #[inline]
+ fn from(err: OomError) -> SwapchainCreationError {
+ SwapchainCreationError::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,
+ }
+ }
+}
+
+/// 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,
+ // Semaphore that is signalled when the acquire is complete. Empty if the acquire has already
+ // happened.
+ semaphore: Option<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> {
+ /// 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
+ }
+
+ /// Returns the corresponding swapchain.
+ #[inline]
+ pub fn swapchain(&self) -> &Arc<Swapchain<W>> {
+ &self.swapchain
+ }
+}
+
+unsafe impl<W> GpuFuture for SwapchainAcquireFuture<W> {
+ #[inline]
+ 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);
+ 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> {
+ 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() {
+ return Err(AccessCheckError::Unknown);
+ }
+
+ if self.swapchain.images[self.image_id]
+ .undefined_layout
+ .load(Ordering::Relaxed)
+ && layout != ImageLayout::Undefined
+ {
+ return Err(AccessCheckError::Denied(AccessError::ImageNotInitialized {
+ requested: layout,
+ }));
+ }
+
+ if layout != ImageLayout::Undefined && layout != ImageLayout::PresentSrc {
+ return Err(AccessCheckError::Denied(
+ AccessError::UnexpectedImageLayout {
+ allowed: ImageLayout::PresentSrc,
+ requested: layout,
+ },
+ ));
+ }
+
+ Ok(None)
+ }
+}
+
+unsafe impl<W> DeviceOwned for SwapchainAcquireFuture<W> {
+ #[inline]
+ fn device(&self) -> &Arc<Device> {
+ &self.swapchain.device
+ }
+}
+
+impl<W> Drop for SwapchainAcquireFuture<W> {
+ fn drop(&mut self) {
+ if let Some(ref fence) = self.fence {
+ fence.wait(None).unwrap(); // TODO: handle error?
+ self.semaphore = None;
+ }
+
+ // TODO: if this future is destroyed without being presented, then eventually acquiring
+ // a new image will block forever ; difficulty: hard
+ }
+}
+
+/// Error that can happen when calling `Swapchain::acquire_fullscreen_exclusive` or `Swapchain::release_fullscreen_exclusive`
+#[derive(Copy, Clone, Debug, PartialEq, Eq)]
+#[repr(u32)]
+pub enum FullscreenExclusiveError {
+ /// Not enough memory.
+ OomError(OomError),
+
+ /// Operation could not be completed for driver specific reasons.
+ InitializationFailed,
+
+ /// The surface is no longer accessible and must be recreated.
+ SurfaceLost,
+
+ /// Fullscreen exclusivity is already acquired.
+ DoubleAcquire,
+
+ /// Fullscreen exclusivity is not current acquired.
+ DoubleRelease,
+
+ /// Swapchain is not in fullscreen exclusive app controlled mode
+ NotAppControlled,
+}
+
+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),
+ }
+ }
+}
+
+impl From<OomError> for FullscreenExclusiveError {
+ #[inline]
+ fn from(err: OomError) -> FullscreenExclusiveError {
+ FullscreenExclusiveError::OomError(err)
+ }
+}
+
+impl error::Error for FullscreenExclusiveError {
+ #[inline]
+ fn source(&self) -> Option<&(dyn error::Error + 'static)> {
+ match *self {
+ FullscreenExclusiveError::OomError(ref err) => Some(err),
+ _ => None,
+ }
+ }
+}
+
+impl fmt::Display for FullscreenExclusiveError {
+ #[inline]
+ fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
+ write!(
+ fmt,
+ "{}",
+ 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"
+ }
+ }
+ )
+ }
+}
+
+/// Error that can happen when calling `acquire_next_image`.
+#[derive(Copy, Clone, Debug, PartialEq, Eq)]
+#[repr(u32)]
+pub enum AcquireError {
+ /// 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 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,
+
+ /// Error during semaphore creation
+ SemaphoreError(SemaphoreError),
+}
+
+impl error::Error for AcquireError {
+ #[inline]
+ fn source(&self) -> Option<&(dyn error::Error + 'static)> {
+ match *self {
+ AcquireError::OomError(ref 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 From<SemaphoreError> for AcquireError {
+ fn from(err: SemaphoreError) -> Self {
+ AcquireError::SemaphoreError(err)
+ }
+}
+
+impl From<OomError> for AcquireError {
+ #[inline]
+ fn from(err: OomError) -> AcquireError {
+ AcquireError::OomError(err)
+ }
+}
+
+impl From<Error> for AcquireError {
+ #[inline]
+ fn from(err: Error) -> AcquireError {
+ 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,
+ _ => panic!("unexpected error: {:?}", err),
+ }
+ }
+}
+
+/// 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>
+where
+ P: GpuFuture,
+{
+ previous: P,
+ queue: Arc<Queue>,
+ swapchain: Arc<Swapchain<W>>,
+ image_id: usize,
+ present_region: Option<PresentRegion>,
+ // True if `flush()` has been called on the future, which means that the present command has
+ // been submitted.
+ flushed: AtomicBool,
+ // True if `signal_finished()` has been called on the future, which means that the future has
+ // been submitted and has already been processed by the GPU.
+ finished: AtomicBool,
+}
+
+impl<P, W> PresentFuture<P, W>
+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
+ }
+
+ /// Returns the corresponding swapchain.
+ #[inline]
+ pub fn swapchain(&self) -> &Arc<Swapchain<W>> {
+ &self.swapchain
+ }
+}
+
+unsafe impl<P, W> GpuFuture for PresentFuture<P, W>
+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());
+
+ // 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::CommandBuffer(cb) => {
+ // 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::BindSparse(cb) => {
+ // 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(present) => {
+ unimplemented!() // TODO:
+ /*present.submit();
+ let mut builder = SubmitPresentBuilder::new();
+ builder.add_swapchain(self.command_buffer.inner(), self.image_id);
+ SubmitAnyBuilder::CommandBuffer(builder)*/
+ }
+ })
+ }
+
+ #[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);
+ }
+
+ 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);
+ }
+
+ present_result?;
+ }
+ _ => 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(self.queue.clone())
+ }
+
+ #[inline]
+ fn check_buffer_access(
+ &self,
+ buffer: &dyn BufferAccess,
+ exclusive: bool,
+ queue: &Queue,
+ ) -> Result<Option<(PipelineStages, AccessFlags)>, AccessCheckError> {
+ self.previous.check_buffer_access(buffer, exclusive, queue)
+ }
+
+ #[inline]
+ fn check_image_access(
+ &self,
+ image: &dyn ImageAccess,
+ layout: ImageLayout,
+ exclusive: bool,
+ 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() {
+ // 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
+ // a later swapchain acquire future. Hence why we return `Unknown` here.
+ Err(AccessCheckError::Unknown)
+ } else {
+ self.previous
+ .check_image_access(image, layout, exclusive, queue)
+ }
+ }
+}
+
+unsafe impl<P, W> DeviceOwned for PresentFuture<P, W>
+where
+ P: GpuFuture,
+{
+ #[inline]
+ fn device(&self) -> &Arc<Device> {
+ self.queue.device()
+ }
+}
+
+impl<P, W> Drop for PresentFuture<P, W>
+where
+ P: GpuFuture,
+{
+ fn drop(&mut self) {
+ unsafe {
+ 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.
+ }
+ }
+ }
+ }
+ }
+}
+
+pub struct AcquiredImage {
+ pub id: usize,
+ pub suboptimal: bool,
+}
+
+/// Unsafe variant of `acquire_next_image`.
+///
+/// # Safety
+///
+/// - 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>,
+ timeout: Option<Duration>,
+ semaphore: Option<&Semaphore>,
+ fence: Option<&Fence>,
+) -> Result<AcquiredImage, AcquireError> {
+ let fns = swapchain.device.fns();
+
+ 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
+ };
+
+ 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),
+ };
+
+ Ok(AcquiredImage { id, suboptimal })
+}
diff --git a/src/sync/event.rs b/src/sync/event.rs
new file mode 100644
index 0000000..2f02da6
--- /dev/null
+++ b/src/sync/event.rs
@@ -0,0 +1,245 @@
+// 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::OomError;
+use crate::Success;
+use crate::VulkanObject;
+use std::mem::MaybeUninit;
+use std::ptr;
+use std::sync::Arc;
+
+/// Used to block the GPU execution until an event on the CPU occurs.
+///
+/// Note that Vulkan implementations may have limits on how long a command buffer will wait for an
+/// event to be signaled, in order to avoid interfering with progress of other clients of the GPU.
+/// If the event isn't signaled within these limits, results are undefined and may include
+/// device loss.
+#[derive(Debug)]
+pub struct Event {
+ // The event.
+ event: ash::vk::Event,
+ // The device.
+ device: Arc<Device>,
+ must_put_in_pool: bool,
+}
+
+impl Event {
+ /// 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) => {
+ unsafe {
+ // Make sure the event isn't signaled
+ let fns = device.fns();
+ check_errors(fns.v1_0.reset_event(device.internal_object(), raw_event))?;
+ }
+ Ok(Event {
+ event: raw_event,
+ device: device,
+ must_put_in_pool: true,
+ })
+ }
+ None => {
+ // Pool is empty, alloc new event
+ Event::alloc_impl(device, true)
+ }
+ }
+ }
+
+ /// Builds a new event.
+ #[inline]
+ pub fn alloc(device: Arc<Device>) -> Result<Event, OomError> {
+ Event::alloc_impl(device, false)
+ }
+
+ 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,
+ })
+ }
+
+ /// Returns true if the event is signaled.
+ #[inline]
+ 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),
+ )?;
+ match result {
+ Success::EventSet => Ok(true),
+ Success::EventReset => Ok(false),
+ _ => unreachable!(),
+ }
+ }
+ }
+
+ /// See the docs of set().
+ #[inline]
+ 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),
+ )?;
+ Ok(())
+ }
+ }
+
+ /// Changes the `Event` to the signaled state.
+ ///
+ /// If a command buffer is waiting on this event, it is then unblocked.
+ ///
+ /// # Panic
+ ///
+ /// - Panics if the device or host ran out of memory.
+ ///
+ #[inline]
+ pub fn set(&mut self) {
+ self.set_raw().unwrap();
+ }
+
+ /// See the docs of reset().
+ #[inline]
+ 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),
+ )?;
+ Ok(())
+ }
+ }
+
+ /// Changes the `Event` to the unsignaled state.
+ ///
+ /// # Panic
+ ///
+ /// - Panics if the device or host ran out of memory.
+ ///
+ #[inline]
+ pub fn reset(&mut self) {
+ self.reset_raw().unwrap();
+ }
+}
+
+unsafe impl DeviceOwned for Event {
+ #[inline]
+ fn device(&self) -> &Arc<Device> {
+ &self.device
+ }
+}
+
+unsafe impl VulkanObject for Event {
+ type Object = ash::vk::Event;
+
+ #[inline]
+ fn internal_object(&self) -> ash::vk::Event {
+ self.event
+ }
+}
+
+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());
+ }
+ }
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use crate::sync::Event;
+ use crate::VulkanObject;
+
+ #[test]
+ fn event_create() {
+ let (device, _) = gfx_dev_and_queue!();
+ let event = Event::alloc(device).unwrap();
+ assert!(!event.signaled().unwrap());
+ }
+
+ #[test]
+ fn event_set() {
+ let (device, _) = gfx_dev_and_queue!();
+ let mut event = Event::alloc(device).unwrap();
+ assert!(!event.signaled().unwrap());
+
+ event.set();
+ assert!(event.signaled().unwrap());
+ }
+
+ #[test]
+ fn event_reset() {
+ let (device, _) = gfx_dev_and_queue!();
+
+ let mut event = Event::alloc(device).unwrap();
+ event.set();
+ assert!(event.signaled().unwrap());
+
+ event.reset();
+ assert!(!event.signaled().unwrap());
+ }
+
+ #[test]
+ fn event_pool() {
+ let (device, _) = gfx_dev_and_queue!();
+
+ assert_eq!(device.event_pool().lock().unwrap().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().unwrap().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);
+ }
+}
diff --git a/src/sync/fence.rs b/src/sync/fence.rs
new file mode 100644
index 0000000..208573a
--- /dev/null
+++ b/src/sync/fence.rs
@@ -0,0 +1,501 @@
+// 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::Success;
+use crate::VulkanObject;
+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.
+///
+/// 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.
+#[derive(Debug)]
+pub struct Fence<D = Arc<Device>>
+where
+ D: SafeDeref<Target = Device>,
+{
+ fence: ash::vk::Fence,
+
+ device: D,
+
+ // 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,
+
+ // 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,
+}
+
+impl<D> Fence<D>
+where
+ D: SafeDeref<Target = Device>,
+{
+ /// Takes a fence from the vulkano-provided fence pool.
+ /// If the pool is empty, a new fence will be allocated.
+ /// 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) => {
+ 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),
+ )?;
+ }
+ Ok(Fence {
+ fence: raw_fence,
+ device: device,
+ signaled: AtomicBool::new(false),
+ must_put_in_pool: true,
+ })
+ }
+ None => {
+ // Pool is empty, alloc new fence
+ Fence::alloc_impl(device, false, true)
+ }
+ }
+ }
+
+ /// Builds a new fence.
+ #[inline]
+ pub fn alloc(device: D) -> Result<Fence<D>, OomError> {
+ Fence::alloc_impl(device, false, false)
+ }
+
+ /// Builds a new fence in signaled state.
+ #[inline]
+ pub fn alloc_signaled(device: D) -> Result<Fence<D>, OomError> {
+ Fence::alloc_impl(device, true, false)
+ }
+
+ 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()
+ },
+ ..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);
+ }
+
+ let fns = self.device.fns();
+ let result = check_errors(
+ fns.v1_0
+ .get_fence_status(self.device.internal_object(), self.fence),
+ )?;
+ match result {
+ Success::Success => {
+ self.signaled.store(true, Ordering::Relaxed);
+ Ok(true)
+ }
+ Success::NotReady => Ok(false),
+ _ => unreachable!(),
+ }
+ }
+ }
+
+ /// Waits until the fence is signaled, or at least until the timeout duration has elapsed.
+ ///
+ /// 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) {
+ return Ok(());
+ }
+
+ 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
+ };
+
+ 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!(),
+ }
+ }
+ }
+
+ /// Waits for multiple fences at once.
+ ///
+ /// # Panic
+ ///
+ /// 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;
+
+ 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"
+ ),
+ };
+
+ if fence.signaled.load(Ordering::Relaxed) {
+ None
+ } else {
+ Some(fence.fence)
+ }
+ })
+ .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
+ };
+
+ let r = if let Some(device) = device {
+ unsafe {
+ 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,
+ timeout_ns,
+ ))?
+ }
+ } else {
+ return Ok(());
+ };
+
+ match r {
+ Success::Success => Ok(()),
+ Success::Timeout => Err(FenceWaitError::Timeout),
+ _ => unreachable!(),
+ }
+ }
+
+ /// Resets the fence.
+ // This function takes a `&mut self` because the Vulkan API requires that the fence be
+ // externally synchronized.
+ #[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(())
+ }
+ }
+
+ /// Resets multiple fences at once.
+ ///
+ /// # Panic
+ ///
+ /// - Panics if not all fences belong to the same device.
+ ///
+ 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
+ .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"
+ ),
+ };
+
+ fence.signaled.store(false, Ordering::Relaxed);
+ fence.fence
+ })
+ .collect();
+
+ 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(),
+ ))?;
+ }
+ }
+ Ok(())
+ }
+}
+
+unsafe impl DeviceOwned for Fence {
+ #[inline]
+ fn device(&self) -> &Arc<Device> {
+ &self.device
+ }
+}
+
+unsafe impl<D> VulkanObject for Fence<D>
+where
+ D: SafeDeref<Target = Device>,
+{
+ type Object = ash::vk::Fence;
+
+ #[inline]
+ fn internal_object(&self) -> ash::vk::Fence {
+ self.fence
+ }
+}
+
+impl<D> Drop for Fence<D>
+where
+ D: SafeDeref<Target = Device>,
+{
+ #[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);
+ } else {
+ let fns = self.device.fns();
+ fns.v1_0
+ .destroy_fence(self.device.internal_object(), self.fence, ptr::null());
+ }
+ }
+ }
+}
+
+/// Error that can be returned when waiting on a fence.
+#[derive(Copy, Clone, Debug, PartialEq, Eq)]
+pub enum FenceWaitError {
+ /// Not enough memory to complete the wait.
+ OomError(OomError),
+
+ /// The specified timeout wasn't long enough.
+ Timeout,
+
+ /// The device has been lost.
+ DeviceLostError,
+}
+
+impl error::Error for FenceWaitError {
+ #[inline]
+ fn source(&self) -> Option<&(dyn error::Error + 'static)> {
+ match *self {
+ FenceWaitError::OomError(ref 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 From<Error> for FenceWaitError {
+ #[inline]
+ fn from(err: Error) -> FenceWaitError {
+ 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),
+ }
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use crate::sync::Fence;
+ use crate::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());
+ }
+
+ #[test]
+ fn fence_create_signaled() {
+ let (device, _) = gfx_dev_and_queue!();
+
+ let fence = Fence::alloc_signaled(device.clone()).unwrap();
+ assert!(fence.ready().unwrap());
+ }
+
+ #[test]
+ fn fence_signaled_wait() {
+ let (device, _) = gfx_dev_and_queue!();
+
+ let fence = Fence::alloc_signaled(device.clone()).unwrap();
+ fence.wait(Some(Duration::new(0, 10))).unwrap();
+ }
+
+ #[test]
+ fn fence_reset() {
+ let (device, _) = gfx_dev_and_queue!();
+
+ let mut fence = Fence::alloc_signaled(device.clone()).unwrap();
+ fence.reset().unwrap();
+ assert!(!fence.ready().unwrap());
+ }
+
+ #[test]
+ fn multiwait_different_devices() {
+ 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();
+
+ 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();
+
+ let _ = Fence::multi_reset(once(&mut fence1).chain(once(&mut fence2)));
+ }
+ );
+ }
+
+ #[test]
+ fn fence_pool() {
+ let (device, _) = gfx_dev_and_queue!();
+
+ assert_eq!(device.fence_pool().lock().unwrap().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().unwrap().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);
+ }
+}
diff --git a/src/sync/future/fence_signal.rs b/src/sync/future/fence_signal.rs
new file mode 100644
index 0000000..c2f5338
--- /dev/null
+++ b/src/sync/future/fence_signal.rs
@@ -0,0 +1,516 @@
+// 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::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;
+
+/// Builds a new fence signal future.
+#[inline]
+pub fn then_signal_fence<F>(future: F, behavior: FenceSignalFutureBehavior) -> FenceSignalFuture<F>
+where
+ F: GpuFuture,
+{
+ let device = future.device().clone();
+
+ assert!(future.queue().is_some()); // TODO: document
+
+ let fence = Fence::from_pool(device.clone()).unwrap();
+ FenceSignalFuture {
+ device: device,
+ state: Mutex::new(FenceSignalFutureState::Pending(future, fence)),
+ behavior: behavior,
+ }
+}
+
+/// Describes the behavior of the future if you submit something after it.
+#[derive(Debug, Copy, Clone, PartialEq, Eq)]
+pub enum FenceSignalFutureBehavior {
+ /// Continue execution on the same queue.
+ Continue,
+ /// Wait for the fence to be signalled before submitting any further operation.
+ Block {
+ /// How long to block the current thread.
+ timeout: Option<Duration>,
+ },
+}
+
+/// Represents a fence being signaled after a previous event.
+///
+/// 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.
+///
+/// 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.
+///
+/// ```
+/// use std::sync::Arc;
+/// use vulkano::sync::GpuFuture;
+///
+/// # let future: Box<GpuFuture> = return;
+/// // Assuming you have a chain of operations, like this:
+/// // let future = ...
+/// // .then_execute(foo)
+/// // .then_execute(bar)
+///
+/// // You can signal a fence at this point of the chain, and put the future in an `Arc`.
+/// let fence_signal = Arc::new(future.then_signal_fence());
+///
+/// // And then continue the chain:
+/// // fence_signal.clone()
+/// // .then_execute(baz)
+/// // .then_execute(qux)
+///
+/// // Later you can wait until you reach the point of `fence_signal`:
+/// fence_signal.wait(None).unwrap();
+/// ```
+#[must_use = "Dropping this object will immediately block the thread until the GPU has finished \
+ processing the submission"]
+pub struct FenceSignalFuture<F>
+where
+ F: GpuFuture,
+{
+ // Current state. See the docs of `FenceSignalFutureState`.
+ state: Mutex<FenceSignalFutureState<F>>,
+ // The device of the future.
+ device: Arc<Device>,
+ behavior: FenceSignalFutureBehavior,
+}
+
+// This future can be in three different states: pending (ie. newly-created), submitted (ie. the
+// command that submits the fence has been submitted), or cleaned (ie. the previous future has
+// been dropped).
+enum FenceSignalFutureState<F> {
+ // Newly-created. Not submitted yet.
+ Pending(F, 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),
+
+ // Submitted to the queue.
+ Flushed(F, Fence),
+
+ // The submission is finished. The previous future and the fence have been cleaned.
+ Cleaned,
+
+ // A function panicked while the state was being modified. Should never happen.
+ Poisoned,
+}
+
+impl<F> FenceSignalFuture<F>
+where
+ F: GpuFuture,
+{
+ /// Blocks the current thread until the fence is signaled by the GPU. Performs a flush if
+ /// necessary.
+ ///
+ /// If `timeout` is `None`, then the wait is infinite. Otherwise the thread will unblock after
+ /// the specified timeout has elapsed and an error will be returned.
+ ///
+ /// 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();
+
+ self.flush_impl(&mut state)?;
+
+ match mem::replace(&mut *state, FenceSignalFutureState::Cleaned) {
+ FenceSignalFutureState::Flushed(previous, fence) => {
+ fence.wait(timeout)?;
+ unsafe {
+ previous.signal_finished();
+ }
+ Ok(())
+ }
+ FenceSignalFutureState::Cleaned => Ok(()),
+ _ => unreachable!(),
+ }
+ }
+}
+
+impl<F> FenceSignalFuture<F>
+where
+ F: GpuFuture,
+{
+ // 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();
+
+ match *state {
+ FenceSignalFutureState::Flushed(ref mut prev, ref fence) => {
+ match fence.wait(Some(Duration::from_secs(0))) {
+ Ok(()) => unsafe { prev.signal_finished() },
+ 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>>,
+ ) -> 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 (previous, fence, partially_flushed) = match old_state {
+ FenceSignalFutureState::Pending(prev, fence) => (prev, fence, false),
+ FenceSignalFutureState::PartiallyFlushed(prev, fence) => (prev, fence, true),
+ other => {
+ // We were already flushed in the past, or we're already poisoned. Don't do
+ // anything.
+ **state = other;
+ return Ok(());
+ }
+ };
+
+ // TODO: meh for unwrap
+ let queue = previous.queue().unwrap().clone();
+
+ // There are three possible outcomes for the flush operation: success, partial success
+ // in which case `result` will contain `Err(OutcomeErr::Partial)`, or total failure
+ // in which case `result` will contain `Err(OutcomeErr::Full)`.
+ enum OutcomeErr<E> {
+ Partial(E),
+ Full(E),
+ }
+ 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()))
+ }
+ SubmitAnyBuilder::SemaphoresWait(sem) => {
+ debug_assert!(!partially_flushed);
+ let b: SubmitCommandBufferBuilder = sem.into();
+ debug_assert!(!b.has_fence());
+ b.submit(&queue).map_err(|err| OutcomeErr::Full(err.into()))
+ }
+ SubmitAnyBuilder::CommandBuffer(mut cb_builder) => {
+ 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()))
+ }
+ SubmitAnyBuilder::BindSparse(mut sparse) => {
+ debug_assert!(!partially_flushed);
+ // Same remark as `CommandBuffer`.
+ assert!(!sparse.has_fence());
+ sparse.set_fence_signal(&fence);
+ sparse
+ .submit(&queue)
+ .map_err(|err| OutcomeErr::Full(err.into()))
+ }
+ SubmitAnyBuilder::QueuePresent(present) => {
+ let intermediary_result = if partially_flushed {
+ Ok(())
+ } else {
+ present.submit(&queue)
+ };
+ match intermediary_result {
+ Ok(()) => {
+ let mut b = SubmitCommandBufferBuilder::new();
+ b.set_fence_signal(&fence);
+ b.submit(&queue)
+ .map_err(|err| OutcomeErr::Partial(err.into()))
+ }
+ Err(err) => Err(OutcomeErr::Full(err.into())),
+ }
+ }
+ };
+
+ // Restore the state before returning.
+ match result {
+ Ok(()) => {
+ **state = FenceSignalFutureState::Flushed(previous, fence);
+ Ok(())
+ }
+ Err(OutcomeErr::Partial(err)) => {
+ **state = FenceSignalFutureState::PartiallyFlushed(previous, fence);
+ Err(err)
+ }
+ Err(OutcomeErr::Full(err)) => {
+ **state = FenceSignalFutureState::Pending(previous, fence);
+ Err(err)
+ }
+ }
+ }
+ }
+}
+
+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),
+ FenceSignalFutureState::Cleaned => None,
+ FenceSignalFutureState::Poisoned => None,
+ }
+ }
+}
+
+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();
+ self.flush_impl(&mut state)?;
+
+ match *state {
+ FenceSignalFutureState::Flushed(_, ref fence) => match self.behavior {
+ FenceSignalFutureBehavior::Block { timeout } => {
+ fence.wait(timeout)?;
+ }
+ FenceSignalFutureBehavior::Continue => (),
+ },
+ FenceSignalFutureState::Cleaned | FenceSignalFutureState::Poisoned => (),
+ FenceSignalFutureState::Pending(_, _) => unreachable!(),
+ FenceSignalFutureState::PartiallyFlushed(_, _) => unreachable!(),
+ }
+
+ Ok(SubmitAnyBuilder::Empty)
+ }
+
+ #[inline]
+ fn flush(&self) -> Result<(), FlushError> {
+ let mut state = self.state.lock().unwrap();
+ self.flush_impl(&mut state)
+ }
+
+ #[inline]
+ unsafe fn signal_finished(&self) {
+ let state = self.state.lock().unwrap();
+ match *state {
+ FenceSignalFutureState::Flushed(ref prev, _) => {
+ prev.signal_finished();
+ }
+ FenceSignalFutureState::Cleaned | FenceSignalFutureState::Poisoned => (),
+ _ => unreachable!(),
+ }
+ }
+
+ #[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
+ }
+ }
+ FenceSignalFutureBehavior::Block { .. } => true,
+ }
+ }
+
+ #[inline]
+ fn queue(&self) -> Option<Arc<Queue>> {
+ let state = self.state.lock().unwrap();
+ if let Some(prev) = state.get_prev() {
+ prev.queue()
+ } else {
+ None
+ }
+ }
+
+ #[inline]
+ fn check_buffer_access(
+ &self,
+ buffer: &dyn BufferAccess,
+ exclusive: bool,
+ queue: &Queue,
+ ) -> Result<Option<(PipelineStages, AccessFlags)>, AccessCheckError> {
+ let state = self.state.lock().unwrap();
+ if let Some(previous) = state.get_prev() {
+ previous.check_buffer_access(buffer, exclusive, queue)
+ } else {
+ Err(AccessCheckError::Unknown)
+ }
+ }
+
+ #[inline]
+ fn check_image_access(
+ &self,
+ image: &dyn ImageAccess,
+ layout: ImageLayout,
+ exclusive: bool,
+ queue: &Queue,
+ ) -> Result<Option<(PipelineStages, AccessFlags)>, AccessCheckError> {
+ let state = self.state.lock().unwrap();
+ if let Some(previous) = state.get_prev() {
+ previous.check_image_access(image, layout, exclusive, queue)
+ } else {
+ Err(AccessCheckError::Unknown)
+ }
+ }
+}
+
+unsafe impl<F> DeviceOwned for FenceSignalFuture<F>
+where
+ F: GpuFuture,
+{
+ #[inline]
+ fn device(&self) -> &Arc<Device> {
+ &self.device
+ }
+}
+
+impl<F> Drop for FenceSignalFuture<F>
+where
+ F: GpuFuture,
+{
+ fn drop(&mut self) {
+ let mut state = self.state.lock().unwrap();
+
+ // 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) {
+ FenceSignalFutureState::Flushed(previous, fence) => {
+ // This is a normal situation. Submitting worked.
+ // TODO: handle errors?
+ fence.wait(None).unwrap();
+ unsafe {
+ previous.signal_finished();
+ }
+ }
+ FenceSignalFutureState::Cleaned => {
+ // Also a normal situation. The user called `cleanup_finished()` before dropping.
+ }
+ FenceSignalFutureState::Poisoned => {
+ // The previous future was already dropped and blocked the current queue.
+ }
+ FenceSignalFutureState::Pending(_, _)
+ | FenceSignalFutureState::PartiallyFlushed(_, _) => {
+ // Flushing produced an error. There's nothing more we can do except drop the
+ // previous future and let it block the current queue.
+ }
+ }
+ }
+}
+
+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,
+ exclusive: bool,
+ queue: &Queue,
+ ) -> Result<Option<(PipelineStages, AccessFlags)>, AccessCheckError> {
+ (**self).check_buffer_access(buffer, exclusive, queue)
+ }
+
+ #[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)
+ }
+}
diff --git a/src/sync/future/join.rs b/src/sync/future/join.rs
new file mode 100644
index 0000000..c45a764
--- /dev/null
+++ b/src/sync/future/join.rs
@@ -0,0 +1,268 @@
+// 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::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;
+
+/// 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()
+ );
+
+ if !first.queue_change_allowed() && !second.queue_change_allowed() {
+ assert!(first.queue().unwrap().is_same(&second.queue().unwrap()));
+ }
+
+ JoinFuture {
+ first: first,
+ second: second,
+ }
+}
+
+/// Two futures joined into one.
+#[must_use]
+pub struct JoinFuture<A, B> {
+ first: A,
+ second: B,
+}
+
+unsafe impl<A, B> DeviceOwned for JoinFuture<A, B>
+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()
+ );
+ device
+ }
+}
+
+unsafe impl<A, B> GpuFuture for JoinFuture<A, B>
+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()?;
+ let second = self.second.build_submission()?;
+
+ // In some cases below we have to submit previous command buffers already, this s done by flushing previous.
+ // Since the implementation should remember being flushed it's safe to call build_submission multiple times
+ Ok(match (first, second) {
+ (SubmitAnyBuilder::Empty, b) => b,
+ (a, SubmitAnyBuilder::Empty) => a,
+ (SubmitAnyBuilder::SemaphoresWait(mut a), SubmitAnyBuilder::SemaphoresWait(b)) => {
+ a.merge(b);
+ SubmitAnyBuilder::SemaphoresWait(a)
+ }
+ (SubmitAnyBuilder::SemaphoresWait(a), SubmitAnyBuilder::CommandBuffer(b)) => {
+ self.second.flush()?;
+ SubmitAnyBuilder::SemaphoresWait(a)
+ }
+ (SubmitAnyBuilder::CommandBuffer(a), SubmitAnyBuilder::SemaphoresWait(b)) => {
+ self.first.flush()?;
+ SubmitAnyBuilder::SemaphoresWait(b)
+ }
+ (SubmitAnyBuilder::SemaphoresWait(a), SubmitAnyBuilder::QueuePresent(b)) => {
+ self.second.flush()?;
+ SubmitAnyBuilder::SemaphoresWait(a)
+ }
+ (SubmitAnyBuilder::QueuePresent(a), SubmitAnyBuilder::SemaphoresWait(b)) => {
+ self.first.flush()?;
+ SubmitAnyBuilder::SemaphoresWait(b)
+ }
+ (SubmitAnyBuilder::SemaphoresWait(a), SubmitAnyBuilder::BindSparse(b)) => {
+ self.second.flush()?;
+ SubmitAnyBuilder::SemaphoresWait(a)
+ }
+ (SubmitAnyBuilder::BindSparse(a), 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::QueuePresent(a), SubmitAnyBuilder::QueuePresent(b)) => {
+ self.first.flush()?;
+ self.second.flush()?;
+ SubmitAnyBuilder::Empty
+ }
+ (SubmitAnyBuilder::CommandBuffer(a), SubmitAnyBuilder::QueuePresent(b)) => {
+ unimplemented!()
+ }
+ (SubmitAnyBuilder::QueuePresent(a), SubmitAnyBuilder::CommandBuffer(b)) => {
+ unimplemented!()
+ }
+ (SubmitAnyBuilder::BindSparse(a), SubmitAnyBuilder::QueuePresent(b)) => {
+ unimplemented!()
+ }
+ (SubmitAnyBuilder::QueuePresent(a), SubmitAnyBuilder::BindSparse(b)) => {
+ unimplemented!()
+ }
+ (SubmitAnyBuilder::BindSparse(a), SubmitAnyBuilder::CommandBuffer(b)) => {
+ unimplemented!()
+ }
+ (SubmitAnyBuilder::CommandBuffer(a), SubmitAnyBuilder::BindSparse(b)) => {
+ 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!()
+ }
+ }
+ }
+ })
+ }
+
+ #[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) {
+ Some(q1)
+ } else if self.first.queue_change_allowed() {
+ Some(q2)
+ } else if self.second.queue_change_allowed() {
+ Some(q1)
+ } else {
+ None
+ }
+ }
+ (Some(q), None) => Some(q),
+ (None, Some(q)) => Some(q),
+ (None, None) => None,
+ }
+ }
+
+ #[inline]
+ fn check_buffer_access(
+ &self,
+ buffer: &dyn BufferAccess,
+ 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);
+ 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(e2))) => {
+ 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))),
+ }
+ }
+
+ #[inline]
+ fn check_image_access(
+ &self,
+ image: &dyn ImageAccess,
+ layout: ImageLayout,
+ exclusive: bool,
+ queue: &Queue,
+ ) -> Result<Option<(PipelineStages, AccessFlags)>, AccessCheckError> {
+ let first = self
+ .first
+ .check_image_access(image, layout, exclusive, queue);
+ 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"
+ );
+ 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))
+ } // 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))),
+ }
+ }
+}
diff --git a/src/sync/future/mod.rs b/src/sync/future/mod.rs
new file mode 100644
index 0000000..e6fde7a
--- /dev/null
+++ b/src/sync/future/mod.rs
@@ -0,0 +1,555 @@
+// 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::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;
+
+mod fence_signal;
+mod join;
+mod now;
+mod semaphore_signal;
+
+/// Represents an event that will happen on the GPU in the future.
+///
+/// See the documentation of the `sync` module for explanations about futures.
+// TODO: consider switching all methods to take `&mut self` for optimization purposes
+pub unsafe trait GpuFuture: DeviceOwned {
+ /// If possible, checks whether the submission has finished. If so, gives up ownership of the
+ /// resources used by these submissions.
+ ///
+ /// It is highly recommended to call `cleanup_finished` from time to time. Doing so will
+ /// prevent memory usage from increasing over time, and will also destroy the locks on
+ /// resources used by the GPU.
+ fn cleanup_finished(&mut self);
+
+ /// Builds a submission that, if submitted, makes sure that the event represented by this
+ /// `GpuFuture` will happen, and possibly contains extra elements (eg. a semaphore wait or an
+ /// event wait) that makes the dependency with subsequent operations work.
+ ///
+ /// It is the responsibility of the caller to ensure that the submission is going to be
+ /// submitted only once. However keep in mind that this function can perfectly be called
+ /// multiple times (as long as the returned object is only submitted once).
+ /// Also note that calling `flush()` on the future may change the value returned by
+ /// `build_submission()`.
+ ///
+ /// It is however the responsibility of the implementation to not return the same submission
+ /// from multiple different future objects. For example if you implement `GpuFuture` on
+ /// `Arc<Foo>` then `build_submission()` must always return `SubmitAnyBuilder::Empty`,
+ /// otherwise it would be possible for the user to clone the `Arc` and make the same
+ /// submission be submitted multiple times.
+ ///
+ /// It is also the responsibility of the implementation to ensure that it works if you call
+ /// `build_submission()` and submits the returned value without calling `flush()` first. In
+ /// other words, `build_submission()` should perform an implicit flush if necessary.
+ ///
+ /// Once the caller has submitted the submission and has determined that the GPU has finished
+ /// executing it, it should call `signal_finished`. Failure to do so will incur a large runtime
+ /// overhead, as the future will have to block to make sure that it is finished.
+ unsafe fn build_submission(&self) -> Result<SubmitAnyBuilder, FlushError>;
+
+ /// Flushes the future and submits to the GPU the actions that will permit this future to
+ /// occur.
+ ///
+ /// The implementation must remember that it was flushed. If the function is called multiple
+ /// times, only the first time must result in a flush.
+ fn flush(&self) -> Result<(), FlushError>;
+
+ /// Sets the future to its "complete" state, meaning that it can safely be destroyed.
+ ///
+ /// This must only be done if you called `build_submission()`, submitted the returned
+ /// submission, and determined that it was finished.
+ ///
+ /// The implementation must be aware that this function can be called multiple times on the
+ /// same future.
+ unsafe fn signal_finished(&self);
+
+ /// Returns the queue that triggers the event. Returns `None` if unknown or irrelevant.
+ ///
+ /// If this function returns `None` and `queue_change_allowed` returns `false`, then a panic
+ /// is likely to occur if you use this future. This is only a problem if you implement
+ /// the `GpuFuture` trait yourself for a type outside of vulkano.
+ fn queue(&self) -> Option<Arc<Queue>>;
+
+ /// Returns `true` if elements submitted after this future can be submitted to a different
+ /// queue than the other returned by `queue()`.
+ fn queue_change_allowed(&self) -> bool;
+
+ /// 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,
+ exclusive: bool,
+ queue: &Queue,
+ ) -> Result<Option<(PipelineStages, AccessFlags)>, 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.
+ ///
+ /// > **Note**: Returning `Ok` means "access granted", while returning `Err` means
+ /// > "don't know". Therefore returning `Err` is never unsafe.
+ ///
+ /// > **Note**: Keep in mind that changing the layout of an image also requires exclusive
+ /// > access.
+ fn check_image_access(
+ &self,
+ image: &dyn ImageAccess,
+ layout: ImageLayout,
+ exclusive: bool,
+ queue: &Queue,
+ ) -> Result<Option<(PipelineStages, AccessFlags)>, AccessCheckError>;
+
+ /// Joins this future with another one, representing the moment when both events have happened.
+ // TODO: handle errors
+ fn join<F>(self, other: F) -> JoinFuture<Self, F>
+ where
+ Self: Sized,
+ F: GpuFuture,
+ {
+ join::join(self, other)
+ }
+
+ /// Executes a command buffer after this future.
+ ///
+ /// > **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>
+ where
+ Self: Sized,
+ Cb: PrimaryCommandBuffer + 'static,
+ {
+ command_buffer.execute_after(self, queue)
+ }
+
+ /// Executes a command buffer after this future, on the same queue as the future.
+ ///
+ /// > **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>
+ where
+ Self: Sized,
+ Cb: PrimaryCommandBuffer + 'static,
+ {
+ let queue = self.queue().unwrap().clone();
+ command_buffer.execute_after(self, queue)
+ }
+
+ /// Signals a semaphore after this future. Returns another future that represents the signal.
+ ///
+ /// Call this function when you want to execute some operations on a queue and want to see the
+ /// result on another queue.
+ #[inline]
+ fn then_signal_semaphore(self) -> SemaphoreSignalFuture<Self>
+ where
+ Self: Sized,
+ {
+ semaphore_signal::then_signal_semaphore(self)
+ }
+
+ /// Signals a semaphore after this future and flushes it. Returns another future that
+ /// represents the moment when the semaphore is signalled.
+ ///
+ /// This is a just a shortcut for `then_signal_semaphore()` followed with `flush()`.
+ ///
+ /// When you want to execute some operations A on a queue and some operations B on another
+ /// queue that need to see the results of A, it can be a good idea to submit A as soon as
+ /// possible while you're preparing B.
+ ///
+ /// If you ran A and B on the same queue, you would have to decide between submitting A then
+ /// B, or A and B simultaneously. Both approaches have their trade-offs. But if A and B are
+ /// on two different queues, then you would need two submits anyway and it is always
+ /// advantageous to submit A as soon as possible.
+ #[inline]
+ fn then_signal_semaphore_and_flush(self) -> Result<SemaphoreSignalFuture<Self>, FlushError>
+ where
+ Self: Sized,
+ {
+ let f = self.then_signal_semaphore();
+ f.flush()?;
+ Ok(f)
+ }
+
+ /// Signals a fence after this future. Returns another future that represents the signal.
+ ///
+ /// > **Note**: More often than not you want to immediately flush the future after calling this
+ /// > function. If so, consider using `then_signal_fence_and_flush`.
+ #[inline]
+ fn then_signal_fence(self) -> FenceSignalFuture<Self>
+ where
+ Self: Sized,
+ {
+ fence_signal::then_signal_fence(self, FenceSignalFutureBehavior::Continue)
+ }
+
+ /// Signals a fence after this future. Returns another future that represents the signal.
+ ///
+ /// This is a just a shortcut for `then_signal_fence()` followed with `flush()`.
+ #[inline]
+ fn then_signal_fence_and_flush(self) -> Result<FenceSignalFuture<Self>, FlushError>
+ where
+ Self: Sized,
+ {
+ let f = self.then_signal_fence();
+ f.flush()?;
+ Ok(f)
+ }
+
+ /// Presents a swapchain image after this future.
+ ///
+ /// You should only ever do this indirectly after a `SwapchainAcquireFuture` of the same image,
+ /// otherwise an error will occur when flushing.
+ ///
+ /// > **Note**: This is just a shortcut for the `Swapchain::present()` function.
+ #[inline]
+ fn then_swapchain_present<W>(
+ self,
+ queue: Arc<Queue>,
+ swapchain: Arc<Swapchain<W>>,
+ image_index: usize,
+ ) -> PresentFuture<Self, W>
+ where
+ Self: Sized,
+ {
+ swapchain::present(swapchain, self, queue, image_index)
+ }
+
+ /// Same as `then_swapchain_present`, except it allows specifying a present region.
+ ///
+ /// > **Note**: This is just a shortcut for the `Swapchain::present_incremental()` function.
+ #[inline]
+ fn then_swapchain_present_incremental<W>(
+ self,
+ queue: Arc<Queue>,
+ swapchain: Arc<Swapchain<W>>,
+ image_index: usize,
+ present_region: PresentRegion,
+ ) -> PresentFuture<Self, W>
+ where
+ Self: Sized,
+ {
+ swapchain::present_incremental(swapchain, self, queue, image_index, present_region)
+ }
+
+ /// Turn the current future into a `Box<dyn GpuFuture>`.
+ ///
+ /// This is a helper function that calls `Box::new(yourFuture) as Box<dyn GpuFuture>`.
+ fn boxed(self) -> Box<dyn GpuFuture>
+ where
+ Self: Sized + 'static,
+ {
+ Box::new(self) as _
+ }
+}
+
+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,
+ exclusive: bool,
+ queue: &Queue,
+ ) -> Result<Option<(PipelineStages, AccessFlags)>, AccessCheckError> {
+ (**self).check_buffer_access(buffer, exclusive, queue)
+ }
+
+ #[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)
+ }
+}
+
+/// Access to a resource was denied.
+#[derive(Clone, Debug, PartialEq, Eq)]
+pub enum AccessError {
+ /// Exclusive access is denied.
+ ExclusiveDenied,
+
+ /// The resource is already in use, and there is no tracking of concurrent usages.
+ AlreadyInUse,
+
+ UnexpectedImageLayout {
+ allowed: ImageLayout,
+ requested: ImageLayout,
+ },
+
+ /// Trying to use an image without transitioning it from the "undefined" or "preinitialized"
+ /// layouts first.
+ ImageNotInitialized {
+ /// The layout that was requested for the image.
+ requested: ImageLayout,
+ },
+
+ /// Trying to use a buffer that still contains garbage data.
+ BufferNotInitialized,
+
+ /// Trying to use a swapchain image without depending on a corresponding acquire image future.
+ SwapchainImageAcquireOnly,
+}
+
+impl error::Error for AccessError {}
+
+impl fmt::Display for AccessError {
+ #[inline]
+ fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
+ write!(
+ fmt,
+ "{}",
+ 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"
+ }
+ AccessError::UnexpectedImageLayout { .. } => {
+ unimplemented!() // TODO: find a description
+ }
+ AccessError::ImageNotInitialized { .. } => {
+ "trying to use an image without transitioning it from the undefined or \
+ preinitialized layouts first"
+ }
+ AccessError::BufferNotInitialized => {
+ "trying to use a buffer that still contains garbage data"
+ }
+ AccessError::SwapchainImageAcquireOnly => {
+ "trying to use a swapchain image without depending on a corresponding acquire \
+ image future"
+ }
+ }
+ )
+ }
+}
+
+/// Error that can happen when checking whether we have access to a resource.
+#[derive(Clone, Debug, PartialEq, Eq)]
+pub enum AccessCheckError {
+ /// Access to the resource has been denied.
+ Denied(AccessError),
+ /// The resource is unknown, therefore we cannot possibly answer whether we have access or not.
+ Unknown,
+}
+
+impl error::Error for AccessCheckError {}
+
+impl fmt::Display for AccessCheckError {
+ #[inline]
+ fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
+ write!(
+ fmt,
+ "{}",
+ match *self {
+ AccessCheckError::Denied(_) => "access to the resource has been denied",
+ AccessCheckError::Unknown => "the resource is unknown",
+ }
+ )
+ }
+}
+
+impl From<AccessError> for AccessCheckError {
+ #[inline]
+ fn from(err: AccessError) -> AccessCheckError {
+ AccessCheckError::Denied(err)
+ }
+}
+
+/// Error that can happen when creating a graphics pipeline.
+#[derive(Clone, Debug, PartialEq, Eq)]
+pub enum FlushError {
+ /// Access to a resource has been denied.
+ AccessError(AccessError),
+
+ /// 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 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 swapchain has lost or doesn't have fullscreen exclusivity possibly for
+ /// implementation-specific reasons outside of the application’s control.
+ FullscreenExclusiveLost,
+
+ /// The flush operation needed to block, but the timeout has elapsed.
+ Timeout,
+}
+
+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),
+ _ => None,
+ }
+ }
+}
+
+impl fmt::Display for FlushError {
+ #[inline]
+ fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
+ write!(
+ fmt,
+ "{}",
+ 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::Timeout => {
+ "the flush operation needed to block, but the timeout has \
+ elapsed"
+ }
+ }
+ )
+ }
+}
+
+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 {
+ 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,
+ }
+ }
+}
+
+impl From<FenceWaitError> for FlushError {
+ #[inline]
+ fn from(err: FenceWaitError) -> FlushError {
+ match err {
+ FenceWaitError::OomError(err) => FlushError::OomError(err),
+ FenceWaitError::Timeout => FlushError::Timeout,
+ FenceWaitError::DeviceLostError => FlushError::DeviceLost,
+ }
+ }
+}
diff --git a/src/sync/future/now.rs b/src/sync/future/now.rs
new file mode 100644
index 0000000..131eed6
--- /dev/null
+++ b/src/sync/future/now.rs
@@ -0,0 +1,90 @@
+// 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::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;
+
+/// Builds a future that represents "now".
+#[inline]
+pub fn now(device: Arc<Device>) -> NowFuture {
+ NowFuture { device: device }
+}
+
+/// A dummy future that represents "now".
+pub struct NowFuture {
+ device: Arc<Device>,
+}
+
+unsafe impl GpuFuture for NowFuture {
+ #[inline]
+ fn cleanup_finished(&mut self) {}
+
+ #[inline]
+ unsafe fn build_submission(&self) -> Result<SubmitAnyBuilder, FlushError> {
+ Ok(SubmitAnyBuilder::Empty)
+ }
+
+ #[inline]
+ fn flush(&self) -> Result<(), FlushError> {
+ Ok(())
+ }
+
+ #[inline]
+ unsafe fn signal_finished(&self) {}
+
+ #[inline]
+ fn queue_change_allowed(&self) -> bool {
+ true
+ }
+
+ #[inline]
+ fn queue(&self) -> Option<Arc<Queue>> {
+ None
+ }
+
+ #[inline]
+ fn check_buffer_access(
+ &self,
+ buffer: &dyn BufferAccess,
+ _: bool,
+ _: &Queue,
+ ) -> Result<Option<(PipelineStages, AccessFlags)>, AccessCheckError> {
+ Err(AccessCheckError::Unknown)
+ }
+
+ #[inline]
+ fn check_image_access(
+ &self,
+ _: &dyn ImageAccess,
+ _: ImageLayout,
+ _: bool,
+ _: &Queue,
+ ) -> Result<Option<(PipelineStages, AccessFlags)>, AccessCheckError> {
+ Err(AccessCheckError::Unknown)
+ }
+}
+
+unsafe impl DeviceOwned for NowFuture {
+ #[inline]
+ fn device(&self) -> &Arc<Device> {
+ &self.device
+ }
+}
diff --git a/src/sync/future/semaphore_signal.rs b/src/sync/future/semaphore_signal.rs
new file mode 100644
index 0000000..829860b
--- /dev/null
+++ b/src/sync/future/semaphore_signal.rs
@@ -0,0 +1,198 @@
+// 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::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;
+
+/// Builds a new semaphore signal future.
+#[inline]
+pub fn then_signal_semaphore<F>(future: F) -> SemaphoreSignalFuture<F>
+where
+ F: GpuFuture,
+{
+ let device = future.device().clone();
+
+ assert!(future.queue().is_some()); // TODO: document
+
+ SemaphoreSignalFuture {
+ previous: future,
+ semaphore: Semaphore::from_pool(device).unwrap(),
+ wait_submitted: Mutex::new(false),
+ finished: AtomicBool::new(false),
+ }
+}
+
+/// Represents a semaphore being signaled after a previous event.
+#[must_use = "Dropping this object will immediately block the thread until the GPU has finished \
+ processing the submission"]
+pub struct SemaphoreSignalFuture<F>
+where
+ F: GpuFuture,
+{
+ previous: F,
+ semaphore: 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`.
+ wait_submitted: Mutex<bool>,
+ finished: AtomicBool,
+}
+
+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 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();
+
+ if *wait_submitted {
+ return Ok(());
+ }
+
+ let queue = self.previous.queue().unwrap().clone();
+
+ match self.previous.build_submission()? {
+ SubmitAnyBuilder::Empty => {
+ let mut builder = SubmitCommandBufferBuilder::new();
+ builder.add_signal_semaphore(&self.semaphore);
+ builder.submit(&queue)?;
+ }
+ SubmitAnyBuilder::SemaphoresWait(sem) => {
+ let mut builder: SubmitCommandBufferBuilder = sem.into();
+ builder.add_signal_semaphore(&self.semaphore);
+ builder.submit(&queue)?;
+ }
+ SubmitAnyBuilder::CommandBuffer(mut builder) => {
+ debug_assert_eq!(builder.num_signal_semaphores(), 0);
+ builder.add_signal_semaphore(&self.semaphore);
+ builder.submit(&queue)?;
+ }
+ 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
+ }
+ };
+
+ // Only write `true` here in order to try again next time if an error occurs.
+ *wait_submitted = true;
+ Ok(())
+ }
+ }
+
+ #[inline]
+ unsafe fn signal_finished(&self) {
+ debug_assert!(*self.wait_submitted.lock().unwrap());
+ 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,
+ exclusive: bool,
+ queue: &Queue,
+ ) -> Result<Option<(PipelineStages, AccessFlags)>, AccessCheckError> {
+ self.previous
+ .check_buffer_access(buffer, exclusive, queue)
+ .map(|_| None)
+ }
+
+ #[inline]
+ fn check_image_access(
+ &self,
+ image: &dyn ImageAccess,
+ layout: ImageLayout,
+ exclusive: bool,
+ queue: &Queue,
+ ) -> Result<Option<(PipelineStages, AccessFlags)>, AccessCheckError> {
+ self.previous
+ .check_image_access(image, layout, exclusive, queue)
+ .map(|_| None)
+ }
+}
+
+unsafe impl<F> DeviceOwned for SemaphoreSignalFuture<F>
+where
+ F: GpuFuture,
+{
+ #[inline]
+ fn device(&self) -> &Arc<Device> {
+ self.semaphore.device()
+ }
+}
+
+impl<F> Drop for SemaphoreSignalFuture<F>
+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();
+ }
+ }
+ }
+}
diff --git a/src/sync/mod.rs b/src/sync/mod.rs
new file mode 100644
index 0000000..decbd7d
--- /dev/null
+++ b/src/sync/mod.rs
@@ -0,0 +1,173 @@
+// 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.
+
+//! Synchronization on the GPU.
+//!
+//! Just like for CPU code, you have to ensure that buffers and images are not accessed mutably by
+//! multiple GPU queues simultaneously and that they are not accessed mutably by the CPU and by the
+//! GPU simultaneously.
+//!
+//! 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
+
+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;
+mod pipeline;
+pub(crate) mod semaphore;
+
+/// Declares in which queue(s) a resource can be used.
+///
+/// When you create a buffer or an image, you have to tell the Vulkan library in which queue
+/// families it will be used. The vulkano library requires you to tell in which queue family
+/// the resource will be used, even for exclusive mode.
+#[derive(Debug, Clone, PartialEq, Eq)]
+// TODO: remove
+pub enum SharingMode {
+ /// The resource is used is only one queue family.
+ Exclusive,
+ /// The resource is used in multiple queue families. Can be slower than `Exclusive`.
+ Concurrent(Vec<u32>), // TODO: Vec is too expensive here
+}
+
+impl<'a> From<&'a Arc<Queue>> for SharingMode {
+ #[inline]
+ fn from(queue: &'a Arc<Queue>) -> SharingMode {
+ SharingMode::Exclusive
+ }
+}
+
+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())
+ }
+}
+
+/// Declares in which queue(s) a resource can be used.
+#[derive(Debug, Clone, PartialEq, Eq)]
+pub enum Sharing<I>
+where
+ I: Iterator<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),
+}
diff --git a/src/sync/pipeline.rs b/src/sync/pipeline.rs
new file mode 100644
index 0000000..62cd95c
--- /dev/null
+++ b/src/sync/pipeline.rs
@@ -0,0 +1,271 @@
+// 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::ops;
+
+macro_rules! pipeline_stages {
+ ($($elem:ident, $var:ident => $val:expr, $queue:expr;)+) => (
+ #[derive(Debug, Copy, Clone, PartialEq, Eq)]
+ pub struct PipelineStages {
+ $(
+ pub $elem: bool,
+ )+
+ }
+
+ impl PipelineStages {
+ /// Builds an `PipelineStages` struct with none of the stages set.
+ pub fn none() -> PipelineStages {
+ PipelineStages {
+ $(
+ $elem: false,
+ )+
+ }
+ }
+ }
+
+ 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
+ }
+ }
+
+ impl ops::BitOr for PipelineStages {
+ type Output = PipelineStages;
+
+ #[inline]
+ fn bitor(self, rhs: PipelineStages) -> PipelineStages {
+ PipelineStages {
+ $(
+ $elem: self.$elem || rhs.$elem,
+ )+
+ }
+ }
+ }
+
+ impl ops::BitOrAssign for PipelineStages {
+ #[inline]
+ fn bitor_assign(&mut self, rhs: PipelineStages) {
+ $(
+ self.$elem = self.$elem || rhs.$elem;
+ )+
+ }
+ }
+
+ #[derive(Debug, Copy, Clone, PartialEq, Eq)]
+ #[repr(u32)]
+ pub enum PipelineStage {
+ $(
+ $var = $val.as_raw(),
+ )+
+ }
+
+ impl PipelineStage {
+ #[inline]
+ pub fn required_queue_flags(&self) -> ash::vk::QueueFlags {
+ match self {
+ $(
+ Self::$var => $queue,
+ )+
+ }
+ }
+ }
+ );
+}
+
+impl From<PipelineStage> for ash::vk::PipelineStageFlags {
+ #[inline]
+ fn from(val: PipelineStage) -> Self {
+ Self::from_raw(val as u32)
+ }
+}
+
+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 AccessFlags {
+ /// Builds an `AccessFlags` struct with all bits set.
+ pub fn all() -> AccessFlags {
+ AccessFlags {
+ $(
+ $elem: true,
+ )+
+ }
+ }
+
+ /// Builds an `AccessFlags` struct with none of the bits set.
+ pub fn none() -> AccessFlags {
+ AccessFlags {
+ $(
+ $elem: false,
+ )+
+ }
+ }
+ }
+
+ 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
+ }
+ }
+
+ impl ops::BitOr for AccessFlags {
+ type Output = AccessFlags;
+
+ #[inline]
+ fn bitor(self, rhs: AccessFlags) -> AccessFlags {
+ AccessFlags {
+ $(
+ $elem: self.$elem || rhs.$elem,
+ )+
+ }
+ }
+ }
+
+ impl ops::BitOrAssign for AccessFlags {
+ #[inline]
+ fn bitor_assign(&mut self, rhs: AccessFlags) {
+ $(
+ self.$elem = self.$elem || rhs.$elem;
+ )+
+ }
+ }
+ );
+}
+
+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,
+}
+
+impl AccessFlags {
+ /// Returns true if the access flags can be used with the given pipeline stages.
+ ///
+ /// 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;
+ }
+
+ if self.indirect_command_read && !stages.draw_indirect && !stages.all_graphics {
+ return false;
+ }
+
+ if (self.index_read || self.vertex_attribute_read)
+ && !stages.vertex_input
+ && !stages.all_graphics
+ {
+ return false;
+ }
+
+ 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
+ {
+ return false;
+ }
+
+ if self.input_attachment_read && !stages.fragment_shader && !stages.all_graphics {
+ return false;
+ }
+
+ if (self.color_attachment_read || self.color_attachment_write)
+ && !stages.color_attachment_output
+ && !stages.all_graphics
+ {
+ return false;
+ }
+
+ 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 (self.transfer_read || self.transfer_write) && !stages.transfer {
+ return false;
+ }
+
+ if (self.host_read || self.host_write) && !stages.host {
+ return false;
+ }
+
+ true
+ }
+}
+
+/// The full specification of memory access by the pipeline for a particular resource.
+#[derive(Clone, Copy, Debug)]
+pub struct PipelineMemoryAccess {
+ /// The pipeline stages the resource will be accessed in.
+ pub stages: PipelineStages,
+ /// The type of memory access that will be performed.
+ pub access: AccessFlags,
+ /// Whether the resource needs exclusive (mutable) access or can be shared.
+ pub exclusive: bool,
+}
diff --git a/src/sync/semaphore/external_semaphore_handle_type.rs b/src/sync/semaphore/external_semaphore_handle_type.rs
new file mode 100644
index 0000000..35af2fa
--- /dev/null
+++ b/src/sync/semaphore/external_semaphore_handle_type.rs
@@ -0,0 +1,101 @@
+// 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/mod.rs b/src/sync/semaphore/mod.rs
new file mode 100644
index 0000000..6fc7688
--- /dev/null
+++ b/src/sync/semaphore/mod.rs
@@ -0,0 +1,15 @@
+// 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.
+
+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;
diff --git a/src/sync/semaphore/semaphore.rs b/src/sync/semaphore/semaphore.rs
new file mode 100644
index 0000000..29c9952
--- /dev/null
+++ b/src/sync/semaphore/semaphore.rs
@@ -0,0 +1,355 @@
+// 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
new file mode 100644
index 0000000..563fa9e
--- /dev/null
+++ b/src/tests.rs
@@ -0,0 +1,101 @@
+// 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.
+
+#![cfg(test)]
+
+/// Creates an instance or returns if initialization fails.
+macro_rules! instance {
+ () => {{
+ use crate::instance;
+ use crate::Version;
+
+ match instance::Instance::new(
+ None,
+ Version::V1_1,
+ &instance::InstanceExtensions::none(),
+ None,
+ ) {
+ Ok(i) => i,
+ Err(_) => return,
+ }
+ }};
+}
+
+/// 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::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 {
+ $(
+ $feature: true,
+ )*
+ .. Features::none()
+ };
+
+ // If the physical device doesn't support the requested features, just return.
+ if !physical.supported_features().is_superset_of(&features) {
+ return;
+ }
+
+ let (device, mut queues) = match Device::new(physical, &features,
+ &extensions, [(queue, 0.5)].iter().cloned())
+ {
+ Ok(r) => r,
+ Err(_) => return
+ };
+
+ (device, queues.next().unwrap())
+ });
+}
+
+macro_rules! assert_should_panic {
+ ($msg:expr, $code:block) => {{
+ let res = ::std::panic::catch_unwind(::std::panic::AssertUnwindSafe(|| $code));
+
+ match res {
+ Ok(_) => panic!("Test expected to panic but didn't"),
+ Err(err) => {
+ if let Some(msg) = err.downcast_ref::<String>() {
+ assert!(msg.contains($msg));
+ } else if let Some(&msg) = err.downcast_ref::<&str>() {
+ assert!(msg.contains($msg));
+ } else {
+ panic!("Couldn't decipher the panic message of the test")
+ }
+ }
+ }
+ }};
+
+ ($code:block) => {{
+ let res = ::std::panic::catch_unwind(::std::panic::AssertUnwindSafe(|| $code));
+
+ match res {
+ Ok(_) => panic!("Test expected to panic but didn't"),
+ Err(_) => {}
+ }
+ }};
+}
diff --git a/src/version.rs b/src/version.rs
new file mode 100644
index 0000000..f4ef595
--- /dev/null
+++ b/src/version.rs
@@ -0,0 +1,145 @@
+// 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 `Version` object is reexported from the `instance` module.
+
+use std::convert::TryFrom;
+use std::fmt;
+
+/// Represents an API version of Vulkan.
+#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
+pub struct Version {
+ /// Major version number.
+ pub major: u32,
+ /// Minor version number.
+ pub minor: u32,
+ /// Patch version number.
+ pub patch: u32,
+}
+
+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);
+
+ /// Constructs a `Version` from the given major and minor version numbers.
+ #[inline]
+ pub const fn major_minor(major: u32, minor: u32) -> Version {
+ Version {
+ major,
+ minor,
+ patch: 0,
+ }
+ }
+}
+
+impl Default for Version {
+ fn default() -> Self {
+ Self::V1_0
+ }
+}
+
+impl From<u32> for Version {
+ #[inline]
+ fn from(val: u32) -> Self {
+ Version {
+ major: ash::vk::api_version_major(val),
+ minor: ash::vk::api_version_minor(val),
+ patch: ash::vk::api_version_patch(val),
+ }
+ }
+}
+
+impl TryFrom<Version> for u32 {
+ type Error = ();
+
+ #[inline]
+ fn try_from(val: Version) -> Result<Self, Self::Error> {
+ if val.major <= 0x3ff && val.minor <= 0x3ff && val.patch <= 0xfff {
+ Ok(ash::vk::make_api_version(
+ 0, val.major, val.minor, val.patch,
+ ))
+ } else {
+ Err(())
+ }
+ }
+}
+
+impl fmt::Debug for Version {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ write!(formatter, "{}.{}.{}", 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)
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use super::Version;
+ use std::convert::TryFrom;
+
+ #[test]
+ fn into_vk_version() {
+ let version = Version {
+ major: 1,
+ minor: 0,
+ patch: 0,
+ };
+ assert_eq!(u32::try_from(version).unwrap(), 0x400000);
+ }
+
+ #[test]
+ fn greater_major() {
+ let v1 = Version {
+ major: 1,
+ minor: 0,
+ patch: 0,
+ };
+ let v2 = Version {
+ major: 2,
+ minor: 0,
+ patch: 0,
+ };
+ assert!(v2 > v1);
+ }
+
+ #[test]
+ fn greater_minor() {
+ let v1 = Version {
+ major: 1,
+ minor: 1,
+ patch: 0,
+ };
+ let v2 = Version {
+ major: 1,
+ minor: 3,
+ patch: 0,
+ };
+ assert!(v2 > v1);
+ }
+
+ #[test]
+ fn greater_patch() {
+ let v1 = Version {
+ major: 1,
+ minor: 0,
+ patch: 4,
+ };
+ let v2 = Version {
+ major: 1,
+ minor: 0,
+ patch: 5,
+ };
+ assert!(v2 > v1);
+ }
+}
diff --git a/vk.xml b/vk.xml
new file mode 100644
index 0000000..81901e6
--- /dev/null
+++ b/vk.xml
@@ -0,0 +1,17283 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<registry>
+ <comment>
+Copyright 2015-2021 The Khronos Group Inc.
+
+SPDX-License-Identifier: Apache-2.0 OR MIT
+ </comment>
+
+ <comment>
+This file, vk.xml, is the Vulkan API Registry. It is a critically important
+and normative part of the Vulkan Specification, including a canonical
+machine-readable definition of the API, parameter and member validation
+language incorporated into the Specification and reference pages, and other
+material which is registered by Khronos, such as tags used by extension and
+layer authors. The authoritative public version of vk.xml is maintained in
+the default branch (currently named main) of the Khronos Vulkan GitHub
+project. The authoritative private version is maintained in the default
+branch of the member gitlab server.
+ </comment>
+
+ <platforms comment="Vulkan platform names, reserved for use with platform- and window system-specific extensions">
+ <platform name="xlib" protect="VK_USE_PLATFORM_XLIB_KHR" comment="X Window System, Xlib client library"/>
+ <platform name="xlib_xrandr" protect="VK_USE_PLATFORM_XLIB_XRANDR_EXT" comment="X Window System, Xlib client library, XRandR extension"/>
+ <platform name="xcb" protect="VK_USE_PLATFORM_XCB_KHR" comment="X Window System, Xcb client library"/>
+ <platform name="wayland" protect="VK_USE_PLATFORM_WAYLAND_KHR" comment="Wayland display server protocol"/>
+ <platform name="directfb" protect="VK_USE_PLATFORM_DIRECTFB_EXT" comment="DirectFB library"/>
+ <platform name="android" protect="VK_USE_PLATFORM_ANDROID_KHR" comment="Android OS"/>
+ <platform name="win32" protect="VK_USE_PLATFORM_WIN32_KHR" comment="Microsoft Win32 API (also refers to Win64 apps)"/>
+ <platform name="vi" protect="VK_USE_PLATFORM_VI_NN" comment="Nintendo Vi"/>
+ <platform name="ios" protect="VK_USE_PLATFORM_IOS_MVK" comment="Apple IOS"/>
+ <platform name="macos" protect="VK_USE_PLATFORM_MACOS_MVK" comment="Apple MacOS"/>
+ <platform name="metal" protect="VK_USE_PLATFORM_METAL_EXT" comment="Metal on CoreAnimation on Apple platforms"/>
+ <platform name="fuchsia" protect="VK_USE_PLATFORM_FUCHSIA" comment="Fuchsia"/>
+ <platform name="ggp" protect="VK_USE_PLATFORM_GGP" comment="Google Games Platform"/>
+ <platform name="provisional" protect="VK_ENABLE_BETA_EXTENSIONS" comment="Enable declarations for beta/provisional extensions"/>
+ <platform name="screen" protect="VK_USE_PLATFORM_SCREEN_QNX" comment="QNX Screen Graphics Subsystem"/>
+ </platforms>
+
+ <tags comment="Vulkan vendor/author tags for extensions and layers">
+ <tag name="IMG" author="Imagination Technologies" contact="Michael Worcester @michaelworcester"/>
+ <tag name="AMD" author="Advanced Micro Devices, Inc." contact="Daniel Rakos @drakos-amd"/>
+ <tag name="AMDX" author="Advanced Micro Devices, Inc." contact="Daniel Rakos @drakos-amd"/>
+ <tag name="ARM" author="ARM Limited" contact="Jan-Harald Fredriksen @janharaldfredriksen-arm"/>
+ <tag name="FSL" author="Freescale Semiconductor, Inc." contact="Norbert Nopper @FslNopper"/>
+ <tag name="BRCM" author="Broadcom Corporation" contact="Graeme Leese @gnl21"/>
+ <tag name="NXP" author="NXP Semiconductors N.V." contact="Norbert Nopper @FslNopper"/>
+ <tag name="NV" author="NVIDIA Corporation" contact="Daniel Koch @dgkoch"/>
+ <tag name="NVX" author="NVIDIA Corporation" contact="Daniel Koch @dgkoch"/>
+ <tag name="VIV" author="Vivante Corporation" contact="Yanjun Zhang gitlab:@yanjunzhang"/>
+ <tag name="VSI" author="VeriSilicon Holdings Co., Ltd." contact="Yanjun Zhang gitlab:@yanjunzhang"/>
+ <tag name="KDAB" author="KDAB" contact="Sean Harmer @seanharmer"/>
+ <tag name="ANDROID" author="Google LLC" contact="Jesse Hall @critsec"/>
+ <tag name="CHROMIUM" author="Google LLC" contact="Jesse Hall @critsec"/>
+ <tag name="FUCHSIA" author="Google LLC" contact="Craig Stout @cdotstout, Jesse Hall @critsec, John Rosasco @rosasco"/>
+ <tag name="GGP" author="Google, LLC" contact="Jean-Francois Roy @jfroy, Hai Nguyen @chaoticbob, Jesse Hall @critsec"/>
+ <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="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"/>
+ <tag name="RENDERDOC" author="RenderDoc (renderdoc.org)" contact="Baldur Karlsson @baldurk"/>
+ <tag name="NN" author="Nintendo Co., Ltd." contact="Yasuhiro Yoshioka gitlab:@yoshioka_yasuhiro"/>
+ <tag name="MVK" author="The Brenwill Workshop Ltd." contact="Bill Hollings @billhollings"/>
+ <tag name="KHR" author="Khronos" contact="Tom Olson @tomolson"/>
+ <tag name="KHX" author="Khronos" contact="Tom Olson @tomolson"/>
+ <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="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"/>
+ </tags>
+
+ <types comment="Vulkan type definitions">
+ <type name="vk_platform" category="include">#include "vulkan/vk_platform.h"</type>
+
+ <comment>WSI extensions</comment>
+
+ <type category="include" name="X11/Xlib.h"/>
+ <type category="include" name="X11/extensions/Xrandr.h"/>
+ <type category="include" name="wayland-client.h"/>
+ <type category="include" name="windows.h"/>
+ <type category="include" name="xcb/xcb.h"/>
+ <type category="include" name="directfb.h"/>
+ <type category="include" name="zircon/types.h"/>
+ <type category="include" name="ggp_c/vulkan_types.h"/>
+ <type category="include" name="screen/screen.h"/>
+ <comment>
+ In the current header structure, each platform's interfaces
+ are confined to a platform-specific header (vulkan_xlib.h,
+ vulkan_win32.h, etc.). These headers are not self-contained,
+ and should not include native headers (X11/Xlib.h,
+ windows.h, etc.). Code should either include vulkan.h after
+ defining the appropriate VK_USE_PLATFORM_platform
+ macros, or include the required native headers prior to
+ explicitly including the corresponding platform header.
+
+ To accomplish this, the dependencies of native types require
+ native headers, but the XML defines the content for those
+ native headers as empty. The actual native header includes
+ can be restored by modifying the native header tags above
+ to #include the header file in the 'name' attribute.
+ </comment>
+
+ <type requires="X11/Xlib.h" name="Display"/>
+ <type requires="X11/Xlib.h" name="VisualID"/>
+ <type requires="X11/Xlib.h" name="Window"/>
+ <type requires="X11/extensions/Xrandr.h" name="RROutput"/>
+ <type requires="wayland-client.h" name="wl_display"/>
+ <type requires="wayland-client.h" name="wl_surface"/>
+ <type requires="windows.h" name="HINSTANCE"/>
+ <type requires="windows.h" name="HWND"/>
+ <type requires="windows.h" name="HMONITOR"/>
+ <type requires="windows.h" name="HANDLE"/>
+ <type requires="windows.h" name="SECURITY_ATTRIBUTES"/>
+ <type requires="windows.h" name="DWORD"/>
+ <type requires="windows.h" name="LPCWSTR"/>
+ <type requires="xcb/xcb.h" name="xcb_connection_t"/>
+ <type requires="xcb/xcb.h" name="xcb_visualid_t"/>
+ <type requires="xcb/xcb.h" name="xcb_window_t"/>
+ <type requires="directfb.h" name="IDirectFB"/>
+ <type requires="directfb.h" name="IDirectFBSurface"/>
+ <type requires="zircon/types.h" name="zx_handle_t"/>
+ <type requires="ggp_c/vulkan_types.h" name="GgpStreamDescriptor"/>
+ <type requires="ggp_c/vulkan_types.h" name="GgpFrameToken"/>
+ <type requires="screen/screen.h" name="_screen_context"/>
+ <type requires="screen/screen.h" name="_screen_window"/>
+
+ <type category="define">// DEPRECATED: This define is deprecated. VK_MAKE_API_VERSION should be used instead.
+#define <name>VK_MAKE_VERSION</name>(major, minor, patch) \
+ ((((uint32_t)(major)) &lt;&lt; 22) | (((uint32_t)(minor)) &lt;&lt; 12) | ((uint32_t)(patch)))</type>
+ <type category="define">// DEPRECATED: This define is deprecated. VK_API_VERSION_MAJOR should be used instead.
+#define <name>VK_VERSION_MAJOR</name>(version) ((uint32_t)(version) &gt;&gt; 22)</type>
+ <type category="define">// DEPRECATED: This define is deprecated. VK_API_VERSION_MINOR should be used instead.
+#define <name>VK_VERSION_MINOR</name>(version) (((uint32_t)(version) &gt;&gt; 12) &amp; 0x3FFU)</type>
+ <type category="define">// DEPRECATED: This define is deprecated. VK_API_VERSION_PATCH should be used instead.
+#define <name>VK_VERSION_PATCH</name>(version) ((uint32_t)(version) &amp; 0xFFFU)</type>
+
+ <type category="define">#define <name>VK_MAKE_API_VERSION</name>(variant, major, minor, patch) \
+ ((((uint32_t)(variant)) &lt;&lt; 29) | (((uint32_t)(major)) &lt;&lt; 22) | (((uint32_t)(minor)) &lt;&lt; 12) | ((uint32_t)(patch)))</type>
+ <type category="define">#define <name>VK_API_VERSION_VARIANT</name>(version) ((uint32_t)(version) &gt;&gt; 29)</type>
+ <type category="define">#define <name>VK_API_VERSION_MAJOR</name>(version) (((uint32_t)(version) &gt;&gt; 22) &amp; 0x7FU)</type>
+ <type category="define">#define <name>VK_API_VERSION_MINOR</name>(version) (((uint32_t)(version) &gt;&gt; 12) &amp; 0x3FFU)</type>
+ <type category="define">#define <name>VK_API_VERSION_PATCH</name>(version) ((uint32_t)(version) &amp; 0xFFFU)</type>
+
+ <type category="define">// DEPRECATED: This define has been removed. Specific version defines (e.g. VK_API_VERSION_1_0), or the VK_MAKE_VERSION macro, should be used instead.
+//#define <name>VK_API_VERSION</name> <type>VK_MAKE_VERSION</type>(1, 0, 0) // Patch version should always be set to 0</type>
+ <type category="define" requires="VK_MAKE_API_VERSION">// Vulkan 1.0 version number
+#define <name>VK_API_VERSION_1_0</name> <type>VK_MAKE_API_VERSION</type>(0, 1, 0, 0)// Patch version should always be set to 0</type>
+ <type category="define" requires="VK_MAKE_API_VERSION">// Vulkan 1.1 version number
+#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">// Version of this file
+#define <name>VK_HEADER_VERSION</name> 186</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>
+
+ <type category="define">
+#define <name>VK_DEFINE_HANDLE</name>(object) typedef struct object##_T* object;</type>
+
+ <type category="define" name="VK_USE_64_BIT_PTR_DEFINES">
+#ifndef VK_USE_64_BIT_PTR_DEFINES
+ #if defined(__LP64__) || defined(_WIN64) || (defined(__x86_64__) &amp;&amp; !defined(__ILP32__) ) || defined(_M_X64) || defined(__ia64) || defined (_M_IA64) || defined(__aarch64__) || defined(__powerpc64__)
+ #define VK_USE_64_BIT_PTR_DEFINES 1
+ #else
+ #define VK_USE_64_BIT_PTR_DEFINES 0
+ #endif
+#endif</type>
+ <type category="define" requires="VK_USE_64_BIT_PTR_DEFINES" name="VK_NULL_HANDLE">
+#ifndef VK_DEFINE_NON_DISPATCHABLE_HANDLE
+ #if (VK_USE_64_BIT_PTR_DEFINES==1)
+ #if (defined(__cplusplus) &amp;&amp; (__cplusplus >= 201103L)) || (defined(_MSVC_LANG) &amp;&amp; (_MSVC_LANG >= 201103L))
+ #define VK_NULL_HANDLE nullptr
+ #else
+ #define VK_NULL_HANDLE ((void*)0)
+ #endif
+ #else
+ #define VK_NULL_HANDLE 0ULL
+ #endif
+#endif
+#ifndef VK_NULL_HANDLE
+ #define VK_NULL_HANDLE 0
+#endif</type>
+ <type category="define" requires="VK_NULL_HANDLE" name="VK_DEFINE_NON_DISPATCHABLE_HANDLE">
+#ifndef VK_DEFINE_NON_DISPATCHABLE_HANDLE
+ #if (VK_USE_64_BIT_PTR_DEFINES==1)
+ #define VK_DEFINE_NON_DISPATCHABLE_HANDLE(object) typedef struct object##_T *object;
+ #else
+ #define VK_DEFINE_NON_DISPATCHABLE_HANDLE(object) typedef uint64_t object;
+ #endif
+#endif</type>
+
+ <type category="basetype">struct <name>ANativeWindow</name>;</type>
+ <type category="basetype">struct <name>AHardwareBuffer</name>;</type>
+ <type category="basetype">
+#ifdef __OBJC__
+@class CAMetalLayer;
+#else
+typedef void <name>CAMetalLayer</name>;
+#endif</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>
+ <type category="basetype">typedef <type>uint32_t</type> <name>VkFlags</name>;</type>
+ <type category="basetype">typedef <type>uint64_t</type> <name>VkFlags64</name>;</type>
+ <type category="basetype">typedef <type>uint64_t</type> <name>VkDeviceSize</name>;</type>
+ <type category="basetype">typedef <type>uint64_t</type> <name>VkDeviceAddress</name>;</type>
+
+ <comment>Basic C types, pulled in via vk_platform.h</comment>
+ <type requires="vk_platform" name="void"/>
+ <type requires="vk_platform" name="char"/>
+ <type requires="vk_platform" name="float"/>
+ <type requires="vk_platform" name="double"/>
+ <type requires="vk_platform" name="int8_t"/>
+ <type requires="vk_platform" name="uint8_t"/>
+ <type requires="vk_platform" name="int16_t"/>
+ <type requires="vk_platform" name="uint16_t"/>
+ <type requires="vk_platform" name="uint32_t"/>
+ <type requires="vk_platform" name="uint64_t"/>
+ <type requires="vk_platform" name="int32_t"/>
+ <type requires="vk_platform" name="int64_t"/>
+ <type requires="vk_platform" name="size_t"/>
+ <type name="int"/>
+
+ <comment>Bitmask types</comment>
+ <type requires="VkFramebufferCreateFlagBits" category="bitmask">typedef <type>VkFlags</type> <name>VkFramebufferCreateFlags</name>;</type>
+ <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="VkPipelineCacheCreateFlagBits" category="bitmask">typedef <type>VkFlags</type> <name>VkPipelineCacheCreateFlags</name>;</type>
+ <type 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 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>
+ <type category="bitmask">typedef <type>VkFlags</type> <name>VkPipelineTessellationStateCreateFlags</name>;</type>
+ <type category="bitmask">typedef <type>VkFlags</type> <name>VkPipelineInputAssemblyStateCreateFlags</name>;</type>
+ <type category="bitmask">typedef <type>VkFlags</type> <name>VkPipelineVertexInputStateCreateFlags</name>;</type>
+ <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 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>
+ <type requires="VkMemoryPropertyFlagBits" category="bitmask">typedef <type>VkFlags</type> <name>VkMemoryPropertyFlags</name>;</type>
+ <type requires="VkMemoryHeapFlagBits" category="bitmask">typedef <type>VkFlags</type> <name>VkMemoryHeapFlags</name>;</type>
+ <type requires="VkAccessFlagBits" category="bitmask">typedef <type>VkFlags</type> <name>VkAccessFlags</name>;</type>
+ <type requires="VkBufferUsageFlagBits" category="bitmask">typedef <type>VkFlags</type> <name>VkBufferUsageFlags</name>;</type>
+ <type requires="VkBufferCreateFlagBits" category="bitmask">typedef <type>VkFlags</type> <name>VkBufferCreateFlags</name>;</type>
+ <type requires="VkShaderStageFlagBits" category="bitmask">typedef <type>VkFlags</type> <name>VkShaderStageFlags</name>;</type>
+ <type requires="VkImageUsageFlagBits" category="bitmask">typedef <type>VkFlags</type> <name>VkImageUsageFlags</name>;</type>
+ <type requires="VkImageCreateFlagBits" category="bitmask">typedef <type>VkFlags</type> <name>VkImageCreateFlags</name>;</type>
+ <type requires="VkImageViewCreateFlagBits" category="bitmask">typedef <type>VkFlags</type> <name>VkImageViewCreateFlags</name>;</type>
+ <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 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>
+ <type requires="VkCommandBufferResetFlagBits" category="bitmask">typedef <type>VkFlags</type> <name>VkCommandBufferResetFlags</name>;</type>
+ <type requires="VkCommandBufferUsageFlagBits" category="bitmask">typedef <type>VkFlags</type> <name>VkCommandBufferUsageFlags</name>;</type>
+ <type requires="VkQueryPipelineStatisticFlagBits" category="bitmask">typedef <type>VkFlags</type> <name>VkQueryPipelineStatisticFlags</name>;</type>
+ <type category="bitmask">typedef <type>VkFlags</type> <name>VkMemoryMapFlags</name>;</type>
+ <type requires="VkImageAspectFlagBits" category="bitmask">typedef <type>VkFlags</type> <name>VkImageAspectFlags</name>;</type>
+ <type requires="VkSparseMemoryBindFlagBits" category="bitmask">typedef <type>VkFlags</type> <name>VkSparseMemoryBindFlags</name>;</type>
+ <type requires="VkSparseImageFormatFlagBits" category="bitmask">typedef <type>VkFlags</type> <name>VkSparseImageFormatFlags</name>;</type>
+ <type requires="VkSubpassDescriptionFlagBits" category="bitmask">typedef <type>VkFlags</type> <name>VkSubpassDescriptionFlags</name>;</type>
+ <type requires="VkPipelineStageFlagBits" category="bitmask">typedef <type>VkFlags</type> <name>VkPipelineStageFlags</name>;</type>
+ <type requires="VkSampleCountFlagBits" category="bitmask">typedef <type>VkFlags</type> <name>VkSampleCountFlags</name>;</type>
+ <type requires="VkAttachmentDescriptionFlagBits" category="bitmask">typedef <type>VkFlags</type> <name>VkAttachmentDescriptionFlags</name>;</type>
+ <type requires="VkStencilFaceFlagBits" category="bitmask">typedef <type>VkFlags</type> <name>VkStencilFaceFlags</name>;</type>
+ <type requires="VkCullModeFlagBits" category="bitmask">typedef <type>VkFlags</type> <name>VkCullModeFlags</name>;</type>
+ <type requires="VkDescriptorPoolCreateFlagBits" category="bitmask">typedef <type>VkFlags</type> <name>VkDescriptorPoolCreateFlags</name>;</type>
+ <type category="bitmask">typedef <type>VkFlags</type> <name>VkDescriptorPoolResetFlags</name>;</type>
+ <type requires="VkDependencyFlagBits" category="bitmask">typedef <type>VkFlags</type> <name>VkDependencyFlags</name>;</type>
+ <type requires="VkSubgroupFeatureFlagBits" category="bitmask">typedef <type>VkFlags</type> <name>VkSubgroupFeatureFlags</name>;</type>
+ <type requires="VkIndirectCommandsLayoutUsageFlagBitsNV" category="bitmask">typedef <type>VkFlags</type> <name>VkIndirectCommandsLayoutUsageFlagsNV</name>;</type>
+ <type requires="VkIndirectStateFlagBitsNV" category="bitmask">typedef <type>VkFlags</type> <name>VkIndirectStateFlagsNV</name>;</type>
+ <type requires="VkGeometryFlagBitsKHR" category="bitmask">typedef <type>VkFlags</type> <name>VkGeometryFlagsKHR</name>;</type>
+ <type category="bitmask" name="VkGeometryFlagsNV" alias="VkGeometryFlagsKHR"/>
+ <type requires="VkGeometryInstanceFlagBitsKHR" category="bitmask">typedef <type>VkFlags</type> <name>VkGeometryInstanceFlagsKHR</name>;</type>
+ <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 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="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>
+ <type category="bitmask" name="VkSemaphoreWaitFlagsKHR" alias="VkSemaphoreWaitFlags"/>
+ <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>
+
+ <comment>WSI extensions</comment>
+ <type requires="VkCompositeAlphaFlagBitsKHR" category="bitmask">typedef <type>VkFlags</type> <name>VkCompositeAlphaFlagsKHR</name>;</type>
+ <type requires="VkDisplayPlaneAlphaFlagBitsKHR" category="bitmask">typedef <type>VkFlags</type> <name>VkDisplayPlaneAlphaFlagsKHR</name>;</type>
+ <type requires="VkSurfaceTransformFlagBitsKHR" category="bitmask">typedef <type>VkFlags</type> <name>VkSurfaceTransformFlagsKHR</name>;</type>
+ <type requires="VkSwapchainCreateFlagBitsKHR" category="bitmask">typedef <type>VkFlags</type> <name>VkSwapchainCreateFlagsKHR</name>;</type>
+ <type category="bitmask">typedef <type>VkFlags</type> <name>VkDisplayModeCreateFlagsKHR</name>;</type>
+ <type category="bitmask">typedef <type>VkFlags</type> <name>VkDisplaySurfaceCreateFlagsKHR</name>;</type>
+ <type category="bitmask">typedef <type>VkFlags</type> <name>VkAndroidSurfaceCreateFlagsKHR</name>;</type>
+ <type category="bitmask">typedef <type>VkFlags</type> <name>VkViSurfaceCreateFlagsNN</name>;</type>
+ <type category="bitmask">typedef <type>VkFlags</type> <name>VkWaylandSurfaceCreateFlagsKHR</name>;</type>
+ <type category="bitmask">typedef <type>VkFlags</type> <name>VkWin32SurfaceCreateFlagsKHR</name>;</type>
+ <type category="bitmask">typedef <type>VkFlags</type> <name>VkXlibSurfaceCreateFlagsKHR</name>;</type>
+ <type category="bitmask">typedef <type>VkFlags</type> <name>VkXcbSurfaceCreateFlagsKHR</name>;</type>
+ <type category="bitmask">typedef <type>VkFlags</type> <name>VkDirectFBSurfaceCreateFlagsEXT</name>;</type>
+ <type category="bitmask">typedef <type>VkFlags</type> <name>VkIOSSurfaceCreateFlagsMVK</name>;</type>
+ <type category="bitmask">typedef <type>VkFlags</type> <name>VkMacOSSurfaceCreateFlagsMVK</name>;</type>
+ <type category="bitmask">typedef <type>VkFlags</type> <name>VkMetalSurfaceCreateFlagsEXT</name>;</type>
+ <type category="bitmask">typedef <type>VkFlags</type> <name>VkImagePipeSurfaceCreateFlagsFUCHSIA</name>;</type>
+ <type category="bitmask">typedef <type>VkFlags</type> <name>VkStreamDescriptorSurfaceCreateFlagsGGP</name>;</type>
+ <type category="bitmask">typedef <type>VkFlags</type> <name>VkHeadlessSurfaceCreateFlagsEXT</name>;</type>
+ <type category="bitmask">typedef <type>VkFlags</type> <name>VkScreenSurfaceCreateFlagsQNX</name>;</type>
+ <type requires="VkPeerMemoryFeatureFlagBits" category="bitmask">typedef <type>VkFlags</type> <name>VkPeerMemoryFeatureFlags</name>;</type>
+ <type category="bitmask" name="VkPeerMemoryFeatureFlagsKHR" alias="VkPeerMemoryFeatureFlags"/>
+ <type requires="VkMemoryAllocateFlagBits" category="bitmask">typedef <type>VkFlags</type> <name>VkMemoryAllocateFlags</name>;</type>
+ <type category="bitmask" name="VkMemoryAllocateFlagsKHR" alias="VkMemoryAllocateFlags"/>
+ <type requires="VkDeviceGroupPresentModeFlagBitsKHR" category="bitmask">typedef <type>VkFlags</type> <name>VkDeviceGroupPresentModeFlagsKHR</name>;</type>
+
+ <type requires="VkDebugReportFlagBitsEXT" category="bitmask">typedef <type>VkFlags</type> <name>VkDebugReportFlagsEXT</name>;</type>
+ <type category="bitmask">typedef <type>VkFlags</type> <name>VkCommandPoolTrimFlags</name>;</type>
+ <type category="bitmask" name="VkCommandPoolTrimFlagsKHR" alias="VkCommandPoolTrimFlags"/>
+ <type requires="VkExternalMemoryHandleTypeFlagBitsNV" category="bitmask">typedef <type>VkFlags</type> <name>VkExternalMemoryHandleTypeFlagsNV</name>;</type>
+ <type requires="VkExternalMemoryFeatureFlagBitsNV" category="bitmask">typedef <type>VkFlags</type> <name>VkExternalMemoryFeatureFlagsNV</name>;</type>
+ <type requires="VkExternalMemoryHandleTypeFlagBits" category="bitmask">typedef <type>VkFlags</type> <name>VkExternalMemoryHandleTypeFlags</name>;</type>
+ <type category="bitmask" name="VkExternalMemoryHandleTypeFlagsKHR" alias="VkExternalMemoryHandleTypeFlags"/>
+ <type requires="VkExternalMemoryFeatureFlagBits" category="bitmask">typedef <type>VkFlags</type> <name>VkExternalMemoryFeatureFlags</name>;</type>
+ <type category="bitmask" name="VkExternalMemoryFeatureFlagsKHR" alias="VkExternalMemoryFeatureFlags"/>
+ <type requires="VkExternalSemaphoreHandleTypeFlagBits" category="bitmask">typedef <type>VkFlags</type> <name>VkExternalSemaphoreHandleTypeFlags</name>;</type>
+ <type category="bitmask" name="VkExternalSemaphoreHandleTypeFlagsKHR" alias="VkExternalSemaphoreHandleTypeFlags"/>
+ <type requires="VkExternalSemaphoreFeatureFlagBits" category="bitmask">typedef <type>VkFlags</type> <name>VkExternalSemaphoreFeatureFlags</name>;</type>
+ <type category="bitmask" name="VkExternalSemaphoreFeatureFlagsKHR" alias="VkExternalSemaphoreFeatureFlags"/>
+ <type requires="VkSemaphoreImportFlagBits" category="bitmask">typedef <type>VkFlags</type> <name>VkSemaphoreImportFlags</name>;</type>
+ <type category="bitmask" name="VkSemaphoreImportFlagsKHR" alias="VkSemaphoreImportFlags"/>
+ <type requires="VkExternalFenceHandleTypeFlagBits" category="bitmask">typedef <type>VkFlags</type> <name>VkExternalFenceHandleTypeFlags</name>;</type>
+ <type category="bitmask" name="VkExternalFenceHandleTypeFlagsKHR" alias="VkExternalFenceHandleTypeFlags"/>
+ <type requires="VkExternalFenceFeatureFlagBits" category="bitmask">typedef <type>VkFlags</type> <name>VkExternalFenceFeatureFlags</name>;</type>
+ <type category="bitmask" name="VkExternalFenceFeatureFlagsKHR" alias="VkExternalFenceFeatureFlags"/>
+ <type requires="VkFenceImportFlagBits" category="bitmask">typedef <type>VkFlags</type> <name>VkFenceImportFlags</name>;</type>
+ <type category="bitmask" name="VkFenceImportFlagsKHR" alias="VkFenceImportFlags"/>
+ <type requires="VkSurfaceCounterFlagBitsEXT" category="bitmask">typedef <type>VkFlags</type> <name>VkSurfaceCounterFlagsEXT</name>;</type>
+ <type category="bitmask">typedef <type>VkFlags</type> <name>VkPipelineViewportSwizzleStateCreateFlagsNV</name>;</type>
+ <type category="bitmask">typedef <type>VkFlags</type> <name>VkPipelineDiscardRectangleStateCreateFlagsEXT</name>;</type>
+ <type category="bitmask">typedef <type>VkFlags</type> <name>VkPipelineCoverageToColorStateCreateFlagsNV</name>;</type>
+ <type category="bitmask">typedef <type>VkFlags</type> <name>VkPipelineCoverageModulationStateCreateFlagsNV</name>;</type>
+ <type category="bitmask">typedef <type>VkFlags</type> <name>VkPipelineCoverageReductionStateCreateFlagsNV</name>;</type>
+ <type category="bitmask">typedef <type>VkFlags</type> <name>VkValidationCacheCreateFlagsEXT</name>;</type>
+ <type requires="VkDebugUtilsMessageSeverityFlagBitsEXT" category="bitmask">typedef <type>VkFlags</type> <name>VkDebugUtilsMessageSeverityFlagsEXT</name>;</type>
+ <type requires="VkDebugUtilsMessageTypeFlagBitsEXT" category="bitmask">typedef <type>VkFlags</type> <name>VkDebugUtilsMessageTypeFlagsEXT</name>;</type>
+ <type category="bitmask">typedef <type>VkFlags</type> <name>VkDebugUtilsMessengerCreateFlagsEXT</name>;</type>
+ <type category="bitmask">typedef <type>VkFlags</type> <name>VkDebugUtilsMessengerCallbackDataFlagsEXT</name>;</type>
+ <type category="bitmask">typedef <type>VkFlags</type> <name>VkDeviceMemoryReportFlagsEXT</name>;</type>
+ <type category="bitmask">typedef <type>VkFlags</type> <name>VkPipelineRasterizationConservativeStateCreateFlagsEXT</name>;</type>
+ <type requires="VkDescriptorBindingFlagBits" category="bitmask">typedef <type>VkFlags</type> <name>VkDescriptorBindingFlags</name>;</type>
+ <type category="bitmask" name="VkDescriptorBindingFlagsEXT" alias="VkDescriptorBindingFlags"/>
+ <type requires="VkConditionalRenderingFlagBitsEXT" category="bitmask">typedef <type>VkFlags</type> <name>VkConditionalRenderingFlagsEXT</name>;</type>
+ <type requires="VkResolveModeFlagBits" category="bitmask">typedef <type>VkFlags</type> <name>VkResolveModeFlags</name>;</type>
+ <type category="bitmask" name="VkResolveModeFlagsKHR" alias="VkResolveModeFlags"/>
+ <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>
+
+ <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="VkVideoSessionCreateFlagBitsKHR" category="bitmask">typedef <type>VkFlags</type> <name>VkVideoSessionCreateFlagsKHR</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>
+
+ <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>
+
+ <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 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="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>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>
+ <type category="handle" parent="VkInstance" objtypeenum="VK_OBJECT_TYPE_PHYSICAL_DEVICE"><type>VK_DEFINE_HANDLE</type>(<name>VkPhysicalDevice</name>)</type>
+ <type category="handle" parent="VkPhysicalDevice" objtypeenum="VK_OBJECT_TYPE_DEVICE"><type>VK_DEFINE_HANDLE</type>(<name>VkDevice</name>)</type>
+ <type category="handle" parent="VkDevice" objtypeenum="VK_OBJECT_TYPE_QUEUE"><type>VK_DEFINE_HANDLE</type>(<name>VkQueue</name>)</type>
+ <type category="handle" parent="VkCommandPool" objtypeenum="VK_OBJECT_TYPE_COMMAND_BUFFER"><type>VK_DEFINE_HANDLE</type>(<name>VkCommandBuffer</name>)</type>
+ <type category="handle" parent="VkDevice" objtypeenum="VK_OBJECT_TYPE_DEVICE_MEMORY"><type>VK_DEFINE_NON_DISPATCHABLE_HANDLE</type>(<name>VkDeviceMemory</name>)</type>
+ <type category="handle" parent="VkDevice" objtypeenum="VK_OBJECT_TYPE_COMMAND_POOL"><type>VK_DEFINE_NON_DISPATCHABLE_HANDLE</type>(<name>VkCommandPool</name>)</type>
+ <type category="handle" parent="VkDevice" objtypeenum="VK_OBJECT_TYPE_BUFFER"><type>VK_DEFINE_NON_DISPATCHABLE_HANDLE</type>(<name>VkBuffer</name>)</type>
+ <type category="handle" parent="VkDevice" objtypeenum="VK_OBJECT_TYPE_BUFFER_VIEW"><type>VK_DEFINE_NON_DISPATCHABLE_HANDLE</type>(<name>VkBufferView</name>)</type>
+ <type category="handle" parent="VkDevice" objtypeenum="VK_OBJECT_TYPE_IMAGE"><type>VK_DEFINE_NON_DISPATCHABLE_HANDLE</type>(<name>VkImage</name>)</type>
+ <type category="handle" parent="VkDevice" objtypeenum="VK_OBJECT_TYPE_IMAGE_VIEW"><type>VK_DEFINE_NON_DISPATCHABLE_HANDLE</type>(<name>VkImageView</name>)</type>
+ <type category="handle" parent="VkDevice" objtypeenum="VK_OBJECT_TYPE_SHADER_MODULE"><type>VK_DEFINE_NON_DISPATCHABLE_HANDLE</type>(<name>VkShaderModule</name>)</type>
+ <type category="handle" parent="VkDevice" objtypeenum="VK_OBJECT_TYPE_PIPELINE"><type>VK_DEFINE_NON_DISPATCHABLE_HANDLE</type>(<name>VkPipeline</name>)</type>
+ <type category="handle" parent="VkDevice" objtypeenum="VK_OBJECT_TYPE_PIPELINE_LAYOUT"><type>VK_DEFINE_NON_DISPATCHABLE_HANDLE</type>(<name>VkPipelineLayout</name>)</type>
+ <type category="handle" parent="VkDevice" objtypeenum="VK_OBJECT_TYPE_SAMPLER"><type>VK_DEFINE_NON_DISPATCHABLE_HANDLE</type>(<name>VkSampler</name>)</type>
+ <type category="handle" parent="VkDescriptorPool" objtypeenum="VK_OBJECT_TYPE_DESCRIPTOR_SET"><type>VK_DEFINE_NON_DISPATCHABLE_HANDLE</type>(<name>VkDescriptorSet</name>)</type>
+ <type category="handle" parent="VkDevice" objtypeenum="VK_OBJECT_TYPE_DESCRIPTOR_SET_LAYOUT"><type>VK_DEFINE_NON_DISPATCHABLE_HANDLE</type>(<name>VkDescriptorSetLayout</name>)</type>
+ <type category="handle" parent="VkDevice" objtypeenum="VK_OBJECT_TYPE_DESCRIPTOR_POOL"><type>VK_DEFINE_NON_DISPATCHABLE_HANDLE</type>(<name>VkDescriptorPool</name>)</type>
+ <type category="handle" parent="VkDevice" objtypeenum="VK_OBJECT_TYPE_FENCE"><type>VK_DEFINE_NON_DISPATCHABLE_HANDLE</type>(<name>VkFence</name>)</type>
+ <type category="handle" parent="VkDevice" objtypeenum="VK_OBJECT_TYPE_SEMAPHORE"><type>VK_DEFINE_NON_DISPATCHABLE_HANDLE</type>(<name>VkSemaphore</name>)</type>
+ <type category="handle" parent="VkDevice" objtypeenum="VK_OBJECT_TYPE_EVENT"><type>VK_DEFINE_NON_DISPATCHABLE_HANDLE</type>(<name>VkEvent</name>)</type>
+ <type category="handle" parent="VkDevice" objtypeenum="VK_OBJECT_TYPE_QUERY_POOL"><type>VK_DEFINE_NON_DISPATCHABLE_HANDLE</type>(<name>VkQueryPool</name>)</type>
+ <type category="handle" parent="VkDevice" objtypeenum="VK_OBJECT_TYPE_FRAMEBUFFER"><type>VK_DEFINE_NON_DISPATCHABLE_HANDLE</type>(<name>VkFramebuffer</name>)</type>
+ <type category="handle" parent="VkDevice" objtypeenum="VK_OBJECT_TYPE_RENDER_PASS"><type>VK_DEFINE_NON_DISPATCHABLE_HANDLE</type>(<name>VkRenderPass</name>)</type>
+ <type category="handle" parent="VkDevice" objtypeenum="VK_OBJECT_TYPE_PIPELINE_CACHE"><type>VK_DEFINE_NON_DISPATCHABLE_HANDLE</type>(<name>VkPipelineCache</name>)</type>
+ <type category="handle" parent="VkDevice" objtypeenum="VK_OBJECT_TYPE_INDIRECT_COMMANDS_LAYOUT_NV"><type>VK_DEFINE_NON_DISPATCHABLE_HANDLE</type>(<name>VkIndirectCommandsLayoutNV</name>)</type>
+ <type category="handle" parent="VkDevice" objtypeenum="VK_OBJECT_TYPE_DESCRIPTOR_UPDATE_TEMPLATE"><type>VK_DEFINE_NON_DISPATCHABLE_HANDLE</type>(<name>VkDescriptorUpdateTemplate</name>)</type>
+ <type category="handle" name="VkDescriptorUpdateTemplateKHR" alias="VkDescriptorUpdateTemplate"/>
+ <type category="handle" parent="VkDevice" objtypeenum="VK_OBJECT_TYPE_SAMPLER_YCBCR_CONVERSION"><type>VK_DEFINE_NON_DISPATCHABLE_HANDLE</type>(<name>VkSamplerYcbcrConversion</name>)</type>
+ <type category="handle" name="VkSamplerYcbcrConversionKHR" alias="VkSamplerYcbcrConversion"/>
+ <type category="handle" parent="VkDevice" objtypeenum="VK_OBJECT_TYPE_VALIDATION_CACHE_EXT"><type>VK_DEFINE_NON_DISPATCHABLE_HANDLE</type>(<name>VkValidationCacheEXT</name>)</type>
+ <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_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_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>
+
+ <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="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>
+
+ <comment>Video extensions</comment>
+ <type category="handle" parent="VkDevice" objtypeenum="VK_OBJECT_TYPE_VIDEO_SESSION_KHR"><type>VK_DEFINE_NON_DISPATCHABLE_HANDLE</type>(<name>VkVideoSessionKHR</name>)</type>
+ <type category="handle" parent="VkVideoSessionKHR" objtypeenum="VK_OBJECT_TYPE_VIDEO_SESSION_PARAMETERS_KHR"><type>VK_DEFINE_NON_DISPATCHABLE_HANDLE</type>(<name>VkVideoSessionParametersKHR</name>)</type>
+
+ <comment>Types generated from corresponding enums tags below</comment>
+ <type name="VkAttachmentLoadOp" category="enum"/>
+ <type name="VkAttachmentStoreOp" category="enum"/>
+ <type name="VkBlendFactor" category="enum"/>
+ <type name="VkBlendOp" category="enum"/>
+ <type name="VkBorderColor" category="enum"/>
+ <type name="VkFramebufferCreateFlagBits" category="enum"/>
+ <type name="VkQueryPoolCreateFlagBits" category="enum"/>
+ <type name="VkRenderPassCreateFlagBits" category="enum"/>
+ <type name="VkSamplerCreateFlagBits" category="enum"/>
+ <type name="VkPipelineCacheHeaderVersion" category="enum"/>
+ <type name="VkPipelineCacheCreateFlagBits" category="enum"/>
+ <type name="VkPipelineShaderStageCreateFlagBits" category="enum"/>
+ <type name="VkDescriptorSetLayoutCreateFlagBits" category="enum"/>
+ <type name="VkInstanceCreateFlagBits" category="enum"/>
+ <type name="VkDeviceQueueCreateFlagBits" category="enum"/>
+ <type name="VkBufferCreateFlagBits" category="enum"/>
+ <type name="VkBufferUsageFlagBits" category="enum"/>
+ <type name="VkColorComponentFlagBits" category="enum"/>
+ <type name="VkComponentSwizzle" category="enum"/>
+ <type name="VkCommandPoolCreateFlagBits" category="enum"/>
+ <type name="VkCommandPoolResetFlagBits" category="enum"/>
+ <type name="VkCommandBufferResetFlagBits" category="enum"/>
+ <type name="VkCommandBufferLevel" category="enum"/>
+ <type name="VkCommandBufferUsageFlagBits" category="enum"/>
+ <type name="VkCompareOp" category="enum"/>
+ <type name="VkCullModeFlagBits" category="enum"/>
+ <type name="VkDescriptorType" category="enum"/>
+ <type name="VkDeviceCreateFlagBits" category="enum"/>
+ <type name="VkDynamicState" category="enum"/>
+ <type name="VkFenceCreateFlagBits" category="enum"/>
+ <type name="VkPolygonMode" category="enum"/>
+ <type name="VkFormat" category="enum"/>
+ <type name="VkFormatFeatureFlagBits" category="enum"/>
+ <type name="VkFrontFace" category="enum"/>
+ <type name="VkImageAspectFlagBits" category="enum"/>
+ <type name="VkImageCreateFlagBits" category="enum"/>
+ <type name="VkImageLayout" category="enum"/>
+ <type name="VkImageTiling" category="enum"/>
+ <type name="VkImageType" category="enum"/>
+ <type name="VkImageUsageFlagBits" category="enum"/>
+ <type name="VkImageViewCreateFlagBits" category="enum"/>
+ <type name="VkImageViewType" category="enum"/>
+ <type name="VkSharingMode" category="enum"/>
+ <type name="VkIndexType" category="enum"/>
+ <type name="VkLogicOp" category="enum"/>
+ <type name="VkMemoryHeapFlagBits" category="enum"/>
+ <type name="VkAccessFlagBits" category="enum"/>
+ <type name="VkMemoryPropertyFlagBits" category="enum"/>
+ <type name="VkPhysicalDeviceType" category="enum"/>
+ <type name="VkPipelineBindPoint" category="enum"/>
+ <type name="VkPipelineCreateFlagBits" category="enum"/>
+ <type name="VkPrimitiveTopology" category="enum"/>
+ <type name="VkQueryControlFlagBits" category="enum"/>
+ <type name="VkQueryPipelineStatisticFlagBits" category="enum"/>
+ <type name="VkQueryResultFlagBits" category="enum"/>
+ <type name="VkQueryType" category="enum"/>
+ <type name="VkQueueFlagBits" category="enum"/>
+ <type name="VkSubpassContents" category="enum"/>
+ <type name="VkResult" category="enum"/>
+ <type name="VkShaderStageFlagBits" category="enum"/>
+ <type name="VkSparseMemoryBindFlagBits" category="enum"/>
+ <type name="VkStencilFaceFlagBits" category="enum"/>
+ <type name="VkStencilOp" category="enum"/>
+ <type name="VkStructureType" category="enum"/>
+ <type name="VkSystemAllocationScope" category="enum"/>
+ <type name="VkInternalAllocationType" category="enum"/>
+ <type name="VkSamplerAddressMode" category="enum"/>
+ <type name="VkFilter" category="enum"/>
+ <type name="VkSamplerMipmapMode" category="enum"/>
+ <type name="VkVertexInputRate" category="enum"/>
+ <type name="VkPipelineStageFlagBits" category="enum"/>
+ <type name="VkSparseImageFormatFlagBits" category="enum"/>
+ <type name="VkSampleCountFlagBits" category="enum"/>
+ <type name="VkAttachmentDescriptionFlagBits" category="enum"/>
+ <type name="VkDescriptorPoolCreateFlagBits" category="enum"/>
+ <type name="VkDependencyFlagBits" category="enum"/>
+ <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>
+
+ <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="VkDescriptorUpdateTemplateType" category="enum"/>
+ <type category="enum" name="VkDescriptorUpdateTemplateTypeKHR" alias="VkDescriptorUpdateTemplateType"/>
+ <type name="VkViewportCoordinateSwizzleNV" category="enum"/>
+ <type name="VkDiscardRectangleModeEXT" category="enum"/>
+ <type name="VkSubpassDescriptionFlagBits" category="enum"/>
+ <type name="VkPointClippingBehavior" category="enum"/>
+ <type category="enum" name="VkPointClippingBehaviorKHR" alias="VkPointClippingBehavior"/>
+ <type name="VkCoverageModulationModeNV" category="enum"/>
+ <type name="VkCoverageReductionModeNV" category="enum"/>
+ <type name="VkValidationCacheHeaderVersionEXT" category="enum"/>
+ <type name="VkShaderInfoTypeAMD" category="enum"/>
+ <type name="VkQueueGlobalPriorityEXT" category="enum"/>
+ <type name="VkTimeDomainEXT" category="enum"/>
+ <type name="VkConservativeRasterizationModeEXT" category="enum"/>
+ <type name="VkResolveModeFlagBits" category="enum"/>
+ <type category="enum" name="VkResolveModeFlagBitsKHR" alias="VkResolveModeFlagBits"/>
+ <type name="VkDescriptorBindingFlagBits" category="enum"/>
+ <type category="enum" name="VkDescriptorBindingFlagBitsEXT" alias="VkDescriptorBindingFlagBits"/>
+ <type name="VkConditionalRenderingFlagBitsEXT" category="enum"/>
+ <type name="VkSemaphoreType" category="enum"/>
+ <type category="enum" name="VkSemaphoreTypeKHR" alias="VkSemaphoreType"/>
+ <type name="VkGeometryFlagBitsKHR" category="enum"/>
+ <type category="enum" name="VkGeometryFlagBitsNV" alias="VkGeometryFlagBitsKHR"/>
+ <type name="VkGeometryInstanceFlagBitsKHR" category="enum"/>
+ <type category="enum" name="VkGeometryInstanceFlagBitsNV" alias="VkGeometryInstanceFlagBitsKHR"/>
+ <type name="VkBuildAccelerationStructureFlagBitsKHR" category="enum"/>
+ <type category="enum" name="VkBuildAccelerationStructureFlagBitsNV" alias="VkBuildAccelerationStructureFlagBitsKHR"/>
+ <type name="VkAccelerationStructureCreateFlagBitsKHR" category="enum"/>
+ <type name="VkBuildAccelerationStructureModeKHR" category="enum"/>
+ <type name="VkCopyAccelerationStructureModeKHR" category="enum"/>
+ <type category="enum" name="VkCopyAccelerationStructureModeNV" alias="VkCopyAccelerationStructureModeKHR"/>
+ <type name="VkAccelerationStructureTypeKHR" category="enum"/>
+ <type category="enum" name="VkAccelerationStructureTypeNV" alias="VkAccelerationStructureTypeKHR"/>
+ <type name="VkGeometryTypeKHR" category="enum"/>
+ <type category="enum" name="VkGeometryTypeNV" alias="VkGeometryTypeKHR"/>
+ <type name="VkRayTracingShaderGroupTypeKHR" category="enum"/>
+ <type category="enum" name="VkRayTracingShaderGroupTypeNV" alias="VkRayTracingShaderGroupTypeKHR"/>
+ <type name="VkAccelerationStructureMemoryRequirementsTypeNV" category="enum"/>
+ <type name="VkAccelerationStructureBuildTypeKHR" category="enum"/>
+ <type name="VkAccelerationStructureCompatibilityKHR" category="enum"/>
+ <type name="VkShaderGroupShaderKHR" category="enum"/>
+ <type name="VkMemoryOverallocationBehaviorAMD" category="enum"/>
+ <type name="VkScopeNV" category="enum"/>
+ <type name="VkComponentTypeNV" category="enum"/>
+ <type name="VkDeviceDiagnosticsConfigFlagBitsNV" category="enum"/>
+ <type name="VkPipelineCreationFeedbackFlagBitsEXT" category="enum"/>
+ <type name="VkPerformanceCounterScopeKHR" category="enum"/>
+ <type name="VkPerformanceCounterUnitKHR" category="enum"/>
+ <type name="VkPerformanceCounterStorageKHR" category="enum"/>
+ <type name="VkPerformanceCounterDescriptionFlagBitsKHR" category="enum"/>
+ <type name="VkAcquireProfilingLockFlagBitsKHR" category="enum"/>
+ <type name="VkSemaphoreWaitFlagBits" category="enum"/>
+ <type category="enum" name="VkSemaphoreWaitFlagBitsKHR" alias="VkSemaphoreWaitFlagBits"/>
+ <type name="VkPerformanceConfigurationTypeINTEL" category="enum"/>
+ <type name="VkQueryPoolSamplingModeINTEL" category="enum"/>
+ <type name="VkPerformanceOverrideTypeINTEL" category="enum"/>
+ <type name="VkPerformanceParameterTypeINTEL" category="enum"/>
+ <type name="VkPerformanceValueTypeINTEL" category="enum"/>
+ <type name="VkLineRasterizationModeEXT" category="enum"/>
+ <type name="VkShaderModuleCreateFlagBits" category="enum"/>
+ <type name="VkPipelineCompilerControlFlagBitsAMD" category="enum"/>
+ <type name="VkShaderCorePropertiesFlagBitsAMD" category="enum"/>
+ <type name="VkToolPurposeFlagBitsEXT" category="enum"/>
+ <type name="VkFragmentShadingRateNV" category="enum"/>
+ <type name="VkFragmentShadingRateTypeNV" category="enum"/>
+ <type name="VkAccessFlagBits2KHR" category="enum"/>
+ <type name="VkPipelineStageFlagBits2KHR" category="enum"/>
+ <type name="VkProvokingVertexModeEXT" category="enum"/>
+
+ <comment>WSI extensions</comment>
+ <type name="VkColorSpaceKHR" category="enum"/>
+ <type name="VkCompositeAlphaFlagBitsKHR" category="enum"/>
+ <type name="VkDisplayPlaneAlphaFlagBitsKHR" category="enum"/>
+ <type name="VkPresentModeKHR" category="enum"/>
+ <type name="VkSurfaceTransformFlagBitsKHR" category="enum"/>
+ <type name="VkDebugReportFlagBitsEXT" category="enum"/>
+ <type name="VkDebugReportObjectTypeEXT" category="enum"/>
+ <type name="VkDeviceMemoryReportEventTypeEXT" category="enum"/>
+ <type name="VkRasterizationOrderAMD" category="enum"/>
+ <type name="VkExternalMemoryHandleTypeFlagBitsNV" category="enum"/>
+ <type name="VkExternalMemoryFeatureFlagBitsNV" category="enum"/>
+ <type name="VkValidationCheckEXT" category="enum"/>
+ <type name="VkValidationFeatureEnableEXT" category="enum"/>
+ <type name="VkValidationFeatureDisableEXT" category="enum"/>
+ <type name="VkExternalMemoryHandleTypeFlagBits" category="enum"/>
+ <type category="enum" name="VkExternalMemoryHandleTypeFlagBitsKHR" alias="VkExternalMemoryHandleTypeFlagBits"/>
+ <type name="VkExternalMemoryFeatureFlagBits" category="enum"/>
+ <type category="enum" name="VkExternalMemoryFeatureFlagBitsKHR" alias="VkExternalMemoryFeatureFlagBits"/>
+ <type name="VkExternalSemaphoreHandleTypeFlagBits" category="enum"/>
+ <type category="enum" name="VkExternalSemaphoreHandleTypeFlagBitsKHR" alias="VkExternalSemaphoreHandleTypeFlagBits"/>
+ <type name="VkExternalSemaphoreFeatureFlagBits" category="enum"/>
+ <type category="enum" name="VkExternalSemaphoreFeatureFlagBitsKHR" alias="VkExternalSemaphoreFeatureFlagBits"/>
+ <type name="VkSemaphoreImportFlagBits" category="enum"/>
+ <type category="enum" name="VkSemaphoreImportFlagBitsKHR" alias="VkSemaphoreImportFlagBits"/>
+ <type name="VkExternalFenceHandleTypeFlagBits" category="enum"/>
+ <type category="enum" name="VkExternalFenceHandleTypeFlagBitsKHR" alias="VkExternalFenceHandleTypeFlagBits"/>
+ <type name="VkExternalFenceFeatureFlagBits" category="enum"/>
+ <type category="enum" name="VkExternalFenceFeatureFlagBitsKHR" alias="VkExternalFenceFeatureFlagBits"/>
+ <type name="VkFenceImportFlagBits" category="enum"/>
+ <type category="enum" name="VkFenceImportFlagBitsKHR" alias="VkFenceImportFlagBits"/>
+ <type name="VkSurfaceCounterFlagBitsEXT" category="enum"/>
+ <type name="VkDisplayPowerStateEXT" category="enum"/>
+ <type name="VkDeviceEventTypeEXT" category="enum"/>
+ <type name="VkDisplayEventTypeEXT" category="enum"/>
+ <type name="VkPeerMemoryFeatureFlagBits" category="enum"/>
+ <type category="enum" name="VkPeerMemoryFeatureFlagBitsKHR" alias="VkPeerMemoryFeatureFlagBits"/>
+ <type name="VkMemoryAllocateFlagBits" category="enum"/>
+ <type category="enum" name="VkMemoryAllocateFlagBitsKHR" alias="VkMemoryAllocateFlagBits"/>
+ <type name="VkDeviceGroupPresentModeFlagBitsKHR" category="enum"/>
+ <type name="VkSwapchainCreateFlagBitsKHR" category="enum"/>
+ <type name="VkSubgroupFeatureFlagBits" category="enum"/>
+ <type name="VkTessellationDomainOrigin" category="enum"/>
+ <type category="enum" name="VkTessellationDomainOriginKHR" alias="VkTessellationDomainOrigin"/>
+ <type name="VkSamplerYcbcrModelConversion" category="enum"/>
+ <type category="enum" name="VkSamplerYcbcrModelConversionKHR" alias="VkSamplerYcbcrModelConversion"/>
+ <type name="VkSamplerYcbcrRange" category="enum"/>
+ <type category="enum" name="VkSamplerYcbcrRangeKHR" alias="VkSamplerYcbcrRange"/>
+ <type name="VkChromaLocation" category="enum"/>
+ <type category="enum" name="VkChromaLocationKHR" alias="VkChromaLocation"/>
+ <type name="VkSamplerReductionMode" category="enum"/>
+ <type category="enum" name="VkSamplerReductionModeEXT" alias="VkSamplerReductionMode"/>
+ <type name="VkBlendOverlapEXT" category="enum"/>
+ <type name="VkDebugUtilsMessageSeverityFlagBitsEXT" category="enum"/>
+ <type name="VkDebugUtilsMessageTypeFlagBitsEXT" category="enum"/>
+ <type name="VkFullScreenExclusiveEXT" category="enum"/>
+ <type name="VkShaderFloatControlsIndependence" category="enum"/>
+ <type category="enum" name="VkShaderFloatControlsIndependenceKHR" alias="VkShaderFloatControlsIndependence"/>
+ <type name="VkSwapchainImageUsageFlagBitsANDROID" category="enum"/>
+ <type name="VkFragmentShadingRateCombinerOpKHR" category="enum"/>
+ <type name="VkSubmitFlagBitsKHR" category="enum"/>
+
+ <comment>Enumerated types in the header, but not used by the API</comment>
+ <type name="VkVendorId" category="enum"/>
+ <type name="VkDriverId" category="enum"/>
+ <type category="enum" name="VkDriverIdKHR" alias="VkDriverId"/>
+ <type name="VkShadingRatePaletteEntryNV" category="enum"/>
+ <type name="VkCoarseSampleOrderTypeNV" category="enum"/>
+ <type name="VkPipelineExecutableStatisticFormatKHR" category="enum"/>
+
+ <comment>Video Core extensions</comment>
+ <type name="VkVideoCodecOperationFlagBitsKHR" category="enum"/>
+ <type name="VkVideoChromaSubsamplingFlagBitsKHR" category="enum"/>
+ <type name="VkVideoComponentBitDepthFlagBitsKHR" category="enum"/>
+ <type name="VkVideoCapabilitiesFlagBitsKHR" 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"/>
+
+ <comment>Video H.264 Decode extensions</comment>
+ <type name="VkVideoDecodeH264FieldLayoutFlagBitsEXT" 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="VkVideoEncodeRateControlModeFlagBitsKHR" category="enum"/>
+
+ <comment>Video H.264 Encode extensions</comment>
+ <type name="VkVideoEncodeH264CapabilitiesFlagBitsEXT" category="enum"/>
+ <type name="VkVideoEncodeH264InputModeFlagBitsEXT" category="enum"/>
+ <type name="VkVideoEncodeH264OutputModeFlagBitsEXT" category="enum"/>
+ <type name="VkVideoEncodeH264CreateFlagBitsEXT" 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>)(
+ <type>void</type>* pUserData,
+ <type>size_t</type> size,
+ <type>VkInternalAllocationType</type> allocationType,
+ <type>VkSystemAllocationScope</type> allocationScope);</type>
+ <type category="funcpointer">typedef void (VKAPI_PTR *<name>PFN_vkInternalFreeNotification</name>)(
+ <type>void</type>* pUserData,
+ <type>size_t</type> size,
+ <type>VkInternalAllocationType</type> allocationType,
+ <type>VkSystemAllocationScope</type> allocationScope);</type>
+ <type category="funcpointer">typedef void* (VKAPI_PTR *<name>PFN_vkReallocationFunction</name>)(
+ <type>void</type>* pUserData,
+ <type>void</type>* pOriginal,
+ <type>size_t</type> size,
+ <type>size_t</type> alignment,
+ <type>VkSystemAllocationScope</type> allocationScope);</type>
+ <type category="funcpointer">typedef void* (VKAPI_PTR *<name>PFN_vkAllocationFunction</name>)(
+ <type>void</type>* pUserData,
+ <type>size_t</type> size,
+ <type>size_t</type> alignment,
+ <type>VkSystemAllocationScope</type> allocationScope);</type>
+ <type category="funcpointer">typedef void (VKAPI_PTR *<name>PFN_vkFreeFunction</name>)(
+ <type>void</type>* pUserData,
+ <type>void</type>* pMemory);</type>
+
+ <comment>The PFN_vkVoidFunction type are used by VkGet*ProcAddr below</comment>
+ <type category="funcpointer">typedef void (VKAPI_PTR *<name>PFN_vkVoidFunction</name>)(void);</type>
+
+ <comment>The PFN_vkDebugReportCallbackEXT type are used by the DEBUG_REPORT extension</comment>
+ <type category="funcpointer">typedef VkBool32 (VKAPI_PTR *<name>PFN_vkDebugReportCallbackEXT</name>)(
+ <type>VkDebugReportFlagsEXT</type> flags,
+ <type>VkDebugReportObjectTypeEXT</type> objectType,
+ <type>uint64_t</type> object,
+ <type>size_t</type> location,
+ <type>int32_t</type> messageCode,
+ const <type>char</type>* pLayerPrefix,
+ const <type>char</type>* pMessage,
+ <type>void</type>* pUserData);</type>
+
+ <comment>The PFN_vkDebugUtilsMessengerCallbackEXT type are used by the VK_EXT_debug_utils extension</comment>
+ <type category="funcpointer" requires="VkDebugUtilsMessengerCallbackDataEXT">typedef VkBool32 (VKAPI_PTR *<name>PFN_vkDebugUtilsMessengerCallbackEXT</name>)(
+ <type>VkDebugUtilsMessageSeverityFlagBitsEXT</type> messageSeverity,
+ <type>VkDebugUtilsMessageTypeFlagsEXT</type> messageTypes,
+ const <type>VkDebugUtilsMessengerCallbackDataEXT</type>* pCallbackData,
+ <type>void</type>* pUserData);</type>
+
+ <comment>The PFN_vkDeviceMemoryReportCallbackEXT type is used by the VK_EXT_device_memory_report extension</comment>
+ <type category="funcpointer" requires="VkDeviceMemoryReportCallbackDataEXT">typedef void (VKAPI_PTR *<name>PFN_vkDeviceMemoryReportCallbackEXT</name>)(
+ const <type>VkDeviceMemoryReportCallbackDataEXT</type>* pCallbackData,
+ <type>void</type>* pUserData);</type>
+
+ <comment>Struct types</comment>
+ <type category="struct" name="VkBaseOutStructure">
+ <member><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">struct <type>VkBaseOutStructure</type>* <name>pNext</name></member>
+ </type>
+ <type category="struct" name="VkBaseInStructure">
+ <member><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const struct <type>VkBaseInStructure</type>* <name>pNext</name></member>
+ </type>
+ <type category="struct" name="VkOffset2D">
+ <member><type>int32_t</type> <name>x</name></member>
+ <member><type>int32_t</type> <name>y</name></member>
+ </type>
+ <type category="struct" name="VkOffset3D">
+ <member><type>int32_t</type> <name>x</name></member>
+ <member><type>int32_t</type> <name>y</name></member>
+ <member><type>int32_t</type> <name>z</name></member>
+ </type>
+ <type category="struct" name="VkExtent2D">
+ <member><type>uint32_t</type> <name>width</name></member>
+ <member><type>uint32_t</type> <name>height</name></member>
+ </type>
+ <type category="struct" name="VkExtent3D">
+ <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="VkViewport">
+ <member noautovalidity="true"><type>float</type> <name>x</name></member>
+ <member noautovalidity="true"><type>float</type> <name>y</name></member>
+ <member noautovalidity="true"><type>float</type> <name>width</name></member>
+ <member noautovalidity="true"><type>float</type> <name>height</name></member>
+ <member><type>float</type> <name>minDepth</name></member>
+ <member><type>float</type> <name>maxDepth</name></member>
+ </type>
+ <type category="struct" name="VkRect2D">
+ <member><type>VkOffset2D</type> <name>offset</name></member>
+ <member><type>VkExtent2D</type> <name>extent</name></member>
+ </type>
+ <type category="struct" name="VkClearRect">
+ <member><type>VkRect2D</type> <name>rect</name></member>
+ <member><type>uint32_t</type> <name>baseArrayLayer</name></member>
+ <member><type>uint32_t</type> <name>layerCount</name></member>
+ </type>
+ <type category="struct" name="VkComponentMapping">
+ <member><type>VkComponentSwizzle</type> <name>r</name></member>
+ <member><type>VkComponentSwizzle</type> <name>g</name></member>
+ <member><type>VkComponentSwizzle</type> <name>b</name></member>
+ <member><type>VkComponentSwizzle</type> <name>a</name></member>
+ </type>
+ <type category="struct" name="VkPhysicalDeviceProperties" returnedonly="true">
+ <member limittype="noauto"><type>uint32_t</type> <name>apiVersion</name></member>
+ <member limittype="noauto"><type>uint32_t</type> <name>driverVersion</name></member>
+ <member limittype="noauto"><type>uint32_t</type> <name>vendorID</name></member>
+ <member limittype="noauto"><type>uint32_t</type> <name>deviceID</name></member>
+ <member limittype="noauto"><type>VkPhysicalDeviceType</type> <name>deviceType</name></member>
+ <member limittype="noauto"><type>char</type> <name>deviceName</name>[<enum>VK_MAX_PHYSICAL_DEVICE_NAME_SIZE</enum>]</member>
+ <member limittype="noauto"><type>uint8_t</type> <name>pipelineCacheUUID</name>[<enum>VK_UUID_SIZE</enum>]</member>
+ <member limittype="struct"><type>VkPhysicalDeviceLimits</type> <name>limits</name></member>
+ <member limittype="struct"><type>VkPhysicalDeviceSparseProperties</type> <name>sparseProperties</name></member>
+ </type>
+ <type category="struct" name="VkExtensionProperties" returnedonly="true">
+ <member><type>char</type> <name>extensionName</name>[<enum>VK_MAX_EXTENSION_NAME_SIZE</enum>]<comment>extension name</comment></member>
+ <member><type>uint32_t</type> <name>specVersion</name><comment>version of the extension specification implemented</comment></member>
+ </type>
+ <type category="struct" name="VkLayerProperties" returnedonly="true">
+ <member><type>char</type> <name>layerName</name>[<enum>VK_MAX_EXTENSION_NAME_SIZE</enum>]<comment>layer name</comment></member>
+ <member><type>uint32_t</type> <name>specVersion</name><comment>version of the layer specification implemented</comment></member>
+ <member><type>uint32_t</type> <name>implementationVersion</name><comment>build or release version of the layer's library</comment></member>
+ <member><type>char</type> <name>description</name>[<enum>VK_MAX_DESCRIPTION_SIZE</enum>]<comment>Free-form description of the layer</comment></member>
+ </type>
+ <type category="struct" name="VkApplicationInfo">
+ <member values="VK_STRUCTURE_TYPE_APPLICATION_INFO"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member optional="true" len="null-terminated">const <type>char</type>* <name>pApplicationName</name></member>
+ <member><type>uint32_t</type> <name>applicationVersion</name></member>
+ <member optional="true" len="null-terminated">const <type>char</type>* <name>pEngineName</name></member>
+ <member><type>uint32_t</type> <name>engineVersion</name></member>
+ <member><type>uint32_t</type> <name>apiVersion</name></member>
+ </type>
+ <type category="struct" name="VkAllocationCallbacks">
+ <member optional="true"><type>void</type>* <name>pUserData</name></member>
+ <member noautovalidity="true"><type>PFN_vkAllocationFunction</type> <name>pfnAllocation</name></member>
+ <member noautovalidity="true"><type>PFN_vkReallocationFunction</type> <name>pfnReallocation</name></member>
+ <member noautovalidity="true"><type>PFN_vkFreeFunction</type> <name>pfnFree</name></member>
+ <member optional="true" noautovalidity="true"><type>PFN_vkInternalAllocationNotification</type> <name>pfnInternalAllocation</name></member>
+ <member optional="true" noautovalidity="true"><type>PFN_vkInternalFreeNotification</type> <name>pfnInternalFree</name></member>
+ </type>
+ <type category="struct" name="VkDeviceQueueCreateInfo">
+ <member values="VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member optional="true"><type>VkDeviceQueueCreateFlags</type> <name>flags</name></member>
+ <member><type>uint32_t</type> <name>queueFamilyIndex</name></member>
+ <member><type>uint32_t</type> <name>queueCount</name></member>
+ <member len="queueCount">const <type>float</type>* <name>pQueuePriorities</name></member>
+ </type>
+ <type category="struct" name="VkDeviceCreateInfo">
+ <member values="VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member optional="true"><type>VkDeviceCreateFlags</type> <name>flags</name></member>
+ <member><type>uint32_t</type> <name>queueCreateInfoCount</name></member>
+ <member len="queueCreateInfoCount">const <type>VkDeviceQueueCreateInfo</type>* <name>pQueueCreateInfos</name></member>
+ <member optional="true"><type>uint32_t</type> <name>enabledLayerCount</name></member>
+ <member len="enabledLayerCount,null-terminated">const <type>char</type>* const* <name>ppEnabledLayerNames</name><comment>Ordered list of layer names to be enabled</comment></member>
+ <member optional="true"><type>uint32_t</type> <name>enabledExtensionCount</name></member>
+ <member len="enabledExtensionCount,null-terminated">const <type>char</type>* const* <name>ppEnabledExtensionNames</name></member>
+ <member optional="true">const <type>VkPhysicalDeviceFeatures</type>* <name>pEnabledFeatures</name></member>
+ </type>
+ <type category="struct" name="VkInstanceCreateInfo">
+ <member values="VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member optional="true"><type>VkInstanceCreateFlags</type> <name>flags</name></member>
+ <member optional="true">const <type>VkApplicationInfo</type>* <name>pApplicationInfo</name></member>
+ <member optional="true"><type>uint32_t</type> <name>enabledLayerCount</name></member>
+ <member len="enabledLayerCount,null-terminated">const <type>char</type>* const* <name>ppEnabledLayerNames</name><comment>Ordered list of layer names to be enabled</comment></member>
+ <member optional="true"><type>uint32_t</type> <name>enabledExtensionCount</name></member>
+ <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>
+ </type>
+ <type category="struct" name="VkPhysicalDeviceMemoryProperties" returnedonly="true">
+ <member><type>uint32_t</type> <name>memoryTypeCount</name></member>
+ <member><type>VkMemoryType</type> <name>memoryTypes</name>[<enum>VK_MAX_MEMORY_TYPES</enum>]</member>
+ <member><type>uint32_t</type> <name>memoryHeapCount</name></member>
+ <member><type>VkMemoryHeap</type> <name>memoryHeaps</name>[<enum>VK_MAX_MEMORY_HEAPS</enum>]</member>
+ </type>
+ <type category="struct" name="VkMemoryAllocateInfo">
+ <member values="VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member><type>VkDeviceSize</type> <name>allocationSize</name><comment>Size of memory allocation</comment></member>
+ <member><type>uint32_t</type> <name>memoryTypeIndex</name><comment>Index of the of the memory type to allocate from</comment></member>
+ </type>
+ <type category="struct" name="VkMemoryRequirements" returnedonly="true">
+ <member><type>VkDeviceSize</type> <name>size</name><comment>Specified in bytes</comment></member>
+ <member><type>VkDeviceSize</type> <name>alignment</name><comment>Specified in bytes</comment></member>
+ <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>
+ </type>
+ <type category="struct" name="VkSparseImageMemoryRequirements" returnedonly="true">
+ <member><type>VkSparseImageFormatProperties</type> <name>formatProperties</name></member>
+ <member><type>uint32_t</type> <name>imageMipTailFirstLod</name></member>
+ <member><type>VkDeviceSize</type> <name>imageMipTailSize</name><comment>Specified in bytes, must be a multiple of sparse block size in bytes / alignment</comment></member>
+ <member><type>VkDeviceSize</type> <name>imageMipTailOffset</name><comment>Specified in bytes, must be a multiple of sparse block size in bytes / alignment</comment></member>
+ <member><type>VkDeviceSize</type> <name>imageMipTailStride</name><comment>Specified in bytes, must be a multiple of sparse block size in bytes / alignment</comment></member>
+ </type>
+ <type category="struct" name="VkMemoryType" returnedonly="true">
+ <member optional="true"><type>VkMemoryPropertyFlags</type> <name>propertyFlags</name><comment>Memory properties of this memory type</comment></member>
+ <member><type>uint32_t</type> <name>heapIndex</name><comment>Index of the memory heap allocations of this memory type are taken from</comment></member>
+ </type>
+ <type category="struct" name="VkMemoryHeap" returnedonly="true">
+ <member><type>VkDeviceSize</type> <name>size</name><comment>Available memory in the heap</comment></member>
+ <member optional="true"><type>VkMemoryHeapFlags</type> <name>flags</name><comment>Flags for the heap</comment></member>
+ </type>
+ <type category="struct" name="VkMappedMemoryRange">
+ <member values="VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE"><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><comment>Mapped memory object</comment></member>
+ <member><type>VkDeviceSize</type> <name>offset</name><comment>Offset within the memory object where the range starts</comment></member>
+ <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>
+ </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>
+ <member><type>uint32_t</type> <name>maxMipLevels</name><comment>max number of mipmap levels for this resource type</comment></member>
+ <member><type>uint32_t</type> <name>maxArrayLayers</name><comment>max array size for this resource type</comment></member>
+ <member optional="true"><type>VkSampleCountFlags</type> <name>sampleCounts</name><comment>supported sample counts for this resource type</comment></member>
+ <member><type>VkDeviceSize</type> <name>maxResourceSize</name><comment>max size (in bytes) of this resource type</comment></member>
+ </type>
+ <type category="struct" name="VkDescriptorBufferInfo">
+ <member optional="true"><type>VkBuffer</type> <name>buffer</name><comment>Buffer used for this descriptor slot.</comment></member>
+ <member><type>VkDeviceSize</type> <name>offset</name><comment>Base offset from buffer start in bytes to update in the descriptor set.</comment></member>
+ <member><type>VkDeviceSize</type> <name>range</name><comment>Size in bytes of the buffer resource for this descriptor update.</comment></member>
+ </type>
+ <type category="struct" name="VkDescriptorImageInfo">
+ <member noautovalidity="true"><type>VkSampler</type> <name>sampler</name><comment>Sampler to write to the descriptor in case it is a SAMPLER or COMBINED_IMAGE_SAMPLER descriptor. Ignored otherwise.</comment></member>
+ <member noautovalidity="true"><type>VkImageView</type> <name>imageView</name><comment>Image view to write to the descriptor in case it is a SAMPLED_IMAGE, STORAGE_IMAGE, COMBINED_IMAGE_SAMPLER, or INPUT_ATTACHMENT descriptor. Ignored otherwise.</comment></member>
+ <member noautovalidity="true"><type>VkImageLayout</type> <name>imageLayout</name><comment>Layout the image is expected to be in when accessed using this descriptor (only used if imageView is not VK_NULL_HANDLE).</comment></member>
+ </type>
+ <type category="struct" name="VkWriteDescriptorSet">
+ <member values="VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member noautovalidity="true"><type>VkDescriptorSet</type> <name>dstSet</name><comment>Destination descriptor set</comment></member>
+ <member><type>uint32_t</type> <name>dstBinding</name><comment>Binding within the destination descriptor set to write</comment></member>
+ <member><type>uint32_t</type> <name>dstArrayElement</name><comment>Array element within the destination binding to write</comment></member>
+ <member><type>uint32_t</type> <name>descriptorCount</name><comment>Number of descriptors to write (determines the size of the array pointed by pDescriptors)</comment></member>
+ <member><type>VkDescriptorType</type> <name>descriptorType</name><comment>Descriptor type to write (determines which members of the array pointed by pDescriptors are going to be used)</comment></member>
+ <member noautovalidity="true" len="descriptorCount">const <type>VkDescriptorImageInfo</type>* <name>pImageInfo</name><comment>Sampler, image view, and layout for SAMPLER, COMBINED_IMAGE_SAMPLER, {SAMPLED,STORAGE}_IMAGE, and INPUT_ATTACHMENT descriptor types.</comment></member>
+ <member noautovalidity="true" len="descriptorCount">const <type>VkDescriptorBufferInfo</type>* <name>pBufferInfo</name><comment>Raw buffer, size, and offset for {UNIFORM,STORAGE}_BUFFER[_DYNAMIC] descriptor types.</comment></member>
+ <member noautovalidity="true" len="descriptorCount">const <type>VkBufferView</type>* <name>pTexelBufferView</name><comment>Buffer view to write to the descriptor for {UNIFORM,STORAGE}_TEXEL_BUFFER descriptor types.</comment></member>
+ </type>
+ <type category="struct" name="VkCopyDescriptorSet">
+ <member values="VK_STRUCTURE_TYPE_COPY_DESCRIPTOR_SET"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member><type>VkDescriptorSet</type> <name>srcSet</name><comment>Source descriptor set</comment></member>
+ <member><type>uint32_t</type> <name>srcBinding</name><comment>Binding within the source descriptor set to copy from</comment></member>
+ <member><type>uint32_t</type> <name>srcArrayElement</name><comment>Array element within the source binding to copy from</comment></member>
+ <member><type>VkDescriptorSet</type> <name>dstSet</name><comment>Destination descriptor set</comment></member>
+ <member><type>uint32_t</type> <name>dstBinding</name><comment>Binding within the destination descriptor set to copy to</comment></member>
+ <member><type>uint32_t</type> <name>dstArrayElement</name><comment>Array element within the destination binding to copy to</comment></member>
+ <member><type>uint32_t</type> <name>descriptorCount</name><comment>Number of descriptors to write (determines the size of the array pointed by pDescriptors)</comment></member>
+ </type>
+ <type category="struct" name="VkBufferCreateInfo">
+ <member values="VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member optional="true"><type>VkBufferCreateFlags</type> <name>flags</name><comment>Buffer creation flags</comment></member>
+ <member><type>VkDeviceSize</type> <name>size</name><comment>Specified in bytes</comment></member>
+ <member><type>VkBufferUsageFlags</type> <name>usage</name><comment>Buffer usage flags</comment></member>
+ <member><type>VkSharingMode</type> <name>sharingMode</name></member>
+ <member optional="true"><type>uint32_t</type> <name>queueFamilyIndexCount</name></member>
+ <member noautovalidity="true" len="queueFamilyIndexCount">const <type>uint32_t</type>* <name>pQueueFamilyIndices</name></member>
+ </type>
+ <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><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>
+ <member><type>VkDeviceSize</type> <name>range</name><comment>View size specified in bytes</comment></member>
+ </type>
+ <type category="struct" name="VkImageSubresource">
+ <member><type>VkImageAspectFlags</type> <name>aspectMask</name></member>
+ <member><type>uint32_t</type> <name>mipLevel</name></member>
+ <member><type>uint32_t</type> <name>arrayLayer</name></member>
+ </type>
+ <type category="struct" name="VkImageSubresourceLayers">
+ <member><type>VkImageAspectFlags</type> <name>aspectMask</name></member>
+ <member><type>uint32_t</type> <name>mipLevel</name></member>
+ <member><type>uint32_t</type> <name>baseArrayLayer</name></member>
+ <member><type>uint32_t</type> <name>layerCount</name></member>
+ </type>
+ <type category="struct" name="VkImageSubresourceRange">
+ <member><type>VkImageAspectFlags</type> <name>aspectMask</name></member>
+ <member><type>uint32_t</type> <name>baseMipLevel</name></member>
+ <member><type>uint32_t</type> <name>levelCount</name></member>
+ <member><type>uint32_t</type> <name>baseArrayLayer</name></member>
+ <member><type>uint32_t</type> <name>layerCount</name></member>
+ </type>
+ <type category="struct" name="VkMemoryBarrier">
+ <member values="VK_STRUCTURE_TYPE_MEMORY_BARRIER"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member optional="true"><type>VkAccessFlags</type> <name>srcAccessMask</name><comment>Memory accesses from the source of the dependency to synchronize</comment></member>
+ <member optional="true"><type>VkAccessFlags</type> <name>dstAccessMask</name><comment>Memory accesses from the destination of the dependency to synchronize</comment></member>
+ </type>
+ <type category="struct" name="VkBufferMemoryBarrier">
+ <member values="VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member noautovalidity="true"><type>VkAccessFlags</type> <name>srcAccessMask</name><comment>Memory accesses from the source of the dependency to synchronize</comment></member>
+ <member noautovalidity="true"><type>VkAccessFlags</type> <name>dstAccessMask</name><comment>Memory accesses from the destination of the dependency to synchronize</comment></member>
+ <member><type>uint32_t</type> <name>srcQueueFamilyIndex</name><comment>Queue family to transition ownership from</comment></member>
+ <member><type>uint32_t</type> <name>dstQueueFamilyIndex</name><comment>Queue family to transition ownership to</comment></member>
+ <member><type>VkBuffer</type> <name>buffer</name><comment>Buffer to sync</comment></member>
+ <member><type>VkDeviceSize</type> <name>offset</name><comment>Offset within the buffer to sync</comment></member>
+ <member><type>VkDeviceSize</type> <name>size</name><comment>Amount of bytes to sync</comment></member>
+ </type>
+ <type category="struct" name="VkImageMemoryBarrier">
+ <member values="VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member noautovalidity="true"><type>VkAccessFlags</type> <name>srcAccessMask</name><comment>Memory accesses from the source of the dependency to synchronize</comment></member>
+ <member noautovalidity="true"><type>VkAccessFlags</type> <name>dstAccessMask</name><comment>Memory accesses from the destination of the dependency to synchronize</comment></member>
+ <member><type>VkImageLayout</type> <name>oldLayout</name><comment>Current layout of the image</comment></member>
+ <member><type>VkImageLayout</type> <name>newLayout</name><comment>New layout to transition the image to</comment></member>
+ <member><type>uint32_t</type> <name>srcQueueFamilyIndex</name><comment>Queue family to transition ownership from</comment></member>
+ <member><type>uint32_t</type> <name>dstQueueFamilyIndex</name><comment>Queue family to transition ownership to</comment></member>
+ <member><type>VkImage</type> <name>image</name><comment>Image to sync</comment></member>
+ <member><type>VkImageSubresourceRange</type> <name>subresourceRange</name><comment>Subresource range to sync</comment></member>
+ </type>
+ <type category="struct" name="VkImageCreateInfo">
+ <member values="VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member optional="true"><type>VkImageCreateFlags</type> <name>flags</name><comment>Image creation flags</comment></member>
+ <member><type>VkImageType</type> <name>imageType</name></member>
+ <member><type>VkFormat</type> <name>format</name></member>
+ <member><type>VkExtent3D</type> <name>extent</name></member>
+ <member><type>uint32_t</type> <name>mipLevels</name></member>
+ <member><type>uint32_t</type> <name>arrayLayers</name></member>
+ <member><type>VkSampleCountFlagBits</type> <name>samples</name></member>
+ <member><type>VkImageTiling</type> <name>tiling</name></member>
+ <member><type>VkImageUsageFlags</type> <name>usage</name><comment>Image usage flags</comment></member>
+ <member><type>VkSharingMode</type> <name>sharingMode</name><comment>Cross-queue-family sharing mode</comment></member>
+ <member optional="true"><type>uint32_t</type> <name>queueFamilyIndexCount</name><comment>Number of queue families to share across</comment></member>
+ <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">
+ <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>
+ <member><type>VkDeviceSize</type> <name>arrayPitch</name><comment>Specified in bytes</comment></member>
+ <member><type>VkDeviceSize</type> <name>depthPitch</name><comment>Specified in bytes</comment></member>
+ </type>
+ <type category="struct" name="VkImageViewCreateInfo">
+ <member values="VK_STRUCTURE_TYPE_IMAGE_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>VkImageViewCreateFlags</type> <name>flags</name></member>
+ <member><type>VkImage</type> <name>image</name></member>
+ <member><type>VkImageViewType</type> <name>viewType</name></member>
+ <member><type>VkFormat</type> <name>format</name></member>
+ <member><type>VkComponentMapping</type> <name>components</name></member>
+ <member><type>VkImageSubresourceRange</type> <name>subresourceRange</name></member>
+ </type>
+ <type category="struct" name="VkBufferCopy">
+ <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="VkSparseMemoryBind">
+ <member><type>VkDeviceSize</type> <name>resourceOffset</name><comment>Specified in bytes</comment></member>
+ <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>
+ </type>
+ <type category="struct" name="VkSparseImageMemoryBind">
+ <member><type>VkImageSubresource</type> <name>subresource</name></member>
+ <member><type>VkOffset3D</type> <name>offset</name></member>
+ <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>
+ </type>
+ <type category="struct" name="VkSparseBufferMemoryBindInfo">
+ <member><type>VkBuffer</type> <name>buffer</name></member>
+ <member><type>uint32_t</type> <name>bindCount</name></member>
+ <member len="bindCount">const <type>VkSparseMemoryBind</type>* <name>pBinds</name></member>
+ </type>
+ <type category="struct" name="VkSparseImageOpaqueMemoryBindInfo">
+ <member><type>VkImage</type> <name>image</name></member>
+ <member><type>uint32_t</type> <name>bindCount</name></member>
+ <member len="bindCount">const <type>VkSparseMemoryBind</type>* <name>pBinds</name></member>
+ </type>
+ <type category="struct" name="VkSparseImageMemoryBindInfo">
+ <member><type>VkImage</type> <name>image</name></member>
+ <member><type>uint32_t</type> <name>bindCount</name></member>
+ <member len="bindCount">const <type>VkSparseImageMemoryBind</type>* <name>pBinds</name></member>
+ </type>
+ <type category="struct" name="VkBindSparseInfo">
+ <member values="VK_STRUCTURE_TYPE_BIND_SPARSE_INFO"><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>waitSemaphoreCount</name></member>
+ <member len="waitSemaphoreCount">const <type>VkSemaphore</type>* <name>pWaitSemaphores</name></member>
+ <member optional="true"><type>uint32_t</type> <name>bufferBindCount</name></member>
+ <member len="bufferBindCount">const <type>VkSparseBufferMemoryBindInfo</type>* <name>pBufferBinds</name></member>
+ <member optional="true"><type>uint32_t</type> <name>imageOpaqueBindCount</name></member>
+ <member len="imageOpaqueBindCount">const <type>VkSparseImageOpaqueMemoryBindInfo</type>* <name>pImageOpaqueBinds</name></member>
+ <member optional="true"><type>uint32_t</type> <name>imageBindCount</name></member>
+ <member len="imageBindCount">const <type>VkSparseImageMemoryBindInfo</type>* <name>pImageBinds</name></member>
+ <member optional="true"><type>uint32_t</type> <name>signalSemaphoreCount</name></member>
+ <member len="signalSemaphoreCount">const <type>VkSemaphore</type>* <name>pSignalSemaphores</name></member>
+ </type>
+ <type category="struct" name="VkImageCopy">
+ <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="VkImageBlit">
+ <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="VkBufferImageCopy">
+ <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="VkImageResolve">
+ <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="VkShaderModuleCreateInfo">
+ <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 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>
+ </type>
+ <type category="struct" name="VkDescriptorSetLayoutBinding">
+ <member><type>uint32_t</type> <name>binding</name><comment>Binding number for this entry</comment></member>
+ <member><type>VkDescriptorType</type> <name>descriptorType</name><comment>Type of the descriptors in this binding</comment></member>
+ <member optional="true"><type>uint32_t</type> <name>descriptorCount</name><comment>Number of descriptors in this binding</comment></member>
+ <member noautovalidity="true"><type>VkShaderStageFlags</type> <name>stageFlags</name><comment>Shader stages this binding is visible to</comment></member>
+ <member noautovalidity="true" optional="true" len="descriptorCount">const <type>VkSampler</type>* <name>pImmutableSamplers</name><comment>Immutable samplers (used if descriptor type is SAMPLER or COMBINED_IMAGE_SAMPLER, is either NULL or contains count number of elements)</comment></member>
+ </type>
+ <type category="struct" name="VkDescriptorSetLayoutCreateInfo">
+ <member values="VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member optional="true"><type>VkDescriptorSetLayoutCreateFlags</type> <name>flags</name></member>
+ <member optional="true"><type>uint32_t</type> <name>bindingCount</name><comment>Number of bindings in the descriptor set layout</comment></member>
+ <member len="bindingCount">const <type>VkDescriptorSetLayoutBinding</type>* <name>pBindings</name><comment>Array of descriptor set layout bindings</comment></member>
+ </type>
+ <type category="struct" name="VkDescriptorPoolSize">
+ <member><type>VkDescriptorType</type> <name>type</name></member>
+ <member><type>uint32_t</type> <name>descriptorCount</name></member>
+ </type>
+ <type category="struct" name="VkDescriptorPoolCreateInfo">
+ <member values="VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO"><type>VkStructureType</type> <name>sType</name></member>
+ <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 len="poolSizeCount">const <type>VkDescriptorPoolSize</type>* <name>pPoolSizes</name></member>
+ </type>
+ <type category="struct" name="VkDescriptorSetAllocateInfo">
+ <member values="VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member><type>VkDescriptorPool</type> <name>descriptorPool</name></member>
+ <member><type>uint32_t</type> <name>descriptorSetCount</name></member>
+ <member len="descriptorSetCount">const <type>VkDescriptorSetLayout</type>* <name>pSetLayouts</name></member>
+ </type>
+ <type category="struct" name="VkSpecializationMapEntry">
+ <member><type>uint32_t</type> <name>constantID</name><comment>The SpecConstant ID specified in the BIL</comment></member>
+ <member><type>uint32_t</type> <name>offset</name><comment>Offset of the value in the data block</comment></member>
+ <member noautovalidity="true"><type>size_t</type> <name>size</name><comment>Size in bytes of the SpecConstant</comment></member>
+ </type>
+ <type category="struct" name="VkSpecializationInfo">
+ <member optional="true"><type>uint32_t</type> <name>mapEntryCount</name><comment>Number of entries in the map</comment></member>
+ <member len="mapEntryCount">const <type>VkSpecializationMapEntry</type>* <name>pMapEntries</name><comment>Array of map entries</comment></member>
+ <member optional="true"><type>size_t</type> <name>dataSize</name><comment>Size in bytes of pData</comment></member>
+ <member len="dataSize">const <type>void</type>* <name>pData</name><comment>Pointer to SpecConstant data</comment></member>
+ </type>
+ <type category="struct" name="VkPipelineShaderStageCreateInfo">
+ <member values="VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO"><type>VkStructureType</type> <name>sType</name></member>
+ <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 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>
+ <type category="struct" name="VkComputePipelineCreateInfo">
+ <member values="VK_STRUCTURE_TYPE_COMPUTE_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>VkPipelineShaderStageCreateInfo</type> <name>stage</name></member>
+ <member><type>VkPipelineLayout</type> <name>layout</name><comment>Interface layout of the pipeline</comment></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>
+ <type category="struct" name="VkVertexInputBindingDescription">
+ <member><type>uint32_t</type> <name>binding</name><comment>Vertex buffer binding id</comment></member>
+ <member><type>uint32_t</type> <name>stride</name><comment>Distance between vertices in bytes (0 = no advancement)</comment></member>
+ <member><type>VkVertexInputRate</type> <name>inputRate</name><comment>The rate at which the vertex data is consumed</comment></member>
+ </type>
+ <type category="struct" name="VkVertexInputAttributeDescription">
+ <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>
+ <member><type>uint32_t</type> <name>offset</name><comment>Offset of first element in bytes from base of vertex</comment></member>
+ </type>
+ <type category="struct" name="VkPipelineVertexInputStateCreateInfo">
+ <member values="VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member optional="true"><type>VkPipelineVertexInputStateCreateFlags</type> <name>flags</name></member>
+ <member optional="true"><type>uint32_t</type> <name>vertexBindingDescriptionCount</name><comment>number of bindings</comment></member>
+ <member len="vertexBindingDescriptionCount">const <type>VkVertexInputBindingDescription</type>* <name>pVertexBindingDescriptions</name></member>
+ <member optional="true"><type>uint32_t</type> <name>vertexAttributeDescriptionCount</name><comment>number of attributes</comment></member>
+ <member len="vertexAttributeDescriptionCount">const <type>VkVertexInputAttributeDescription</type>* <name>pVertexAttributeDescriptions</name></member>
+ </type>
+ <type category="struct" name="VkPipelineInputAssemblyStateCreateInfo">
+ <member values="VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member optional="true"><type>VkPipelineInputAssemblyStateCreateFlags</type> <name>flags</name></member>
+ <member><type>VkPrimitiveTopology</type> <name>topology</name></member>
+ <member><type>VkBool32</type> <name>primitiveRestartEnable</name></member>
+ </type>
+ <type category="struct" name="VkPipelineTessellationStateCreateInfo">
+ <member values="VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_STATE_CREATE_INFO"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member optional="true"><type>VkPipelineTessellationStateCreateFlags</type> <name>flags</name></member>
+ <member><type>uint32_t</type> <name>patchControlPoints</name></member>
+ </type>
+ <type category="struct" name="VkPipelineViewportStateCreateInfo">
+ <member values="VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member optional="true"><type>VkPipelineViewportStateCreateFlags</type> <name>flags</name></member>
+ <member optional="true"><type>uint32_t</type> <name>viewportCount</name></member>
+ <member noautovalidity="true" optional="true" len="viewportCount">const <type>VkViewport</type>* <name>pViewports</name></member>
+ <member optional="true"><type>uint32_t</type> <name>scissorCount</name></member>
+ <member noautovalidity="true" optional="true" len="scissorCount">const <type>VkRect2D</type>* <name>pScissors</name></member>
+ </type>
+ <type category="struct" name="VkPipelineRasterizationStateCreateInfo">
+ <member values="VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member optional="true"><type>VkPipelineRasterizationStateCreateFlags</type> <name>flags</name></member>
+ <member><type>VkBool32</type> <name>depthClampEnable</name></member>
+ <member><type>VkBool32</type> <name>rasterizerDiscardEnable</name></member>
+ <member><type>VkPolygonMode</type> <name>polygonMode</name><comment>optional (GL45)</comment></member>
+ <member optional="true"><type>VkCullModeFlags</type> <name>cullMode</name></member>
+ <member><type>VkFrontFace</type> <name>frontFace</name></member>
+ <member><type>VkBool32</type> <name>depthBiasEnable</name></member>
+ <member><type>float</type> <name>depthBiasConstantFactor</name></member>
+ <member><type>float</type> <name>depthBiasClamp</name></member>
+ <member><type>float</type> <name>depthBiasSlopeFactor</name></member>
+ <member><type>float</type> <name>lineWidth</name></member>
+ </type>
+ <type category="struct" name="VkPipelineMultisampleStateCreateInfo">
+ <member values="VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member optional="true"><type>VkPipelineMultisampleStateCreateFlags</type> <name>flags</name></member>
+ <member><type>VkSampleCountFlagBits</type> <name>rasterizationSamples</name><comment>Number of samples used for rasterization</comment></member>
+ <member><type>VkBool32</type> <name>sampleShadingEnable</name><comment>optional (GL45)</comment></member>
+ <member><type>float</type> <name>minSampleShading</name><comment>optional (GL45)</comment></member>
+ <member optional="true" len="latexmath:[\lceil{\mathit{rasterizationSamples} \over 32}\rceil]" altlen="(rasterizationSamples + 31) / 32">const <type>VkSampleMask</type>* <name>pSampleMask</name><comment>Array of sampleMask words</comment></member>
+ <member><type>VkBool32</type> <name>alphaToCoverageEnable</name></member>
+ <member><type>VkBool32</type> <name>alphaToOneEnable</name></member>
+ </type>
+ <type category="struct" name="VkPipelineColorBlendAttachmentState">
+ <member><type>VkBool32</type> <name>blendEnable</name></member>
+ <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>
+ <member optional="true"><type>VkColorComponentFlags</type> <name>colorWriteMask</name></member>
+ </type>
+ <type category="struct" name="VkPipelineColorBlendStateCreateInfo">
+ <member values="VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member optional="true"><type>VkPipelineColorBlendStateCreateFlags</type> <name>flags</name></member>
+ <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><type>float</type> <name>blendConstants</name>[4]</member>
+ </type>
+ <type category="struct" name="VkPipelineDynamicStateCreateInfo">
+ <member values="VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member optional="true"><type>VkPipelineDynamicStateCreateFlags</type> <name>flags</name></member>
+ <member optional="true"><type>uint32_t</type> <name>dynamicStateCount</name></member>
+ <member len="dynamicStateCount">const <type>VkDynamicState</type>* <name>pDynamicStates</name></member>
+ </type>
+ <type category="struct" name="VkStencilOpState">
+ <member><type>VkStencilOp</type> <name>failOp</name></member>
+ <member><type>VkStencilOp</type> <name>passOp</name></member>
+ <member><type>VkStencilOp</type> <name>depthFailOp</name></member>
+ <member><type>VkCompareOp</type> <name>compareOp</name></member>
+ <member><type>uint32_t</type> <name>compareMask</name></member>
+ <member><type>uint32_t</type> <name>writeMask</name></member>
+ <member><type>uint32_t</type> <name>reference</name></member>
+ </type>
+ <type category="struct" name="VkPipelineDepthStencilStateCreateInfo">
+ <member values="VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member optional="true"><type>VkPipelineDepthStencilStateCreateFlags</type> <name>flags</name></member>
+ <member><type>VkBool32</type> <name>depthTestEnable</name></member>
+ <member><type>VkBool32</type> <name>depthWriteEnable</name></member>
+ <member><type>VkCompareOp</type> <name>depthCompareOp</name></member>
+ <member><type>VkBool32</type> <name>depthBoundsTestEnable</name><comment>optional (depth_bounds_test)</comment></member>
+ <member><type>VkBool32</type> <name>stencilTestEnable</name></member>
+ <member><type>VkStencilOpState</type> <name>front</name></member>
+ <member><type>VkStencilOpState</type> <name>back</name></member>
+ <member><type>float</type> <name>minDepthBounds</name></member>
+ <member><type>float</type> <name>maxDepthBounds</name></member>
+ </type>
+ <type category="struct" name="VkGraphicsPipelineCreateInfo">
+ <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">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>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>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>
+ <type category="struct" name="VkPipelineCacheCreateInfo">
+ <member values="VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member optional="true"><type>VkPipelineCacheCreateFlags</type> <name>flags</name></member>
+ <member optional="true"><type>size_t</type> <name>initialDataSize</name><comment>Size of initial data to populate cache, in bytes</comment></member>
+ <member len="initialDataSize">const <type>void</type>* <name>pInitialData</name><comment>Initial data to populate cache</comment></member>
+ </type>
+ <type category="struct" name="VkPipelineCacheHeaderVersionOne">
+ <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>VkPipelineCacheHeaderVersion</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>uint8_t</type> <name>pipelineCacheUUID</name>[<enum>VK_UUID_SIZE</enum>]</member>
+ </type>
+ <type category="struct" name="VkPushConstantRange">
+ <member><type>VkShaderStageFlags</type> <name>stageFlags</name><comment>Which stages use the range</comment></member>
+ <member><type>uint32_t</type> <name>offset</name><comment>Start of the range, in bytes</comment></member>
+ <member><type>uint32_t</type> <name>size</name><comment>Size of the range, in bytes</comment></member>
+ </type>
+ <type category="struct" name="VkPipelineLayoutCreateInfo">
+ <member values="VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO"><type>VkStructureType</type> <name>sType</name></member>
+ <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="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>
+ <type category="struct" name="VkSamplerCreateInfo">
+ <member values="VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member optional="true"><type>VkSamplerCreateFlags</type> <name>flags</name></member>
+ <member><type>VkFilter</type> <name>magFilter</name><comment>Filter mode for magnification</comment></member>
+ <member><type>VkFilter</type> <name>minFilter</name><comment>Filter mode for minifiation</comment></member>
+ <member><type>VkSamplerMipmapMode</type> <name>mipmapMode</name><comment>Mipmap selection mode</comment></member>
+ <member><type>VkSamplerAddressMode</type> <name>addressModeU</name></member>
+ <member><type>VkSamplerAddressMode</type> <name>addressModeV</name></member>
+ <member><type>VkSamplerAddressMode</type> <name>addressModeW</name></member>
+ <member><type>float</type> <name>mipLodBias</name></member>
+ <member><type>VkBool32</type> <name>anisotropyEnable</name></member>
+ <member><type>float</type> <name>maxAnisotropy</name></member>
+ <member><type>VkBool32</type> <name>compareEnable</name></member>
+ <member noautovalidity="true"><type>VkCompareOp</type> <name>compareOp</name></member>
+ <member><type>float</type> <name>minLod</name></member>
+ <member><type>float</type> <name>maxLod</name></member>
+ <member noautovalidity="true"><type>VkBorderColor</type> <name>borderColor</name></member>
+ <member><type>VkBool32</type> <name>unnormalizedCoordinates</name></member>
+ </type>
+ <type category="struct" name="VkCommandPoolCreateInfo">
+ <member values="VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member optional="true"><type>VkCommandPoolCreateFlags</type> <name>flags</name><comment>Command pool creation flags</comment></member>
+ <member><type>uint32_t</type> <name>queueFamilyIndex</name></member>
+ </type>
+ <type category="struct" name="VkCommandBufferAllocateInfo">
+ <member values="VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member><type>VkCommandPool</type> <name>commandPool</name></member>
+ <member><type>VkCommandBufferLevel</type> <name>level</name></member>
+ <member><type>uint32_t</type> <name>commandBufferCount</name></member>
+ </type>
+ <type category="struct" name="VkCommandBufferInheritanceInfo">
+ <member values="VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member optional="true" noautovalidity="true"><type>VkRenderPass</type> <name>renderPass</name><comment>Render pass for secondary command buffers</comment></member>
+ <member><type>uint32_t</type> <name>subpass</name></member>
+ <member optional="true" noautovalidity="true"><type>VkFramebuffer</type> <name>framebuffer</name><comment>Framebuffer for secondary command buffers</comment></member>
+ <member><type>VkBool32</type> <name>occlusionQueryEnable</name><comment>Whether this secondary command buffer may be executed during an occlusion query</comment></member>
+ <member optional="true" noautovalidity="true"><type>VkQueryControlFlags</type> <name>queryFlags</name><comment>Query flags used by this secondary command buffer, if executed during an occlusion query</comment></member>
+ <member optional="true" noautovalidity="true"><type>VkQueryPipelineStatisticFlags</type> <name>pipelineStatistics</name><comment>Pipeline statistics that may be counted for this secondary command buffer</comment></member>
+ </type>
+ <type category="struct" name="VkCommandBufferBeginInfo">
+ <member values="VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member optional="true"><type>VkCommandBufferUsageFlags</type> <name>flags</name><comment>Command buffer usage flags</comment></member>
+ <member optional="true" noautovalidity="true">const <type>VkCommandBufferInheritanceInfo</type>* <name>pInheritanceInfo</name><comment>Pointer to inheritance info for secondary command buffers</comment></member>
+ </type>
+ <type category="struct" name="VkRenderPassBeginInfo">
+ <member values="VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member><type>VkRenderPass</type> <name>renderPass</name></member>
+ <member><type>VkFramebuffer</type> <name>framebuffer</name></member>
+ <member><type>VkRect2D</type> <name>renderArea</name></member>
+ <member optional="true"><type>uint32_t</type> <name>clearValueCount</name></member>
+ <member len="clearValueCount" noautovalidity="true">const <type>VkClearValue</type>* <name>pClearValues</name></member>
+ </type>
+ <type category="union" name="VkClearColorValue" comment="// Union allowing specification of floating point, integer, or unsigned integer color data. Actual value selected is based on image/attachment being cleared.">
+ <member><type>float</type> <name>float32</name>[4]</member>
+ <member><type>int32_t</type> <name>int32</name>[4]</member>
+ <member><type>uint32_t</type> <name>uint32</name>[4]</member>
+ </type>
+ <type category="struct" name="VkClearDepthStencilValue">
+ <member><type>float</type> <name>depth</name></member>
+ <member><type>uint32_t</type> <name>stencil</name></member>
+ </type>
+ <type category="union" name="VkClearValue" comment="// Union allowing specification of color or depth and stencil values. Actual value selected is based on attachment being cleared.">
+ <member noautovalidity="true"><type>VkClearColorValue</type> <name>color</name></member>
+ <member><type>VkClearDepthStencilValue</type> <name>depthStencil</name></member>
+ </type>
+ <type category="struct" name="VkClearAttachment">
+ <member><type>VkImageAspectFlags</type> <name>aspectMask</name></member>
+ <member><type>uint32_t</type> <name>colorAttachment</name></member>
+ <member noautovalidity="true"><type>VkClearValue</type> <name>clearValue</name></member>
+ </type>
+ <type category="struct" name="VkAttachmentDescription">
+ <member optional="true"><type>VkAttachmentDescriptionFlags</type> <name>flags</name></member>
+ <member><type>VkFormat</type> <name>format</name></member>
+ <member><type>VkSampleCountFlagBits</type> <name>samples</name></member>
+ <member><type>VkAttachmentLoadOp</type> <name>loadOp</name><comment>Load operation for color or depth data</comment></member>
+ <member><type>VkAttachmentStoreOp</type> <name>storeOp</name><comment>Store operation for color or depth data</comment></member>
+ <member><type>VkAttachmentLoadOp</type> <name>stencilLoadOp</name><comment>Load operation for stencil data</comment></member>
+ <member><type>VkAttachmentStoreOp</type> <name>stencilStoreOp</name><comment>Store operation for stencil data</comment></member>
+ <member><type>VkImageLayout</type> <name>initialLayout</name></member>
+ <member><type>VkImageLayout</type> <name>finalLayout</name></member>
+ </type>
+ <type category="struct" name="VkAttachmentReference">
+ <member><type>uint32_t</type> <name>attachment</name></member>
+ <member><type>VkImageLayout</type> <name>layout</name></member>
+ </type>
+ <type category="struct" name="VkSubpassDescription">
+ <member optional="true"><type>VkSubpassDescriptionFlags</type> <name>flags</name></member>
+ <member><type>VkPipelineBindPoint</type> <name>pipelineBindPoint</name><comment>Must be VK_PIPELINE_BIND_POINT_GRAPHICS for now</comment></member>
+ <member optional="true"><type>uint32_t</type> <name>inputAttachmentCount</name></member>
+ <member len="inputAttachmentCount">const <type>VkAttachmentReference</type>* <name>pInputAttachments</name></member>
+ <member optional="true"><type>uint32_t</type> <name>colorAttachmentCount</name></member>
+ <member len="colorAttachmentCount">const <type>VkAttachmentReference</type>* <name>pColorAttachments</name></member>
+ <member optional="true" len="colorAttachmentCount">const <type>VkAttachmentReference</type>* <name>pResolveAttachments</name></member>
+ <member optional="true">const <type>VkAttachmentReference</type>* <name>pDepthStencilAttachment</name></member>
+ <member optional="true"><type>uint32_t</type> <name>preserveAttachmentCount</name></member>
+ <member len="preserveAttachmentCount">const <type>uint32_t</type>* <name>pPreserveAttachments</name></member>
+ </type>
+ <type category="struct" name="VkSubpassDependency">
+ <member><type>uint32_t</type> <name>srcSubpass</name></member>
+ <member><type>uint32_t</type> <name>dstSubpass</name></member>
+ <member optional="true"><type>VkPipelineStageFlags</type> <name>srcStageMask</name></member>
+ <member optional="true"><type>VkPipelineStageFlags</type> <name>dstStageMask</name></member>
+ <member optional="true"><type>VkAccessFlags</type> <name>srcAccessMask</name><comment>Memory accesses from the source of the dependency to synchronize</comment></member>
+ <member optional="true"><type>VkAccessFlags</type> <name>dstAccessMask</name><comment>Memory accesses from the destination of the dependency to synchronize</comment></member>
+ <member optional="true"><type>VkDependencyFlags</type> <name>dependencyFlags</name></member>
+ </type>
+ <type category="struct" name="VkRenderPassCreateInfo">
+ <member values="VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member optional="true"><type>VkRenderPassCreateFlags</type> <name>flags</name></member>
+ <member optional="true"><type>uint32_t</type> <name>attachmentCount</name></member>
+ <member len="attachmentCount">const <type>VkAttachmentDescription</type>* <name>pAttachments</name></member>
+ <member><type>uint32_t</type> <name>subpassCount</name></member>
+ <member len="subpassCount">const <type>VkSubpassDescription</type>* <name>pSubpasses</name></member>
+ <member optional="true"><type>uint32_t</type> <name>dependencyCount</name></member>
+ <member len="dependencyCount">const <type>VkSubpassDependency</type>* <name>pDependencies</name></member>
+ </type>
+ <type category="struct" name="VkEventCreateInfo">
+ <member values="VK_STRUCTURE_TYPE_EVENT_CREATE_INFO"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member optional="true"><type>VkEventCreateFlags</type> <name>flags</name><comment>Event creation flags</comment></member>
+ </type>
+ <type category="struct" name="VkFenceCreateInfo">
+ <member values="VK_STRUCTURE_TYPE_FENCE_CREATE_INFO"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member optional="true"><type>VkFenceCreateFlags</type> <name>flags</name><comment>Fence creation flags</comment></member>
+ </type>
+ <type category="struct" name="VkPhysicalDeviceFeatures">
+ <member><type>VkBool32</type> <name>robustBufferAccess</name><comment>out of bounds buffer accesses are well defined</comment></member>
+ <member><type>VkBool32</type> <name>fullDrawIndexUint32</name><comment>full 32-bit range of indices for indexed draw calls</comment></member>
+ <member><type>VkBool32</type> <name>imageCubeArray</name><comment>image views which are arrays of cube maps</comment></member>
+ <member><type>VkBool32</type> <name>independentBlend</name><comment>blending operations are controlled per-attachment</comment></member>
+ <member><type>VkBool32</type> <name>geometryShader</name><comment>geometry stage</comment></member>
+ <member><type>VkBool32</type> <name>tessellationShader</name><comment>tessellation control and evaluation stage</comment></member>
+ <member><type>VkBool32</type> <name>sampleRateShading</name><comment>per-sample shading and interpolation</comment></member>
+ <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>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>
+ <member><type>VkBool32</type> <name>depthBounds</name><comment>depth bounds test</comment></member>
+ <member><type>VkBool32</type> <name>wideLines</name><comment>lines with width greater than 1</comment></member>
+ <member><type>VkBool32</type> <name>largePoints</name><comment>points with size greater than 1</comment></member>
+ <member><type>VkBool32</type> <name>alphaToOne</name><comment>the fragment alpha component can be forced to maximum representable alpha value</comment></member>
+ <member><type>VkBool32</type> <name>multiViewport</name><comment>viewport arrays</comment></member>
+ <member><type>VkBool32</type> <name>samplerAnisotropy</name><comment>anisotropic sampler filtering</comment></member>
+ <member><type>VkBool32</type> <name>textureCompressionETC2</name><comment>ETC texture compression formats</comment></member>
+ <member><type>VkBool32</type> <name>textureCompressionASTC_LDR</name><comment>ASTC LDR texture compression formats</comment></member>
+ <member><type>VkBool32</type> <name>textureCompressionBC</name><comment>BC1-7 texture compressed formats</comment></member>
+ <member><type>VkBool32</type> <name>occlusionQueryPrecise</name><comment>precise occlusion queries returning actual sample counts</comment></member>
+ <member><type>VkBool32</type> <name>pipelineStatisticsQuery</name><comment>pipeline statistics query</comment></member>
+ <member><type>VkBool32</type> <name>vertexPipelineStoresAndAtomics</name><comment>stores and atomic ops on storage buffers and images are supported in vertex, tessellation, and geometry stages</comment></member>
+ <member><type>VkBool32</type> <name>fragmentStoresAndAtomics</name><comment>stores and atomic ops on storage buffers and images are supported in the fragment stage</comment></member>
+ <member><type>VkBool32</type> <name>shaderTessellationAndGeometryPointSize</name><comment>tessellation and geometry stages can export point size</comment></member>
+ <member><type>VkBool32</type> <name>shaderImageGatherExtended</name><comment>image gather with run-time values and independent offsets</comment></member>
+ <member><type>VkBool32</type> <name>shaderStorageImageExtendedFormats</name><comment>the extended set of formats can be used for storage images</comment></member>
+ <member><type>VkBool32</type> <name>shaderStorageImageMultisample</name><comment>multisample images can be used for storage images</comment></member>
+ <member><type>VkBool32</type> <name>shaderStorageImageReadWithoutFormat</name><comment>read from storage image does not require format qualifier</comment></member>
+ <member><type>VkBool32</type> <name>shaderStorageImageWriteWithoutFormat</name><comment>write to storage image does not require format qualifier</comment></member>
+ <member><type>VkBool32</type> <name>shaderUniformBufferArrayDynamicIndexing</name><comment>arrays of uniform buffers can be accessed with dynamically uniform indices</comment></member>
+ <member><type>VkBool32</type> <name>shaderSampledImageArrayDynamicIndexing</name><comment>arrays of sampled images can be accessed with dynamically uniform indices</comment></member>
+ <member><type>VkBool32</type> <name>shaderStorageBufferArrayDynamicIndexing</name><comment>arrays of storage buffers can be accessed with dynamically uniform indices</comment></member>
+ <member><type>VkBool32</type> <name>shaderStorageImageArrayDynamicIndexing</name><comment>arrays of storage images can be accessed with dynamically uniform indices</comment></member>
+ <member><type>VkBool32</type> <name>shaderClipDistance</name><comment>clip distance in shaders</comment></member>
+ <member><type>VkBool32</type> <name>shaderCullDistance</name><comment>cull distance in shaders</comment></member>
+ <member><type>VkBool32</type> <name>shaderFloat64</name><comment>64-bit floats (doubles) in shaders</comment></member>
+ <member><type>VkBool32</type> <name>shaderInt64</name><comment>64-bit integers in shaders</comment></member>
+ <member><type>VkBool32</type> <name>shaderInt16</name><comment>16-bit integers in shaders</comment></member>
+ <member><type>VkBool32</type> <name>shaderResourceResidency</name><comment>shader can use texture operations that return resource residency information (requires sparseNonResident support)</comment></member>
+ <member><type>VkBool32</type> <name>shaderResourceMinLod</name><comment>shader can use texture operations that specify minimum resource LOD</comment></member>
+ <member><type>VkBool32</type> <name>sparseBinding</name><comment>Sparse resources support: Resource memory can be managed at opaque page level rather than object level</comment></member>
+ <member><type>VkBool32</type> <name>sparseResidencyBuffer</name><comment>Sparse resources support: GPU can access partially resident buffers </comment></member>
+ <member><type>VkBool32</type> <name>sparseResidencyImage2D</name><comment>Sparse resources support: GPU can access partially resident 2D (non-MSAA non-depth/stencil) images </comment></member>
+ <member><type>VkBool32</type> <name>sparseResidencyImage3D</name><comment>Sparse resources support: GPU can access partially resident 3D images </comment></member>
+ <member><type>VkBool32</type> <name>sparseResidency2Samples</name><comment>Sparse resources support: GPU can access partially resident MSAA 2D images with 2 samples</comment></member>
+ <member><type>VkBool32</type> <name>sparseResidency4Samples</name><comment>Sparse resources support: GPU can access partially resident MSAA 2D images with 4 samples</comment></member>
+ <member><type>VkBool32</type> <name>sparseResidency8Samples</name><comment>Sparse resources support: GPU can access partially resident MSAA 2D images with 8 samples</comment></member>
+ <member><type>VkBool32</type> <name>sparseResidency16Samples</name><comment>Sparse resources support: GPU can access partially resident MSAA 2D images with 16 samples</comment></member>
+ <member><type>VkBool32</type> <name>sparseResidencyAliased</name><comment>Sparse resources support: GPU can correctly access data aliased into multiple locations (opt-in)</comment></member>
+ <member><type>VkBool32</type> <name>variableMultisampleRate</name><comment>multisample rate must be the same for all pipelines in a subpass</comment></member>
+ <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>
+ </type>
+ <type category="struct" name="VkPhysicalDeviceLimits" returnedonly="true">
+ <comment>resource maximum sizes</comment>
+ <member limittype="max"><type>uint32_t</type> <name>maxImageDimension1D</name><comment>max 1D image dimension</comment></member>
+ <member limittype="max"><type>uint32_t</type> <name>maxImageDimension2D</name><comment>max 2D image dimension</comment></member>
+ <member limittype="max"><type>uint32_t</type> <name>maxImageDimension3D</name><comment>max 3D image dimension</comment></member>
+ <member limittype="max"><type>uint32_t</type> <name>maxImageDimensionCube</name><comment>max cubemap image dimension</comment></member>
+ <member limittype="max"><type>uint32_t</type> <name>maxImageArrayLayers</name><comment>max layers for image arrays</comment></member>
+ <member limittype="max"><type>uint32_t</type> <name>maxTexelBufferElements</name><comment>max texel buffer size (fstexels)</comment></member>
+ <member limittype="max"><type>uint32_t</type> <name>maxUniformBufferRange</name><comment>max uniform buffer range (bytes)</comment></member>
+ <member limittype="max"><type>uint32_t</type> <name>maxStorageBufferRange</name><comment>max storage buffer range (bytes)</comment></member>
+ <member limittype="max"><type>uint32_t</type> <name>maxPushConstantsSize</name><comment>max size of the push constants pool (bytes)</comment></member>
+ <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="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>
+ <member limittype="max"><type>uint32_t</type> <name>maxPerStageDescriptorSamplers</name><comment>max number of samplers allowed per-stage in a descriptor set</comment></member>
+ <member limittype="max"><type>uint32_t</type> <name>maxPerStageDescriptorUniformBuffers</name><comment>max number of uniform buffers allowed per-stage in a descriptor set</comment></member>
+ <member limittype="max"><type>uint32_t</type> <name>maxPerStageDescriptorStorageBuffers</name><comment>max number of storage buffers allowed per-stage in a descriptor set</comment></member>
+ <member limittype="max"><type>uint32_t</type> <name>maxPerStageDescriptorSampledImages</name><comment>max number of sampled images allowed per-stage in a descriptor set</comment></member>
+ <member limittype="max"><type>uint32_t</type> <name>maxPerStageDescriptorStorageImages</name><comment>max number of storage images allowed per-stage in a descriptor set</comment></member>
+ <member limittype="max"><type>uint32_t</type> <name>maxPerStageDescriptorInputAttachments</name><comment>max number of input attachments allowed per-stage in a descriptor set</comment></member>
+ <member limittype="max"><type>uint32_t</type> <name>maxPerStageResources</name><comment>max number of resources allowed by a single stage</comment></member>
+ <member limittype="max"><type>uint32_t</type> <name>maxDescriptorSetSamplers</name><comment>max number of samplers allowed in all stages in a descriptor set</comment></member>
+ <member limittype="max"><type>uint32_t</type> <name>maxDescriptorSetUniformBuffers</name><comment>max number of uniform buffers allowed in all stages in a descriptor set</comment></member>
+ <member limittype="max"><type>uint32_t</type> <name>maxDescriptorSetUniformBuffersDynamic</name><comment>max number of dynamic uniform buffers allowed in all stages in a descriptor set</comment></member>
+ <member limittype="max"><type>uint32_t</type> <name>maxDescriptorSetStorageBuffers</name><comment>max number of storage buffers allowed in all stages in a descriptor set</comment></member>
+ <member limittype="max"><type>uint32_t</type> <name>maxDescriptorSetStorageBuffersDynamic</name><comment>max number of dynamic storage buffers allowed in all stages in a descriptor set</comment></member>
+ <member limittype="max"><type>uint32_t</type> <name>maxDescriptorSetSampledImages</name><comment>max number of sampled images allowed in all stages in a descriptor set</comment></member>
+ <member limittype="max"><type>uint32_t</type> <name>maxDescriptorSetStorageImages</name><comment>max number of storage images allowed in all stages in a descriptor set</comment></member>
+ <member limittype="max"><type>uint32_t</type> <name>maxDescriptorSetInputAttachments</name><comment>max number of input attachments allowed in all stages in a descriptor set</comment></member>
+ <comment>vertex stage limits</comment>
+ <member limittype="max"><type>uint32_t</type> <name>maxVertexInputAttributes</name><comment>max number of vertex input attribute slots</comment></member>
+ <member limittype="max"><type>uint32_t</type> <name>maxVertexInputBindings</name><comment>max number of vertex input binding slots</comment></member>
+ <member limittype="max"><type>uint32_t</type> <name>maxVertexInputAttributeOffset</name><comment>max vertex input attribute offset added to vertex buffer offset</comment></member>
+ <member limittype="max"><type>uint32_t</type> <name>maxVertexInputBindingStride</name><comment>max vertex input binding stride</comment></member>
+ <member limittype="max"><type>uint32_t</type> <name>maxVertexOutputComponents</name><comment>max number of output components written by vertex shader</comment></member>
+ <comment>tessellation control stage limits</comment>
+ <member limittype="max"><type>uint32_t</type> <name>maxTessellationGenerationLevel</name><comment>max level supported by tessellation primitive generator</comment></member>
+ <member limittype="max"><type>uint32_t</type> <name>maxTessellationPatchSize</name><comment>max patch size (vertices)</comment></member>
+ <member limittype="max"><type>uint32_t</type> <name>maxTessellationControlPerVertexInputComponents</name><comment>max number of input components per-vertex in TCS</comment></member>
+ <member limittype="max"><type>uint32_t</type> <name>maxTessellationControlPerVertexOutputComponents</name><comment>max number of output components per-vertex in TCS</comment></member>
+ <member limittype="max"><type>uint32_t</type> <name>maxTessellationControlPerPatchOutputComponents</name><comment>max number of output components per-patch in TCS</comment></member>
+ <member limittype="max"><type>uint32_t</type> <name>maxTessellationControlTotalOutputComponents</name><comment>max total number of per-vertex and per-patch output components in TCS</comment></member>
+ <comment>tessellation evaluation stage limits</comment>
+ <member limittype="max"><type>uint32_t</type> <name>maxTessellationEvaluationInputComponents</name><comment>max number of input components per vertex in TES</comment></member>
+ <member limittype="max"><type>uint32_t</type> <name>maxTessellationEvaluationOutputComponents</name><comment>max number of output components per vertex in TES</comment></member>
+ <comment>geometry stage limits</comment>
+ <member limittype="max"><type>uint32_t</type> <name>maxGeometryShaderInvocations</name><comment>max invocation count supported in geometry shader</comment></member>
+ <member limittype="max"><type>uint32_t</type> <name>maxGeometryInputComponents</name><comment>max number of input components read in geometry stage</comment></member>
+ <member limittype="max"><type>uint32_t</type> <name>maxGeometryOutputComponents</name><comment>max number of output components written in geometry stage</comment></member>
+ <member limittype="max"><type>uint32_t</type> <name>maxGeometryOutputVertices</name><comment>max number of vertices that can be emitted in geometry stage</comment></member>
+ <member limittype="max"><type>uint32_t</type> <name>maxGeometryTotalOutputComponents</name><comment>max total number of components (all vertices) written in geometry stage</comment></member>
+ <comment>fragment stage limits</comment>
+ <member limittype="max"><type>uint32_t</type> <name>maxFragmentInputComponents</name><comment>max number of input components read in fragment stage</comment></member>
+ <member limittype="max"><type>uint32_t</type> <name>maxFragmentOutputAttachments</name><comment>max number of output attachments written in fragment stage</comment></member>
+ <member limittype="max"><type>uint32_t</type> <name>maxFragmentDualSrcAttachments</name><comment>max number of output attachments written when using dual source blending</comment></member>
+ <member limittype="max"><type>uint32_t</type> <name>maxFragmentCombinedOutputResources</name><comment>max total number of storage buffers, storage images and output buffers</comment></member>
+ <comment>compute stage limits</comment>
+ <member limittype="max"><type>uint32_t</type> <name>maxComputeSharedMemorySize</name><comment>max total storage size of work group local storage (bytes)</comment></member>
+ <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="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>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="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="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>
+ <member limittype="bitmask" optional="true"><type>VkSampleCountFlags</type> <name>framebufferColorSampleCounts</name><comment>supported color sample counts for a framebuffer</comment></member>
+ <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="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="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>
+ </type>
+ <type category="struct" name="VkSemaphoreCreateInfo">
+ <member values="VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member optional="true"><type>VkSemaphoreCreateFlags</type> <name>flags</name><comment>Semaphore creation flags</comment></member>
+ </type>
+ <type category="struct" name="VkQueryPoolCreateInfo">
+ <member values="VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member optional="true"><type>VkQueryPoolCreateFlags</type> <name>flags</name></member>
+ <member><type>VkQueryType</type> <name>queryType</name></member>
+ <member><type>uint32_t</type> <name>queryCount</name></member>
+ <member optional="true" noautovalidity="true"><type>VkQueryPipelineStatisticFlags</type> <name>pipelineStatistics</name><comment>Optional</comment></member>
+ </type>
+ <type category="struct" name="VkFramebufferCreateInfo">
+ <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 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>
+ <member><type>uint32_t</type> <name>height</name></member>
+ <member><type>uint32_t</type> <name>layers</name></member>
+ </type>
+ <type category="struct" name="VkDrawIndirectCommand">
+ <member><type>uint32_t</type> <name>vertexCount</name></member>
+ <member><type>uint32_t</type> <name>instanceCount</name></member>
+ <member><type>uint32_t</type> <name>firstVertex</name></member>
+ <member noautovalidity="true"><type>uint32_t</type> <name>firstInstance</name></member>
+ </type>
+ <type category="struct" name="VkDrawIndexedIndirectCommand">
+ <member><type>uint32_t</type> <name>indexCount</name></member>
+ <member><type>uint32_t</type> <name>instanceCount</name></member>
+ <member><type>uint32_t</type> <name>firstIndex</name></member>
+ <member><type>int32_t</type> <name>vertexOffset</name></member>
+ <member noautovalidity="true"><type>uint32_t</type> <name>firstInstance</name></member>
+ </type>
+ <type category="struct" name="VkDispatchIndirectCommand">
+ <member noautovalidity="true"><type>uint32_t</type> <name>x</name></member>
+ <member noautovalidity="true"><type>uint32_t</type> <name>y</name></member>
+ <member noautovalidity="true"><type>uint32_t</type> <name>z</name></member>
+ </type>
+ <type category="struct" name="VkMultiDrawInfoEXT">
+ <member><type>uint32_t</type> <name>firstVertex</name></member>
+ <member><type>uint32_t</type> <name>vertexCount</name></member>
+ </type>
+ <type category="struct" name="VkMultiDrawIndexedInfoEXT">
+ <member><type>uint32_t</type> <name>firstIndex</name></member>
+ <member><type>uint32_t</type> <name>indexCount</name></member>
+ <member><type>int32_t</type> <name>vertexOffset</name></member>
+ </type>
+ <type category="struct" name="VkSubmitInfo">
+ <member values="VK_STRUCTURE_TYPE_SUBMIT_INFO"><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>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="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>
+ <member len="signalSemaphoreCount">const <type>VkSemaphore</type>* <name>pSignalSemaphores</name></member>
+ </type>
+ <comment>WSI extensions</comment>
+ <type category="struct" name="VkDisplayPropertiesKHR" returnedonly="true">
+ <member><type>VkDisplayKHR</type> <name>display</name><comment>Handle of the display object</comment></member>
+ <member len="null-terminated">const <type>char</type>* <name>displayName</name><comment>Name of the display</comment></member>
+ <member><type>VkExtent2D</type> <name>physicalDimensions</name><comment>In millimeters?</comment></member>
+ <member><type>VkExtent2D</type> <name>physicalResolution</name><comment>Max resolution for CRT?</comment></member>
+ <member optional="true"><type>VkSurfaceTransformFlagsKHR</type> <name>supportedTransforms</name><comment>one or more bits from VkSurfaceTransformFlagsKHR</comment></member>
+ <member><type>VkBool32</type> <name>planeReorderPossible</name><comment>VK_TRUE if the overlay plane's z-order can be changed on this display.</comment></member>
+ <member><type>VkBool32</type> <name>persistentContent</name><comment>VK_TRUE if this is a "smart" display that supports self-refresh/internal buffering.</comment></member>
+ </type>
+ <type category="struct" name="VkDisplayPlanePropertiesKHR" returnedonly="true">
+ <member><type>VkDisplayKHR</type> <name>currentDisplay</name><comment>Display the plane is currently associated with. Will be VK_NULL_HANDLE if the plane is not in use.</comment></member>
+ <member><type>uint32_t</type> <name>currentStackIndex</name><comment>Current z-order of the plane.</comment></member>
+ </type>
+ <type category="struct" name="VkDisplayModeParametersKHR">
+ <member><type>VkExtent2D</type> <name>visibleRegion</name><comment>Visible scanout region.</comment></member>
+ <member noautovalidity="true"><type>uint32_t</type> <name>refreshRate</name><comment>Number of times per second the display is updated.</comment></member>
+ </type>
+ <type category="struct" name="VkDisplayModePropertiesKHR" returnedonly="true">
+ <member><type>VkDisplayModeKHR</type> <name>displayMode</name><comment>Handle of this display mode.</comment></member>
+ <member><type>VkDisplayModeParametersKHR</type> <name>parameters</name><comment>The parameters this mode uses.</comment></member>
+ </type>
+ <type category="struct" name="VkDisplayModeCreateInfoKHR">
+ <member values="VK_STRUCTURE_TYPE_DISPLAY_MODE_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>VkDisplayModeCreateFlagsKHR</type> <name>flags</name></member>
+ <member><type>VkDisplayModeParametersKHR</type> <name>parameters</name><comment>The parameters this mode uses.</comment></member>
+ </type>
+ <type category="struct" name="VkDisplayPlaneCapabilitiesKHR" returnedonly="true">
+ <member optional="true"><type>VkDisplayPlaneAlphaFlagsKHR</type> <name>supportedAlpha</name><comment>Types of alpha blending supported, if any.</comment></member>
+ <member><type>VkOffset2D</type> <name>minSrcPosition</name><comment>Does the plane have any position and extent restrictions?</comment></member>
+ <member><type>VkOffset2D</type> <name>maxSrcPosition</name></member>
+ <member><type>VkExtent2D</type> <name>minSrcExtent</name></member>
+ <member><type>VkExtent2D</type> <name>maxSrcExtent</name></member>
+ <member><type>VkOffset2D</type> <name>minDstPosition</name></member>
+ <member><type>VkOffset2D</type> <name>maxDstPosition</name></member>
+ <member><type>VkExtent2D</type> <name>minDstExtent</name></member>
+ <member><type>VkExtent2D</type> <name>maxDstExtent</name></member>
+ </type>
+ <type category="struct" name="VkDisplaySurfaceCreateInfoKHR">
+ <member values="VK_STRUCTURE_TYPE_DISPLAY_SURFACE_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>VkDisplaySurfaceCreateFlagsKHR</type> <name>flags</name></member>
+ <member><type>VkDisplayModeKHR</type> <name>displayMode</name><comment>The mode to use when displaying this surface</comment></member>
+ <member><type>uint32_t</type> <name>planeIndex</name><comment>The plane on which this surface appears. Must be between 0 and the value returned by vkGetPhysicalDeviceDisplayPlanePropertiesKHR() in pPropertyCount.</comment></member>
+ <member><type>uint32_t</type> <name>planeStackIndex</name><comment>The z-order of the plane.</comment></member>
+ <member><type>VkSurfaceTransformFlagBitsKHR</type> <name>transform</name><comment>Transform to apply to the images as part of the scanout operation</comment></member>
+ <member><type>float</type> <name>globalAlpha</name><comment>Global alpha value. Must be between 0 and 1, inclusive. Ignored if alphaMode is not VK_DISPLAY_PLANE_ALPHA_GLOBAL_BIT_KHR</comment></member>
+ <member><type>VkDisplayPlaneAlphaFlagBitsKHR</type> <name>alphaMode</name><comment>What type of alpha blending to use. Must be a bit from vkGetDisplayPlanePropertiesKHR::supportedAlpha.</comment></member>
+ <member><type>VkExtent2D</type> <name>imageExtent</name><comment>size of the images to use with this surface</comment></member>
+ </type>
+ <type category="struct" name="VkDisplayPresentInfoKHR" structextends="VkPresentInfoKHR">
+ <member values="VK_STRUCTURE_TYPE_DISPLAY_PRESENT_INFO_KHR"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member><type>VkRect2D</type> <name>srcRect</name><comment>Rectangle within the presentable image to read pixel data from when presenting to the display.</comment></member>
+ <member><type>VkRect2D</type> <name>dstRect</name><comment>Rectangle within the current display mode's visible region to display srcRectangle in.</comment></member>
+ <member><type>VkBool32</type> <name>persistent</name><comment>For smart displays, use buffered mode. If the display properties member "persistentMode" is VK_FALSE, this member must always be VK_FALSE.</comment></member>
+ </type>
+ <type category="struct" name="VkSurfaceCapabilitiesKHR" returnedonly="true">
+ <member><type>uint32_t</type> <name>minImageCount</name><comment>Supported minimum number of images for the surface</comment></member>
+ <member><type>uint32_t</type> <name>maxImageCount</name><comment>Supported maximum number of images for the surface, 0 for unlimited</comment></member>
+ <member><type>VkExtent2D</type> <name>currentExtent</name><comment>Current image width and height for the surface, (0, 0) if undefined</comment></member>
+ <member><type>VkExtent2D</type> <name>minImageExtent</name><comment>Supported minimum image width and height for the surface</comment></member>
+ <member><type>VkExtent2D</type> <name>maxImageExtent</name><comment>Supported maximum image width and height for the surface</comment></member>
+ <member><type>uint32_t</type> <name>maxImageArrayLayers</name><comment>Supported maximum number of image layers for the surface</comment></member>
+ <member><type>VkSurfaceTransformFlagsKHR</type> <name>supportedTransforms</name><comment>1 or more bits representing the transforms supported</comment></member>
+ <member><type>VkSurfaceTransformFlagBitsKHR</type> <name>currentTransform</name><comment>The surface's current transform relative to the device's natural orientation</comment></member>
+ <member><type>VkCompositeAlphaFlagsKHR</type> <name>supportedCompositeAlpha</name><comment>1 or more bits representing the alpha compositing modes supported</comment></member>
+ <member><type>VkImageUsageFlags</type> <name>supportedUsageFlags</name><comment>Supported image usage flags for the surface</comment></member>
+ </type>
+ <type category="struct" name="VkAndroidSurfaceCreateInfoKHR">
+ <member values="VK_STRUCTURE_TYPE_ANDROID_SURFACE_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>VkAndroidSurfaceCreateFlagsKHR</type> <name>flags</name></member>
+ <member noautovalidity="true">struct <type>ANativeWindow</type>* <name>window</name></member>
+ </type>
+ <type category="struct" name="VkViSurfaceCreateInfoNN">
+ <member values="VK_STRUCTURE_TYPE_VI_SURFACE_CREATE_INFO_NN"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member optional="true"><type>VkViSurfaceCreateFlagsNN</type> <name>flags</name></member>
+ <member noautovalidity="true"><type>void</type>* <name>window</name></member>
+ </type>
+ <type category="struct" name="VkWaylandSurfaceCreateInfoKHR">
+ <member values="VK_STRUCTURE_TYPE_WAYLAND_SURFACE_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>VkWaylandSurfaceCreateFlagsKHR</type> <name>flags</name></member>
+ <member noautovalidity="true">struct <type>wl_display</type>* <name>display</name></member>
+ <member noautovalidity="true">struct <type>wl_surface</type>* <name>surface</name></member>
+ </type>
+ <type category="struct" name="VkWin32SurfaceCreateInfoKHR">
+ <member values="VK_STRUCTURE_TYPE_WIN32_SURFACE_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>VkWin32SurfaceCreateFlagsKHR</type> <name>flags</name></member>
+ <member><type>HINSTANCE</type> <name>hinstance</name></member>
+ <member><type>HWND</type> <name>hwnd</name></member>
+ </type>
+ <type category="struct" name="VkXlibSurfaceCreateInfoKHR">
+ <member values="VK_STRUCTURE_TYPE_XLIB_SURFACE_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>VkXlibSurfaceCreateFlagsKHR</type> <name>flags</name></member>
+ <member noautovalidity="true"><type>Display</type>* <name>dpy</name></member>
+ <member><type>Window</type> <name>window</name></member>
+ </type>
+ <type category="struct" name="VkXcbSurfaceCreateInfoKHR">
+ <member values="VK_STRUCTURE_TYPE_XCB_SURFACE_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>VkXcbSurfaceCreateFlagsKHR</type> <name>flags</name></member>
+ <member noautovalidity="true"><type>xcb_connection_t</type>* <name>connection</name></member>
+ <member><type>xcb_window_t</type> <name>window</name></member>
+ </type>
+ <type category="struct" name="VkDirectFBSurfaceCreateInfoEXT">
+ <member values="VK_STRUCTURE_TYPE_DIRECTFB_SURFACE_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>VkDirectFBSurfaceCreateFlagsEXT</type> <name>flags</name></member>
+ <member noautovalidity="true"><type>IDirectFB</type>* <name>dfb</name></member>
+ <member noautovalidity="true"><type>IDirectFBSurface</type>* <name>surface</name></member>
+ </type>
+ <type category="struct" name="VkImagePipeSurfaceCreateInfoFUCHSIA">
+ <member values="VK_STRUCTURE_TYPE_IMAGEPIPE_SURFACE_CREATE_INFO_FUCHSIA"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member optional="true"><type>VkImagePipeSurfaceCreateFlagsFUCHSIA</type> <name>flags</name></member>
+ <member><type>zx_handle_t</type> <name>imagePipeHandle</name></member>
+ </type>
+ <type category="struct" name="VkStreamDescriptorSurfaceCreateInfoGGP">
+ <member values="VK_STRUCTURE_TYPE_STREAM_DESCRIPTOR_SURFACE_CREATE_INFO_GGP"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member optional="true"><type>VkStreamDescriptorSurfaceCreateFlagsGGP</type> <name>flags</name></member>
+ <member><type>GgpStreamDescriptor</type> <name>streamDescriptor</name></member>
+ </type>
+ <type category="struct" name="VkScreenSurfaceCreateInfoQNX">
+ <member values="VK_STRUCTURE_TYPE_SCREEN_SURFACE_CREATE_INFO_QNX"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member optional="true"><type>VkScreenSurfaceCreateFlagsQNX</type> <name>flags</name></member>
+ <member noautovalidity="true">struct <type>_screen_context</type>* <name>context</name></member>
+ <member noautovalidity="true">struct <type>_screen_window</type>* <name>window</name></member>
+ </type>
+ <type category="struct" name="VkSurfaceFormatKHR" returnedonly="true">
+ <member><type>VkFormat</type> <name>format</name><comment>Supported pair of rendering format</comment></member>
+ <member><type>VkColorSpaceKHR</type> <name>colorSpace</name><comment>and color space for the surface</comment></member>
+ </type>
+ <type category="struct" name="VkSwapchainCreateInfoKHR">
+ <member values="VK_STRUCTURE_TYPE_SWAPCHAIN_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>VkSwapchainCreateFlagsKHR</type> <name>flags</name></member>
+ <member><type>VkSurfaceKHR</type> <name>surface</name><comment>The swapchain's target surface</comment></member>
+ <member><type>uint32_t</type> <name>minImageCount</name><comment>Minimum number of presentation images the application needs</comment></member>
+ <member><type>VkFormat</type> <name>imageFormat</name><comment>Format of the presentation images</comment></member>
+ <member><type>VkColorSpaceKHR</type> <name>imageColorSpace</name><comment>Colorspace of the presentation images</comment></member>
+ <member><type>VkExtent2D</type> <name>imageExtent</name><comment>Dimensions of the presentation images</comment></member>
+ <member><type>uint32_t</type> <name>imageArrayLayers</name><comment>Determines the number of views for multiview/stereo presentation</comment></member>
+ <member><type>VkImageUsageFlags</type> <name>imageUsage</name><comment>Bits indicating how the presentation images will be used</comment></member>
+ <member><type>VkSharingMode</type> <name>imageSharingMode</name><comment>Sharing mode used for the presentation images</comment></member>
+ <member optional="true"><type>uint32_t</type> <name>queueFamilyIndexCount</name><comment>Number of queue families having access to the images in case of concurrent sharing mode</comment></member>
+ <member noautovalidity="true" len="queueFamilyIndexCount">const <type>uint32_t</type>* <name>pQueueFamilyIndices</name><comment>Array of queue family indices having access to the images in case of concurrent sharing mode</comment></member>
+ <member><type>VkSurfaceTransformFlagBitsKHR</type> <name>preTransform</name><comment>The transform, relative to the device's natural orientation, applied to the image content prior to presentation</comment></member>
+ <member><type>VkCompositeAlphaFlagBitsKHR</type> <name>compositeAlpha</name><comment>The alpha blending mode used when compositing this surface with other surfaces in the window system</comment></member>
+ <member><type>VkPresentModeKHR</type> <name>presentMode</name><comment>Which presentation mode to use for presents on this swap chain</comment></member>
+ <member><type>VkBool32</type> <name>clipped</name><comment>Specifies whether presentable images may be affected by window clip regions</comment></member>
+ <member optional="true"><type>VkSwapchainKHR</type> <name>oldSwapchain</name><comment>Existing swap chain to replace, if any</comment></member>
+ </type>
+ <type category="struct" name="VkPresentInfoKHR">
+ <member values="VK_STRUCTURE_TYPE_PRESENT_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>waitSemaphoreCount</name><comment>Number of semaphores to wait for before presenting</comment></member>
+ <member len="waitSemaphoreCount">const <type>VkSemaphore</type>* <name>pWaitSemaphores</name><comment>Semaphores to wait for before presenting</comment></member>
+ <member><type>uint32_t</type> <name>swapchainCount</name><comment>Number of swapchains to present in this call</comment></member>
+ <member len="swapchainCount">const <type>VkSwapchainKHR</type>* <name>pSwapchains</name><comment>Swapchains to present an image from</comment></member>
+ <member len="swapchainCount">const <type>uint32_t</type>* <name>pImageIndices</name><comment>Indices of which presentable images to present</comment></member>
+ <member optional="true" len="swapchainCount"><type>VkResult</type>* <name>pResults</name><comment>Optional (i.e. if non-NULL) VkResult for each swapchain</comment></member>
+ </type>
+ <type category="struct" name="VkDebugReportCallbackCreateInfoEXT" structextends="VkInstanceCreateInfo">
+ <member values="VK_STRUCTURE_TYPE_DEBUG_REPORT_CALLBACK_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>VkDebugReportFlagsEXT</type> <name>flags</name><comment>Indicates which events call this callback</comment></member>
+ <member><type>PFN_vkDebugReportCallbackEXT</type> <name>pfnCallback</name><comment>Function pointer of a callback function</comment></member>
+ <member optional="true"><type>void</type>* <name>pUserData</name><comment>User data provided to callback function</comment></member>
+ </type>
+ <type category="struct" name="VkValidationFlagsEXT" structextends="VkInstanceCreateInfo">
+ <member values="VK_STRUCTURE_TYPE_VALIDATION_FLAGS_EXT"><type>VkStructureType</type> <name>sType</name><comment>Must be VK_STRUCTURE_TYPE_VALIDATION_FLAGS_EXT</comment></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member><type>uint32_t</type> <name>disabledValidationCheckCount</name><comment>Number of validation checks to disable</comment></member>
+ <member len="disabledValidationCheckCount">const <type>VkValidationCheckEXT</type>* <name>pDisabledValidationChecks</name><comment>Validation checks to disable</comment></member>
+ </type>
+ <type category="struct" name="VkValidationFeaturesEXT" structextends="VkInstanceCreateInfo">
+ <member values="VK_STRUCTURE_TYPE_VALIDATION_FEATURES_EXT"><type>VkStructureType</type> <name>sType</name><comment>Must be VK_STRUCTURE_TYPE_VALIDATION_FEATURES_EXT</comment></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member optional="true"><type>uint32_t</type> <name>enabledValidationFeatureCount</name><comment>Number of validation features to enable</comment></member>
+ <member len="enabledValidationFeatureCount">const <type>VkValidationFeatureEnableEXT</type>* <name>pEnabledValidationFeatures</name><comment>Validation features to enable</comment></member>
+ <member optional="true"><type>uint32_t</type> <name>disabledValidationFeatureCount</name><comment>Number of validation features to disable</comment></member>
+ <member len="disabledValidationFeatureCount">const <type>VkValidationFeatureDisableEXT</type>* <name>pDisabledValidationFeatures</name><comment>Validation features to disable</comment></member>
+ </type>
+ <type category="struct" name="VkPipelineRasterizationStateRasterizationOrderAMD" structextends="VkPipelineRasterizationStateCreateInfo">
+ <member values="VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_RASTERIZATION_ORDER_AMD"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member><type>VkRasterizationOrderAMD</type> <name>rasterizationOrder</name><comment>Rasterization order to use for the pipeline</comment></member>
+ </type>
+ <type category="struct" name="VkDebugMarkerObjectNameInfoEXT">
+ <member values="VK_STRUCTURE_TYPE_DEBUG_MARKER_OBJECT_NAME_INFO_EXT"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member><type>VkDebugReportObjectTypeEXT</type> <name>objectType</name><comment>The type of the object</comment></member>
+ <member objecttype="objectType"><type>uint64_t</type> <name>object</name><comment>The handle of the object, cast to uint64_t</comment></member>
+ <member len="null-terminated">const <type>char</type>* <name>pObjectName</name><comment>Name to apply to the object</comment></member>
+ </type>
+ <type category="struct" name="VkDebugMarkerObjectTagInfoEXT">
+ <member values="VK_STRUCTURE_TYPE_DEBUG_MARKER_OBJECT_TAG_INFO_EXT"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member><type>VkDebugReportObjectTypeEXT</type> <name>objectType</name><comment>The type of the object</comment></member>
+ <member objecttype="objectType"><type>uint64_t</type> <name>object</name><comment>The handle of the object, cast to uint64_t</comment></member>
+ <member><type>uint64_t</type> <name>tagName</name><comment>The name of the tag to set on the object</comment></member>
+ <member><type>size_t</type> <name>tagSize</name><comment>The length in bytes of the tag data</comment></member>
+ <member len="tagSize">const <type>void</type>* <name>pTag</name><comment>Tag data to attach to the object</comment></member>
+ </type>
+ <type category="struct" name="VkDebugMarkerMarkerInfoEXT">
+ <member values="VK_STRUCTURE_TYPE_DEBUG_MARKER_MARKER_INFO_EXT"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member len="null-terminated">const <type>char</type>* <name>pMarkerName</name><comment>Name of the debug marker</comment></member>
+ <member><type>float</type> <name>color</name>[4]<comment>Optional color for debug marker</comment></member>
+ </type>
+ <type category="struct" name="VkDedicatedAllocationImageCreateInfoNV" structextends="VkImageCreateInfo">
+ <member values="VK_STRUCTURE_TYPE_DEDICATED_ALLOCATION_IMAGE_CREATE_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>dedicatedAllocation</name><comment>Whether this image uses a dedicated allocation</comment></member>
+ </type>
+ <type category="struct" name="VkDedicatedAllocationBufferCreateInfoNV" structextends="VkBufferCreateInfo">
+ <member values="VK_STRUCTURE_TYPE_DEDICATED_ALLOCATION_BUFFER_CREATE_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>dedicatedAllocation</name><comment>Whether this buffer uses a dedicated allocation</comment></member>
+ </type>
+ <type category="struct" name="VkDedicatedAllocationMemoryAllocateInfoNV" structextends="VkMemoryAllocateInfo">
+ <member values="VK_STRUCTURE_TYPE_DEDICATED_ALLOCATION_MEMORY_ALLOCATE_INFO_NV"><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><comment>Image that this allocation will be bound to</comment></member>
+ <member optional="true"><type>VkBuffer</type> <name>buffer</name><comment>Buffer that this allocation will be bound to</comment></member>
+ </type>
+ <type category="struct" name="VkExternalImageFormatPropertiesNV" returnedonly="true">
+ <member><type>VkImageFormatProperties</type> <name>imageFormatProperties</name></member>
+ <member optional="true"><type>VkExternalMemoryFeatureFlagsNV</type> <name>externalMemoryFeatures</name></member>
+ <member optional="true"><type>VkExternalMemoryHandleTypeFlagsNV</type> <name>exportFromImportedHandleTypes</name></member>
+ <member optional="true"><type>VkExternalMemoryHandleTypeFlagsNV</type> <name>compatibleHandleTypes</name></member>
+ </type>
+ <type category="struct" name="VkExternalMemoryImageCreateInfoNV" structextends="VkImageCreateInfo">
+ <member values="VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO_NV"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member optional="true"><type>VkExternalMemoryHandleTypeFlagsNV</type> <name>handleTypes</name></member>
+ </type>
+ <type category="struct" name="VkExportMemoryAllocateInfoNV" structextends="VkMemoryAllocateInfo">
+ <member values="VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO_NV"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member optional="true"><type>VkExternalMemoryHandleTypeFlagsNV</type> <name>handleTypes</name></member>
+ </type>
+ <type category="struct" name="VkImportMemoryWin32HandleInfoNV" structextends="VkMemoryAllocateInfo">
+ <member values="VK_STRUCTURE_TYPE_IMPORT_MEMORY_WIN32_HANDLE_INFO_NV"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member optional="true"><type>VkExternalMemoryHandleTypeFlagsNV</type> <name>handleType</name></member>
+ <member optional="true"><type>HANDLE</type> <name>handle</name></member>
+ </type>
+ <type category="struct" name="VkExportMemoryWin32HandleInfoNV" structextends="VkMemoryAllocateInfo">
+ <member values="VK_STRUCTURE_TYPE_EXPORT_MEMORY_WIN32_HANDLE_INFO_NV"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <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">
+ <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>
+ <member len="acquireCount">const <type>VkDeviceMemory</type>* <name>pAcquireSyncs</name></member>
+ <member len="acquireCount">const <type>uint64_t</type>* <name>pAcquireKeys</name></member>
+ <member len="acquireCount">const <type>uint32_t</type>* <name>pAcquireTimeoutMilliseconds</name></member>
+ <member optional="true"><type>uint32_t</type> <name>releaseCount</name></member>
+ <member len="releaseCount">const <type>VkDeviceMemory</type>* <name>pReleaseSyncs</name></member>
+ <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 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>
+ <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>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member><type>VkPrivateDataSlotCreateFlagsEXT</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>
+ <member optional="true"><type>void</type>* <name>pNext</name></member>
+ <member><type>VkBool32</type> <name>privateData</name></member>
+ </type>
+ <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>
+ <member limittype="max"><type>uint32_t</type> <name>maxGraphicsShaderGroupCount</name></member>
+ <member limittype="max"><type>uint32_t</type> <name>maxIndirectSequenceCount</name></member>
+ <member limittype="max"><type>uint32_t</type> <name>maxIndirectCommandsTokenCount</name></member>
+ <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>
+ </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>
+ </type>
+ <type category="struct" name="VkGraphicsShaderGroupCreateInfoNV">
+ <member values="VK_STRUCTURE_TYPE_GRAPHICS_SHADER_GROUP_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>stageCount</name></member>
+ <member len="stageCount">const <type>VkPipelineShaderStageCreateInfo</type>* <name>pStages</name></member>
+ <member noautovalidity="true" optional="true">const <type>VkPipelineVertexInputStateCreateInfo</type>* <name>pVertexInputState</name></member>
+ <member noautovalidity="true" optional="true">const <type>VkPipelineTessellationStateCreateInfo</type>* <name>pTessellationState</name></member>
+ </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 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>
+ </type>
+ <type category="struct" name="VkBindShaderGroupIndirectCommandNV">
+ <member><type>uint32_t</type> <name>groupIndex</name></member>
+ </type>
+ <type category="struct" name="VkBindIndexBufferIndirectCommandNV">
+ <member><type>VkDeviceAddress</type> <name>bufferAddress</name></member>
+ <member><type>uint32_t</type> <name>size</name></member>
+ <member><type>VkIndexType</type> <name>indexType</name></member>
+ </type>
+ <type category="struct" name="VkBindVertexBufferIndirectCommandNV">
+ <member><type>VkDeviceAddress</type> <name>bufferAddress</name></member>
+ <member><type>uint32_t</type> <name>size</name></member>
+ <member><type>uint32_t</type> <name>stride</name></member>
+ </type>
+ <type category="struct" name="VkSetStateFlagsIndirectCommandNV">
+ <member><type>uint32_t</type> <name>data</name></member>
+ </type>
+ <type category="struct" name="VkIndirectCommandsStreamNV">
+ <member><type>VkBuffer</type> <name>buffer</name></member>
+ <member><type>VkDeviceSize</type> <name>offset</name></member>
+ </type>
+ <type category="struct" name="VkIndirectCommandsLayoutTokenNV">
+ <member values="VK_STRUCTURE_TYPE_INDIRECT_COMMANDS_LAYOUT_TOKEN_NV"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member><type>VkIndirectCommandsTokenTypeNV</type> <name>tokenType</name></member>
+ <member><type>uint32_t</type> <name>stream</name></member>
+ <member><type>uint32_t</type> <name>offset</name></member>
+ <member><type>uint32_t</type> <name>vertexBindingUnit</name></member>
+ <member><type>VkBool32</type> <name>vertexDynamicStride</name></member>
+ <member optional="true"><type>VkPipelineLayout</type> <name>pushconstantPipelineLayout</name></member>
+ <member optional="true"><type>VkShaderStageFlags</type> <name>pushconstantShaderStageFlags</name></member>
+ <member><type>uint32_t</type> <name>pushconstantOffset</name></member>
+ <member><type>uint32_t</type> <name>pushconstantSize</name></member>
+ <member optional="true"><type>VkIndirectStateFlagsNV</type> <name>indirectStateFlags</name></member>
+ <member optional="true"><type>uint32_t</type> <name>indexTypeCount</name></member>
+ <member len="indexTypeCount">const <type>VkIndexType</type>* <name>pIndexTypes</name></member>
+ <member len="indexTypeCount">const <type>uint32_t</type>* <name>pIndexTypeValues</name></member>
+ </type>
+ <type category="struct" name="VkIndirectCommandsLayoutCreateInfoNV">
+ <member values="VK_STRUCTURE_TYPE_INDIRECT_COMMANDS_LAYOUT_CREATE_INFO_NV"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member optional="true"><type>VkIndirectCommandsLayoutUsageFlagsNV</type> <name>flags</name></member>
+ <member><type>VkPipelineBindPoint</type> <name>pipelineBindPoint</name></member>
+ <member><type>uint32_t</type> <name>tokenCount</name></member>
+ <member len="tokenCount">const <type>VkIndirectCommandsLayoutTokenNV</type>* <name>pTokens</name></member>
+ <member><type>uint32_t</type> <name>streamCount</name></member>
+ <member len="streamCount">const <type>uint32_t</type>* <name>pStreamStrides</name></member>
+ </type>
+ <type category="struct" name="VkGeneratedCommandsInfoNV">
+ <member values="VK_STRUCTURE_TYPE_GENERATED_COMMANDS_INFO_NV"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member><type>VkPipelineBindPoint</type> <name>pipelineBindPoint</name></member>
+ <member><type>VkPipeline</type> <name>pipeline</name></member>
+ <member><type>VkIndirectCommandsLayoutNV</type> <name>indirectCommandsLayout</name></member>
+ <member><type>uint32_t</type> <name>streamCount</name></member>
+ <member len="streamCount">const <type>VkIndirectCommandsStreamNV</type>* <name>pStreams</name></member>
+ <member><type>uint32_t</type> <name>sequencesCount</name></member>
+ <member><type>VkBuffer</type> <name>preprocessBuffer</name></member>
+ <member><type>VkDeviceSize</type> <name>preprocessOffset</name></member>
+ <member><type>VkDeviceSize</type> <name>preprocessSize</name></member>
+ <member optional="true"><type>VkBuffer</type> <name>sequencesCountBuffer</name></member>
+ <member><type>VkDeviceSize</type> <name>sequencesCountOffset</name></member>
+ <member optional="true"><type>VkBuffer</type> <name>sequencesIndexBuffer</name></member>
+ <member><type>VkDeviceSize</type> <name>sequencesIndexOffset</name></member>
+ </type>
+ <type category="struct" name="VkGeneratedCommandsMemoryRequirementsInfoNV">
+ <member values="VK_STRUCTURE_TYPE_GENERATED_COMMANDS_MEMORY_REQUIREMENTS_INFO_NV"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member><type>VkPipelineBindPoint</type> <name>pipelineBindPoint</name></member>
+ <member><type>VkPipeline</type> <name>pipeline</name></member>
+ <member><type>VkIndirectCommandsLayoutNV</type> <name>indirectCommandsLayout</name></member>
+ <member><type>uint32_t</type> <name>maxSequencesCount</name></member>
+ </type>
+ <type category="struct" name="VkPhysicalDeviceFeatures2" structextends="VkDeviceCreateInfo">
+ <member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true"><type>void</type>* <name>pNext</name></member>
+ <member><type>VkPhysicalDeviceFeatures</type> <name>features</name></member>
+ </type>
+ <type category="struct" name="VkPhysicalDeviceFeatures2KHR" alias="VkPhysicalDeviceFeatures2"/>
+ <type category="struct" name="VkPhysicalDeviceProperties2" returnedonly="true">
+ <member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true"><type>void</type>* <name>pNext</name></member>
+ <member limittype="struct"><type>VkPhysicalDeviceProperties</type> <name>properties</name></member>
+ </type>
+ <type category="struct" name="VkPhysicalDeviceProperties2KHR" alias="VkPhysicalDeviceProperties2"/>
+ <type category="struct" name="VkFormatProperties2" returnedonly="true">
+ <member values="VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true"><type>void</type>* <name>pNext</name></member>
+ <member><type>VkFormatProperties</type> <name>formatProperties</name></member>
+ </type>
+ <type category="struct" name="VkFormatProperties2KHR" alias="VkFormatProperties2"/>
+ <type category="struct" name="VkImageFormatProperties2" returnedonly="true">
+ <member values="VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true"><type>void</type>* <name>pNext</name></member>
+ <member><type>VkImageFormatProperties</type> <name>imageFormatProperties</name></member>
+ </type>
+ <type category="struct" name="VkImageFormatProperties2KHR" alias="VkImageFormatProperties2"/>
+ <type category="struct" name="VkPhysicalDeviceImageFormatInfo2">
+ <member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2"><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>
+ <member><type>VkImageType</type> <name>type</name></member>
+ <member><type>VkImageTiling</type> <name>tiling</name></member>
+ <member><type>VkImageUsageFlags</type> <name>usage</name></member>
+ <member optional="true"><type>VkImageCreateFlags</type> <name>flags</name></member>
+ </type>
+ <type category="struct" name="VkPhysicalDeviceImageFormatInfo2KHR" alias="VkPhysicalDeviceImageFormatInfo2"/>
+ <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>
+ </type>
+ <type category="struct" name="VkQueueFamilyProperties2KHR" alias="VkQueueFamilyProperties2"/>
+ <type category="struct" name="VkPhysicalDeviceMemoryProperties2" returnedonly="true">
+ <member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_PROPERTIES_2"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true"><type>void</type>* <name>pNext</name></member>
+ <member><type>VkPhysicalDeviceMemoryProperties</type> <name>memoryProperties</name></member>
+ </type>
+ <type category="struct" name="VkPhysicalDeviceMemoryProperties2KHR" alias="VkPhysicalDeviceMemoryProperties2"/>
+ <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>
+ </type>
+ <type category="struct" name="VkSparseImageFormatProperties2KHR" alias="VkSparseImageFormatProperties2"/>
+ <type category="struct" name="VkPhysicalDeviceSparseImageFormatInfo2">
+ <member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SPARSE_IMAGE_FORMAT_INFO_2"><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>
+ <member><type>VkImageType</type> <name>type</name></member>
+ <member><type>VkSampleCountFlagBits</type> <name>samples</name></member>
+ <member><type>VkImageUsageFlags</type> <name>usage</name></member>
+ <member><type>VkImageTiling</type> <name>tiling</name></member>
+ </type>
+ <type category="struct" name="VkPhysicalDeviceSparseImageFormatInfo2KHR" alias="VkPhysicalDeviceSparseImageFormatInfo2"/>
+ <type category="struct" name="VkPhysicalDevicePushDescriptorPropertiesKHR" returnedonly="true" structextends="VkPhysicalDeviceProperties2">
+ <member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PUSH_DESCRIPTOR_PROPERTIES_KHR"><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>maxPushDescriptors</name></member>
+ </type>
+ <type category="struct" name="VkConformanceVersion">
+ <member><type>uint8_t</type> <name>major</name></member>
+ <member><type>uint8_t</type> <name>minor</name></member>
+ <member><type>uint8_t</type> <name>subminor</name></member>
+ <member><type>uint8_t</type> <name>patch</name></member>
+ </type>
+ <type category="struct" name="VkConformanceVersionKHR" alias="VkConformanceVersion"/>
+ <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>
+ </type>
+ <type category="struct" name="VkPhysicalDeviceDriverPropertiesKHR" alias="VkPhysicalDeviceDriverProperties"/>
+ <type category="struct" name="VkPresentRegionsKHR" structextends="VkPresentInfoKHR">
+ <member values="VK_STRUCTURE_TYPE_PRESENT_REGIONS_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>swapchainCount</name><comment>Copy of VkPresentInfoKHR::swapchainCount</comment></member>
+ <member len="swapchainCount" optional="true">const <type>VkPresentRegionKHR</type>* <name>pRegions</name><comment>The regions that have changed</comment></member>
+ </type>
+ <type category="struct" name="VkPresentRegionKHR">
+ <member optional="true"><type>uint32_t</type> <name>rectangleCount</name><comment>Number of rectangles in pRectangles</comment></member>
+ <member optional="true" len="rectangleCount">const <type>VkRectLayerKHR</type>* <name>pRectangles</name><comment>Array of rectangles that have changed in a swapchain's image(s)</comment></member>
+ </type>
+ <type category="struct" name="VkRectLayerKHR">
+ <member><type>VkOffset2D</type> <name>offset</name><comment>upper-left corner of a rectangle that has not changed, in pixels of a presentation images</comment></member>
+ <member noautovalidity="true"><type>VkExtent2D</type> <name>extent</name><comment>Dimensions of a rectangle that has not changed, in pixels of a presentation images</comment></member>
+ <member><type>uint32_t</type> <name>layer</name><comment>Layer of a swapchain's image(s), for stereoscopic-3D images</comment></member>
+ </type>
+ <type category="struct" name="VkPhysicalDeviceVariablePointersFeatures" structextends="VkPhysicalDeviceFeatures2,VkDeviceCreateInfo">
+ <member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VARIABLE_POINTERS_FEATURES"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true"><type>void</type>* <name>pNext</name></member>
+ <member><type>VkBool32</type> <name>variablePointersStorageBuffer</name></member>
+ <member><type>VkBool32</type> <name>variablePointers</name></member>
+ </type>
+ <type category="struct" name="VkPhysicalDeviceVariablePointersFeaturesKHR" alias="VkPhysicalDeviceVariablePointersFeatures"/>
+ <type category="struct" name="VkPhysicalDeviceVariablePointerFeaturesKHR" alias="VkPhysicalDeviceVariablePointersFeatures"/>
+ <type category="struct" name="VkPhysicalDeviceVariablePointerFeatures" alias="VkPhysicalDeviceVariablePointersFeatures"/>
+ <type category="struct" name="VkExternalMemoryProperties" returnedonly="true">
+ <member><type>VkExternalMemoryFeatureFlags</type> <name>externalMemoryFeatures</name></member>
+ <member optional="true"><type>VkExternalMemoryHandleTypeFlags</type> <name>exportFromImportedHandleTypes</name></member>
+ <member><type>VkExternalMemoryHandleTypeFlags</type> <name>compatibleHandleTypes</name></member>
+ </type>
+ <type category="struct" name="VkExternalMemoryPropertiesKHR" alias="VkExternalMemoryProperties"/>
+ <type category="struct" name="VkPhysicalDeviceExternalImageFormatInfo" structextends="VkPhysicalDeviceImageFormatInfo2">
+ <member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_IMAGE_FORMAT_INFO"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member optional="true"><type>VkExternalMemoryHandleTypeFlagBits</type> <name>handleType</name></member>
+ </type>
+ <type category="struct" name="VkPhysicalDeviceExternalImageFormatInfoKHR" alias="VkPhysicalDeviceExternalImageFormatInfo"/>
+ <type category="struct" name="VkExternalImageFormatProperties" returnedonly="true" structextends="VkImageFormatProperties2">
+ <member values="VK_STRUCTURE_TYPE_EXTERNAL_IMAGE_FORMAT_PROPERTIES"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true"><type>void</type>* <name>pNext</name></member>
+ <member><type>VkExternalMemoryProperties</type> <name>externalMemoryProperties</name></member>
+ </type>
+ <type category="struct" name="VkExternalImageFormatPropertiesKHR" alias="VkExternalImageFormatProperties"/>
+ <type category="struct" name="VkPhysicalDeviceExternalBufferInfo">
+ <member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_BUFFER_INFO"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member optional="true"><type>VkBufferCreateFlags</type> <name>flags</name></member>
+ <member><type>VkBufferUsageFlags</type> <name>usage</name></member>
+ <member><type>VkExternalMemoryHandleTypeFlagBits</type> <name>handleType</name></member>
+ </type>
+ <type category="struct" name="VkPhysicalDeviceExternalBufferInfoKHR" alias="VkPhysicalDeviceExternalBufferInfo"/>
+ <type category="struct" name="VkExternalBufferProperties" returnedonly="true">
+ <member values="VK_STRUCTURE_TYPE_EXTERNAL_BUFFER_PROPERTIES"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true"><type>void</type>* <name>pNext</name></member>
+ <member><type>VkExternalMemoryProperties</type> <name>externalMemoryProperties</name></member>
+ </type>
+ <type category="struct" name="VkExternalBufferPropertiesKHR" alias="VkExternalBufferProperties"/>
+ <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>
+ </type>
+ <type category="struct" name="VkPhysicalDeviceIDPropertiesKHR" alias="VkPhysicalDeviceIDProperties"/>
+ <type category="struct" name="VkExternalMemoryImageCreateInfo" structextends="VkImageCreateInfo">
+ <member values="VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member optional="true"><type>VkExternalMemoryHandleTypeFlags</type> <name>handleTypes</name></member>
+ </type>
+ <type category="struct" name="VkExternalMemoryImageCreateInfoKHR" alias="VkExternalMemoryImageCreateInfo"/>
+ <type category="struct" name="VkExternalMemoryBufferCreateInfo" structextends="VkBufferCreateInfo">
+ <member values="VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_BUFFER_CREATE_INFO"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member optional="true"><type>VkExternalMemoryHandleTypeFlags</type> <name>handleTypes</name></member>
+ </type>
+ <type category="struct" name="VkExternalMemoryBufferCreateInfoKHR" alias="VkExternalMemoryBufferCreateInfo"/>
+ <type category="struct" name="VkExportMemoryAllocateInfo" structextends="VkMemoryAllocateInfo">
+ <member values="VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member optional="true"><type>VkExternalMemoryHandleTypeFlags</type> <name>handleTypes</name></member>
+ </type>
+ <type category="struct" name="VkExportMemoryAllocateInfoKHR" alias="VkExportMemoryAllocateInfo"/>
+ <type category="struct" name="VkImportMemoryWin32HandleInfoKHR" structextends="VkMemoryAllocateInfo">
+ <member values="VK_STRUCTURE_TYPE_IMPORT_MEMORY_WIN32_HANDLE_INFO_KHR"><type>VkStructureType</type> <name>sType</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>HANDLE</type> <name>handle</name></member>
+ <member optional="true"><type>LPCWSTR</type> <name>name</name></member>
+ </type>
+ <type category="struct" name="VkExportMemoryWin32HandleInfoKHR" structextends="VkMemoryAllocateInfo">
+ <member values="VK_STRUCTURE_TYPE_EXPORT_MEMORY_WIN32_HANDLE_INFO_KHR"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member optional="true">const <type>SECURITY_ATTRIBUTES</type>* <name>pAttributes</name></member>
+ <member><type>DWORD</type> <name>dwAccess</name></member>
+ <member><type>LPCWSTR</type> <name>name</name></member>
+ </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"><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><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><type>VkDeviceMemory</type> <name>memory</name></member>
+ <member><type>VkExternalMemoryHandleTypeFlagBits</type> <name>handleType</name></member>
+ </type>
+ <type category="struct" name="VkMemoryWin32HandlePropertiesKHR" returnedonly="true">
+ <member values="VK_STRUCTURE_TYPE_MEMORY_WIN32_HANDLE_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>memoryTypeBits</name></member>
+ </type>
+ <type category="struct" name="VkMemoryGetWin32HandleInfoKHR">
+ <member values="VK_STRUCTURE_TYPE_MEMORY_GET_WIN32_HANDLE_INFO_KHR"><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>VkExternalMemoryHandleTypeFlagBits</type> <name>handleType</name></member>
+ </type>
+ <type category="struct" name="VkImportMemoryFdInfoKHR" structextends="VkMemoryAllocateInfo">
+ <member values="VK_STRUCTURE_TYPE_IMPORT_MEMORY_FD_INFO_KHR"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member optional="true"><type>VkExternalMemoryHandleTypeFlagBits</type> <name>handleType</name></member>
+ <member><type>int</type> <name>fd</name></member>
+ </type>
+ <type category="struct" name="VkMemoryFdPropertiesKHR" returnedonly="true">
+ <member values="VK_STRUCTURE_TYPE_MEMORY_FD_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>memoryTypeBits</name></member>
+ </type>
+ <type category="struct" name="VkMemoryGetFdInfoKHR">
+ <member values="VK_STRUCTURE_TYPE_MEMORY_GET_FD_INFO_KHR"><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>VkExternalMemoryHandleTypeFlagBits</type> <name>handleType</name></member>
+ </type>
+ <type category="struct" name="VkWin32KeyedMutexAcquireReleaseInfoKHR" structextends="VkSubmitInfo,VkSubmitInfo2KHR">
+ <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>
+ <member len="acquireCount">const <type>VkDeviceMemory</type>* <name>pAcquireSyncs</name></member>
+ <member len="acquireCount">const <type>uint64_t</type>* <name>pAcquireKeys</name></member>
+ <member len="acquireCount">const <type>uint32_t</type>* <name>pAcquireTimeouts</name></member>
+ <member optional="true"><type>uint32_t</type> <name>releaseCount</name></member>
+ <member len="releaseCount">const <type>VkDeviceMemory</type>* <name>pReleaseSyncs</name></member>
+ <member len="releaseCount">const <type>uint64_t</type>* <name>pReleaseKeys</name></member>
+ </type>
+ <type category="struct" name="VkPhysicalDeviceExternalSemaphoreInfo">
+ <member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_SEMAPHORE_INFO"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member><type>VkExternalSemaphoreHandleTypeFlagBits</type> <name>handleType</name></member>
+ </type>
+ <type category="struct" name="VkPhysicalDeviceExternalSemaphoreInfoKHR" alias="VkPhysicalDeviceExternalSemaphoreInfo"/>
+ <type category="struct" name="VkExternalSemaphoreProperties" returnedonly="true">
+ <member values="VK_STRUCTURE_TYPE_EXTERNAL_SEMAPHORE_PROPERTIES"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true"><type>void</type>* <name>pNext</name></member>
+ <member><type>VkExternalSemaphoreHandleTypeFlags</type> <name>exportFromImportedHandleTypes</name></member>
+ <member><type>VkExternalSemaphoreHandleTypeFlags</type> <name>compatibleHandleTypes</name></member>
+ <member optional="true"><type>VkExternalSemaphoreFeatureFlags</type> <name>externalSemaphoreFeatures</name></member>
+ </type>
+ <type category="struct" name="VkExternalSemaphorePropertiesKHR" alias="VkExternalSemaphoreProperties"/>
+ <type category="struct" name="VkExportSemaphoreCreateInfo" structextends="VkSemaphoreCreateInfo">
+ <member values="VK_STRUCTURE_TYPE_EXPORT_SEMAPHORE_CREATE_INFO"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member optional="true"><type>VkExternalSemaphoreHandleTypeFlags</type> <name>handleTypes</name></member>
+ </type>
+ <type category="struct" name="VkExportSemaphoreCreateInfoKHR" alias="VkExportSemaphoreCreateInfo"/>
+ <type category="struct" name="VkImportSemaphoreWin32HandleInfoKHR">
+ <member values="VK_STRUCTURE_TYPE_IMPORT_SEMAPHORE_WIN32_HANDLE_INFO_KHR"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member externsync="true"><type>VkSemaphore</type> <name>semaphore</name></member>
+ <member optional="true"><type>VkSemaphoreImportFlags</type> <name>flags</name></member>
+ <member noautovalidity="true"><type>VkExternalSemaphoreHandleTypeFlagBits</type> <name>handleType</name></member>
+ <member optional="true"><type>HANDLE</type> <name>handle</name></member>
+ <member optional="true"><type>LPCWSTR</type> <name>name</name></member>
+ </type>
+ <type category="struct" name="VkExportSemaphoreWin32HandleInfoKHR" structextends="VkSemaphoreCreateInfo">
+ <member values="VK_STRUCTURE_TYPE_EXPORT_SEMAPHORE_WIN32_HANDLE_INFO_KHR"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member optional="true">const <type>SECURITY_ATTRIBUTES</type>* <name>pAttributes</name></member>
+ <member><type>DWORD</type> <name>dwAccess</name></member>
+ <member><type>LPCWSTR</type> <name>name</name></member>
+ </type>
+ <type category="struct" name="VkD3D12FenceSubmitInfoKHR" structextends="VkSubmitInfo">
+ <member values="VK_STRUCTURE_TYPE_D3D12_FENCE_SUBMIT_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>waitSemaphoreValuesCount</name></member>
+ <member optional="true" len="waitSemaphoreValuesCount">const <type>uint64_t</type>* <name>pWaitSemaphoreValues</name></member>
+ <member optional="true"><type>uint32_t</type> <name>signalSemaphoreValuesCount</name></member>
+ <member optional="true" len="signalSemaphoreValuesCount">const <type>uint64_t</type>* <name>pSignalSemaphoreValues</name></member>
+ </type>
+ <type category="struct" name="VkSemaphoreGetWin32HandleInfoKHR">
+ <member values="VK_STRUCTURE_TYPE_SEMAPHORE_GET_WIN32_HANDLE_INFO_KHR"><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>VkExternalSemaphoreHandleTypeFlagBits</type> <name>handleType</name></member>
+ </type>
+ <type category="struct" name="VkImportSemaphoreFdInfoKHR">
+ <member values="VK_STRUCTURE_TYPE_IMPORT_SEMAPHORE_FD_INFO_KHR"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member externsync="true"><type>VkSemaphore</type> <name>semaphore</name></member>
+ <member optional="true"><type>VkSemaphoreImportFlags</type> <name>flags</name></member>
+ <member><type>VkExternalSemaphoreHandleTypeFlagBits</type> <name>handleType</name></member>
+ <member><type>int</type> <name>fd</name></member>
+ </type>
+ <type category="struct" name="VkSemaphoreGetFdInfoKHR">
+ <member values="VK_STRUCTURE_TYPE_SEMAPHORE_GET_FD_INFO_KHR"><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>VkExternalSemaphoreHandleTypeFlagBits</type> <name>handleType</name></member>
+ </type>
+ <type category="struct" name="VkImportSemaphoreZirconHandleInfoFUCHSIA">
+ <member values="VK_STRUCTURE_TYPE_IMPORT_SEMAPHORE_ZIRCON_HANDLE_INFO_FUCHSIA"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member externsync="true"><type>VkSemaphore</type> <name>semaphore</name></member>
+ <member optional="true"><type>VkSemaphoreImportFlags</type> <name>flags</name></member>
+ <member><type>VkExternalSemaphoreHandleTypeFlagBits</type> <name>handleType</name></member>
+ <member><type>zx_handle_t</type> <name>zirconHandle</name></member>
+ </type>
+ <type category="struct" name="VkSemaphoreGetZirconHandleInfoFUCHSIA">
+ <member values="VK_STRUCTURE_TYPE_SEMAPHORE_GET_ZIRCON_HANDLE_INFO_FUCHSIA"><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>VkExternalSemaphoreHandleTypeFlagBits</type> <name>handleType</name></member>
+ </type>
+ <type category="struct" name="VkPhysicalDeviceExternalFenceInfo">
+ <member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_FENCE_INFO"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member><type>VkExternalFenceHandleTypeFlagBits</type> <name>handleType</name></member>
+ </type>
+ <type category="struct" name="VkPhysicalDeviceExternalFenceInfoKHR" alias="VkPhysicalDeviceExternalFenceInfo"/>
+ <type category="struct" name="VkExternalFenceProperties" returnedonly="true">
+ <member values="VK_STRUCTURE_TYPE_EXTERNAL_FENCE_PROPERTIES"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true"><type>void</type>* <name>pNext</name></member>
+ <member><type>VkExternalFenceHandleTypeFlags</type> <name>exportFromImportedHandleTypes</name></member>
+ <member><type>VkExternalFenceHandleTypeFlags</type> <name>compatibleHandleTypes</name></member>
+ <member optional="true"><type>VkExternalFenceFeatureFlags</type> <name>externalFenceFeatures</name></member>
+ </type>
+ <type category="struct" name="VkExternalFencePropertiesKHR" alias="VkExternalFenceProperties"/>
+ <type category="struct" name="VkExportFenceCreateInfo" structextends="VkFenceCreateInfo">
+ <member values="VK_STRUCTURE_TYPE_EXPORT_FENCE_CREATE_INFO"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member optional="true"><type>VkExternalFenceHandleTypeFlags</type> <name>handleTypes</name></member>
+ </type>
+ <type category="struct" name="VkExportFenceCreateInfoKHR" alias="VkExportFenceCreateInfo"/>
+ <type category="struct" name="VkImportFenceWin32HandleInfoKHR">
+ <member values="VK_STRUCTURE_TYPE_IMPORT_FENCE_WIN32_HANDLE_INFO_KHR"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member externsync="true"><type>VkFence</type> <name>fence</name></member>
+ <member optional="true"><type>VkFenceImportFlags</type> <name>flags</name></member>
+ <member noautovalidity="true"><type>VkExternalFenceHandleTypeFlagBits</type> <name>handleType</name></member>
+ <member optional="true"><type>HANDLE</type> <name>handle</name></member>
+ <member optional="true"><type>LPCWSTR</type> <name>name</name></member>
+ </type>
+ <type category="struct" name="VkExportFenceWin32HandleInfoKHR" structextends="VkFenceCreateInfo">
+ <member values="VK_STRUCTURE_TYPE_EXPORT_FENCE_WIN32_HANDLE_INFO_KHR"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member optional="true">const <type>SECURITY_ATTRIBUTES</type>* <name>pAttributes</name></member>
+ <member><type>DWORD</type> <name>dwAccess</name></member>
+ <member><type>LPCWSTR</type> <name>name</name></member>
+ </type>
+ <type category="struct" name="VkFenceGetWin32HandleInfoKHR">
+ <member values="VK_STRUCTURE_TYPE_FENCE_GET_WIN32_HANDLE_INFO_KHR"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member><type>VkFence</type> <name>fence</name></member>
+ <member><type>VkExternalFenceHandleTypeFlagBits</type> <name>handleType</name></member>
+ </type>
+ <type category="struct" name="VkImportFenceFdInfoKHR">
+ <member values="VK_STRUCTURE_TYPE_IMPORT_FENCE_FD_INFO_KHR"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member externsync="true"><type>VkFence</type> <name>fence</name></member>
+ <member optional="true"><type>VkFenceImportFlags</type> <name>flags</name></member>
+ <member><type>VkExternalFenceHandleTypeFlagBits</type> <name>handleType</name></member>
+ <member><type>int</type> <name>fd</name></member>
+ </type>
+ <type category="struct" name="VkFenceGetFdInfoKHR">
+ <member values="VK_STRUCTURE_TYPE_FENCE_GET_FD_INFO_KHR"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member><type>VkFence</type> <name>fence</name></member>
+ <member><type>VkExternalFenceHandleTypeFlagBits</type> <name>handleType</name></member>
+ </type>
+ <type category="struct" name="VkPhysicalDeviceMultiviewFeatures" structextends="VkPhysicalDeviceFeatures2,VkDeviceCreateInfo">
+ <member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_FEATURES"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true"><type>void</type>* <name>pNext</name></member>
+ <member><type>VkBool32</type> <name>multiview</name><comment>Multiple views in a renderpass</comment></member>
+ <member><type>VkBool32</type> <name>multiviewGeometryShader</name><comment>Multiple views in a renderpass w/ geometry shader</comment></member>
+ <member><type>VkBool32</type> <name>multiviewTessellationShader</name><comment>Multiple views in a renderpass w/ tessellation shader</comment></member>
+ </type>
+ <type category="struct" name="VkPhysicalDeviceMultiviewFeaturesKHR" alias="VkPhysicalDeviceMultiviewFeatures"/>
+ <type category="struct" name="VkPhysicalDeviceMultiviewProperties" returnedonly="true" structextends="VkPhysicalDeviceProperties2">
+ <member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_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>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>
+ </type>
+ <type category="struct" name="VkPhysicalDeviceMultiviewPropertiesKHR" alias="VkPhysicalDeviceMultiviewProperties"/>
+ <type category="struct" name="VkRenderPassMultiviewCreateInfo" structextends="VkRenderPassCreateInfo">
+ <member values="VK_STRUCTURE_TYPE_RENDER_PASS_MULTIVIEW_CREATE_INFO"><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>subpassCount</name></member>
+ <member len="subpassCount">const <type>uint32_t</type>* <name>pViewMasks</name></member>
+ <member optional="true"><type>uint32_t</type> <name>dependencyCount</name></member>
+ <member len="dependencyCount">const <type>int32_t</type>* <name>pViewOffsets</name></member>
+ <member optional="true"><type>uint32_t</type> <name>correlationMaskCount</name></member>
+ <member len="correlationMaskCount">const <type>uint32_t</type>* <name>pCorrelationMasks</name></member>
+ </type>
+ <type category="struct" name="VkRenderPassMultiviewCreateInfoKHR" alias="VkRenderPassMultiviewCreateInfo"/>
+ <type category="struct" name="VkSurfaceCapabilities2EXT" returnedonly="true">
+ <member values="VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES_2_EXT"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true"><type>void</type>* <name>pNext</name></member>
+ <member><type>uint32_t</type> <name>minImageCount</name><comment>Supported minimum number of images for the surface</comment></member>
+ <member><type>uint32_t</type> <name>maxImageCount</name><comment>Supported maximum number of images for the surface, 0 for unlimited</comment></member>
+ <member><type>VkExtent2D</type> <name>currentExtent</name><comment>Current image width and height for the surface, (0, 0) if undefined</comment></member>
+ <member><type>VkExtent2D</type> <name>minImageExtent</name><comment>Supported minimum image width and height for the surface</comment></member>
+ <member><type>VkExtent2D</type> <name>maxImageExtent</name><comment>Supported maximum image width and height for the surface</comment></member>
+ <member><type>uint32_t</type> <name>maxImageArrayLayers</name><comment>Supported maximum number of image layers for the surface</comment></member>
+ <member><type>VkSurfaceTransformFlagsKHR</type> <name>supportedTransforms</name><comment>1 or more bits representing the transforms supported</comment></member>
+ <member><type>VkSurfaceTransformFlagBitsKHR</type> <name>currentTransform</name><comment>The surface's current transform relative to the device's natural orientation</comment></member>
+ <member><type>VkCompositeAlphaFlagsKHR</type> <name>supportedCompositeAlpha</name><comment>1 or more bits representing the alpha compositing modes supported</comment></member>
+ <member><type>VkImageUsageFlags</type> <name>supportedUsageFlags</name><comment>Supported image usage flags for the surface</comment></member>
+ <member optional="true"><type>VkSurfaceCounterFlagsEXT</type> <name>supportedSurfaceCounters</name></member>
+ </type>
+ <type category="struct" name="VkDisplayPowerInfoEXT">
+ <member values="VK_STRUCTURE_TYPE_DISPLAY_POWER_INFO_EXT"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member><type>VkDisplayPowerStateEXT</type> <name>powerState</name></member>
+ </type>
+ <type category="struct" name="VkDeviceEventInfoEXT">
+ <member values="VK_STRUCTURE_TYPE_DEVICE_EVENT_INFO_EXT"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member><type>VkDeviceEventTypeEXT</type> <name>deviceEvent</name></member>
+ </type>
+ <type category="struct" name="VkDisplayEventInfoEXT">
+ <member values="VK_STRUCTURE_TYPE_DISPLAY_EVENT_INFO_EXT"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member><type>VkDisplayEventTypeEXT</type> <name>displayEvent</name></member>
+ </type>
+ <type category="struct" name="VkSwapchainCounterCreateInfoEXT" structextends="VkSwapchainCreateInfoKHR">
+ <member values="VK_STRUCTURE_TYPE_SWAPCHAIN_COUNTER_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>VkSurfaceCounterFlagsEXT</type> <name>surfaceCounters</name></member>
+ </type>
+ <type category="struct" name="VkPhysicalDeviceGroupProperties" returnedonly="true">
+ <member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_GROUP_PROPERTIES"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true"><type>void</type>* <name>pNext</name></member>
+ <member><type>uint32_t</type> <name>physicalDeviceCount</name></member>
+ <member><type>VkPhysicalDevice</type> <name>physicalDevices</name>[<enum>VK_MAX_DEVICE_GROUP_SIZE</enum>]</member>
+ <member><type>VkBool32</type> <name>subsetAllocation</name></member>
+ </type>
+ <type category="struct" name="VkPhysicalDeviceGroupPropertiesKHR" alias="VkPhysicalDeviceGroupProperties"/>
+ <type category="struct" name="VkMemoryAllocateFlagsInfo" structextends="VkMemoryAllocateInfo">
+ <member values="VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_FLAGS_INFO"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member optional="true"><type>VkMemoryAllocateFlags</type> <name>flags</name></member>
+ <member><type>uint32_t</type> <name>deviceMask</name></member>
+ </type>
+ <type category="struct" name="VkMemoryAllocateFlagsInfoKHR" alias="VkMemoryAllocateFlagsInfo"/>
+ <type category="struct" name="VkBindBufferMemoryInfo">
+ <member values="VK_STRUCTURE_TYPE_BIND_BUFFER_MEMORY_INFO"><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>
+ <member><type>VkDeviceMemory</type> <name>memory</name></member>
+ <member><type>VkDeviceSize</type> <name>memoryOffset</name></member>
+ </type>
+ <type category="struct" name="VkBindBufferMemoryInfoKHR" alias="VkBindBufferMemoryInfo"/>
+ <type category="struct" name="VkBindBufferMemoryDeviceGroupInfo" structextends="VkBindBufferMemoryInfo">
+ <member values="VK_STRUCTURE_TYPE_BIND_BUFFER_MEMORY_DEVICE_GROUP_INFO"><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>deviceIndexCount</name></member>
+ <member len="deviceIndexCount">const <type>uint32_t</type>* <name>pDeviceIndices</name></member>
+ </type>
+ <type category="struct" name="VkBindBufferMemoryDeviceGroupInfoKHR" alias="VkBindBufferMemoryDeviceGroupInfo"/>
+ <type category="struct" name="VkBindImageMemoryInfo">
+ <member values="VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_INFO"><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 noautovalidity="true"><type>VkDeviceMemory</type> <name>memory</name></member>
+ <member><type>VkDeviceSize</type> <name>memoryOffset</name></member>
+ </type>
+ <type category="struct" name="VkBindImageMemoryInfoKHR" alias="VkBindImageMemoryInfo"/>
+ <type category="struct" name="VkBindImageMemoryDeviceGroupInfo" structextends="VkBindImageMemoryInfo">
+ <member values="VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_DEVICE_GROUP_INFO"><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>deviceIndexCount</name></member>
+ <member len="deviceIndexCount">const <type>uint32_t</type>* <name>pDeviceIndices</name></member>
+ <member optional="true"><type>uint32_t</type> <name>splitInstanceBindRegionCount</name></member>
+ <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">
+ <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>
+ <member optional="true"><type>uint32_t</type> <name>deviceRenderAreaCount</name></member>
+ <member len="deviceRenderAreaCount">const <type>VkRect2D</type>* <name>pDeviceRenderAreas</name></member>
+ </type>
+ <type category="struct" name="VkDeviceGroupRenderPassBeginInfoKHR" alias="VkDeviceGroupRenderPassBeginInfo"/>
+ <type category="struct" name="VkDeviceGroupCommandBufferBeginInfo" structextends="VkCommandBufferBeginInfo">
+ <member values="VK_STRUCTURE_TYPE_DEVICE_GROUP_COMMAND_BUFFER_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>
+ </type>
+ <type category="struct" name="VkDeviceGroupCommandBufferBeginInfoKHR" alias="VkDeviceGroupCommandBufferBeginInfo"/>
+ <type category="struct" name="VkDeviceGroupSubmitInfo" structextends="VkSubmitInfo">
+ <member values="VK_STRUCTURE_TYPE_DEVICE_GROUP_SUBMIT_INFO"><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>waitSemaphoreCount</name></member>
+ <member len="waitSemaphoreCount">const <type>uint32_t</type>* <name>pWaitSemaphoreDeviceIndices</name></member>
+ <member optional="true"><type>uint32_t</type> <name>commandBufferCount</name></member>
+ <member len="commandBufferCount">const <type>uint32_t</type>* <name>pCommandBufferDeviceMasks</name></member>
+ <member optional="true"><type>uint32_t</type> <name>signalSemaphoreCount</name></member>
+ <member len="signalSemaphoreCount">const <type>uint32_t</type>* <name>pSignalSemaphoreDeviceIndices</name></member>
+ </type>
+ <type category="struct" name="VkDeviceGroupSubmitInfoKHR" alias="VkDeviceGroupSubmitInfo"/>
+ <type category="struct" name="VkDeviceGroupBindSparseInfo" structextends="VkBindSparseInfo">
+ <member values="VK_STRUCTURE_TYPE_DEVICE_GROUP_BIND_SPARSE_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>resourceDeviceIndex</name></member>
+ <member><type>uint32_t</type> <name>memoryDeviceIndex</name></member>
+ </type>
+ <type category="struct" name="VkDeviceGroupBindSparseInfoKHR" alias="VkDeviceGroupBindSparseInfo"/>
+ <type category="struct" name="VkDeviceGroupPresentCapabilitiesKHR" returnedonly="true">
+ <member values="VK_STRUCTURE_TYPE_DEVICE_GROUP_PRESENT_CAPABILITIES_KHR"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true"><type>void</type>* <name>pNext</name></member>
+ <member><type>uint32_t</type> <name>presentMask</name>[<enum>VK_MAX_DEVICE_GROUP_SIZE</enum>]</member>
+ <member><type>VkDeviceGroupPresentModeFlagsKHR</type> <name>modes</name></member>
+ </type>
+ <type category="struct" name="VkImageSwapchainCreateInfoKHR" structextends="VkImageCreateInfo">
+ <member values="VK_STRUCTURE_TYPE_IMAGE_SWAPCHAIN_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>VkSwapchainKHR</type> <name>swapchain</name></member>
+ </type>
+ <type category="struct" name="VkBindImageMemorySwapchainInfoKHR" structextends="VkBindImageMemoryInfo">
+ <member values="VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_SWAPCHAIN_INFO_KHR"><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></member>
+ <member><type>uint32_t</type> <name>imageIndex</name></member>
+ </type>
+ <type category="struct" name="VkAcquireNextImageInfoKHR">
+ <member values="VK_STRUCTURE_TYPE_ACQUIRE_NEXT_IMAGE_INFO_KHR"><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></member>
+ <member><type>uint64_t</type> <name>timeout</name></member>
+ <member optional="true" externsync="true"><type>VkSemaphore</type> <name>semaphore</name></member>
+ <member optional="true" externsync="true"><type>VkFence</type> <name>fence</name></member>
+ <member><type>uint32_t</type> <name>deviceMask</name></member>
+ </type>
+ <type category="struct" name="VkDeviceGroupPresentInfoKHR" structextends="VkPresentInfoKHR">
+ <member values="VK_STRUCTURE_TYPE_DEVICE_GROUP_PRESENT_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>swapchainCount</name></member>
+ <member len="swapchainCount">const <type>uint32_t</type>* <name>pDeviceMasks</name></member>
+ <member><type>VkDeviceGroupPresentModeFlagBitsKHR</type> <name>mode</name></member>
+ </type>
+ <type category="struct" name="VkDeviceGroupDeviceCreateInfo" structextends="VkDeviceCreateInfo">
+ <member values="VK_STRUCTURE_TYPE_DEVICE_GROUP_DEVICE_CREATE_INFO"><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>physicalDeviceCount</name></member>
+ <member len="physicalDeviceCount">const <type>VkPhysicalDevice</type>* <name>pPhysicalDevices</name></member>
+ </type>
+ <type category="struct" name="VkDeviceGroupDeviceCreateInfoKHR" alias="VkDeviceGroupDeviceCreateInfo"/>
+ <type category="struct" name="VkDeviceGroupSwapchainCreateInfoKHR" structextends="VkSwapchainCreateInfoKHR">
+ <member values="VK_STRUCTURE_TYPE_DEVICE_GROUP_SWAPCHAIN_CREATE_INFO_KHR"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member><type>VkDeviceGroupPresentModeFlagsKHR</type> <name>modes</name></member>
+ </type>
+ <type category="struct" name="VkDescriptorUpdateTemplateEntry">
+ <member><type>uint32_t</type> <name>dstBinding</name><comment>Binding within the destination descriptor set to write</comment></member>
+ <member><type>uint32_t</type> <name>dstArrayElement</name><comment>Array element within the destination binding to write</comment></member>
+ <member><type>uint32_t</type> <name>descriptorCount</name><comment>Number of descriptors to write</comment></member>
+ <member><type>VkDescriptorType</type> <name>descriptorType</name><comment>Descriptor type to write</comment></member>
+ <member><type>size_t</type> <name>offset</name><comment>Offset into pData where the descriptors to update are stored</comment></member>
+ <member><type>size_t</type> <name>stride</name><comment>Stride between two descriptors in pData when writing more than one descriptor</comment></member>
+ </type>
+ <type category="struct" name="VkDescriptorUpdateTemplateEntryKHR" alias="VkDescriptorUpdateTemplateEntry"/>
+ <type category="struct" name="VkDescriptorUpdateTemplateCreateInfo">
+ <member values="VK_STRUCTURE_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_CREATE_INFO"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member optional="true"><type>VkDescriptorUpdateTemplateCreateFlags</type> <name>flags</name></member>
+ <member><type>uint32_t</type> <name>descriptorUpdateEntryCount</name><comment>Number of descriptor update entries to use for the update template</comment></member>
+ <member len="descriptorUpdateEntryCount">const <type>VkDescriptorUpdateTemplateEntry</type>* <name>pDescriptorUpdateEntries</name><comment>Descriptor update entries for the template</comment></member>
+ <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>uint32_t</type> <name>set</name></member>
+ </type>
+ <type category="struct" name="VkDescriptorUpdateTemplateCreateInfoKHR" alias="VkDescriptorUpdateTemplateCreateInfo"/>
+ <type category="struct" name="VkXYColorEXT" comment="Chromaticity coordinate">
+ <member><type>float</type> <name>x</name></member>
+ <member><type>float</type> <name>y</name></member>
+ </type>
+ <type category="struct" name="VkPhysicalDevicePresentIdFeaturesKHR" structextends="VkPhysicalDeviceFeatures2,VkDeviceCreateInfo">
+ <member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRESENT_ID_FEATURES_KHR"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true"><type>void</type>* <name>pNext</name></member>
+ <member><type>VkBool32</type> <name>presentId</name><comment>Present ID in VkPresentInfoKHR</comment></member>
+ </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><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>
+ <type category="struct" name="VkPhysicalDevicePresentWaitFeaturesKHR" structextends="VkPhysicalDeviceFeatures2,VkDeviceCreateInfo">
+ <member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRESENT_WAIT_FEATURES_KHR"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true"><type>void</type>* <name>pNext</name></member>
+ <member><type>VkBool32</type> <name>presentWait</name><comment>vkWaitForPresentKHR is supported</comment></member>
+ </type>
+ <type category="struct" name="VkHdrMetadataEXT">
+ <comment>Display primary in chromaticity coordinates</comment>
+ <member values="VK_STRUCTURE_TYPE_HDR_METADATA_EXT"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <comment> From SMPTE 2086</comment>
+ <member noautovalidity="true"><type>VkXYColorEXT</type> <name>displayPrimaryRed</name><comment>Display primary's Red</comment></member>
+ <member noautovalidity="true"><type>VkXYColorEXT</type> <name>displayPrimaryGreen</name><comment>Display primary's Green</comment></member>
+ <member noautovalidity="true"><type>VkXYColorEXT</type> <name>displayPrimaryBlue</name><comment>Display primary's Blue</comment></member>
+ <member noautovalidity="true"><type>VkXYColorEXT</type> <name>whitePoint</name><comment>Display primary's Blue</comment></member>
+ <member noautovalidity="true"><type>float</type> <name>maxLuminance</name><comment>Display maximum luminance</comment></member>
+ <member noautovalidity="true"><type>float</type> <name>minLuminance</name><comment>Display minimum luminance</comment></member>
+ <comment> From CTA 861.3</comment>
+ <member noautovalidity="true"><type>float</type> <name>maxContentLightLevel</name><comment>Content maximum luminance</comment></member>
+ <member noautovalidity="true"><type>float</type> <name>maxFrameAverageLightLevel</name></member>
+ </type>
+ <type category="struct" name="VkDisplayNativeHdrSurfaceCapabilitiesAMD" returnedonly="true" structextends="VkSurfaceCapabilities2KHR">
+ <member values="VK_STRUCTURE_TYPE_DISPLAY_NATIVE_HDR_SURFACE_CAPABILITIES_AMD"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true"><type>void</type>* <name>pNext</name></member>
+ <member><type>VkBool32</type> <name>localDimmingSupport</name></member>
+ </type>
+ <type category="struct" name="VkSwapchainDisplayNativeHdrCreateInfoAMD" structextends="VkSwapchainCreateInfoKHR">
+ <member values="VK_STRUCTURE_TYPE_SWAPCHAIN_DISPLAY_NATIVE_HDR_CREATE_INFO_AMD"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member><type>VkBool32</type> <name>localDimmingEnable</name></member>
+ </type>
+ <type category="struct" name="VkRefreshCycleDurationGOOGLE" returnedonly="true">
+ <member><type>uint64_t</type> <name>refreshDuration</name><comment>Number of nanoseconds from the start of one refresh cycle to the next</comment></member>
+ </type>
+ <type category="struct" name="VkPastPresentationTimingGOOGLE" returnedonly="true">
+ <member><type>uint32_t</type> <name>presentID</name><comment>Application-provided identifier, previously given to vkQueuePresentKHR</comment></member>
+ <member><type>uint64_t</type> <name>desiredPresentTime</name><comment>Earliest time an image should have been presented, previously given to vkQueuePresentKHR</comment></member>
+ <member><type>uint64_t</type> <name>actualPresentTime</name><comment>Time the image was actually displayed</comment></member>
+ <member><type>uint64_t</type> <name>earliestPresentTime</name><comment>Earliest time the image could have been displayed</comment></member>
+ <member><type>uint64_t</type> <name>presentMargin</name><comment>How early vkQueuePresentKHR was processed vs. how soon it needed to be and make earliestPresentTime</comment></member>
+ </type>
+ <type category="struct" name="VkPresentTimesInfoGOOGLE" structextends="VkPresentInfoKHR">
+ <member values="VK_STRUCTURE_TYPE_PRESENT_TIMES_INFO_GOOGLE"><type>VkStructureType</type> <name>sType</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>VkPresentTimeGOOGLE</type>* <name>pTimes</name><comment>The earliest times to present images</comment></member>
+ </type>
+ <type category="struct" name="VkPresentTimeGOOGLE">
+ <member><type>uint32_t</type> <name>presentID</name><comment>Application-provided identifier</comment></member>
+ <member><type>uint64_t</type> <name>desiredPresentTime</name><comment>Earliest time an image should be presented</comment></member>
+ </type>
+ <type category="struct" name="VkIOSSurfaceCreateInfoMVK">
+ <member values="VK_STRUCTURE_TYPE_IOS_SURFACE_CREATE_INFO_MVK"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member optional="true"><type>VkIOSSurfaceCreateFlagsMVK</type> <name>flags</name></member>
+ <member noautovalidity="true">const <type>void</type>* <name>pView</name></member>
+ </type>
+ <type category="struct" name="VkMacOSSurfaceCreateInfoMVK">
+ <member values="VK_STRUCTURE_TYPE_MACOS_SURFACE_CREATE_INFO_MVK"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member optional="true"><type>VkMacOSSurfaceCreateFlagsMVK</type> <name>flags</name></member>
+ <member noautovalidity="true">const <type>void</type>* <name>pView</name></member>
+ </type>
+ <type category="struct" name="VkMetalSurfaceCreateInfoEXT">
+ <member values="VK_STRUCTURE_TYPE_METAL_SURFACE_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>VkMetalSurfaceCreateFlagsEXT</type> <name>flags</name></member>
+ <member noautovalidity="true">const <type>CAMetalLayer</type>* <name>pLayer</name></member>
+ </type>
+ <type category="struct" name="VkViewportWScalingNV">
+ <member><type>float</type> <name>xcoeff</name></member>
+ <member><type>float</type> <name>ycoeff</name></member>
+ </type>
+ <type category="struct" name="VkPipelineViewportWScalingStateCreateInfoNV" structextends="VkPipelineViewportStateCreateInfo">
+ <member values="VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_W_SCALING_STATE_CREATE_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>viewportWScalingEnable</name></member>
+ <member><type>uint32_t</type> <name>viewportCount</name></member>
+ <member noautovalidity="true" optional="true" len="viewportCount">const <type>VkViewportWScalingNV</type>* <name>pViewportWScalings</name></member>
+ </type>
+ <type category="struct" name="VkViewportSwizzleNV">
+ <member><type>VkViewportCoordinateSwizzleNV</type> <name>x</name></member>
+ <member><type>VkViewportCoordinateSwizzleNV</type> <name>y</name></member>
+ <member><type>VkViewportCoordinateSwizzleNV</type> <name>z</name></member>
+ <member><type>VkViewportCoordinateSwizzleNV</type> <name>w</name></member>
+ </type>
+ <type category="struct" name="VkPipelineViewportSwizzleStateCreateInfoNV" structextends="VkPipelineViewportStateCreateInfo">
+ <member values="VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_SWIZZLE_STATE_CREATE_INFO_NV"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member optional="true"><type>VkPipelineViewportSwizzleStateCreateFlagsNV</type> <name>flags</name></member>
+ <member><type>uint32_t</type> <name>viewportCount</name></member>
+ <member len="viewportCount">const <type>VkViewportSwizzleNV</type>* <name>pViewportSwizzles</name></member>
+ </type>
+ <type category="struct" name="VkPhysicalDeviceDiscardRectanglePropertiesEXT" returnedonly="true" structextends="VkPhysicalDeviceProperties2">
+ <member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DISCARD_RECTANGLE_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>maxDiscardRectangles</name><comment>max number of active discard rectangles</comment></member>
+ </type>
+ <type category="struct" name="VkPipelineDiscardRectangleStateCreateInfoEXT" structextends="VkGraphicsPipelineCreateInfo">
+ <member values="VK_STRUCTURE_TYPE_PIPELINE_DISCARD_RECTANGLE_STATE_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>VkPipelineDiscardRectangleStateCreateFlagsEXT</type> <name>flags</name></member>
+ <member><type>VkDiscardRectangleModeEXT</type> <name>discardRectangleMode</name></member>
+ <member optional="true"><type>uint32_t</type> <name>discardRectangleCount</name></member>
+ <member noautovalidity="true" len="discardRectangleCount">const <type>VkRect2D</type>* <name>pDiscardRectangles</name></member>
+ </type>
+ <type category="struct" name="VkPhysicalDeviceMultiviewPerViewAttributesPropertiesNVX" returnedonly="true" structextends="VkPhysicalDeviceProperties2">
+ <member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_PER_VIEW_ATTRIBUTES_PROPERTIES_NVX"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true"><type>void</type>* <name>pNext</name></member>
+ <member limittype="bitmask"><type>VkBool32</type> <name>perViewPositionAllComponents</name></member>
+ </type>
+ <type category="struct" name="VkInputAttachmentAspectReference">
+ <member><type>uint32_t</type> <name>subpass</name></member>
+ <member><type>uint32_t</type> <name>inputAttachmentIndex</name></member>
+ <member><type>VkImageAspectFlags</type> <name>aspectMask</name></member>
+ </type>
+ <type category="struct" name="VkInputAttachmentAspectReferenceKHR" alias="VkInputAttachmentAspectReference"/>
+ <type category="struct" name="VkRenderPassInputAttachmentAspectCreateInfo" structextends="VkRenderPassCreateInfo">
+ <member values="VK_STRUCTURE_TYPE_RENDER_PASS_INPUT_ATTACHMENT_ASPECT_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>aspectReferenceCount</name></member>
+ <member len="aspectReferenceCount">const <type>VkInputAttachmentAspectReference</type>* <name>pAspectReferences</name></member>
+ </type>
+ <type category="struct" name="VkRenderPassInputAttachmentAspectCreateInfoKHR" alias="VkRenderPassInputAttachmentAspectCreateInfo"/>
+ <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>
+ </type>
+ <type category="struct" name="VkSurfaceCapabilities2KHR" returnedonly="true">
+ <member values="VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES_2_KHR"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true"><type>void</type>* <name>pNext</name></member>
+ <member><type>VkSurfaceCapabilitiesKHR</type> <name>surfaceCapabilities</name></member>
+ </type>
+ <type category="struct" name="VkSurfaceFormat2KHR" returnedonly="true">
+ <member values="VK_STRUCTURE_TYPE_SURFACE_FORMAT_2_KHR"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true"><type>void</type>* <name>pNext</name></member>
+ <member><type>VkSurfaceFormatKHR</type> <name>surfaceFormat</name></member>
+ </type>
+ <type category="struct" name="VkDisplayProperties2KHR" returnedonly="true">
+ <member values="VK_STRUCTURE_TYPE_DISPLAY_PROPERTIES_2_KHR"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true"><type>void</type>* <name>pNext</name></member>
+ <member><type>VkDisplayPropertiesKHR</type> <name>displayProperties</name></member>
+ </type>
+ <type category="struct" name="VkDisplayPlaneProperties2KHR" returnedonly="true">
+ <member values="VK_STRUCTURE_TYPE_DISPLAY_PLANE_PROPERTIES_2_KHR"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true"><type>void</type>* <name>pNext</name></member>
+ <member><type>VkDisplayPlanePropertiesKHR</type> <name>displayPlaneProperties</name></member>
+ </type>
+ <type category="struct" name="VkDisplayModeProperties2KHR" returnedonly="true">
+ <member values="VK_STRUCTURE_TYPE_DISPLAY_MODE_PROPERTIES_2_KHR"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true"><type>void</type>* <name>pNext</name></member>
+ <member><type>VkDisplayModePropertiesKHR</type> <name>displayModeProperties</name></member>
+ </type>
+ <type category="struct" name="VkDisplayPlaneInfo2KHR">
+ <member values="VK_STRUCTURE_TYPE_DISPLAY_PLANE_INFO_2_KHR"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member externsync="true"><type>VkDisplayModeKHR</type> <name>mode</name></member>
+ <member><type>uint32_t</type> <name>planeIndex</name></member>
+ </type>
+ <type category="struct" name="VkDisplayPlaneCapabilities2KHR" returnedonly="true">
+ <member values="VK_STRUCTURE_TYPE_DISPLAY_PLANE_CAPABILITIES_2_KHR"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true"><type>void</type>* <name>pNext</name></member>
+ <member><type>VkDisplayPlaneCapabilitiesKHR</type> <name>capabilities</name></member>
+ </type>
+ <type category="struct" name="VkSharedPresentSurfaceCapabilitiesKHR" returnedonly="true" structextends="VkSurfaceCapabilities2KHR">
+ <member values="VK_STRUCTURE_TYPE_SHARED_PRESENT_SURFACE_CAPABILITIES_KHR"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true"><type>void</type>* <name>pNext</name></member>
+ <member optional="true"><type>VkImageUsageFlags</type> <name>sharedPresentSupportedUsageFlags</name><comment>Supported image usage flags if swapchain created using a shared present mode</comment></member>
+ </type>
+ <type category="struct" name="VkPhysicalDevice16BitStorageFeatures" structextends="VkPhysicalDeviceFeatures2,VkDeviceCreateInfo">
+ <member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_16BIT_STORAGE_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>
+ <member><type>VkBool32</type> <name>storagePushConstant16</name><comment>16-bit integer/floating-point variables supported in PushConstant</comment></member>
+ <member><type>VkBool32</type> <name>storageInputOutput16</name><comment>16-bit integer/floating-point variables supported in shader inputs and outputs</comment></member>
+ </type>
+ <type category="struct" name="VkPhysicalDevice16BitStorageFeaturesKHR" alias="VkPhysicalDevice16BitStorageFeatures"/>
+ <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="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>
+ </type>
+ <type category="struct" name="VkPhysicalDeviceShaderSubgroupExtendedTypesFeatures" structextends="VkPhysicalDeviceFeatures2,VkDeviceCreateInfo">
+ <member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_SUBGROUP_EXTENDED_TYPES_FEATURES"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true"><type>void</type>* <name>pNext</name></member>
+ <member noautovalidity="true"><type>VkBool32</type> <name>shaderSubgroupExtendedTypes</name><comment>Flag to specify whether subgroup operations with extended types are supported</comment></member>
+ </type>
+ <type category="struct" name="VkPhysicalDeviceShaderSubgroupExtendedTypesFeaturesKHR" alias="VkPhysicalDeviceShaderSubgroupExtendedTypesFeatures"/>
+ <type category="struct" name="VkBufferMemoryRequirementsInfo2">
+ <member values="VK_STRUCTURE_TYPE_BUFFER_MEMORY_REQUIREMENTS_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>buffer</name></member>
+ </type>
+ <type category="struct" name="VkBufferMemoryRequirementsInfo2KHR" alias="VkBufferMemoryRequirementsInfo2"/>
+ <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>
+ <member><type>VkImage</type> <name>image</name></member>
+ </type>
+ <type category="struct" name="VkImageMemoryRequirementsInfo2KHR" alias="VkImageMemoryRequirementsInfo2"/>
+ <type category="struct" name="VkImageSparseMemoryRequirementsInfo2">
+ <member values="VK_STRUCTURE_TYPE_IMAGE_SPARSE_MEMORY_REQUIREMENTS_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>image</name></member>
+ </type>
+ <type category="struct" name="VkImageSparseMemoryRequirementsInfo2KHR" alias="VkImageSparseMemoryRequirementsInfo2"/>
+ <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>
+ <member><type>VkMemoryRequirements</type> <name>memoryRequirements</name></member>
+ </type>
+ <type category="struct" name="VkMemoryRequirements2KHR" alias="VkMemoryRequirements2"/>
+ <type category="struct" name="VkSparseImageMemoryRequirements2" returnedonly="true">
+ <member values="VK_STRUCTURE_TYPE_SPARSE_IMAGE_MEMORY_REQUIREMENTS_2"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true"><type>void</type>* <name>pNext</name></member>
+ <member><type>VkSparseImageMemoryRequirements</type> <name>memoryRequirements</name></member>
+ </type>
+ <type category="struct" name="VkSparseImageMemoryRequirements2KHR" alias="VkSparseImageMemoryRequirements2"/>
+ <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>
+ </type>
+ <type category="struct" name="VkPhysicalDevicePointClippingPropertiesKHR" alias="VkPhysicalDevicePointClippingProperties"/>
+ <type category="struct" name="VkMemoryDedicatedRequirements" returnedonly="true" structextends="VkMemoryRequirements2">
+ <member values="VK_STRUCTURE_TYPE_MEMORY_DEDICATED_REQUIREMENTS"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true"><type>void</type>* <name>pNext</name></member>
+ <member><type>VkBool32</type> <name>prefersDedicatedAllocation</name></member>
+ <member><type>VkBool32</type> <name>requiresDedicatedAllocation</name></member>
+ </type>
+ <type category="struct" name="VkMemoryDedicatedRequirementsKHR" alias="VkMemoryDedicatedRequirements"/>
+ <type category="struct" name="VkMemoryDedicatedAllocateInfo" structextends="VkMemoryAllocateInfo">
+ <member values="VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO"><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><comment>Image that this allocation will be bound to</comment></member>
+ <member optional="true"><type>VkBuffer</type> <name>buffer</name><comment>Buffer that this allocation will be bound to</comment></member>
+ </type>
+ <type category="struct" name="VkMemoryDedicatedAllocateInfoKHR" alias="VkMemoryDedicatedAllocateInfo"/>
+ <type category="struct" name="VkImageViewUsageCreateInfo" structextends="VkImageViewCreateInfo">
+ <member values="VK_STRUCTURE_TYPE_IMAGE_VIEW_USAGE_CREATE_INFO"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member><type>VkImageUsageFlags</type> <name>usage</name></member>
+ </type>
+ <type category="struct" name="VkImageViewUsageCreateInfoKHR" alias="VkImageViewUsageCreateInfo"/>
+ <type category="struct" name="VkPipelineTessellationDomainOriginStateCreateInfo" structextends="VkPipelineTessellationStateCreateInfo">
+ <member values="VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_DOMAIN_ORIGIN_STATE_CREATE_INFO"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member><type>VkTessellationDomainOrigin</type> <name>domainOrigin</name></member>
+ </type>
+ <type category="struct" name="VkPipelineTessellationDomainOriginStateCreateInfoKHR" alias="VkPipelineTessellationDomainOriginStateCreateInfo"/>
+ <type category="struct" name="VkSamplerYcbcrConversionInfo" structextends="VkSamplerCreateInfo,VkImageViewCreateInfo">
+ <member values="VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_INFO"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member><type>VkSamplerYcbcrConversion</type> <name>conversion</name></member>
+ </type>
+ <type category="struct" name="VkSamplerYcbcrConversionInfoKHR" alias="VkSamplerYcbcrConversionInfo"/>
+ <type category="struct" name="VkSamplerYcbcrConversionCreateInfo">
+ <member values="VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_CREATE_INFO"><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>
+ <member><type>VkSamplerYcbcrModelConversion</type> <name>ycbcrModel</name></member>
+ <member><type>VkSamplerYcbcrRange</type> <name>ycbcrRange</name></member>
+ <member><type>VkComponentMapping</type> <name>components</name></member>
+ <member><type>VkChromaLocation</type> <name>xChromaOffset</name></member>
+ <member><type>VkChromaLocation</type> <name>yChromaOffset</name></member>
+ <member><type>VkFilter</type> <name>chromaFilter</name></member>
+ <member><type>VkBool32</type> <name>forceExplicitReconstruction</name></member>
+ </type>
+ <type category="struct" name="VkSamplerYcbcrConversionCreateInfoKHR" alias="VkSamplerYcbcrConversionCreateInfo"/>
+ <type category="struct" name="VkBindImagePlaneMemoryInfo" structextends="VkBindImageMemoryInfo">
+ <member values="VK_STRUCTURE_TYPE_BIND_IMAGE_PLANE_MEMORY_INFO"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member><type>VkImageAspectFlagBits</type> <name>planeAspect</name></member>
+ </type>
+ <type category="struct" name="VkBindImagePlaneMemoryInfoKHR" alias="VkBindImagePlaneMemoryInfo"/>
+ <type category="struct" name="VkImagePlaneMemoryRequirementsInfo" structextends="VkImageMemoryRequirementsInfo2">
+ <member values="VK_STRUCTURE_TYPE_IMAGE_PLANE_MEMORY_REQUIREMENTS_INFO"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member><type>VkImageAspectFlagBits</type> <name>planeAspect</name></member>
+ </type>
+ <type category="struct" name="VkImagePlaneMemoryRequirementsInfoKHR" alias="VkImagePlaneMemoryRequirementsInfo"/>
+ <type category="struct" name="VkPhysicalDeviceSamplerYcbcrConversionFeatures" structextends="VkPhysicalDeviceFeatures2,VkDeviceCreateInfo">
+ <member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLER_YCBCR_CONVERSION_FEATURES"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true"><type>void</type>* <name>pNext</name></member>
+ <member><type>VkBool32</type> <name>samplerYcbcrConversion</name><comment>Sampler color conversion supported</comment></member>
+ </type>
+ <type category="struct" name="VkPhysicalDeviceSamplerYcbcrConversionFeaturesKHR" alias="VkPhysicalDeviceSamplerYcbcrConversionFeatures"/>
+ <type category="struct" name="VkSamplerYcbcrConversionImageFormatProperties" returnedonly="true" structextends="VkImageFormatProperties2">
+ <member values="VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_IMAGE_FORMAT_PROPERTIES"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true"><type>void</type>* <name>pNext</name></member>
+ <member><type>uint32_t</type> <name>combinedImageSamplerDescriptorCount</name></member>
+ </type>
+ <type category="struct" name="VkSamplerYcbcrConversionImageFormatPropertiesKHR" alias="VkSamplerYcbcrConversionImageFormatProperties"/>
+ <type category="struct" name="VkTextureLODGatherFormatPropertiesAMD" returnedonly="true" structextends="VkImageFormatProperties2">
+ <member values="VK_STRUCTURE_TYPE_TEXTURE_LOD_GATHER_FORMAT_PROPERTIES_AMD"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true"><type>void</type>* <name>pNext</name></member>
+ <member><type>VkBool32</type> <name>supportsTextureGatherLODBiasAMD</name></member>
+ </type>
+ <type category="struct" name="VkConditionalRenderingBeginInfoEXT">
+ <member values="VK_STRUCTURE_TYPE_CONDITIONAL_RENDERING_BEGIN_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>
+ <member><type>VkDeviceSize</type> <name>offset</name></member>
+ <member optional="true"><type>VkConditionalRenderingFlagsEXT</type> <name>flags</name></member>
+ </type>
+ <type category="struct" name="VkProtectedSubmitInfo" structextends="VkSubmitInfo">
+ <member values="VK_STRUCTURE_TYPE_PROTECTED_SUBMIT_INFO"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member><type>VkBool32</type> <name>protectedSubmit</name><comment>Submit protected command buffers</comment></member>
+ </type>
+ <type category="struct" name="VkPhysicalDeviceProtectedMemoryFeatures" structextends="VkPhysicalDeviceFeatures2,VkDeviceCreateInfo">
+ <member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROTECTED_MEMORY_FEATURES"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true"><type>void</type>* <name>pNext</name></member>
+ <member><type>VkBool32</type> <name>protectedMemory</name></member>
+ </type>
+ <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>
+ </type>
+ <type category="struct" name="VkDeviceQueueInfo2">
+ <member values="VK_STRUCTURE_TYPE_DEVICE_QUEUE_INFO_2"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member optional="true"><type>VkDeviceQueueCreateFlags</type> <name>flags</name></member>
+ <member><type>uint32_t</type> <name>queueFamilyIndex</name></member>
+ <member><type>uint32_t</type> <name>queueIndex</name></member>
+ </type>
+ <type category="struct" name="VkPipelineCoverageToColorStateCreateInfoNV" structextends="VkPipelineMultisampleStateCreateInfo">
+ <member values="VK_STRUCTURE_TYPE_PIPELINE_COVERAGE_TO_COLOR_STATE_CREATE_INFO_NV"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member optional="true"><type>VkPipelineCoverageToColorStateCreateFlagsNV</type> <name>flags</name></member>
+ <member><type>VkBool32</type> <name>coverageToColorEnable</name></member>
+ <member optional="true"><type>uint32_t</type> <name>coverageToColorLocation</name></member>
+ </type>
+ <type category="struct" name="VkPhysicalDeviceSamplerFilterMinmaxProperties" returnedonly="true" structextends="VkPhysicalDeviceProperties2">
+ <member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLER_FILTER_MINMAX_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>filterMinmaxSingleComponentFormats</name></member>
+ <member limittype="bitmask"><type>VkBool32</type> <name>filterMinmaxImageComponentMapping</name></member>
+ </type>
+ <type category="struct" name="VkPhysicalDeviceSamplerFilterMinmaxPropertiesEXT" alias="VkPhysicalDeviceSamplerFilterMinmaxProperties"/>
+ <type category="struct" name="VkSampleLocationEXT">
+ <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">
+ <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>
+ <member><type>VkExtent2D</type> <name>sampleLocationGridSize</name></member>
+ <member optional="true"><type>uint32_t</type> <name>sampleLocationsCount</name></member>
+ <member len="sampleLocationsCount">const <type>VkSampleLocationEXT</type>* <name>pSampleLocations</name></member>
+ </type>
+ <type category="struct" name="VkAttachmentSampleLocationsEXT">
+ <member><type>uint32_t</type> <name>attachmentIndex</name></member>
+ <member><type>VkSampleLocationsInfoEXT</type> <name>sampleLocationsInfo</name></member>
+ </type>
+ <type category="struct" name="VkSubpassSampleLocationsEXT">
+ <member><type>uint32_t</type> <name>subpassIndex</name></member>
+ <member><type>VkSampleLocationsInfoEXT</type> <name>sampleLocationsInfo</name></member>
+ </type>
+ <type category="struct" name="VkRenderPassSampleLocationsBeginInfoEXT" structextends="VkRenderPassBeginInfo">
+ <member values="VK_STRUCTURE_TYPE_RENDER_PASS_SAMPLE_LOCATIONS_BEGIN_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>attachmentInitialSampleLocationsCount</name></member>
+ <member len="attachmentInitialSampleLocationsCount">const <type>VkAttachmentSampleLocationsEXT</type>* <name>pAttachmentInitialSampleLocations</name></member>
+ <member optional="true"><type>uint32_t</type> <name>postSubpassSampleLocationsCount</name></member>
+ <member len="postSubpassSampleLocationsCount">const <type>VkSubpassSampleLocationsEXT</type>* <name>pPostSubpassSampleLocations</name></member>
+ </type>
+ <type category="struct" name="VkPipelineSampleLocationsStateCreateInfoEXT" structextends="VkPipelineMultisampleStateCreateInfo">
+ <member values="VK_STRUCTURE_TYPE_PIPELINE_SAMPLE_LOCATIONS_STATE_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>sampleLocationsEnable</name></member>
+ <member><type>VkSampleLocationsInfoEXT</type> <name>sampleLocationsInfo</name></member>
+ </type>
+ <type category="struct" name="VkPhysicalDeviceSampleLocationsPropertiesEXT" returnedonly="true" structextends="VkPhysicalDeviceProperties2">
+ <member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLE_LOCATIONS_PROPERTIES_EXT"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true"><type>void</type>* <name>pNext</name></member>
+ <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="bitmask"><type>VkBool32</type> <name>variableSampleLocations</name></member>
+ </type>
+ <type category="struct" name="VkMultisamplePropertiesEXT" returnedonly="true">
+ <member values="VK_STRUCTURE_TYPE_MULTISAMPLE_PROPERTIES_EXT"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true"><type>void</type>* <name>pNext</name></member>
+ <member><type>VkExtent2D</type> <name>maxSampleLocationGridSize</name></member>
+ </type>
+ <type category="struct" name="VkSamplerReductionModeCreateInfo" structextends="VkSamplerCreateInfo">
+ <member values="VK_STRUCTURE_TYPE_SAMPLER_REDUCTION_MODE_CREATE_INFO"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member><type>VkSamplerReductionMode</type> <name>reductionMode</name></member>
+ </type>
+ <type category="struct" name="VkSamplerReductionModeCreateInfoEXT" alias="VkSamplerReductionModeCreateInfo"/>
+ <type category="struct" name="VkPhysicalDeviceBlendOperationAdvancedFeaturesEXT" structextends="VkPhysicalDeviceFeatures2,VkDeviceCreateInfo">
+ <member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BLEND_OPERATION_ADVANCED_FEATURES_EXT"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true"><type>void</type>* <name>pNext</name></member>
+ <member><type>VkBool32</type> <name>advancedBlendCoherentOperations</name></member>
+ </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><type>VkBool32</type> <name>multiDraw</name></member>
+ </type>
+ <type category="struct" name="VkPhysicalDeviceBlendOperationAdvancedPropertiesEXT" returnedonly="true" structextends="VkPhysicalDeviceProperties2">
+ <member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BLEND_OPERATION_ADVANCED_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>advancedBlendMaxColorAttachments</name></member>
+ <member limittype="bitmask"><type>VkBool32</type> <name>advancedBlendIndependentBlend</name></member>
+ <member limittype="bitmask"><type>VkBool32</type> <name>advancedBlendNonPremultipliedSrcColor</name></member>
+ <member limittype="bitmask"><type>VkBool32</type> <name>advancedBlendNonPremultipliedDstColor</name></member>
+ <member limittype="bitmask"><type>VkBool32</type> <name>advancedBlendCorrelatedOverlap</name></member>
+ <member limittype="bitmask"><type>VkBool32</type> <name>advancedBlendAllOperations</name></member>
+ </type>
+ <type category="struct" name="VkPipelineColorBlendAdvancedStateCreateInfoEXT" structextends="VkPipelineColorBlendStateCreateInfo">
+ <member values="VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_ADVANCED_STATE_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>srcPremultiplied</name></member>
+ <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>
+ <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>
+ <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>
+ <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>
+ </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>
+ <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>
+ <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>
+ <member optional="true"><type>VkPipelineCoverageModulationStateCreateFlagsNV</type> <name>flags</name></member>
+ <member><type>VkCoverageModulationModeNV</type> <name>coverageModulationMode</name></member>
+ <member><type>VkBool32</type> <name>coverageModulationTableEnable</name></member>
+ <member optional="true"><type>uint32_t</type> <name>coverageModulationTableCount</name></member>
+ <member noautovalidity="true" optional="true" len="coverageModulationTableCount">const <type>float</type>* <name>pCoverageModulationTable</name></member>
+ </type>
+ <type category="struct" name="VkImageFormatListCreateInfo" structextends="VkImageCreateInfo,VkSwapchainCreateInfoKHR,VkPhysicalDeviceImageFormatInfo2">
+ <member values="VK_STRUCTURE_TYPE_IMAGE_FORMAT_LIST_CREATE_INFO"><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>viewFormatCount</name></member>
+ <member len="viewFormatCount">const <type>VkFormat</type>* <name>pViewFormats</name></member>
+ </type>
+ <type category="struct" name="VkImageFormatListCreateInfoKHR" alias="VkImageFormatListCreateInfo"/>
+ <type category="struct" name="VkValidationCacheCreateInfoEXT">
+ <member values="VK_STRUCTURE_TYPE_VALIDATION_CACHE_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>VkValidationCacheCreateFlagsEXT</type> <name>flags</name></member>
+ <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">
+ <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>
+ </type>
+ <type category="struct" name="VkPhysicalDeviceMaintenance3Properties" returnedonly="true" structextends="VkPhysicalDeviceProperties2">
+ <member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_3_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>maxPerSetDescriptors</name></member>
+ <member limittype="max"><type>VkDeviceSize</type> <name>maxMemoryAllocationSize</name></member>
+ </type>
+ <type category="struct" name="VkPhysicalDeviceMaintenance3PropertiesKHR" alias="VkPhysicalDeviceMaintenance3Properties"/>
+ <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>
+ <member><type>VkBool32</type> <name>supported</name></member>
+ </type>
+ <type category="struct" name="VkDescriptorSetLayoutSupportKHR" alias="VkDescriptorSetLayoutSupport"/>
+ <type category="struct" name="VkPhysicalDeviceShaderDrawParametersFeatures" structextends="VkPhysicalDeviceFeatures2,VkDeviceCreateInfo">
+ <member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_DRAW_PARAMETERS_FEATURES"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true"><type>void</type>* <name>pNext</name></member>
+ <member><type>VkBool32</type> <name>shaderDrawParameters</name></member>
+ </type>
+ <type category="struct" name="VkPhysicalDeviceShaderDrawParameterFeatures" alias="VkPhysicalDeviceShaderDrawParametersFeatures"/>
+ <type category="struct" name="VkPhysicalDeviceShaderFloat16Int8Features" structextends="VkPhysicalDeviceFeatures2,VkDeviceCreateInfo">
+ <member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_FLOAT16_INT8_FEATURES"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true"><type>void</type>* <name>pNext</name></member>
+ <member><type>VkBool32</type> <name>shaderFloat16</name><comment>16-bit floats (halfs) in shaders</comment></member>
+ <member><type>VkBool32</type> <name>shaderInt8</name><comment>8-bit integers in shaders</comment></member>
+ </type>
+ <type category="struct" name="VkPhysicalDeviceShaderFloat16Int8FeaturesKHR" alias="VkPhysicalDeviceShaderFloat16Int8Features"/>
+ <type category="struct" name="VkPhysicalDeviceFloat16Int8FeaturesKHR" alias="VkPhysicalDeviceShaderFloat16Int8Features"/>
+ <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="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>
+ <member limittype="bitmask"><type>VkBool32</type> <name>shaderDenormPreserveFloat16</name><comment>An implementation can preserve denormals</comment></member>
+ <member limittype="bitmask"><type>VkBool32</type> <name>shaderDenormPreserveFloat32</name><comment>An implementation can preserve denormals</comment></member>
+ <member limittype="bitmask"><type>VkBool32</type> <name>shaderDenormPreserveFloat64</name><comment>An implementation can preserve denormals</comment></member>
+ <member limittype="bitmask"><type>VkBool32</type> <name>shaderDenormFlushToZeroFloat16</name><comment>An implementation can flush to zero denormals</comment></member>
+ <member limittype="bitmask"><type>VkBool32</type> <name>shaderDenormFlushToZeroFloat32</name><comment>An implementation can flush to zero denormals</comment></member>
+ <member limittype="bitmask"><type>VkBool32</type> <name>shaderDenormFlushToZeroFloat64</name><comment>An implementation can flush to zero denormals</comment></member>
+ <member limittype="bitmask"><type>VkBool32</type> <name>shaderRoundingModeRTEFloat16</name><comment>An implementation can support RTE</comment></member>
+ <member limittype="bitmask"><type>VkBool32</type> <name>shaderRoundingModeRTEFloat32</name><comment>An implementation can support RTE</comment></member>
+ <member limittype="bitmask"><type>VkBool32</type> <name>shaderRoundingModeRTEFloat64</name><comment>An implementation can support RTE</comment></member>
+ <member limittype="bitmask"><type>VkBool32</type> <name>shaderRoundingModeRTZFloat16</name><comment>An implementation can support RTZ</comment></member>
+ <member limittype="bitmask"><type>VkBool32</type> <name>shaderRoundingModeRTZFloat32</name><comment>An implementation can support RTZ</comment></member>
+ <member limittype="bitmask"><type>VkBool32</type> <name>shaderRoundingModeRTZFloat64</name><comment>An implementation can support RTZ</comment></member>
+ </type>
+ <type category="struct" name="VkPhysicalDeviceFloatControlsPropertiesKHR" alias="VkPhysicalDeviceFloatControlsProperties"/>
+ <type category="struct" name="VkPhysicalDeviceHostQueryResetFeatures" structextends="VkPhysicalDeviceFeatures2,VkDeviceCreateInfo">
+ <member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_HOST_QUERY_RESET_FEATURES"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true"><type>void</type>* <name>pNext</name></member>
+ <member><type>VkBool32</type> <name>hostQueryReset</name></member>
+ </type>
+ <type category="struct" name="VkPhysicalDeviceHostQueryResetFeaturesEXT" alias="VkPhysicalDeviceHostQueryResetFeatures"/>
+ <type category="struct" name="VkNativeBufferUsage2ANDROID">
+ <member><type>uint64_t</type> <name>consumer</name></member>
+ <member><type>uint64_t</type> <name>producer</name></member>
+ </type>
+ <type category="struct" name="VkNativeBufferANDROID">
+ <member values="VK_STRUCTURE_TYPE_NATIVE_BUFFER_ANDROID"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member>const <type>void</type>* <name>handle</name></member>
+ <member><type>int</type> <name>stride</name></member>
+ <member><type>int</type> <name>format</name></member>
+ <member><type>int</type> <name>usage</name></member>
+ <member><type>VkNativeBufferUsage2ANDROID</type> <name>usage2</name></member>
+ </type>
+ <type category="struct" name="VkSwapchainImageCreateInfoANDROID">
+ <member values="VK_STRUCTURE_TYPE_SWAPCHAIN_IMAGE_CREATE_INFO_ANDROID"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member><type>VkSwapchainImageUsageFlagsANDROID</type> <name>usage</name></member>
+ </type>
+ <type category="struct" name="VkPhysicalDevicePresentationPropertiesANDROID">
+ <member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRESENTATION_PROPERTIES_ANDROID"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member><type>VkBool32</type> <name>sharedImage</name></member>
+ </type>
+ <type category="struct" name="VkShaderResourceUsageAMD" returnedonly="true">
+ <member><type>uint32_t</type> <name>numUsedVgprs</name></member>
+ <member><type>uint32_t</type> <name>numUsedSgprs</name></member>
+ <member><type>uint32_t</type> <name>ldsSizePerLocalWorkGroup</name></member>
+ <member><type>size_t</type> <name>ldsUsageSizeInBytes</name></member>
+ <member><type>size_t</type> <name>scratchMemUsageInBytes</name></member>
+ </type>
+ <type category="struct" name="VkShaderStatisticsInfoAMD" returnedonly="true">
+ <member><type>VkShaderStageFlags</type> <name>shaderStageMask</name></member>
+ <member><type>VkShaderResourceUsageAMD</type> <name>resourceUsage</name></member>
+ <member><type>uint32_t</type> <name>numPhysicalVgprs</name></member>
+ <member><type>uint32_t</type> <name>numPhysicalSgprs</name></member>
+ <member><type>uint32_t</type> <name>numAvailableVgprs</name></member>
+ <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>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member><type>VkQueueGlobalPriorityEXT</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>
+ <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>
+ <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>
+ </type>
+ <type category="struct" name="VkDebugUtilsObjectNameInfoEXT">
+ <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>
+ <member objecttype="objectType"><type>uint64_t</type> <name>objectHandle</name></member>
+ <member optional="true" len="null-terminated">const <type>char</type>* <name>pObjectName</name></member>
+ </type>
+ <type category="struct" name="VkDebugUtilsObjectTagInfoEXT">
+ <member values="VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_TAG_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>
+ <member objecttype="objectType"><type>uint64_t</type> <name>objectHandle</name></member>
+ <member><type>uint64_t</type> <name>tagName</name></member>
+ <member><type>size_t</type> <name>tagSize</name></member>
+ <member len="tagSize">const <type>void</type>* <name>pTag</name></member>
+ </type>
+ <type category="struct" name="VkDebugUtilsLabelEXT">
+ <member values="VK_STRUCTURE_TYPE_DEBUG_UTILS_LABEL_EXT"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member len="null-terminated">const <type>char</type>* <name>pLabelName</name></member>
+ <member><type>float</type> <name>color</name>[4]</member>
+ </type>
+ <type category="struct" name="VkDebugUtilsMessengerCreateInfoEXT" allowduplicate="true" structextends="VkInstanceCreateInfo">
+ <member values="VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_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>VkDebugUtilsMessengerCreateFlagsEXT</type> <name>flags</name></member>
+ <member><type>VkDebugUtilsMessageSeverityFlagsEXT</type> <name>messageSeverity</name></member>
+ <member><type>VkDebugUtilsMessageTypeFlagsEXT</type> <name>messageType</name></member>
+ <member><type>PFN_vkDebugUtilsMessengerCallbackEXT</type> <name>pfnUserCallback</name></member>
+ <member optional="true"><type>void</type>* <name>pUserData</name></member>
+ </type>
+ <type category="struct" name="VkDebugUtilsMessengerCallbackDataEXT">
+ <member values="VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CALLBACK_DATA_EXT"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member optional="true"><type>VkDebugUtilsMessengerCallbackDataFlagsEXT</type> <name>flags</name></member>
+ <member optional="true" len="null-terminated">const <type>char</type>* <name>pMessageIdName</name></member>
+ <member><type>int32_t</type> <name>messageIdNumber</name></member>
+ <member len="null-terminated">const <type>char</type>* <name>pMessage</name></member>
+ <member optional="true"><type>uint32_t</type> <name>queueLabelCount</name></member>
+ <member len="queueLabelCount">const <type>VkDebugUtilsLabelEXT</type>* <name>pQueueLabels</name></member>
+ <member optional="true"><type>uint32_t</type> <name>cmdBufLabelCount</name></member>
+ <member len="cmdBufLabelCount">const <type>VkDebugUtilsLabelEXT</type>* <name>pCmdBufLabels</name></member>
+ <member optional="true"><type>uint32_t</type> <name>objectCount</name></member>
+ <member len="objectCount">const <type>VkDebugUtilsObjectNameInfoEXT</type>* <name>pObjects</name></member>
+ </type>
+ <type category="struct" name="VkPhysicalDeviceDeviceMemoryReportFeaturesEXT" structextends="VkPhysicalDeviceFeatures2,VkDeviceCreateInfo">
+ <member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEVICE_MEMORY_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>deviceMemoryReport</name></member>
+ </type>
+ <type category="struct" name="VkDeviceDeviceMemoryReportCreateInfoEXT" allowduplicate="true" structextends="VkDeviceCreateInfo">
+ <member values="VK_STRUCTURE_TYPE_DEVICE_DEVICE_MEMORY_REPORT_CREATE_INFO_EXT"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member><type>VkDeviceMemoryReportFlagsEXT</type> <name>flags</name></member>
+ <member><type>PFN_vkDeviceMemoryReportCallbackEXT</type> <name>pfnUserCallback</name></member>
+ <member><type>void</type>* <name>pUserData</name></member>
+ </type>
+ <type category="struct" name="VkDeviceMemoryReportCallbackDataEXT" returnedonly="true">
+ <member values="VK_STRUCTURE_TYPE_DEVICE_MEMORY_REPORT_CALLBACK_DATA_EXT"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true"><type>void</type>* <name>pNext</name></member>
+ <member><type>VkDeviceMemoryReportFlagsEXT</type> <name>flags</name></member>
+ <member><type>VkDeviceMemoryReportEventTypeEXT</type> <name>type</name></member>
+ <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><type>uint32_t</type> <name>heapIndex</name></member>
+ </type>
+ <type category="struct" name="VkImportMemoryHostPointerInfoEXT" structextends="VkMemoryAllocateInfo">
+ <member values="VK_STRUCTURE_TYPE_IMPORT_MEMORY_HOST_POINTER_INFO_EXT"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member><type>VkExternalMemoryHandleTypeFlagBits</type> <name>handleType</name></member>
+ <member optional="false"><type>void</type>* <name>pHostPointer</name></member>
+ </type>
+ <type category="struct" name="VkMemoryHostPointerPropertiesEXT" returnedonly="true">
+ <member values="VK_STRUCTURE_TYPE_MEMORY_HOST_POINTER_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>memoryTypeBits</name></member>
+ </type>
+ <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>
+ </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="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>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>
+ <type category="struct" name="VkCalibratedTimestampInfoEXT">
+ <member values="VK_STRUCTURE_TYPE_CALIBRATED_TIMESTAMP_INFO_EXT"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member><type>VkTimeDomainEXT</type> <name>timeDomain</name></member>
+ </type>
+ <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>
+ </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>
+ <member optional="true"><type>void</type>* <name>pNext</name><comment>Pointer to next structure</comment></member>
+ <member limittype="bitmask"><type>VkShaderCorePropertiesFlagsAMD</type> <name>shaderCoreFeatures</name><comment>features supported by the shader core</comment></member>
+ <member limittype="max"><type>uint32_t</type> <name>activeComputeUnitCount</name><comment>number of active compute units across all shader engines/arrays</comment></member>
+ </type>
+ <type category="struct" name="VkPipelineRasterizationConservativeStateCreateInfoEXT" structextends="VkPipelineRasterizationStateCreateInfo">
+ <member values="VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_CONSERVATIVE_STATE_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>VkPipelineRasterizationConservativeStateCreateFlagsEXT</type> <name>flags</name><comment>Reserved</comment></member>
+ <member><type>VkConservativeRasterizationModeEXT</type> <name>conservativeRasterizationMode</name><comment>Conservative rasterization mode</comment></member>
+ <member><type>float</type> <name>extraPrimitiveOverestimationSize</name><comment>Extra overestimation to add to the primitive</comment></member>
+ </type>
+ <type category="struct" name="VkPhysicalDeviceDescriptorIndexingFeatures" structextends="VkPhysicalDeviceFeatures2,VkDeviceCreateInfo">
+ <member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_INDEXING_FEATURES"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true"><type>void</type>* <name>pNext</name></member>
+ <member><type>VkBool32</type> <name>shaderInputAttachmentArrayDynamicIndexing</name></member>
+ <member><type>VkBool32</type> <name>shaderUniformTexelBufferArrayDynamicIndexing</name></member>
+ <member><type>VkBool32</type> <name>shaderStorageTexelBufferArrayDynamicIndexing</name></member>
+ <member><type>VkBool32</type> <name>shaderUniformBufferArrayNonUniformIndexing</name></member>
+ <member><type>VkBool32</type> <name>shaderSampledImageArrayNonUniformIndexing</name></member>
+ <member><type>VkBool32</type> <name>shaderStorageBufferArrayNonUniformIndexing</name></member>
+ <member><type>VkBool32</type> <name>shaderStorageImageArrayNonUniformIndexing</name></member>
+ <member><type>VkBool32</type> <name>shaderInputAttachmentArrayNonUniformIndexing</name></member>
+ <member><type>VkBool32</type> <name>shaderUniformTexelBufferArrayNonUniformIndexing</name></member>
+ <member><type>VkBool32</type> <name>shaderStorageTexelBufferArrayNonUniformIndexing</name></member>
+ <member><type>VkBool32</type> <name>descriptorBindingUniformBufferUpdateAfterBind</name></member>
+ <member><type>VkBool32</type> <name>descriptorBindingSampledImageUpdateAfterBind</name></member>
+ <member><type>VkBool32</type> <name>descriptorBindingStorageImageUpdateAfterBind</name></member>
+ <member><type>VkBool32</type> <name>descriptorBindingStorageBufferUpdateAfterBind</name></member>
+ <member><type>VkBool32</type> <name>descriptorBindingUniformTexelBufferUpdateAfterBind</name></member>
+ <member><type>VkBool32</type> <name>descriptorBindingStorageTexelBufferUpdateAfterBind</name></member>
+ <member><type>VkBool32</type> <name>descriptorBindingUpdateUnusedWhilePending</name></member>
+ <member><type>VkBool32</type> <name>descriptorBindingPartiallyBound</name></member>
+ <member><type>VkBool32</type> <name>descriptorBindingVariableDescriptorCount</name></member>
+ <member><type>VkBool32</type> <name>runtimeDescriptorArray</name></member>
+ </type>
+ <type category="struct" name="VkPhysicalDeviceDescriptorIndexingFeaturesEXT" alias="VkPhysicalDeviceDescriptorIndexingFeatures"/>
+ <type category="struct" name="VkPhysicalDeviceDescriptorIndexingProperties" returnedonly="true" structextends="VkPhysicalDeviceProperties2">
+ <member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_INDEXING_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>maxUpdateAfterBindDescriptorsInAllPools</name></member>
+ <member limittype="bitmask"><type>VkBool32</type> <name>shaderUniformBufferArrayNonUniformIndexingNative</name></member>
+ <member limittype="bitmask"><type>VkBool32</type> <name>shaderSampledImageArrayNonUniformIndexingNative</name></member>
+ <member limittype="bitmask"><type>VkBool32</type> <name>shaderStorageBufferArrayNonUniformIndexingNative</name></member>
+ <member limittype="bitmask"><type>VkBool32</type> <name>shaderStorageImageArrayNonUniformIndexingNative</name></member>
+ <member limittype="bitmask"><type>VkBool32</type> <name>shaderInputAttachmentArrayNonUniformIndexingNative</name></member>
+ <member limittype="bitmask"><type>VkBool32</type> <name>robustBufferAccessUpdateAfterBind</name></member>
+ <member limittype="bitmask"><type>VkBool32</type> <name>quadDivergentImplicitLod</name></member>
+ <member limittype="max"><type>uint32_t</type> <name>maxPerStageDescriptorUpdateAfterBindSamplers</name></member>
+ <member limittype="max"><type>uint32_t</type> <name>maxPerStageDescriptorUpdateAfterBindUniformBuffers</name></member>
+ <member limittype="max"><type>uint32_t</type> <name>maxPerStageDescriptorUpdateAfterBindStorageBuffers</name></member>
+ <member limittype="max"><type>uint32_t</type> <name>maxPerStageDescriptorUpdateAfterBindSampledImages</name></member>
+ <member limittype="max"><type>uint32_t</type> <name>maxPerStageDescriptorUpdateAfterBindStorageImages</name></member>
+ <member limittype="max"><type>uint32_t</type> <name>maxPerStageDescriptorUpdateAfterBindInputAttachments</name></member>
+ <member limittype="max"><type>uint32_t</type> <name>maxPerStageUpdateAfterBindResources</name></member>
+ <member limittype="max"><type>uint32_t</type> <name>maxDescriptorSetUpdateAfterBindSamplers</name></member>
+ <member limittype="max"><type>uint32_t</type> <name>maxDescriptorSetUpdateAfterBindUniformBuffers</name></member>
+ <member limittype="max"><type>uint32_t</type> <name>maxDescriptorSetUpdateAfterBindUniformBuffersDynamic</name></member>
+ <member limittype="max"><type>uint32_t</type> <name>maxDescriptorSetUpdateAfterBindStorageBuffers</name></member>
+ <member limittype="max"><type>uint32_t</type> <name>maxDescriptorSetUpdateAfterBindStorageBuffersDynamic</name></member>
+ <member limittype="max"><type>uint32_t</type> <name>maxDescriptorSetUpdateAfterBindSampledImages</name></member>
+ <member limittype="max"><type>uint32_t</type> <name>maxDescriptorSetUpdateAfterBindStorageImages</name></member>
+ <member limittype="max"><type>uint32_t</type> <name>maxDescriptorSetUpdateAfterBindInputAttachments</name></member>
+ </type>
+ <type category="struct" name="VkPhysicalDeviceDescriptorIndexingPropertiesEXT" alias="VkPhysicalDeviceDescriptorIndexingProperties"/>
+ <type category="struct" name="VkDescriptorSetLayoutBindingFlagsCreateInfo" structextends="VkDescriptorSetLayoutCreateInfo">
+ <member values="VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_BINDING_FLAGS_CREATE_INFO"><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>bindingCount</name></member>
+ <member len="bindingCount" optional="false,true">const <type>VkDescriptorBindingFlags</type>* <name>pBindingFlags</name></member>
+ </type>
+ <type category="struct" name="VkDescriptorSetLayoutBindingFlagsCreateInfoEXT" alias="VkDescriptorSetLayoutBindingFlagsCreateInfo"/>
+ <type category="struct" name="VkDescriptorSetVariableDescriptorCountAllocateInfo" structextends="VkDescriptorSetAllocateInfo">
+ <member values="VK_STRUCTURE_TYPE_DESCRIPTOR_SET_VARIABLE_DESCRIPTOR_COUNT_ALLOCATE_INFO"><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>descriptorSetCount</name></member>
+ <member len="descriptorSetCount">const <type>uint32_t</type>* <name>pDescriptorCounts</name></member>
+ </type>
+ <type category="struct" name="VkDescriptorSetVariableDescriptorCountAllocateInfoEXT" alias="VkDescriptorSetVariableDescriptorCountAllocateInfo"/>
+ <type category="struct" name="VkDescriptorSetVariableDescriptorCountLayoutSupport" structextends="VkDescriptorSetLayoutSupport" returnedonly="true">
+ <member values="VK_STRUCTURE_TYPE_DESCRIPTOR_SET_VARIABLE_DESCRIPTOR_COUNT_LAYOUT_SUPPORT"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true"><type>void</type>* <name>pNext</name></member>
+ <member><type>uint32_t</type> <name>maxVariableDescriptorCount</name></member>
+ </type>
+ <type category="struct" name="VkDescriptorSetVariableDescriptorCountLayoutSupportEXT" alias="VkDescriptorSetVariableDescriptorCountLayoutSupport"/>
+ <type category="struct" name="VkAttachmentDescription2">
+ <member values="VK_STRUCTURE_TYPE_ATTACHMENT_DESCRIPTION_2"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member optional="true"><type>VkAttachmentDescriptionFlags</type> <name>flags</name></member>
+ <member><type>VkFormat</type> <name>format</name></member>
+ <member><type>VkSampleCountFlagBits</type> <name>samples</name></member>
+ <member><type>VkAttachmentLoadOp</type> <name>loadOp</name><comment>Load operation for color or depth data</comment></member>
+ <member><type>VkAttachmentStoreOp</type> <name>storeOp</name><comment>Store operation for color or depth data</comment></member>
+ <member><type>VkAttachmentLoadOp</type> <name>stencilLoadOp</name><comment>Load operation for stencil data</comment></member>
+ <member><type>VkAttachmentStoreOp</type> <name>stencilStoreOp</name><comment>Store operation for stencil data</comment></member>
+ <member><type>VkImageLayout</type> <name>initialLayout</name></member>
+ <member><type>VkImageLayout</type> <name>finalLayout</name></member>
+ </type>
+ <type category="struct" name="VkAttachmentDescription2KHR" alias="VkAttachmentDescription2"/>
+ <type category="struct" name="VkAttachmentReference2">
+ <member values="VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member><type>uint32_t</type> <name>attachment</name></member>
+ <member><type>VkImageLayout</type> <name>layout</name></member>
+ <member noautovalidity="true"><type>VkImageAspectFlags</type> <name>aspectMask</name></member>
+ </type>
+ <type category="struct" name="VkAttachmentReference2KHR" alias="VkAttachmentReference2"/>
+ <type category="struct" name="VkSubpassDescription2">
+ <member values="VK_STRUCTURE_TYPE_SUBPASS_DESCRIPTION_2"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member optional="true"><type>VkSubpassDescriptionFlags</type> <name>flags</name></member>
+ <member><type>VkPipelineBindPoint</type> <name>pipelineBindPoint</name></member>
+ <member><type>uint32_t</type> <name>viewMask</name></member>
+ <member optional="true"><type>uint32_t</type> <name>inputAttachmentCount</name></member>
+ <member len="inputAttachmentCount">const <type>VkAttachmentReference2</type>* <name>pInputAttachments</name></member>
+ <member optional="true"><type>uint32_t</type> <name>colorAttachmentCount</name></member>
+ <member len="colorAttachmentCount">const <type>VkAttachmentReference2</type>* <name>pColorAttachments</name></member>
+ <member optional="true" len="colorAttachmentCount">const <type>VkAttachmentReference2</type>* <name>pResolveAttachments</name></member>
+ <member optional="true">const <type>VkAttachmentReference2</type>* <name>pDepthStencilAttachment</name></member>
+ <member optional="true"><type>uint32_t</type> <name>preserveAttachmentCount</name></member>
+ <member len="preserveAttachmentCount">const <type>uint32_t</type>* <name>pPreserveAttachments</name></member>
+ </type>
+ <type category="struct" name="VkSubpassDescription2KHR" alias="VkSubpassDescription2"/>
+ <type category="struct" name="VkSubpassDependency2">
+ <member values="VK_STRUCTURE_TYPE_SUBPASS_DEPENDENCY_2"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member><type>uint32_t</type> <name>srcSubpass</name></member>
+ <member><type>uint32_t</type> <name>dstSubpass</name></member>
+ <member optional="true"><type>VkPipelineStageFlags</type> <name>srcStageMask</name></member>
+ <member optional="true"><type>VkPipelineStageFlags</type> <name>dstStageMask</name></member>
+ <member optional="true"><type>VkAccessFlags</type> <name>srcAccessMask</name></member>
+ <member optional="true"><type>VkAccessFlags</type> <name>dstAccessMask</name></member>
+ <member optional="true"><type>VkDependencyFlags</type> <name>dependencyFlags</name></member>
+ <member><type>int32_t</type> <name>viewOffset</name></member>
+ </type>
+ <type category="struct" name="VkSubpassDependency2KHR" alias="VkSubpassDependency2"/>
+ <type category="struct" name="VkRenderPassCreateInfo2">
+ <member values="VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO_2"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member optional="true"><type>VkRenderPassCreateFlags</type> <name>flags</name></member>
+ <member optional="true"><type>uint32_t</type> <name>attachmentCount</name></member>
+ <member len="attachmentCount">const <type>VkAttachmentDescription2</type>* <name>pAttachments</name></member>
+ <member><type>uint32_t</type> <name>subpassCount</name></member>
+ <member len="subpassCount">const <type>VkSubpassDescription2</type>* <name>pSubpasses</name></member>
+ <member optional="true"><type>uint32_t</type> <name>dependencyCount</name></member>
+ <member len="dependencyCount">const <type>VkSubpassDependency2</type>* <name>pDependencies</name></member>
+ <member optional="true"><type>uint32_t</type> <name>correlatedViewMaskCount</name></member>
+ <member len="correlatedViewMaskCount">const <type>uint32_t</type>* <name>pCorrelatedViewMasks</name></member>
+ </type>
+ <type category="struct" name="VkRenderPassCreateInfo2KHR" alias="VkRenderPassCreateInfo2"/>
+ <type category="struct" name="VkSubpassBeginInfo">
+ <member values="VK_STRUCTURE_TYPE_SUBPASS_BEGIN_INFO"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member><type>VkSubpassContents</type> <name>contents</name></member>
+ </type>
+ <type category="struct" name="VkSubpassBeginInfoKHR" alias="VkSubpassBeginInfo"/>
+ <type category="struct" name="VkSubpassEndInfo">
+ <member values="VK_STRUCTURE_TYPE_SUBPASS_END_INFO"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ </type>
+ <type category="struct" name="VkSubpassEndInfoKHR" alias="VkSubpassEndInfo"/>
+ <type category="struct" name="VkPhysicalDeviceTimelineSemaphoreFeatures" structextends="VkPhysicalDeviceFeatures2,VkDeviceCreateInfo">
+ <member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TIMELINE_SEMAPHORE_FEATURES"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true"><type>void</type>* <name>pNext</name></member>
+ <member><type>VkBool32</type> <name>timelineSemaphore</name></member>
+ </type>
+ <type category="struct" name="VkPhysicalDeviceTimelineSemaphoreFeaturesKHR" alias="VkPhysicalDeviceTimelineSemaphoreFeatures"/>
+ <type category="struct" name="VkPhysicalDeviceTimelineSemaphoreProperties" structextends="VkPhysicalDeviceProperties2" returnedonly="true">
+ <member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TIMELINE_SEMAPHORE_PROPERTIES"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true"><type>void</type>* <name>pNext</name></member>
+ <member limittype="max"><type>uint64_t</type> <name>maxTimelineSemaphoreValueDifference</name></member>
+ </type>
+ <type category="struct" name="VkPhysicalDeviceTimelineSemaphorePropertiesKHR" alias="VkPhysicalDeviceTimelineSemaphoreProperties"/>
+ <type category="struct" name="VkSemaphoreTypeCreateInfo" structextends="VkSemaphoreCreateInfo,VkPhysicalDeviceExternalSemaphoreInfo">
+ <member values="VK_STRUCTURE_TYPE_SEMAPHORE_TYPE_CREATE_INFO"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member><type>VkSemaphoreType</type> <name>semaphoreType</name></member>
+ <member><type>uint64_t</type> <name>initialValue</name></member>
+ </type>
+ <type category="struct" name="VkSemaphoreTypeCreateInfoKHR" alias="VkSemaphoreTypeCreateInfo"/>
+ <type category="struct" name="VkTimelineSemaphoreSubmitInfo" structextends="VkSubmitInfo,VkBindSparseInfo">
+ <member values="VK_STRUCTURE_TYPE_TIMELINE_SEMAPHORE_SUBMIT_INFO"><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>waitSemaphoreValueCount</name></member>
+ <member optional="true" len="waitSemaphoreValueCount">const <type>uint64_t</type>* <name>pWaitSemaphoreValues</name></member>
+ <member optional="true"><type>uint32_t</type> <name>signalSemaphoreValueCount</name></member>
+ <member optional="true" len="signalSemaphoreValueCount">const <type>uint64_t</type>* <name>pSignalSemaphoreValues</name></member>
+ </type>
+ <type category="struct" name="VkTimelineSemaphoreSubmitInfoKHR" alias="VkTimelineSemaphoreSubmitInfo"/>
+ <type category="struct" name="VkSemaphoreWaitInfo">
+ <member values="VK_STRUCTURE_TYPE_SEMAPHORE_WAIT_INFO"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member optional="true"><type>VkSemaphoreWaitFlags</type> <name>flags</name></member>
+ <member><type>uint32_t</type> <name>semaphoreCount</name></member>
+ <member len="semaphoreCount">const <type>VkSemaphore</type>* <name>pSemaphores</name></member>
+ <member len="semaphoreCount">const <type>uint64_t</type>* <name>pValues</name></member>
+ </type>
+ <type category="struct" name="VkSemaphoreWaitInfoKHR" alias="VkSemaphoreWaitInfo"/>
+ <type category="struct" name="VkSemaphoreSignalInfo">
+ <member values="VK_STRUCTURE_TYPE_SEMAPHORE_SIGNAL_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>
+ </type>
+ <type category="struct" name="VkSemaphoreSignalInfoKHR" alias="VkSemaphoreSignalInfo"/>
+ <type category="struct" name="VkVertexInputBindingDivisorDescriptionEXT">
+ <member><type>uint32_t</type> <name>binding</name></member>
+ <member><type>uint32_t</type> <name>divisor</name></member>
+ </type>
+ <type category="struct" name="VkPipelineVertexInputDivisorStateCreateInfoEXT" structextends="VkPipelineVertexInputStateCreateInfo">
+ <member values="VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_DIVISOR_STATE_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>vertexBindingDivisorCount</name></member>
+ <member len="vertexBindingDivisorCount">const <type>VkVertexInputBindingDivisorDescriptionEXT</type>* <name>pVertexBindingDivisors</name></member>
+ </type>
+ <type category="struct" name="VkPhysicalDeviceVertexAttributeDivisorPropertiesEXT" returnedonly="true" structextends="VkPhysicalDeviceProperties2">
+ <member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VERTEX_ATTRIBUTE_DIVISOR_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>maxVertexAttribDivisor</name><comment>max value of vertex attribute divisor</comment></member>
+ </type>
+ <type category="struct" name="VkPhysicalDevicePCIBusInfoPropertiesEXT" structextends="VkPhysicalDeviceProperties2" returnedonly="true">
+ <member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PCI_BUS_INFO_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>pciDomain</name></member>
+ <member limittype="noauto"><type>uint32_t</type> <name>pciBus</name></member>
+ <member limittype="noauto"><type>uint32_t</type> <name>pciDevice</name></member>
+ <member limittype="noauto"><type>uint32_t</type> <name>pciFunction</name></member>
+ </type>
+ <type category="struct" name="VkImportAndroidHardwareBufferInfoANDROID" structextends="VkMemoryAllocateInfo">
+ <member values="VK_STRUCTURE_TYPE_IMPORT_ANDROID_HARDWARE_BUFFER_INFO_ANDROID"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member>struct <type>AHardwareBuffer</type>* <name>buffer</name></member>
+ </type>
+ <type category="struct" name="VkAndroidHardwareBufferUsageANDROID" structextends="VkImageFormatProperties2" returnedonly="true">
+ <member values="VK_STRUCTURE_TYPE_ANDROID_HARDWARE_BUFFER_USAGE_ANDROID"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true"><type>void</type>* <name>pNext</name></member>
+ <member><type>uint64_t</type> <name>androidHardwareBufferUsage</name></member>
+ </type>
+ <type category="struct" name="VkAndroidHardwareBufferPropertiesANDROID" returnedonly="true">
+ <member values="VK_STRUCTURE_TYPE_ANDROID_HARDWARE_BUFFER_PROPERTIES_ANDROID"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true"><type>void</type>* <name>pNext</name></member>
+ <member><type>VkDeviceSize</type> <name>allocationSize</name></member>
+ <member><type>uint32_t</type> <name>memoryTypeBits</name></member>
+ </type>
+ <type category="struct" name="VkMemoryGetAndroidHardwareBufferInfoANDROID">
+ <member values="VK_STRUCTURE_TYPE_MEMORY_GET_ANDROID_HARDWARE_BUFFER_INFO_ANDROID"><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>
+ </type>
+ <type category="struct" name="VkAndroidHardwareBufferFormatPropertiesANDROID" structextends="VkAndroidHardwareBufferPropertiesANDROID" returnedonly="true">
+ <member values="VK_STRUCTURE_TYPE_ANDROID_HARDWARE_BUFFER_FORMAT_PROPERTIES_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>VkFormatFeatureFlags</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="VkCommandBufferInheritanceConditionalRenderingInfoEXT" structextends="VkCommandBufferInheritanceInfo">
+ <member values="VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_CONDITIONAL_RENDERING_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>conditionalRenderingEnable</name><comment>Whether this secondary command buffer may be executed during an active conditional rendering</comment></member>
+ </type>
+ <type category="struct" name="VkExternalFormatANDROID" structextends="VkImageCreateInfo,VkSamplerYcbcrConversionCreateInfo">
+ <member values="VK_STRUCTURE_TYPE_EXTERNAL_FORMAT_ANDROID"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true"><type>void</type>* <name>pNext</name></member>
+ <member><type>uint64_t</type> <name>externalFormat</name></member>
+ </type>
+ <type category="struct" name="VkPhysicalDevice8BitStorageFeatures" structextends="VkPhysicalDeviceFeatures2,VkDeviceCreateInfo">
+ <member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_8BIT_STORAGE_FEATURES"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true"><type>void</type>* <name>pNext</name></member>
+ <member><type>VkBool32</type> <name>storageBuffer8BitAccess</name><comment>8-bit integer variables supported in StorageBuffer</comment></member>
+ <member><type>VkBool32</type> <name>uniformAndStorageBuffer8BitAccess</name><comment>8-bit integer variables supported in StorageBuffer and Uniform</comment></member>
+ <member><type>VkBool32</type> <name>storagePushConstant8</name><comment>8-bit integer variables supported in PushConstant</comment></member>
+ </type>
+ <type category="struct" name="VkPhysicalDevice8BitStorageFeaturesKHR" alias="VkPhysicalDevice8BitStorageFeatures"/>
+ <type category="struct" name="VkPhysicalDeviceConditionalRenderingFeaturesEXT" structextends="VkPhysicalDeviceFeatures2,VkDeviceCreateInfo">
+ <member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CONDITIONAL_RENDERING_FEATURES_EXT"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true"><type>void</type>* <name>pNext</name></member>
+ <member><type>VkBool32</type> <name>conditionalRendering</name></member>
+ <member><type>VkBool32</type> <name>inheritedConditionalRendering</name></member>
+ </type>
+ <type category="struct" name="VkPhysicalDeviceVulkanMemoryModelFeatures" structextends="VkPhysicalDeviceFeatures2,VkDeviceCreateInfo">
+ <member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_MEMORY_MODEL_FEATURES"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true"><type>void</type>* <name>pNext</name></member>
+ <member><type>VkBool32</type> <name>vulkanMemoryModel</name></member>
+ <member><type>VkBool32</type> <name>vulkanMemoryModelDeviceScope</name></member>
+ <member><type>VkBool32</type> <name>vulkanMemoryModelAvailabilityVisibilityChains</name></member>
+ </type>
+ <type category="struct" name="VkPhysicalDeviceVulkanMemoryModelFeaturesKHR" alias="VkPhysicalDeviceVulkanMemoryModelFeatures"/>
+ <type category="struct" name="VkPhysicalDeviceShaderAtomicInt64Features" structextends="VkPhysicalDeviceFeatures2,VkDeviceCreateInfo">
+ <member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_ATOMIC_INT64_FEATURES"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true"><type>void</type>* <name>pNext</name></member>
+ <member><type>VkBool32</type> <name>shaderBufferInt64Atomics</name></member>
+ <member><type>VkBool32</type> <name>shaderSharedInt64Atomics</name></member>
+ </type>
+ <type category="struct" name="VkPhysicalDeviceShaderAtomicInt64FeaturesKHR" alias="VkPhysicalDeviceShaderAtomicInt64Features"/>
+ <type category="struct" name="VkPhysicalDeviceShaderAtomicFloatFeaturesEXT" structextends="VkPhysicalDeviceFeatures2,VkDeviceCreateInfo">
+ <member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_ATOMIC_FLOAT_FEATURES_EXT"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true"><type>void</type>* <name>pNext</name></member>
+ <member><type>VkBool32</type> <name>shaderBufferFloat32Atomics</name></member>
+ <member><type>VkBool32</type> <name>shaderBufferFloat32AtomicAdd</name></member>
+ <member><type>VkBool32</type> <name>shaderBufferFloat64Atomics</name></member>
+ <member><type>VkBool32</type> <name>shaderBufferFloat64AtomicAdd</name></member>
+ <member><type>VkBool32</type> <name>shaderSharedFloat32Atomics</name></member>
+ <member><type>VkBool32</type> <name>shaderSharedFloat32AtomicAdd</name></member>
+ <member><type>VkBool32</type> <name>shaderSharedFloat64Atomics</name></member>
+ <member><type>VkBool32</type> <name>shaderSharedFloat64AtomicAdd</name></member>
+ <member><type>VkBool32</type> <name>shaderImageFloat32Atomics</name></member>
+ <member><type>VkBool32</type> <name>shaderImageFloat32AtomicAdd</name></member>
+ <member><type>VkBool32</type> <name>sparseImageFloat32Atomics</name></member>
+ <member><type>VkBool32</type> <name>sparseImageFloat32AtomicAdd</name></member>
+ </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><type>VkBool32</type> <name>shaderBufferFloat16Atomics</name></member>
+ <member><type>VkBool32</type> <name>shaderBufferFloat16AtomicAdd</name></member>
+ <member><type>VkBool32</type> <name>shaderBufferFloat16AtomicMinMax</name></member>
+ <member><type>VkBool32</type> <name>shaderBufferFloat32AtomicMinMax</name></member>
+ <member><type>VkBool32</type> <name>shaderBufferFloat64AtomicMinMax</name></member>
+ <member><type>VkBool32</type> <name>shaderSharedFloat16Atomics</name></member>
+ <member><type>VkBool32</type> <name>shaderSharedFloat16AtomicAdd</name></member>
+ <member><type>VkBool32</type> <name>shaderSharedFloat16AtomicMinMax</name></member>
+ <member><type>VkBool32</type> <name>shaderSharedFloat32AtomicMinMax</name></member>
+ <member><type>VkBool32</type> <name>shaderSharedFloat64AtomicMinMax</name></member>
+ <member><type>VkBool32</type> <name>shaderImageFloat32AtomicMinMax</name></member>
+ <member><type>VkBool32</type> <name>sparseImageFloat32AtomicMinMax</name></member>
+ </type>
+ <type category="struct" name="VkPhysicalDeviceVertexAttributeDivisorFeaturesEXT" structextends="VkPhysicalDeviceFeatures2,VkDeviceCreateInfo">
+ <member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VERTEX_ATTRIBUTE_DIVISOR_FEATURES_EXT"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true"><type>void</type>* <name>pNext</name></member>
+ <member><type>VkBool32</type> <name>vertexAttributeInstanceRateDivisor</name></member>
+ <member><type>VkBool32</type> <name>vertexAttributeInstanceRateZeroDivisor</name></member>
+ </type>
+ <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>
+ </type>
+ <type category="struct" name="VkCheckpointDataNV" returnedonly="true">
+ <member values="VK_STRUCTURE_TYPE_CHECKPOINT_DATA_NV"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true"><type>void</type>* <name>pNext</name></member>
+ <member><type>VkPipelineStageFlagBits</type> <name>stage</name></member>
+ <member noautovalidity="true"><type>void</type>* <name>pCheckpointMarker</name></member>
+ </type>
+ <type category="struct" name="VkPhysicalDeviceDepthStencilResolveProperties" structextends="VkPhysicalDeviceProperties2" returnedonly="true">
+ <member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEPTH_STENCIL_RESOLVE_PROPERTIES"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true"><type>void</type>* <name>pNext</name></member>
+ <member limittype="bitmask"><type>VkResolveModeFlags</type> <name>supportedDepthResolveModes</name><comment>supported depth resolve modes</comment></member>
+ <member limittype="bitmask"><type>VkResolveModeFlags</type> <name>supportedStencilResolveModes</name><comment>supported stencil resolve modes</comment></member>
+ <member limittype="bitmask"><type>VkBool32</type> <name>independentResolveNone</name><comment>depth and stencil resolve modes can be set independently if one of them is none</comment></member>
+ <member limittype="bitmask"><type>VkBool32</type> <name>independentResolve</name><comment>depth and stencil resolve modes can be set independently</comment></member>
+ </type>
+ <type category="struct" name="VkPhysicalDeviceDepthStencilResolvePropertiesKHR" alias="VkPhysicalDeviceDepthStencilResolveProperties"/>
+ <type category="struct" name="VkSubpassDescriptionDepthStencilResolve" structextends="VkSubpassDescription2">
+ <member values="VK_STRUCTURE_TYPE_SUBPASS_DESCRIPTION_DEPTH_STENCIL_RESOLVE"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member noautovalidity="true"><type>VkResolveModeFlagBits</type> <name>depthResolveMode</name><comment>depth resolve mode</comment></member>
+ <member noautovalidity="true"><type>VkResolveModeFlagBits</type> <name>stencilResolveMode</name><comment>stencil resolve mode</comment></member>
+ <member optional="true">const <type>VkAttachmentReference2</type>* <name>pDepthStencilResolveAttachment</name><comment>depth/stencil resolve attachment</comment></member>
+ </type>
+ <type category="struct" name="VkSubpassDescriptionDepthStencilResolveKHR" alias="VkSubpassDescriptionDepthStencilResolve"/>
+ <type category="struct" name="VkImageViewASTCDecodeModeEXT" structextends="VkImageViewCreateInfo">
+ <member values="VK_STRUCTURE_TYPE_IMAGE_VIEW_ASTC_DECODE_MODE_EXT"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member><type>VkFormat</type> <name>decodeMode</name></member>
+ </type>
+ <type category="struct" name="VkPhysicalDeviceASTCDecodeFeaturesEXT" structextends="VkPhysicalDeviceFeatures2,VkDeviceCreateInfo">
+ <member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ASTC_DECODE_FEATURES_EXT"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true"><type>void</type>* <name>pNext</name></member>
+ <member><type>VkBool32</type> <name>decodeModeSharedExponent</name></member>
+ </type>
+ <type category="struct" name="VkPhysicalDeviceTransformFeedbackFeaturesEXT" structextends="VkPhysicalDeviceFeatures2,VkDeviceCreateInfo">
+ <member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TRANSFORM_FEEDBACK_FEATURES_EXT"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true"><type>void</type>* <name>pNext</name></member>
+ <member><type>VkBool32</type> <name>transformFeedback</name></member>
+ <member><type>VkBool32</type> <name>geometryStreams</name></member>
+ </type>
+ <type category="struct" name="VkPhysicalDeviceTransformFeedbackPropertiesEXT" structextends="VkPhysicalDeviceProperties2" returnedonly="true">
+ <member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TRANSFORM_FEEDBACK_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>maxTransformFeedbackStreams</name></member>
+ <member limittype="max"><type>uint32_t</type> <name>maxTransformFeedbackBuffers</name></member>
+ <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="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>
+ <member limittype="bitmask"><type>VkBool32</type> <name>transformFeedbackDraw</name></member>
+ </type>
+ <type category="struct" name="VkPipelineRasterizationStateStreamCreateInfoEXT" structextends="VkPipelineRasterizationStateCreateInfo">
+ <member values="VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_STREAM_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>VkPipelineRasterizationStateStreamCreateFlagsEXT</type> <name>flags</name></member>
+ <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 optional="true"><type>void</type>* <name>pNext</name></member>
+ <member><type>VkBool32</type> <name>representativeFragmentTest</name></member>
+ </type>
+ <type category="struct" name="VkPipelineRepresentativeFragmentTestStateCreateInfoNV" structextends="VkGraphicsPipelineCreateInfo">
+ <member values="VK_STRUCTURE_TYPE_PIPELINE_REPRESENTATIVE_FRAGMENT_TEST_STATE_CREATE_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>representativeFragmentTestEnable</name></member>
+ </type>
+ <type category="struct" name="VkPhysicalDeviceExclusiveScissorFeaturesNV" structextends="VkPhysicalDeviceFeatures2,VkDeviceCreateInfo">
+ <member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXCLUSIVE_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>exclusiveScissor</name></member>
+ </type>
+ <type category="struct" name="VkPipelineViewportExclusiveScissorStateCreateInfoNV" structextends="VkPipelineViewportStateCreateInfo">
+ <member values="VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_EXCLUSIVE_SCISSOR_STATE_CREATE_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>exclusiveScissorCount</name></member>
+ <member noautovalidity="true" len="exclusiveScissorCount">const <type>VkRect2D</type>* <name>pExclusiveScissors</name></member>
+ </type>
+ <type category="struct" name="VkPhysicalDeviceCornerSampledImageFeaturesNV" structextends="VkPhysicalDeviceFeatures2,VkDeviceCreateInfo">
+ <member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CORNER_SAMPLED_IMAGE_FEATURES_NV"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true"><type>void</type>* <name>pNext</name></member>
+ <member><type>VkBool32</type> <name>cornerSampledImage</name></member>
+ </type>
+ <type category="struct" name="VkPhysicalDeviceComputeShaderDerivativesFeaturesNV" structextends="VkPhysicalDeviceFeatures2,VkDeviceCreateInfo">
+ <member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COMPUTE_SHADER_DERIVATIVES_FEATURES_NV"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true"><type>void</type>* <name>pNext</name></member>
+ <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="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>
+ <member><type>VkBool32</type> <name>imageFootprint</name></member>
+ </type>
+ <type category="struct" name="VkPhysicalDeviceDedicatedAllocationImageAliasingFeaturesNV" structextends="VkPhysicalDeviceFeatures2,VkDeviceCreateInfo">
+ <member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEDICATED_ALLOCATION_IMAGE_ALIASING_FEATURES_NV"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true"><type>void</type>* <name>pNext</name></member>
+ <member><type>VkBool32</type> <name>dedicatedAllocationImageAliasing</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>
+ </type>
+ <type category="struct" name="VkPipelineViewportShadingRateImageStateCreateInfoNV" structextends="VkPipelineViewportStateCreateInfo">
+ <member values="VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_SHADING_RATE_IMAGE_STATE_CREATE_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>shadingRateImageEnable</name></member>
+ <member optional="true"><type>uint32_t</type> <name>viewportCount</name></member>
+ <member noautovalidity="true" len="viewportCount">const <type>VkShadingRatePaletteNV</type>* <name>pShadingRatePalettes</name></member>
+ </type>
+ <type category="struct" name="VkPhysicalDeviceShadingRateImageFeaturesNV" structextends="VkPhysicalDeviceFeatures2,VkDeviceCreateInfo">
+ <member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADING_RATE_IMAGE_FEATURES_NV"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true"><type>void</type>* <name>pNext</name></member>
+ <member><type>VkBool32</type> <name>shadingRateImage</name></member>
+ <member><type>VkBool32</type> <name>shadingRateCoarseSampleOrder</name></member>
+ </type>
+ <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="max"><type>uint32_t</type> <name>shadingRatePaletteSize</name></member>
+ <member limittype="max"><type>uint32_t</type> <name>shadingRateMaxCoarseSamples</name></member>
+ </type>
+ <type category="struct" name="VkPhysicalDeviceInvocationMaskFeaturesHUAWEI" structextends="VkPhysicalDeviceFeatures2,VkDeviceCreateInfo">
+ <member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INVOCATION_MASK_FEATURES_HUAWEI"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true"><type>void</type>* <name>pNext</name></member>
+ <member><type>VkBool32</type> <name>invocationMask</name></member>
+ </type>
+ <type category="struct" name="VkCoarseSampleLocationNV">
+ <member><type>uint32_t</type> <name>pixelX</name></member>
+ <member><type>uint32_t</type> <name>pixelY</name></member>
+ <member><type>uint32_t</type> <name>sample</name></member>
+ </type>
+ <type category="struct" name="VkCoarseSampleOrderCustomNV">
+ <member><type>VkShadingRatePaletteEntryNV</type> <name>shadingRate</name></member>
+ <member><type>uint32_t</type> <name>sampleCount</name></member>
+ <member><type>uint32_t</type> <name>sampleLocationCount</name></member>
+ <member len="sampleLocationCount">const <type>VkCoarseSampleLocationNV</type>* <name>pSampleLocations</name></member>
+ </type>
+ <type category="struct" name="VkPipelineViewportCoarseSampleOrderStateCreateInfoNV" structextends="VkPipelineViewportStateCreateInfo">
+ <member values="VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_COARSE_SAMPLE_ORDER_STATE_CREATE_INFO_NV"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member><type>VkCoarseSampleOrderTypeNV</type> <name>sampleOrderType</name></member>
+ <member optional="true"><type>uint32_t</type> <name>customSampleOrderCount</name></member>
+ <member len="customSampleOrderCount">const <type>VkCoarseSampleOrderCustomNV</type>* <name>pCustomSampleOrders</name></member>
+ </type>
+ <type category="struct" name="VkPhysicalDeviceMeshShaderFeaturesNV" structextends="VkPhysicalDeviceFeatures2,VkDeviceCreateInfo">
+ <member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MESH_SHADER_FEATURES_NV"><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>
+ </type>
+ <type category="struct" name="VkPhysicalDeviceMeshShaderPropertiesNV" returnedonly="true" structextends="VkPhysicalDeviceProperties2">
+ <member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MESH_SHADER_PROPERTIES_NV"><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>maxDrawMeshTasksCount</name></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>maxTaskTotalMemorySize</name></member>
+ <member limittype="max"><type>uint32_t</type> <name>maxTaskOutputCount</name></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>maxMeshTotalMemorySize</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>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>
+ </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="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>
+ <member><type>VkRayTracingShaderGroupTypeKHR</type> <name>type</name></member>
+ <member><type>uint32_t</type> <name>generalShader</name></member>
+ <member><type>uint32_t</type> <name>closestHitShader</name></member>
+ <member><type>uint32_t</type> <name>anyHitShader</name></member>
+ <member><type>uint32_t</type> <name>intersectionShader</name></member>
+ </type>
+ <type category="struct" name="VkRayTracingShaderGroupCreateInfoKHR">
+ <member values="VK_STRUCTURE_TYPE_RAY_TRACING_SHADER_GROUP_CREATE_INFO_KHR"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member><type>VkRayTracingShaderGroupTypeKHR</type> <name>type</name></member>
+ <member><type>uint32_t</type> <name>generalShader</name></member>
+ <member><type>uint32_t</type> <name>closestHitShader</name></member>
+ <member><type>uint32_t</type> <name>anyHitShader</name></member>
+ <member><type>uint32_t</type> <name>intersectionShader</name></member>
+ <member optional="true">const <type>void</type>* <name>pShaderGroupCaptureReplayHandle</name></member>
+ </type>
+ <type category="struct" name="VkRayTracingPipelineCreateInfoNV">
+ <member values="VK_STRUCTURE_TYPE_RAY_TRACING_PIPELINE_CREATE_INFO_NV"><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><type>uint32_t</type> <name>groupCount</name></member>
+ <member len="groupCount">const <type>VkRayTracingShaderGroupCreateInfoNV</type>* <name>pGroups</name></member>
+ <member><type>uint32_t</type> <name>maxRecursionDepth</name></member>
+ <member><type>VkPipelineLayout</type> <name>layout</name><comment>Interface layout of the pipeline</comment></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>
+ <type category="struct" name="VkRayTracingPipelineCreateInfoKHR">
+ <member values="VK_STRUCTURE_TYPE_RAY_TRACING_PIPELINE_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>VkPipelineCreateFlags</type> <name>flags</name><comment>Pipeline creation flags</comment></member>
+ <member optional="true"><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 optional="true"><type>uint32_t</type> <name>groupCount</name></member>
+ <member len="groupCount">const <type>VkRayTracingShaderGroupCreateInfoKHR</type>* <name>pGroups</name></member>
+ <member><type>uint32_t</type> <name>maxPipelineRayRecursionDepth</name></member>
+ <member optional="true">const <type>VkPipelineLibraryCreateInfoKHR</type>* <name>pLibraryInfo</name></member>
+ <member optional="true">const <type>VkRayTracingPipelineInterfaceCreateInfoKHR</type>* <name>pLibraryInterface</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 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>
+ <type category="struct" name="VkGeometryTrianglesNV">
+ <member values="VK_STRUCTURE_TYPE_GEOMETRY_TRIANGLES_NV"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member optional="true"><type>VkBuffer</type> <name>vertexData</name></member>
+ <member><type>VkDeviceSize</type> <name>vertexOffset</name></member>
+ <member><type>uint32_t</type> <name>vertexCount</name></member>
+ <member><type>VkDeviceSize</type> <name>vertexStride</name></member>
+ <member><type>VkFormat</type> <name>vertexFormat</name></member>
+ <member optional="true"><type>VkBuffer</type> <name>indexData</name></member>
+ <member><type>VkDeviceSize</type> <name>indexOffset</name></member>
+ <member><type>uint32_t</type> <name>indexCount</name></member>
+ <member><type>VkIndexType</type> <name>indexType</name></member>
+ <member optional="true"><type>VkBuffer</type> <name>transformData</name><comment>Optional reference to array of floats representing a 3x4 row major affine transformation matrix.</comment></member>
+ <member><type>VkDeviceSize</type> <name>transformOffset</name></member>
+ </type>
+ <type category="struct" name="VkGeometryAABBNV">
+ <member values="VK_STRUCTURE_TYPE_GEOMETRY_AABB_NV"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member optional="true"><type>VkBuffer</type> <name>aabbData</name></member>
+ <member><type>uint32_t</type> <name>numAABBs</name></member>
+ <member><type>uint32_t</type> <name>stride</name><comment>Stride in bytes between AABBs</comment></member>
+ <member><type>VkDeviceSize</type> <name>offset</name><comment>Offset in bytes of the first AABB in aabbData</comment></member>
+ </type>
+ <type category="struct" name="VkGeometryDataNV">
+ <member><type>VkGeometryTrianglesNV</type> <name>triangles</name></member>
+ <member><type>VkGeometryAABBNV</type> <name>aabbs</name></member>
+ </type>
+ <type category="struct" name="VkGeometryNV">
+ <member values="VK_STRUCTURE_TYPE_GEOMETRY_NV"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member><type>VkGeometryTypeKHR</type> <name>geometryType</name></member>
+ <member><type>VkGeometryDataNV</type> <name>geometry</name></member>
+ <member optional="true"><type>VkGeometryFlagsKHR</type> <name>flags</name></member>
+ </type>
+ <type category="struct" name="VkAccelerationStructureInfoNV">
+ <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>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>
+ </type>
+ <type category="struct" name="VkAccelerationStructureCreateInfoNV">
+ <member values="VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_CREATE_INFO_NV"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member><type>VkDeviceSize</type> <name>compactedSize</name></member>
+ <member><type>VkAccelerationStructureInfoNV</type> <name>info</name></member>
+ </type>
+ <type category="struct" name="VkBindAccelerationStructureMemoryInfoNV">
+ <member values="VK_STRUCTURE_TYPE_BIND_ACCELERATION_STRUCTURE_MEMORY_INFO_NV"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member><type>VkAccelerationStructureNV</type> <name>accelerationStructure</name></member>
+ <member><type>VkDeviceMemory</type> <name>memory</name></member>
+ <member><type>VkDeviceSize</type> <name>memoryOffset</name></member>
+ <member optional="true"><type>uint32_t</type> <name>deviceIndexCount</name></member>
+ <member len="deviceIndexCount">const <type>uint32_t</type>* <name>pDeviceIndices</name></member>
+ </type>
+ <type category="struct" name="VkWriteDescriptorSetAccelerationStructureKHR" structextends="VkWriteDescriptorSet">
+ <member values="VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_ACCELERATION_STRUCTURE_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>accelerationStructureCount</name></member>
+ <member optional="false,true" len="accelerationStructureCount">const <type>VkAccelerationStructureKHR</type>* <name>pAccelerationStructures</name></member>
+ </type>
+ <type category="struct" name="VkWriteDescriptorSetAccelerationStructureNV" structextends="VkWriteDescriptorSet">
+ <member values="VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_ACCELERATION_STRUCTURE_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>accelerationStructureCount</name></member>
+ <member optional="false,true" len="accelerationStructureCount">const <type>VkAccelerationStructureNV</type>* <name>pAccelerationStructures</name></member>
+ </type>
+ <type category="struct" name="VkAccelerationStructureMemoryRequirementsInfoNV">
+ <member values="VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_INFO_NV"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member><type>VkAccelerationStructureMemoryRequirementsTypeNV</type> <name>type</name></member>
+ <member><type>VkAccelerationStructureNV</type> <name>accelerationStructure</name></member>
+ </type>
+ <type category="struct" name="VkPhysicalDeviceAccelerationStructureFeaturesKHR" structextends="VkPhysicalDeviceFeatures2,VkDeviceCreateInfo">
+ <member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ACCELERATION_STRUCTURE_FEATURES_KHR"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true"><type>void</type>* <name>pNext</name></member>
+ <member><type>VkBool32</type> <name>accelerationStructure</name></member>
+ <member><type>VkBool32</type> <name>accelerationStructureCaptureReplay</name></member>
+ <member><type>VkBool32</type> <name>accelerationStructureIndirectBuild</name></member>
+ <member><type>VkBool32</type> <name>accelerationStructureHostCommands</name></member>
+ <member><type>VkBool32</type> <name>descriptorBindingAccelerationStructureUpdateAfterBind</name></member>
+ </type>
+ <type category="struct" name="VkPhysicalDeviceRayTracingPipelineFeaturesKHR" structextends="VkPhysicalDeviceFeatures2,VkDeviceCreateInfo">
+ <member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_FEATURES_KHR"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true"><type>void</type>* <name>pNext</name></member>
+ <member><type>VkBool32</type> <name>rayTracingPipeline</name></member>
+ <member><type>VkBool32</type> <name>rayTracingPipelineShaderGroupHandleCaptureReplay</name></member>
+ <member><type>VkBool32</type> <name>rayTracingPipelineShaderGroupHandleCaptureReplayMixed</name></member>
+ <member><type>VkBool32</type> <name>rayTracingPipelineTraceRaysIndirect</name></member>
+ <member><type>VkBool32</type> <name>rayTraversalPrimitiveCulling</name></member>
+ </type>
+ <type category="struct" name="VkPhysicalDeviceRayQueryFeaturesKHR" structextends="VkPhysicalDeviceFeatures2,VkDeviceCreateInfo">
+ <member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_QUERY_FEATURES_KHR"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true"><type>void</type>* <name>pNext</name></member>
+ <member><type>VkBool32</type> <name>rayQuery</name></member>
+ </type>
+ <type category="struct" name="VkPhysicalDeviceAccelerationStructurePropertiesKHR" returnedonly="true" structextends="VkPhysicalDeviceProperties2">
+ <member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ACCELERATION_STRUCTURE_PROPERTIES_KHR"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true"><type>void</type>* <name>pNext</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>maxPrimitiveCount</name></member>
+ <member limittype="max"><type>uint32_t</type> <name>maxPerStageDescriptorAccelerationStructures</name></member>
+ <member limittype="max"><type>uint32_t</type> <name>maxPerStageDescriptorUpdateAfterBindAccelerationStructures</name></member>
+ <member limittype="max"><type>uint32_t</type> <name>maxDescriptorSetAccelerationStructures</name></member>
+ <member limittype="max"><type>uint32_t</type> <name>maxDescriptorSetUpdateAfterBindAccelerationStructures</name></member>
+ <member limittype="min"><type>uint32_t</type> <name>minAccelerationStructureScratchOffsetAlignment</name></member>
+ </type>
+ <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="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="max"><type>uint32_t</type> <name>maxRayDispatchInvocationCount</name></member>
+ <member limittype="noauto"><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="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="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>
+ <member limittype="max"><type>uint32_t</type> <name>maxDescriptorSetAccelerationStructures</name></member>
+ </type>
+ <type category="struct" name="VkStridedDeviceAddressRegionKHR">
+ <member optional="true"><type>VkDeviceAddress</type> <name>deviceAddress</name></member>
+ <member><type>VkDeviceSize</type> <name>stride</name></member>
+ <member><type>VkDeviceSize</type> <name>size</name></member>
+ </type>
+ <type category="struct" name="VkTraceRaysIndirectCommandKHR">
+ <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="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>
+ </type>
+ <type category="struct" name="VkDrmFormatModifierPropertiesEXT" returnedonly="true">
+ <member><type>uint64_t</type> <name>drmFormatModifier</name></member>
+ <member><type>uint32_t</type> <name>drmFormatModifierPlaneCount</name></member>
+ <member><type>VkFormatFeatureFlags</type> <name>drmFormatModifierTilingFeatures</name></member>
+ </type>
+ <type category="struct" name="VkPhysicalDeviceImageDrmFormatModifierInfoEXT" structextends="VkPhysicalDeviceImageFormatInfo2">
+ <member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_DRM_FORMAT_MODIFIER_INFO_EXT"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member><type>uint64_t</type> <name>drmFormatModifier</name></member>
+ <member><type>VkSharingMode</type> <name>sharingMode</name></member>
+ <member optional="true"><type>uint32_t</type> <name>queueFamilyIndexCount</name></member>
+ <member noautovalidity="true" len="queueFamilyIndexCount">const <type>uint32_t</type>* <name>pQueueFamilyIndices</name></member>
+ </type>
+ <type category="struct" name="VkImageDrmFormatModifierListCreateInfoEXT" structextends="VkImageCreateInfo">
+ <member values="VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_LIST_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>drmFormatModifierCount</name></member>
+ <member len="drmFormatModifierCount">const <type>uint64_t</type>* <name>pDrmFormatModifiers</name></member>
+ </type>
+ <type category="struct" name="VkImageDrmFormatModifierExplicitCreateInfoEXT" structextends="VkImageCreateInfo">
+ <member values="VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_EXPLICIT_CREATE_INFO_EXT"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member><type>uint64_t</type> <name>drmFormatModifier</name></member>
+ <member optional="false"><type>uint32_t</type> <name>drmFormatModifierPlaneCount</name></member>
+ <member len="drmFormatModifierPlaneCount">const <type>VkSubresourceLayout</type>* <name>pPlaneLayouts</name></member>
+ </type>
+ <type category="struct" name="VkImageDrmFormatModifierPropertiesEXT" returnedonly="true">
+ <member values="VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_PROPERTIES_EXT"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true"><type>void</type>* <name>pNext</name></member>
+ <member><type>uint64_t</type> <name>drmFormatModifier</name></member>
+ </type>
+ <type category="struct" name="VkImageStencilUsageCreateInfo" structextends="VkImageCreateInfo,VkPhysicalDeviceImageFormatInfo2">
+ <member values="VK_STRUCTURE_TYPE_IMAGE_STENCIL_USAGE_CREATE_INFO"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member><type>VkImageUsageFlags</type> <name>stencilUsage</name></member>
+ </type>
+ <type category="struct" name="VkImageStencilUsageCreateInfoEXT" alias="VkImageStencilUsageCreateInfo"/>
+ <type category="struct" name="VkDeviceMemoryOverallocationCreateInfoAMD" structextends="VkDeviceCreateInfo">
+ <member values="VK_STRUCTURE_TYPE_DEVICE_MEMORY_OVERALLOCATION_CREATE_INFO_AMD"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member><type>VkMemoryOverallocationBehaviorAMD</type> <name>overallocationBehavior</name></member>
+ </type>
+ <type category="struct" name="VkPhysicalDeviceFragmentDensityMapFeaturesEXT" structextends="VkPhysicalDeviceFeatures2,VkDeviceCreateInfo">
+ <member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_DENSITY_MAP_FEATURES_EXT"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true"><type>void</type>* <name>pNext</name></member>
+ <member><type>VkBool32</type> <name>fragmentDensityMap</name></member>
+ <member><type>VkBool32</type> <name>fragmentDensityMapDynamic</name></member>
+ <member><type>VkBool32</type> <name>fragmentDensityMapNonSubsampledImages</name></member>
+ </type>
+ <type category="struct" name="VkPhysicalDeviceFragmentDensityMap2FeaturesEXT" structextends="VkPhysicalDeviceFeatures2,VkDeviceCreateInfo">
+ <member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_DENSITY_MAP_2_FEATURES_EXT"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true"><type>void</type>* <name>pNext</name></member>
+ <member><type>VkBool32</type> <name>fragmentDensityMapDeferred</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>
+ </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="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="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="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>
+ <member><type>VkBool32</type> <name>scalarBlockLayout</name></member>
+ </type>
+ <type category="struct" name="VkPhysicalDeviceScalarBlockLayoutFeaturesEXT" alias="VkPhysicalDeviceScalarBlockLayoutFeatures"/>
+ <type category="struct" name="VkSurfaceProtectedCapabilitiesKHR" structextends="VkSurfaceCapabilities2KHR">
+ <member values="VK_STRUCTURE_TYPE_SURFACE_PROTECTED_CAPABILITIES_KHR"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member><type>VkBool32</type> <name>supportsProtected</name><comment>Represents if surface can be protected</comment></member>
+ </type>
+ <type category="struct" name="VkPhysicalDeviceUniformBufferStandardLayoutFeatures" structextends="VkPhysicalDeviceFeatures2,VkDeviceCreateInfo">
+ <member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_UNIFORM_BUFFER_STANDARD_LAYOUT_FEATURES"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true"><type>void</type>* <name>pNext</name></member>
+ <member><type>VkBool32</type> <name>uniformBufferStandardLayout</name></member>
+ </type>
+ <type category="struct" name="VkPhysicalDeviceUniformBufferStandardLayoutFeaturesKHR" alias="VkPhysicalDeviceUniformBufferStandardLayoutFeatures"/>
+ <type category="struct" name="VkPhysicalDeviceDepthClipEnableFeaturesEXT" structextends="VkPhysicalDeviceFeatures2,VkDeviceCreateInfo">
+ <member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEPTH_CLIP_ENABLE_FEATURES_EXT"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true"><type>void</type>* <name>pNext</name></member>
+ <member><type>VkBool32</type> <name>depthClipEnable</name></member>
+ </type>
+ <type category="struct" name="VkPipelineRasterizationDepthClipStateCreateInfoEXT" structextends="VkPipelineRasterizationStateCreateInfo">
+ <member values="VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_DEPTH_CLIP_STATE_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>VkPipelineRasterizationDepthClipStateCreateFlagsEXT</type> <name>flags</name><comment>Reserved</comment></member>
+ <member><type>VkBool32</type> <name>depthClipEnable</name></member>
+ </type>
+ <type category="struct" name="VkPhysicalDeviceMemoryBudgetPropertiesEXT" structextends="VkPhysicalDeviceMemoryProperties2" returnedonly="true">
+ <member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_BUDGET_PROPERTIES_EXT"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true"><type>void</type>* <name>pNext</name></member>
+ <member><type>VkDeviceSize</type> <name>heapBudget</name>[<enum>VK_MAX_MEMORY_HEAPS</enum>]</member>
+ <member><type>VkDeviceSize</type> <name>heapUsage</name>[<enum>VK_MAX_MEMORY_HEAPS</enum>]</member>
+ </type>
+ <type category="struct" name="VkPhysicalDeviceMemoryPriorityFeaturesEXT" structextends="VkPhysicalDeviceFeatures2,VkDeviceCreateInfo">
+ <member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_PRIORITY_FEATURES_EXT"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true"><type>void</type>* <name>pNext</name></member>
+ <member><type>VkBool32</type> <name>memoryPriority</name></member>
+ </type>
+ <type category="struct" name="VkMemoryPriorityAllocateInfoEXT" structextends="VkMemoryAllocateInfo">
+ <member values="VK_STRUCTURE_TYPE_MEMORY_PRIORITY_ALLOCATE_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>priority</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>
+ <member><type>VkBool32</type> <name>bufferDeviceAddress</name></member>
+ <member><type>VkBool32</type> <name>bufferDeviceAddressCaptureReplay</name></member>
+ <member><type>VkBool32</type> <name>bufferDeviceAddressMultiDevice</name></member>
+ </type>
+ <type category="struct" name="VkPhysicalDeviceBufferDeviceAddressFeaturesKHR" alias="VkPhysicalDeviceBufferDeviceAddressFeatures"/>
+ <type category="struct" name="VkPhysicalDeviceBufferDeviceAddressFeaturesEXT" structextends="VkPhysicalDeviceFeatures2,VkDeviceCreateInfo">
+ <member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BUFFER_DEVICE_ADDRESS_FEATURES_EXT"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true"><type>void</type>* <name>pNext</name></member>
+ <member><type>VkBool32</type> <name>bufferDeviceAddress</name></member>
+ <member><type>VkBool32</type> <name>bufferDeviceAddressCaptureReplay</name></member>
+ <member><type>VkBool32</type> <name>bufferDeviceAddressMultiDevice</name></member>
+ </type>
+ <type category="struct" name="VkPhysicalDeviceBufferAddressFeaturesEXT" alias="VkPhysicalDeviceBufferDeviceAddressFeaturesEXT"/>
+ <type category="struct" name="VkBufferDeviceAddressInfo">
+ <member values="VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO"><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="VkBufferDeviceAddressInfoKHR" alias="VkBufferDeviceAddressInfo"/>
+ <type category="struct" name="VkBufferDeviceAddressInfoEXT" alias="VkBufferDeviceAddressInfo"/>
+ <type category="struct" name="VkBufferOpaqueCaptureAddressCreateInfo" structextends="VkBufferCreateInfo">
+ <member values="VK_STRUCTURE_TYPE_BUFFER_OPAQUE_CAPTURE_ADDRESS_CREATE_INFO"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member><type>uint64_t</type> <name>opaqueCaptureAddress</name></member>
+ </type>
+ <type category="struct" name="VkBufferOpaqueCaptureAddressCreateInfoKHR" alias="VkBufferOpaqueCaptureAddressCreateInfo"/>
+ <type category="struct" name="VkBufferDeviceAddressCreateInfoEXT" structextends="VkBufferCreateInfo">
+ <member values="VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_CREATE_INFO_EXT"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member><type>VkDeviceAddress</type> <name>deviceAddress</name></member>
+ </type>
+ <type category="struct" name="VkPhysicalDeviceImageViewImageFormatInfoEXT" structextends="VkPhysicalDeviceImageFormatInfo2">
+ <member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_VIEW_IMAGE_FORMAT_INFO_EXT"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true"><type>void</type>* <name>pNext</name></member>
+ <member><type>VkImageViewType</type> <name>imageViewType</name></member>
+ </type>
+ <type category="struct" name="VkFilterCubicImageViewImageFormatPropertiesEXT" returnedonly="true" structextends="VkImageFormatProperties2">
+ <member values="VK_STRUCTURE_TYPE_FILTER_CUBIC_IMAGE_VIEW_IMAGE_FORMAT_PROPERTIES_EXT"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true"><type>void</type>* <name>pNext</name></member>
+ <member><type>VkBool32</type> <name>filterCubic</name><comment>The combinations of format, image type (and image view type if provided) can be filtered with VK_FILTER_CUBIC_EXT</comment></member>
+ <member><type>VkBool32</type> <name>filterCubicMinmax</name><comment>The combination of format, image type (and image view type if provided) can be filtered with VK_FILTER_CUBIC_EXT and ReductionMode of Min or Max</comment></member>
+ </type>
+ <type category="struct" name="VkPhysicalDeviceImagelessFramebufferFeatures" structextends="VkPhysicalDeviceFeatures2,VkDeviceCreateInfo">
+ <member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGELESS_FRAMEBUFFER_FEATURES"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true"><type>void</type>* <name>pNext</name></member>
+ <member><type>VkBool32</type> <name>imagelessFramebuffer</name></member>
+ </type>
+ <type category="struct" name="VkPhysicalDeviceImagelessFramebufferFeaturesKHR" alias="VkPhysicalDeviceImagelessFramebufferFeatures"/>
+ <type category="struct" name="VkFramebufferAttachmentsCreateInfo" structextends="VkFramebufferCreateInfo">
+ <member values="VK_STRUCTURE_TYPE_FRAMEBUFFER_ATTACHMENTS_CREATE_INFO"><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>attachmentImageInfoCount</name></member>
+ <member len="attachmentImageInfoCount">const <type>VkFramebufferAttachmentImageInfo</type>* <name>pAttachmentImageInfos</name></member>
+ </type>
+ <type category="struct" name="VkFramebufferAttachmentsCreateInfoKHR" alias="VkFramebufferAttachmentsCreateInfo"/>
+ <type category="struct" name="VkFramebufferAttachmentImageInfo">
+ <member values="VK_STRUCTURE_TYPE_FRAMEBUFFER_ATTACHMENT_IMAGE_INFO"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member optional="true"><type>VkImageCreateFlags</type> <name>flags</name><comment>Image creation flags</comment></member>
+ <member><type>VkImageUsageFlags</type> <name>usage</name><comment>Image usage flags</comment></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>layerCount</name></member>
+ <member optional="true"><type>uint32_t</type> <name>viewFormatCount</name></member>
+ <member len="viewFormatCount">const <type>VkFormat</type>* <name>pViewFormats</name></member>
+ </type>
+ <type category="struct" name="VkFramebufferAttachmentImageInfoKHR" alias="VkFramebufferAttachmentImageInfo"/>
+ <type category="struct" name="VkRenderPassAttachmentBeginInfo" structextends="VkRenderPassBeginInfo">
+ <member values="VK_STRUCTURE_TYPE_RENDER_PASS_ATTACHMENT_BEGIN_INFO"><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>attachmentCount</name></member>
+ <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>
+ <member><type>VkBool32</type> <name>textureCompressionASTC_HDR</name></member>
+ </type>
+ <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>
+ <member><type>VkBool32</type> <name>cooperativeMatrix</name></member>
+ <member><type>VkBool32</type> <name>cooperativeMatrixRobustBufferAccess</name></member>
+ </type>
+ <type category="struct" name="VkPhysicalDeviceCooperativeMatrixPropertiesNV" returnedonly="true" structextends="VkPhysicalDeviceProperties2">
+ <member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COOPERATIVE_MATRIX_PROPERTIES_NV"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true"><type>void</type>* <name>pNext</name></member>
+ <member limittype="bitmask"><type>VkShaderStageFlags</type> <name>cooperativeMatrixSupportedStages</name></member>
+ </type>
+ <type category="struct" name="VkCooperativeMatrixPropertiesNV">
+ <member values="VK_STRUCTURE_TYPE_COOPERATIVE_MATRIX_PROPERTIES_NV"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true"><type>void</type>* <name>pNext</name></member>
+ <member><type>uint32_t</type> <name>MSize</name></member>
+ <member><type>uint32_t</type> <name>NSize</name></member>
+ <member><type>uint32_t</type> <name>KSize</name></member>
+ <member><type>VkComponentTypeNV</type> <name>AType</name></member>
+ <member><type>VkComponentTypeNV</type> <name>BType</name></member>
+ <member><type>VkComponentTypeNV</type> <name>CType</name></member>
+ <member><type>VkComponentTypeNV</type> <name>DType</name></member>
+ <member><type>VkScopeNV</type> <name>scope</name></member>
+ </type>
+ <type category="struct" name="VkPhysicalDeviceYcbcrImageArraysFeaturesEXT" structextends="VkPhysicalDeviceFeatures2,VkDeviceCreateInfo">
+ <member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_YCBCR_IMAGE_ARRAYS_FEATURES_EXT"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true"><type>void</type>* <name>pNext</name></member>
+ <member><type>VkBool32</type> <name>ycbcrImageArrays</name></member>
+ </type>
+ <type category="struct" name="VkImageViewHandleInfoNVX">
+ <member values="VK_STRUCTURE_TYPE_IMAGE_VIEW_HANDLE_INFO_NVX"><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>VkDescriptorType</type> <name>descriptorType</name></member>
+ <member optional="true"><type>VkSampler</type> <name>sampler</name></member>
+ </type>
+ <type category="struct" name="VkImageViewAddressPropertiesNVX" returnedonly="true">
+ <member values="VK_STRUCTURE_TYPE_IMAGE_VIEW_ADDRESS_PROPERTIES_NVX"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true"><type>void</type>* <name>pNext</name></member>
+ <member><type>VkDeviceAddress</type> <name>deviceAddress</name></member>
+ <member><type>VkDeviceSize</type> <name>size</name></member>
+ </type>
+ <type category="struct" name="VkPresentFrameTokenGGP" structextends="VkPresentInfoKHR">
+ <member values="VK_STRUCTURE_TYPE_PRESENT_FRAME_TOKEN_GGP"><type>VkStructureType</type> <name>sType</name></member>
+ <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>
+ <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>
+ <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>
+ <member><type>VkFullScreenExclusiveEXT</type> <name>fullScreenExclusive</name></member>
+ </type>
+ <type category="struct" name="VkSurfaceFullScreenExclusiveWin32InfoEXT" structextends="VkPhysicalDeviceSurfaceInfo2KHR,VkSwapchainCreateInfoKHR">
+ <member values="VK_STRUCTURE_TYPE_SURFACE_FULL_SCREEN_EXCLUSIVE_WIN32_INFO_EXT"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member><type>HMONITOR</type> <name>hmonitor</name></member>
+ </type>
+ <type category="struct" name="VkSurfaceCapabilitiesFullScreenExclusiveEXT" structextends="VkSurfaceCapabilities2KHR">
+ <member values="VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES_FULL_SCREEN_EXCLUSIVE_EXT"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true"><type>void</type>* <name>pNext</name></member>
+ <member><type>VkBool32</type> <name>fullScreenExclusiveSupported</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>
+ <member><type>VkBool32</type> <name>performanceCounterQueryPools</name><comment>performance counters supported in query pools</comment></member>
+ <member><type>VkBool32</type> <name>performanceCounterMultipleQueryPools</name><comment>performance counters from multiple query pools can be accessed in the same primary command buffer</comment></member>
+ </type>
+ <type category="struct" name="VkPhysicalDevicePerformanceQueryPropertiesKHR" returnedonly="true" structextends="VkPhysicalDeviceProperties2">
+ <member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PERFORMANCE_QUERY_PROPERTIES_KHR"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true"><type>void</type>* <name>pNext</name></member>
+ <member limittype="bitmask" noautovalidity="true"><type>VkBool32</type> <name>allowCommandBufferQueryCopies</name><comment>Flag to specify whether performance queries are allowed to be used in vkCmdCopyQueryPoolResults</comment></member>
+ </type>
+ <type category="struct" name="VkPerformanceCounterKHR" returnedonly="true">
+ <member values="VK_STRUCTURE_TYPE_PERFORMANCE_COUNTER_KHR"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true"><type>void</type>* <name>pNext</name></member>
+ <member><type>VkPerformanceCounterUnitKHR</type> <name>unit</name></member>
+ <member><type>VkPerformanceCounterScopeKHR</type> <name>scope</name></member>
+ <member><type>VkPerformanceCounterStorageKHR</type> <name>storage</name></member>
+ <member><type>uint8_t</type> <name>uuid</name>[<enum>VK_UUID_SIZE</enum>]</member>
+ </type>
+ <type category="struct" name="VkPerformanceCounterDescriptionKHR" returnedonly="true">
+ <member values="VK_STRUCTURE_TYPE_PERFORMANCE_COUNTER_DESCRIPTION_KHR"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true"><type>void</type>* <name>pNext</name></member>
+ <member optional="true"><type>VkPerformanceCounterDescriptionFlagsKHR</type> <name>flags</name></member>
+ <member><type>char</type> <name>name</name>[<enum>VK_MAX_DESCRIPTION_SIZE</enum>]</member>
+ <member><type>char</type> <name>category</name>[<enum>VK_MAX_DESCRIPTION_SIZE</enum>]</member>
+ <member><type>char</type> <name>description</name>[<enum>VK_MAX_DESCRIPTION_SIZE</enum>]</member>
+ </type>
+ <type category="struct" name="VkQueryPoolPerformanceCreateInfoKHR" structextends="VkQueryPoolCreateInfo">
+ <member values="VK_STRUCTURE_TYPE_QUERY_POOL_PERFORMANCE_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><type>uint32_t</type> <name>counterIndexCount</name></member>
+ <member len="counterIndexCount">const <type>uint32_t</type>* <name>pCounterIndices</name></member>
+ </type>
+ <type category="union" name="VkPerformanceCounterResultKHR" comment="// Union of all the possible return types a counter result could return">
+ <member><type>int32_t</type> <name>int32</name></member>
+ <member><type>int64_t</type> <name>int64</name></member>
+ <member><type>uint32_t</type> <name>uint32</name></member>
+ <member><type>uint64_t</type> <name>uint64</name></member>
+ <member><type>float</type> <name>float32</name></member>
+ <member><type>double</type> <name>float64</name></member>
+ </type>
+ <type category="struct" name="VkAcquireProfilingLockInfoKHR">
+ <member values="VK_STRUCTURE_TYPE_ACQUIRE_PROFILING_LOCK_INFO_KHR"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <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">
+ <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>
+ </type>
+ <type category="struct" name="VkHeadlessSurfaceCreateInfoEXT">
+ <member values="VK_STRUCTURE_TYPE_HEADLESS_SURFACE_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>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 optional="true"><type>void</type>* <name>pNext</name></member>
+ <member><type>VkBool32</type> <name>coverageReductionMode</name></member>
+ </type>
+ <type category="struct" name="VkPipelineCoverageReductionStateCreateInfoNV" structextends="VkPipelineMultisampleStateCreateInfo">
+ <member values="VK_STRUCTURE_TYPE_PIPELINE_COVERAGE_REDUCTION_STATE_CREATE_INFO_NV"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member optional="true"><type>VkPipelineCoverageReductionStateCreateFlagsNV</type> <name>flags</name></member>
+ <member><type>VkCoverageReductionModeNV</type> <name>coverageReductionMode</name></member>
+ </type>
+ <type category="struct" name="VkFramebufferMixedSamplesCombinationNV" returnedonly="true">
+ <member values="VK_STRUCTURE_TYPE_FRAMEBUFFER_MIXED_SAMPLES_COMBINATION_NV"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true"><type>void</type>* <name>pNext</name></member>
+ <member><type>VkCoverageReductionModeNV</type> <name>coverageReductionMode</name></member>
+ <member><type>VkSampleCountFlagBits</type> <name>rasterizationSamples</name></member>
+ <member><type>VkSampleCountFlags</type> <name>depthStencilSamples</name></member>
+ <member><type>VkSampleCountFlags</type> <name>colorSamples</name></member>
+ </type>
+ <type category="struct" name="VkPhysicalDeviceShaderIntegerFunctions2FeaturesINTEL" structextends="VkPhysicalDeviceFeatures2,VkDeviceCreateInfo">
+ <member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_INTEGER_FUNCTIONS_2_FEATURES_INTEL"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true"><type>void</type>* <name>pNext</name></member>
+ <member><type>VkBool32</type> <name>shaderIntegerFunctions2</name></member>
+ </type>
+ <type category="union" name="VkPerformanceValueDataINTEL">
+ <member selection="VK_PERFORMANCE_VALUE_TYPE_UINT32_INTEL"><type>uint32_t</type> <name>value32</name></member>
+ <member selection="VK_PERFORMANCE_VALUE_TYPE_UINT64_INTEL"><type>uint64_t</type> <name>value64</name></member>
+ <member selection="VK_PERFORMANCE_VALUE_TYPE_FLOAT_INTEL"><type>float</type> <name>valueFloat</name></member>
+ <member selection="VK_PERFORMANCE_VALUE_TYPE_BOOL_INTEL"><type>VkBool32</type> <name>valueBool</name></member>
+ <member selection="VK_PERFORMANCE_VALUE_TYPE_STRING_INTEL" len="null-terminated">const <type>char</type>* <name>valueString</name></member>
+ </type>
+ <type category="struct" name="VkPerformanceValueINTEL">
+ <member><type>VkPerformanceValueTypeINTEL</type> <name>type</name></member>
+ <member selector="type" noautovalidity="true"><type>VkPerformanceValueDataINTEL</type> <name>data</name></member>
+ </type>
+ <type category="struct" name="VkInitializePerformanceApiInfoINTEL" >
+ <member values="VK_STRUCTURE_TYPE_INITIALIZE_PERFORMANCE_API_INFO_INTEL"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member optional="true"><type>void</type>* <name>pUserData</name></member>
+ </type>
+ <type category="struct" name="VkQueryPoolPerformanceQueryCreateInfoINTEL" structextends="VkQueryPoolCreateInfo">
+ <member values="VK_STRUCTURE_TYPE_QUERY_POOL_PERFORMANCE_QUERY_CREATE_INFO_INTEL"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member><type>VkQueryPoolSamplingModeINTEL</type> <name>performanceCountersSampling</name></member>
+ </type>
+ <type category="struct" name="VkQueryPoolCreateInfoINTEL" alias="VkQueryPoolPerformanceQueryCreateInfoINTEL"/>
+ <type category="struct" name="VkPerformanceMarkerInfoINTEL">
+ <member values="VK_STRUCTURE_TYPE_PERFORMANCE_MARKER_INFO_INTEL"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member><type>uint64_t</type> <name>marker</name></member>
+ </type>
+ <type category="struct" name="VkPerformanceStreamMarkerInfoINTEL">
+ <member values="VK_STRUCTURE_TYPE_PERFORMANCE_STREAM_MARKER_INFO_INTEL"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member><type>uint32_t</type> <name>marker</name></member>
+ </type>
+ <type category="struct" name="VkPerformanceOverrideInfoINTEL">
+ <member values="VK_STRUCTURE_TYPE_PERFORMANCE_OVERRIDE_INFO_INTEL"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member><type>VkPerformanceOverrideTypeINTEL</type> <name>type</name></member>
+ <member><type>VkBool32</type> <name>enable</name></member>
+ <member><type>uint64_t</type> <name>parameter</name></member>
+ </type>
+ <type category="struct" name="VkPerformanceConfigurationAcquireInfoINTEL">
+ <member values="VK_STRUCTURE_TYPE_PERFORMANCE_CONFIGURATION_ACQUIRE_INFO_INTEL"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member><type>VkPerformanceConfigurationTypeINTEL</type> <name>type</name></member>
+ </type>
+ <type category="struct" name="VkPhysicalDeviceShaderClockFeaturesKHR" structextends="VkPhysicalDeviceFeatures2,VkDeviceCreateInfo">
+ <member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_CLOCK_FEATURES_KHR"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true"><type>void</type>* <name>pNext</name></member>
+ <member><type>VkBool32</type> <name>shaderSubgroupClock</name></member>
+ <member><type>VkBool32</type> <name>shaderDeviceClock</name></member>
+ </type>
+ <type category="struct" name="VkPhysicalDeviceIndexTypeUint8FeaturesEXT" structextends="VkPhysicalDeviceFeatures2,VkDeviceCreateInfo">
+ <member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INDEX_TYPE_UINT8_FEATURES_EXT"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true"><type>void</type>* <name>pNext</name></member>
+ <member><type>VkBool32</type> <name>indexTypeUint8</name></member>
+ </type>
+ <type category="struct" name="VkPhysicalDeviceShaderSMBuiltinsPropertiesNV" returnedonly="true" structextends="VkPhysicalDeviceProperties2">
+ <member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_SM_BUILTINS_PROPERTIES_NV"><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>shaderSMCount</name></member>
+ <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 optional="true"><type>void</type>* <name>pNext</name></member>
+ <member><type>VkBool32</type> <name>shaderSMBuiltins</name></member>
+ </type>
+ <type category="struct" name="VkPhysicalDeviceFragmentShaderInterlockFeaturesEXT" structextends="VkPhysicalDeviceFeatures2,VkDeviceCreateInfo">
+ <member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADER_INTERLOCK_FEATURES_EXT"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true"><type>void</type>* <name>pNext</name><comment>Pointer to next structure</comment></member>
+ <member><type>VkBool32</type> <name>fragmentShaderSampleInterlock</name></member>
+ <member><type>VkBool32</type> <name>fragmentShaderPixelInterlock</name></member>
+ <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 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 optional="true"><type>void</type>* <name>pNext</name></member>
+ <member><type>VkImageLayout</type> <name>stencilLayout</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 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>
+ </type>
+ <type category="struct" name="VkAttachmentDescriptionStencilLayoutKHR" alias="VkAttachmentDescriptionStencilLayout"/>
+ <type category="struct" name="VkPhysicalDevicePipelineExecutablePropertiesFeaturesKHR" structextends="VkPhysicalDeviceFeatures2,VkDeviceCreateInfo">
+ <member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PIPELINE_EXECUTABLE_PROPERTIES_FEATURES_KHR"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true"><type>void</type>* <name>pNext</name></member>
+ <member><type>VkBool32</type> <name>pipelineExecutableInfo</name></member>
+ </type>
+ <type category="struct" name="VkPipelineInfoKHR">
+ <member values="VK_STRUCTURE_TYPE_PIPELINE_INFO_KHR"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member><type>VkPipeline</type> <name>pipeline</name></member>
+ </type>
+ <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>
+ <member><type>VkShaderStageFlags</type> <name>stages</name></member>
+ <member><type>char</type> <name>name</name>[<enum>VK_MAX_DESCRIPTION_SIZE</enum>]</member>
+ <member><type>char</type> <name>description</name>[<enum>VK_MAX_DESCRIPTION_SIZE</enum>]</member>
+ <member><type>uint32_t</type> <name>subgroupSize</name></member>
+ </type>
+ <type category="struct" name="VkPipelineExecutableInfoKHR">
+ <member values="VK_STRUCTURE_TYPE_PIPELINE_EXECUTABLE_INFO_KHR"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member><type>VkPipeline</type> <name>pipeline</name></member>
+ <member><type>uint32_t</type> <name>executableIndex</name></member>
+ </type>
+ <type category="union" name="VkPipelineExecutableStatisticValueKHR" returnedonly="true">
+ <member selection="VK_PIPELINE_EXECUTABLE_STATISTIC_FORMAT_BOOL32_KHR"><type>VkBool32</type> <name>b32</name></member>
+ <member selection="VK_PIPELINE_EXECUTABLE_STATISTIC_FORMAT_INT64_KHR"><type>int64_t</type> <name>i64</name></member>
+ <member selection="VK_PIPELINE_EXECUTABLE_STATISTIC_FORMAT_UINT64_KHR"><type>uint64_t</type> <name>u64</name></member>
+ <member selection="VK_PIPELINE_EXECUTABLE_STATISTIC_FORMAT_FLOAT64_KHR"><type>double</type> <name>f64</name></member>
+ </type>
+ <type category="struct" name="VkPipelineExecutableStatisticKHR" returnedonly="true">
+ <member values="VK_STRUCTURE_TYPE_PIPELINE_EXECUTABLE_STATISTIC_KHR"><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_DESCRIPTION_SIZE</enum>]</member>
+ <member><type>char</type> <name>description</name>[<enum>VK_MAX_DESCRIPTION_SIZE</enum>]</member>
+ <member><type>VkPipelineExecutableStatisticFormatKHR</type> <name>format</name></member>
+ <member selector="format" noautovalidity="true"><type>VkPipelineExecutableStatisticValueKHR</type> <name>value</name></member>
+ </type>
+ <type category="struct" name="VkPipelineExecutableInternalRepresentationKHR" returnedonly="true">
+ <member values="VK_STRUCTURE_TYPE_PIPELINE_EXECUTABLE_INTERNAL_REPRESENTATION_KHR"><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_DESCRIPTION_SIZE</enum>]</member>
+ <member><type>char</type> <name>description</name>[<enum>VK_MAX_DESCRIPTION_SIZE</enum>]</member>
+ <member><type>VkBool32</type> <name>isText</name></member>
+ <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>
+ <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>
+ <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 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="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>
+ </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>
+ <member><type>uint32_t</type> <name>requiredSubgroupSize</name></member>
+ </type>
+ <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><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>
+ </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>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member><type>uint64_t</type> <name>opaqueCaptureAddress</name></member>
+ </type>
+ <type category="struct" name="VkMemoryOpaqueCaptureAddressAllocateInfoKHR" alias="VkMemoryOpaqueCaptureAddressAllocateInfo"/>
+ <type category="struct" name="VkDeviceMemoryOpaqueCaptureAddressInfo">
+ <member values="VK_STRUCTURE_TYPE_DEVICE_MEMORY_OPAQUE_CAPTURE_ADDRESS_INFO"><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>
+ </type>
+ <type category="struct" name="VkDeviceMemoryOpaqueCaptureAddressInfoKHR" alias="VkDeviceMemoryOpaqueCaptureAddressInfo"/>
+ <type category="struct" name="VkPhysicalDeviceLineRasterizationFeaturesEXT" structextends="VkPhysicalDeviceFeatures2,VkDeviceCreateInfo">
+ <member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LINE_RASTERIZATION_FEATURES_EXT"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true"><type>void</type>* <name>pNext</name></member>
+ <member><type>VkBool32</type> <name>rectangularLines</name></member>
+ <member><type>VkBool32</type> <name>bresenhamLines</name></member>
+ <member><type>VkBool32</type> <name>smoothLines</name></member>
+ <member><type>VkBool32</type> <name>stippledRectangularLines</name></member>
+ <member><type>VkBool32</type> <name>stippledBresenhamLines</name></member>
+ <member><type>VkBool32</type> <name>stippledSmoothLines</name></member>
+ </type>
+ <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>
+ </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>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member><type>VkLineRasterizationModeEXT</type> <name>lineRasterizationMode</name></member>
+ <member><type>VkBool32</type> <name>stippledLineEnable</name></member>
+ <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>
+ <member optional="true"><type>void</type>* <name>pNext</name></member>
+ <member><type>VkBool32</type> <name>pipelineCreationCacheControl</name></member>
+ </type>
+ <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 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>
+ <member><type>VkBool32</type> <name>storagePushConstant16</name><comment>16-bit integer/floating-point variables supported in PushConstant</comment></member>
+ <member><type>VkBool32</type> <name>storageInputOutput16</name><comment>16-bit integer/floating-point variables supported in shader inputs and outputs</comment></member>
+ <member><type>VkBool32</type> <name>multiview</name><comment>Multiple views in a renderpass</comment></member>
+ <member><type>VkBool32</type> <name>multiviewGeometryShader</name><comment>Multiple views in a renderpass w/ geometry shader</comment></member>
+ <member><type>VkBool32</type> <name>multiviewTessellationShader</name><comment>Multiple views in a renderpass w/ tessellation shader</comment></member>
+ <member><type>VkBool32</type> <name>variablePointersStorageBuffer</name></member>
+ <member><type>VkBool32</type> <name>variablePointers</name></member>
+ <member><type>VkBool32</type> <name>protectedMemory</name></member>
+ <member><type>VkBool32</type> <name>samplerYcbcrConversion</name><comment>Sampler color conversion supported</comment></member>
+ <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 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="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="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="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 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>
+ <member><type>VkBool32</type> <name>storageBuffer8BitAccess</name><comment>8-bit integer variables supported in StorageBuffer</comment></member>
+ <member><type>VkBool32</type> <name>uniformAndStorageBuffer8BitAccess</name><comment>8-bit integer variables supported in StorageBuffer and Uniform</comment></member>
+ <member><type>VkBool32</type> <name>storagePushConstant8</name><comment>8-bit integer variables supported in PushConstant</comment></member>
+ <member><type>VkBool32</type> <name>shaderBufferInt64Atomics</name></member>
+ <member><type>VkBool32</type> <name>shaderSharedInt64Atomics</name></member>
+ <member><type>VkBool32</type> <name>shaderFloat16</name><comment>16-bit floats (halfs) in shaders</comment></member>
+ <member><type>VkBool32</type> <name>shaderInt8</name><comment>8-bit integers in shaders</comment></member>
+ <member><type>VkBool32</type> <name>descriptorIndexing</name></member>
+ <member><type>VkBool32</type> <name>shaderInputAttachmentArrayDynamicIndexing</name></member>
+ <member><type>VkBool32</type> <name>shaderUniformTexelBufferArrayDynamicIndexing</name></member>
+ <member><type>VkBool32</type> <name>shaderStorageTexelBufferArrayDynamicIndexing</name></member>
+ <member><type>VkBool32</type> <name>shaderUniformBufferArrayNonUniformIndexing</name></member>
+ <member><type>VkBool32</type> <name>shaderSampledImageArrayNonUniformIndexing</name></member>
+ <member><type>VkBool32</type> <name>shaderStorageBufferArrayNonUniformIndexing</name></member>
+ <member><type>VkBool32</type> <name>shaderStorageImageArrayNonUniformIndexing</name></member>
+ <member><type>VkBool32</type> <name>shaderInputAttachmentArrayNonUniformIndexing</name></member>
+ <member><type>VkBool32</type> <name>shaderUniformTexelBufferArrayNonUniformIndexing</name></member>
+ <member><type>VkBool32</type> <name>shaderStorageTexelBufferArrayNonUniformIndexing</name></member>
+ <member><type>VkBool32</type> <name>descriptorBindingUniformBufferUpdateAfterBind</name></member>
+ <member><type>VkBool32</type> <name>descriptorBindingSampledImageUpdateAfterBind</name></member>
+ <member><type>VkBool32</type> <name>descriptorBindingStorageImageUpdateAfterBind</name></member>
+ <member><type>VkBool32</type> <name>descriptorBindingStorageBufferUpdateAfterBind</name></member>
+ <member><type>VkBool32</type> <name>descriptorBindingUniformTexelBufferUpdateAfterBind</name></member>
+ <member><type>VkBool32</type> <name>descriptorBindingStorageTexelBufferUpdateAfterBind</name></member>
+ <member><type>VkBool32</type> <name>descriptorBindingUpdateUnusedWhilePending</name></member>
+ <member><type>VkBool32</type> <name>descriptorBindingPartiallyBound</name></member>
+ <member><type>VkBool32</type> <name>descriptorBindingVariableDescriptorCount</name></member>
+ <member><type>VkBool32</type> <name>runtimeDescriptorArray</name></member>
+ <member><type>VkBool32</type> <name>samplerFilterMinmax</name></member>
+ <member><type>VkBool32</type> <name>scalarBlockLayout</name></member>
+ <member><type>VkBool32</type> <name>imagelessFramebuffer</name></member>
+ <member><type>VkBool32</type> <name>uniformBufferStandardLayout</name></member>
+ <member><type>VkBool32</type> <name>shaderSubgroupExtendedTypes</name></member>
+ <member><type>VkBool32</type> <name>separateDepthStencilLayouts</name></member>
+ <member><type>VkBool32</type> <name>hostQueryReset</name></member>
+ <member><type>VkBool32</type> <name>timelineSemaphore</name></member>
+ <member><type>VkBool32</type> <name>bufferDeviceAddress</name></member>
+ <member><type>VkBool32</type> <name>bufferDeviceAddressCaptureReplay</name></member>
+ <member><type>VkBool32</type> <name>bufferDeviceAddressMultiDevice</name></member>
+ <member><type>VkBool32</type> <name>vulkanMemoryModel</name></member>
+ <member><type>VkBool32</type> <name>vulkanMemoryModelDeviceScope</name></member>
+ <member><type>VkBool32</type> <name>vulkanMemoryModelAvailabilityVisibilityChains</name></member>
+ <member><type>VkBool32</type> <name>shaderOutputViewportIndex</name></member>
+ <member><type>VkBool32</type> <name>shaderOutputLayer</name></member>
+ <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 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="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>
+ <member limittype="bitmask"><type>VkBool32</type> <name>shaderDenormPreserveFloat16</name><comment>An implementation can preserve denormals</comment></member>
+ <member limittype="bitmask"><type>VkBool32</type> <name>shaderDenormPreserveFloat32</name><comment>An implementation can preserve denormals</comment></member>
+ <member limittype="bitmask"><type>VkBool32</type> <name>shaderDenormPreserveFloat64</name><comment>An implementation can preserve denormals</comment></member>
+ <member limittype="bitmask"><type>VkBool32</type> <name>shaderDenormFlushToZeroFloat16</name><comment>An implementation can flush to zero denormals</comment></member>
+ <member limittype="bitmask"><type>VkBool32</type> <name>shaderDenormFlushToZeroFloat32</name><comment>An implementation can flush to zero denormals</comment></member>
+ <member limittype="bitmask"><type>VkBool32</type> <name>shaderDenormFlushToZeroFloat64</name><comment>An implementation can flush to zero denormals</comment></member>
+ <member limittype="bitmask"><type>VkBool32</type> <name>shaderRoundingModeRTEFloat16</name><comment>An implementation can support RTE</comment></member>
+ <member limittype="bitmask"><type>VkBool32</type> <name>shaderRoundingModeRTEFloat32</name><comment>An implementation can support RTE</comment></member>
+ <member limittype="bitmask"><type>VkBool32</type> <name>shaderRoundingModeRTEFloat64</name><comment>An implementation can support RTE</comment></member>
+ <member limittype="bitmask"><type>VkBool32</type> <name>shaderRoundingModeRTZFloat16</name><comment>An implementation can support RTZ</comment></member>
+ <member limittype="bitmask"><type>VkBool32</type> <name>shaderRoundingModeRTZFloat32</name><comment>An implementation can support RTZ</comment></member>
+ <member limittype="bitmask"><type>VkBool32</type> <name>shaderRoundingModeRTZFloat64</name><comment>An implementation can support RTZ</comment></member>
+ <member limittype="max"><type>uint32_t</type> <name>maxUpdateAfterBindDescriptorsInAllPools</name></member>
+ <member limittype="bitmask"><type>VkBool32</type> <name>shaderUniformBufferArrayNonUniformIndexingNative</name></member>
+ <member limittype="bitmask"><type>VkBool32</type> <name>shaderSampledImageArrayNonUniformIndexingNative</name></member>
+ <member limittype="bitmask"><type>VkBool32</type> <name>shaderStorageBufferArrayNonUniformIndexingNative</name></member>
+ <member limittype="bitmask"><type>VkBool32</type> <name>shaderStorageImageArrayNonUniformIndexingNative</name></member>
+ <member limittype="bitmask"><type>VkBool32</type> <name>shaderInputAttachmentArrayNonUniformIndexingNative</name></member>
+ <member limittype="bitmask"><type>VkBool32</type> <name>robustBufferAccessUpdateAfterBind</name></member>
+ <member limittype="bitmask"><type>VkBool32</type> <name>quadDivergentImplicitLod</name></member>
+ <member limittype="max"><type>uint32_t</type> <name>maxPerStageDescriptorUpdateAfterBindSamplers</name></member>
+ <member limittype="max"><type>uint32_t</type> <name>maxPerStageDescriptorUpdateAfterBindUniformBuffers</name></member>
+ <member limittype="max"><type>uint32_t</type> <name>maxPerStageDescriptorUpdateAfterBindStorageBuffers</name></member>
+ <member limittype="max"><type>uint32_t</type> <name>maxPerStageDescriptorUpdateAfterBindSampledImages</name></member>
+ <member limittype="max"><type>uint32_t</type> <name>maxPerStageDescriptorUpdateAfterBindStorageImages</name></member>
+ <member limittype="max"><type>uint32_t</type> <name>maxPerStageDescriptorUpdateAfterBindInputAttachments</name></member>
+ <member limittype="max"><type>uint32_t</type> <name>maxPerStageUpdateAfterBindResources</name></member>
+ <member limittype="max"><type>uint32_t</type> <name>maxDescriptorSetUpdateAfterBindSamplers</name></member>
+ <member limittype="max"><type>uint32_t</type> <name>maxDescriptorSetUpdateAfterBindUniformBuffers</name></member>
+ <member limittype="max"><type>uint32_t</type> <name>maxDescriptorSetUpdateAfterBindUniformBuffersDynamic</name></member>
+ <member limittype="max"><type>uint32_t</type> <name>maxDescriptorSetUpdateAfterBindStorageBuffers</name></member>
+ <member limittype="max"><type>uint32_t</type> <name>maxDescriptorSetUpdateAfterBindStorageBuffersDynamic</name></member>
+ <member limittype="max"><type>uint32_t</type> <name>maxDescriptorSetUpdateAfterBindSampledImages</name></member>
+ <member limittype="max"><type>uint32_t</type> <name>maxDescriptorSetUpdateAfterBindStorageImages</name></member>
+ <member limittype="max"><type>uint32_t</type> <name>maxDescriptorSetUpdateAfterBindInputAttachments</name></member>
+ <member limittype="bitmask"><type>VkResolveModeFlags</type> <name>supportedDepthResolveModes</name><comment>supported depth resolve modes</comment></member>
+ <member limittype="bitmask"><type>VkResolveModeFlags</type> <name>supportedStencilResolveModes</name><comment>supported stencil resolve modes</comment></member>
+ <member limittype="bitmask"><type>VkBool32</type> <name>independentResolveNone</name><comment>depth and stencil resolve modes can be set independently if one of them is none</comment></member>
+ <member limittype="bitmask"><type>VkBool32</type> <name>independentResolve</name><comment>depth and stencil resolve modes can be set independently</comment></member>
+ <member limittype="bitmask"><type>VkBool32</type> <name>filterMinmaxSingleComponentFormats</name></member>
+ <member limittype="bitmask"><type>VkBool32</type> <name>filterMinmaxImageComponentMapping</name></member>
+ <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="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>
+ <member optional="true"><type>VkPipelineCompilerControlFlagsAMD</type> <name>compilerControlFlags</name></member>
+ </type>
+ <type category="struct" name="VkPhysicalDeviceCoherentMemoryFeaturesAMD" structextends="VkPhysicalDeviceFeatures2,VkDeviceCreateInfo">
+ <member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COHERENT_MEMORY_FEATURES_AMD"><type>VkStructureType</type> <name>sType</name></member>
+ <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>
+ <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>
+ </type>
+ <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>
+ <member noautovalidity="true"><type>VkClearColorValue</type> <name>customBorderColor</name></member>
+ <member><type>VkFormat</type> <name>format</name></member>
+ </type>
+ <type category="struct" name="VkPhysicalDeviceCustomBorderColorPropertiesEXT" structextends="VkPhysicalDeviceProperties2" returnedonly="true">
+ <member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CUSTOM_BORDER_COLOR_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>maxCustomBorderColorSamplers</name></member>
+ </type>
+ <type category="struct" name="VkPhysicalDeviceCustomBorderColorFeaturesEXT" structextends="VkPhysicalDeviceFeatures2,VkDeviceCreateInfo">
+ <member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CUSTOM_BORDER_COLOR_FEATURES_EXT"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true"><type>void</type>* <name>pNext</name></member>
+ <member><type>VkBool32</type> <name>customBorderColors</name></member>
+ <member><type>VkBool32</type> <name>customBorderColorWithoutFormat</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>
+ </type>
+ <type category="union" name="VkDeviceOrHostAddressConstKHR">
+ <member noautovalidity="true"><type>VkDeviceAddress</type> <name>deviceAddress</name></member>
+ <member noautovalidity="true">const <type>void</type>* <name>hostAddress</name></member>
+ </type>
+ <type category="struct" name="VkAccelerationStructureGeometryTrianglesDataKHR">
+ <member values="VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_TRIANGLES_DATA_KHR"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member><type>VkFormat</type> <name>vertexFormat</name></member>
+ <member noautovalidity="true"><type>VkDeviceOrHostAddressConstKHR</type> <name>vertexData</name></member>
+ <member><type>VkDeviceSize</type> <name>vertexStride</name></member>
+ <member><type>uint32_t</type> <name>maxVertex</name></member>
+ <member><type>VkIndexType</type> <name>indexType</name></member>
+ <member noautovalidity="true"><type>VkDeviceOrHostAddressConstKHR</type> <name>indexData</name></member>
+ <member noautovalidity="true"><type>VkDeviceOrHostAddressConstKHR</type> <name>transformData</name></member>
+ </type>
+ <type category="struct" name="VkAccelerationStructureGeometryAabbsDataKHR">
+ <member values="VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_AABBS_DATA_KHR"><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>data</name></member>
+ <member><type>VkDeviceSize</type> <name>stride</name></member>
+ </type>
+ <type category="struct" name="VkAccelerationStructureGeometryInstancesDataKHR">
+ <member values="VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_INSTANCES_DATA_KHR"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member><type>VkBool32</type> <name>arrayOfPointers</name></member>
+ <member noautovalidity="true"><type>VkDeviceOrHostAddressConstKHR</type> <name>data</name></member>
+ </type>
+ <type category="union" name="VkAccelerationStructureGeometryDataKHR">
+ <member selection="VK_GEOMETRY_TYPE_TRIANGLES_KHR"><type>VkAccelerationStructureGeometryTrianglesDataKHR</type> <name>triangles</name></member>
+ <member selection="VK_GEOMETRY_TYPE_AABBS_KHR"><type>VkAccelerationStructureGeometryAabbsDataKHR</type> <name>aabbs</name></member>
+ <member selection="VK_GEOMETRY_TYPE_INSTANCES_KHR"><type>VkAccelerationStructureGeometryInstancesDataKHR</type> <name>instances</name></member>
+ </type>
+ <type category="struct" name="VkAccelerationStructureGeometryKHR">
+ <member values="VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_KHR"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member><type>VkGeometryTypeKHR</type> <name>geometryType</name></member>
+ <member selector="geometryType"><type>VkAccelerationStructureGeometryDataKHR</type> <name>geometry</name></member>
+ <member optional="true"><type>VkGeometryFlagsKHR</type> <name>flags</name></member>
+ </type>
+ <type category="struct" name="VkAccelerationStructureBuildGeometryInfoKHR">
+ <member values="VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_BUILD_GEOMETRY_INFO_KHR"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member><type>VkAccelerationStructureTypeKHR</type> <name>type</name></member>
+ <member optional="true"><type>VkBuildAccelerationStructureFlagsKHR</type> <name>flags</name></member>
+ <member noautovalidity="true"><type>VkBuildAccelerationStructureModeKHR</type> <name>mode</name></member>
+ <member optional="true" noautovalidity="true"><type>VkAccelerationStructureKHR</type> <name>srcAccelerationStructure</name></member>
+ <member optional="true" noautovalidity="true"><type>VkAccelerationStructureKHR</type> <name>dstAccelerationStructure</name></member>
+ <member optional="true"><type>uint32_t</type> <name>geometryCount</name></member>
+ <member len="geometryCount" optional="true">const <type>VkAccelerationStructureGeometryKHR</type>* <name>pGeometries</name></member>
+ <member len="geometryCount,1" optional="true,false">const <type>VkAccelerationStructureGeometryKHR</type>* const* <name>ppGeometries</name></member>
+ <member noautovalidity="true"><type>VkDeviceOrHostAddressKHR</type> <name>scratchData</name></member>
+ </type>
+ <type category="struct" name="VkAccelerationStructureBuildRangeInfoKHR">
+ <member><type>uint32_t</type> <name>primitiveCount</name></member>
+ <member><type>uint32_t</type> <name>primitiveOffset</name></member>
+ <member><type>uint32_t</type> <name>firstVertex</name></member>
+ <member><type>uint32_t</type> <name>transformOffset</name></member>
+ </type>
+ <type category="struct" name="VkAccelerationStructureCreateInfoKHR">
+ <member values="VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_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>VkAccelerationStructureCreateFlagsKHR</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>VkAccelerationStructureTypeKHR</type> <name>type</name></member>
+ <member optional="true"><type>VkDeviceAddress</type> <name>deviceAddress</name></member>
+ </type>
+ <type category="struct" name="VkAabbPositionsKHR">
+ <member><type>float</type> <name>minX</name></member>
+ <member><type>float</type> <name>minY</name></member>
+ <member><type>float</type> <name>minZ</name></member>
+ <member><type>float</type> <name>maxX</name></member>
+ <member><type>float</type> <name>maxY</name></member>
+ <member><type>float</type> <name>maxZ</name></member>
+ </type>
+ <type category="struct" name="VkAabbPositionsNV" alias="VkAabbPositionsKHR"/>
+ <type category="struct" name="VkTransformMatrixKHR">
+ <member><type>float</type> <name>matrix</name>[3][4]</member>
+ </type>
+ <type category="struct" name="VkTransformMatrixNV" alias="VkTransformMatrixKHR"/>
+ <type category="struct" name="VkAccelerationStructureInstanceKHR">
+ <comment>The bitfields in this structure are non-normative since bitfield ordering is implementation-defined in C. The specification defines the normative layout.</comment>
+ <member><type>VkTransformMatrixKHR</type> <name>transform</name></member>
+ <member><type>uint32_t</type> <name>instanceCustomIndex</name>:24</member>
+ <member><type>uint32_t</type> <name>mask</name>:8</member>
+ <member><type>uint32_t</type> <name>instanceShaderBindingTableRecordOffset</name>:24</member>
+ <member optional="true"><type>VkGeometryInstanceFlagsKHR</type> <name>flags</name>:8</member>
+ <member><type>uint64_t</type> <name>accelerationStructureReference</name></member>
+ </type>
+ <type category="struct" name="VkAccelerationStructureInstanceNV" alias="VkAccelerationStructureInstanceKHR"/>
+ <type category="struct" name="VkAccelerationStructureDeviceAddressInfoKHR">
+ <member values="VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_DEVICE_ADDRESS_INFO_KHR"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member><type>VkAccelerationStructureKHR</type> <name>accelerationStructure</name></member>
+ </type>
+ <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>
+ </type>
+ <type category="struct" name="VkCopyAccelerationStructureInfoKHR">
+ <member values="VK_STRUCTURE_TYPE_COPY_ACCELERATION_STRUCTURE_INFO_KHR"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member><type>VkAccelerationStructureKHR</type> <name>src</name></member>
+ <member><type>VkAccelerationStructureKHR</type> <name>dst</name></member>
+ <member><type>VkCopyAccelerationStructureModeKHR</type> <name>mode</name></member>
+ </type>
+ <type category="struct" name="VkCopyAccelerationStructureToMemoryInfoKHR">
+ <member values="VK_STRUCTURE_TYPE_COPY_ACCELERATION_STRUCTURE_TO_MEMORY_INFO_KHR"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member><type>VkAccelerationStructureKHR</type> <name>src</name></member>
+ <member noautovalidity="true"><type>VkDeviceOrHostAddressKHR</type> <name>dst</name></member>
+ <member><type>VkCopyAccelerationStructureModeKHR</type> <name>mode</name></member>
+ </type>
+ <type category="struct" name="VkCopyMemoryToAccelerationStructureInfoKHR">
+ <member values="VK_STRUCTURE_TYPE_COPY_MEMORY_TO_ACCELERATION_STRUCTURE_INFO_KHR"><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>VkAccelerationStructureKHR</type> <name>dst</name></member>
+ <member><type>VkCopyAccelerationStructureModeKHR</type> <name>mode</name></member>
+ </type>
+ <type category="struct" name="VkRayTracingPipelineInterfaceCreateInfoKHR">
+ <member values="VK_STRUCTURE_TYPE_RAY_TRACING_PIPELINE_INTERFACE_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>maxPipelineRayPayloadSize</name></member>
+ <member><type>uint32_t</type> <name>maxPipelineRayHitAttributeSize</name></member>
+ </type>
+ <type category="struct" name="VkPipelineLibraryCreateInfoKHR">
+ <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>
+ <member len="libraryCount">const <type>VkPipeline</type>* <name>pLibraries</name></member>
+ </type>
+ <type category="struct" name="VkPhysicalDeviceExtendedDynamicStateFeaturesEXT" structextends="VkPhysicalDeviceFeatures2,VkDeviceCreateInfo">
+ <member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTENDED_DYNAMIC_STATE_FEATURES_EXT"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true"><type>void</type>* <name>pNext</name></member>
+ <member><type>VkBool32</type> <name>extendedDynamicState</name></member>
+ </type>
+ <type category="struct" name="VkPhysicalDeviceExtendedDynamicState2FeaturesEXT" structextends="VkPhysicalDeviceFeatures2,VkDeviceCreateInfo">
+ <member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTENDED_DYNAMIC_STATE_2_FEATURES_EXT"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true"><type>void</type>* <name>pNext</name></member>
+ <member><type>VkBool32</type> <name>extendedDynamicState2</name></member>
+ <member><type>VkBool32</type> <name>extendedDynamicState2LogicOp</name></member>
+ <member><type>VkBool32</type> <name>extendedDynamicState2PatchControlPoints</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">
+ <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>
+ </type>
+ <type category="struct" name="VkCommandBufferInheritanceRenderPassTransformInfoQCOM" structextends="VkCommandBufferInheritanceInfo">
+ <member values="VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_RENDER_PASS_TRANSFORM_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>
+ <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 optional="true"><type>void</type>* <name>pNext</name></member>
+ <member><type>VkBool32</type> <name>diagnosticsConfig</name></member>
+ </type>
+ <type category="struct" name="VkDeviceDiagnosticsConfigCreateInfoNV" structextends="VkDeviceCreateInfo">
+ <member values="VK_STRUCTURE_TYPE_DEVICE_DIAGNOSTICS_CONFIG_CREATE_INFO_NV"><type>VkStructureType</type> <name>sType</name></member>
+ <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>
+ <member><type>VkBool32</type> <name>shaderZeroInitializeWorkgroupMemory</name></member>
+ </type>
+ <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><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><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>
+ </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>
+ <member><type>VkBool32</type> <name>robustImageAccess</name></member>
+ </type>
+ <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><type>VkBool32</type> <name>workgroupMemoryExplicitLayout</name></member>
+ <member><type>VkBool32</type> <name>workgroupMemoryExplicitLayoutScalarBlockLayout</name></member>
+ <member><type>VkBool32</type> <name>workgroupMemoryExplicitLayout8BitAccess</name></member>
+ <member><type>VkBool32</type> <name>workgroupMemoryExplicitLayout16BitAccess</name></member>
+ </type>
+ <type category="struct" name="VkPhysicalDevicePortabilitySubsetFeaturesKHR" structextends="VkPhysicalDeviceFeatures2,VkDeviceCreateInfo">
+ <member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PORTABILITY_SUBSET_FEATURES_KHR"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true"><type>void</type>* <name>pNext</name></member>
+ <member><type>VkBool32</type> <name>constantAlphaColorBlendFactors</name></member>
+ <member><type>VkBool32</type> <name>events</name></member>
+ <member><type>VkBool32</type> <name>imageViewFormatReinterpretation</name></member>
+ <member><type>VkBool32</type> <name>imageViewFormatSwizzle</name></member>
+ <member><type>VkBool32</type> <name>imageView2DOn3DImage</name></member>
+ <member><type>VkBool32</type> <name>multisampleArrayImage</name></member>
+ <member><type>VkBool32</type> <name>mutableComparisonSamplers</name></member>
+ <member><type>VkBool32</type> <name>pointPolygons</name></member>
+ <member><type>VkBool32</type> <name>samplerMipLodBias</name></member>
+ <member><type>VkBool32</type> <name>separateStencilMaskRef</name></member>
+ <member><type>VkBool32</type> <name>shaderSampleRateInterpolationFunctions</name></member>
+ <member><type>VkBool32</type> <name>tessellationIsolines</name></member>
+ <member><type>VkBool32</type> <name>tessellationPointMode</name></member>
+ <member><type>VkBool32</type> <name>triangleFans</name></member>
+ <member><type>VkBool32</type> <name>vertexAttributeAccessBeyondStride</name></member>
+ </type>
+ <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>
+ </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><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><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>
+ <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="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>
+ <member><type>VkBool32</type> <name>shaderImageInt64Atomics</name></member>
+ <member><type>VkBool32</type> <name>sparseImageInt64Atomics</name></member>
+ </type>
+ <type category="struct" name="VkFragmentShadingRateAttachmentInfoKHR" structextends="VkSubpassDescription2">
+ <member values="VK_STRUCTURE_TYPE_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">const <type>VkAttachmentReference2</type>* <name>pFragmentShadingRateAttachment</name></member>
+ <member><type>VkExtent2D</type> <name>shadingRateAttachmentTexelSize</name></member>
+ </type>
+ <type category="struct" name="VkPipelineFragmentShadingRateStateCreateInfoKHR" structextends="VkGraphicsPipelineCreateInfo">
+ <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>
+ </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>
+ <member optional="true"><type>void</type>* <name>pNext</name></member>
+ <member><type>VkBool32</type> <name>pipelineFragmentShadingRate</name></member>
+ <member><type>VkBool32</type> <name>primitiveFragmentShadingRate</name></member>
+ <member><type>VkBool32</type> <name>attachmentFragmentShadingRate</name></member>
+ </type>
+ <type category="struct" name="VkPhysicalDeviceFragmentShadingRatePropertiesKHR" structextends="VkPhysicalDeviceProperties2" returnedonly="true">
+ <member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADING_RATE_PROPERTIES_KHR"><type>VkStructureType</type> <name>sType</name></member>
+ <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="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"><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>
+ <member limittype="bitmask"><type>VkBool32</type> <name>fragmentShadingRateWithShaderSampleMask</name></member>
+ <member limittype="bitmask"><type>VkBool32</type> <name>fragmentShadingRateWithConservativeRasterization</name></member>
+ <member limittype="bitmask"><type>VkBool32</type> <name>fragmentShadingRateWithFragmentShaderInterlock</name></member>
+ <member limittype="bitmask"><type>VkBool32</type> <name>fragmentShadingRateWithCustomSampleLocations</name></member>
+ <member limittype="bitmask"><type>VkBool32</type> <name>fragmentShadingRateStrictMultiplyCombiner</name></member>
+ </type>
+ <type category="struct" name="VkPhysicalDeviceFragmentShadingRateKHR" returnedonly="true">
+ <member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADING_RATE_KHR"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true"><type>void</type>* <name>pNext</name></member>
+ <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>
+ <member optional="true" noautovalidity="true"><type>void</type>* <name>pNext</name></member>
+ <member><type>VkBool32</type> <name>shaderTerminateInvocation</name></member>
+ </type>
+ <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><type>VkBool32</type> <name>fragmentShadingRateEnums</name></member>
+ <member><type>VkBool32</type> <name>supersampleFragmentShadingRates</name></member>
+ <member><type>VkBool32</type> <name>noInvocationFragmentShadingRates</name></member>
+ </type>
+ <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>
+ </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>
+ </type>
+ <type category="struct" name="VkAccelerationStructureBuildSizesInfoKHR">
+ <member values="VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_BUILD_SIZES_INFO_KHR"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member><type>VkDeviceSize</type> <name>accelerationStructureSize</name></member>
+ <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>
+ <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>
+ <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>
+ <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><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><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><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><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>
+ <member><type>uint32_t</type> <name>offset</name><comment>Offset of first element in bytes from base of vertex</comment></member>
+ </type>
+ <type category="struct" name="VkPhysicalDeviceColorWriteEnableFeaturesEXT" structextends="VkPhysicalDeviceFeatures2,VkDeviceCreateInfo">
+ <member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COLOR_WRITE_ENABLE_FEATURES_EXT"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true"><type>void</type>* <name>pNext</name></member>
+ <member><type>VkBool32</type> <name>colorWriteEnable</name></member>
+ </type>
+ <type category="struct" name="VkPipelineColorWriteCreateInfoEXT" structextends="VkPipelineColorBlendStateCreateInfo">
+ <member values="VK_STRUCTURE_TYPE_PIPELINE_COLOR_WRITE_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>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>
+ <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><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>
+ <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>
+ <member optional="true"><type>uint32_t</type> <name>waitSemaphoreInfoCount</name></member>
+ <member len="waitSemaphoreInfoCount">const <type>VkSemaphoreSubmitInfoKHR</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 optional="true"><type>uint32_t</type> <name>signalSemaphoreInfoCount</name></member>
+ <member len="signalSemaphoreInfoCount">const <type>VkSemaphoreSubmitInfoKHR</type>* <name>pSignalSemaphoreInfos</name></member>
+ </type>
+ <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>
+ </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 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>
+ <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>
+ <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>
+ <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>
+ <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>
+ </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>
+ </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>
+ </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="StdVideoH264ChromaFormatIdc"/>
+ <type requires="vk_video/vulkan_video_codec_h264std.h" name="StdVideoH264PocType"/>
+ <type requires="vk_video/vulkan_video_codec_h264std.h" name="StdVideoH264SpsFlags"/>
+ <type requires="vk_video/vulkan_video_codec_h264std.h" name="StdVideoH264ScalingLists"/>
+ <type requires="vk_video/vulkan_video_codec_h264std.h" name="StdVideoH264SequenceParameterSetVui"/>
+ <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="StdVideoH264PpsFlags"/>
+ <type requires="vk_video/vulkan_video_codec_h264std.h" name="StdVideoH264SliceType"/>
+ <type requires="vk_video/vulkan_video_codec_h264std.h" name="StdVideoH264CabacInitIdc"/>
+ <type requires="vk_video/vulkan_video_codec_h264std.h" name="StdVideoH264DisableDeblockingFilterIdc"/>
+ <type requires="vk_video/vulkan_video_codec_h264std.h" name="StdVideoH264PictureType"/>
+ <type requires="vk_video/vulkan_video_codec_h264std.h" name="StdVideoH264ModificationOfPicNumsIdc"/>
+ <type requires="vk_video/vulkan_video_codec_h264std.h" name="StdVideoH264MemMgmtControlOp"/>
+ <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>
+ <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>
+ <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"/>
+ <type requires="vk_video/vulkan_video_codec_h265std.h" name="StdVideoH265VideoParameterSet"/>
+ <type requires="vk_video/vulkan_video_codec_h265std.h" name="StdVideoH265SequenceParameterSet"/>
+ <type requires="vk_video/vulkan_video_codec_h265std.h" name="StdVideoH265PictureParameterSet"/>
+ <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="StdVideoH265SpsFlags"/>
+ <type requires="vk_video/vulkan_video_codec_h265std.h" name="StdVideoH265ScalingLists"/>
+ <type requires="vk_video/vulkan_video_codec_h265std.h" name="StdVideoH265SequenceParameterSetVui"/>
+ <type requires="vk_video/vulkan_video_codec_h265std.h" name="StdVideoH265PredictorPaletteEntries"/>
+ <type requires="vk_video/vulkan_video_codec_h265std.h" name="StdVideoH265PpsFlags"/>
+ <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 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>
+ <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>
+ </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>
+ </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>
+ </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>
+ </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>
+ </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>
+ </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>
+ </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>
+ </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="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="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>
+ </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>
+ </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>
+ </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>
+ </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>
+ </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>
+ </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>
+ </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><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>
+ </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><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><type>size_t</type> <name>dataSize</name></member>
+ <member>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><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><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>
+ <member><type>uint32_t</type> <name>gridDimZ</name></member>
+ <member><type>uint32_t</type> <name>blockDimX</name></member>
+ <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 len="paramCount">const <type>void</type>* const * <name>pParams</name></member>
+ <member><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="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>
+ </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><type>VkBool32</type> <name>rayTracingMotionBlur</name></member>
+ <member><type>VkBool32</type> <name>rayTracingMotionBlurPipelineTraceRaysIndirect</name></member>
+ </type>
+ <type name="VkAccelerationStructureMotionInstanceTypeNV" category="enum"/>
+ <type category="struct" name="VkAccelerationStructureGeometryMotionTrianglesDataNV" structextends="VkAccelerationStructureGeometryTrianglesDataKHR">
+ <member values="VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_MOTION_TRIANGLES_DATA_NV"><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>vertexData</name></member>
+ </type>
+ <type category="struct" name="VkAccelerationStructureMotionInfoNV" structextends="VkAccelerationStructureCreateInfoKHR">
+ <member values="VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_MOTION_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>maxInstances</name></member>
+ <member optional="true"><type>VkAccelerationStructureMotionInfoFlagsNV</type> <name>flags</name></member>
+ </type>
+ <type category="struct" name="VkSRTDataNV">
+ <member><type>float</type> <name>sx</name></member>
+ <member><type>float</type> <name>a</name></member>
+ <member><type>float</type> <name>b</name></member>
+ <member><type>float</type> <name>pvx</name></member>
+ <member><type>float</type> <name>sy</name></member>
+ <member><type>float</type> <name>c</name></member>
+ <member><type>float</type> <name>pvy</name></member>
+ <member><type>float</type> <name>sz</name></member>
+ <member><type>float</type> <name>pvz</name></member>
+ <member><type>float</type> <name>qx</name></member>
+ <member><type>float</type> <name>qy</name></member>
+ <member><type>float</type> <name>qz</name></member>
+ <member><type>float</type> <name>qw</name></member>
+ <member><type>float</type> <name>tx</name></member>
+ <member><type>float</type> <name>ty</name></member>
+ <member><type>float</type> <name>tz</name></member>
+ </type>
+ <type category="struct" name="VkAccelerationStructureSRTMotionInstanceNV">
+ <comment>The bitfields in this structure are non-normative since bitfield ordering is implementation-defined in C. The specification defines the normative layout.</comment>
+ <member><type>VkSRTDataNV</type> <name>transformT0</name></member>
+ <member><type>VkSRTDataNV</type> <name>transformT1</name></member>
+ <member><type>uint32_t</type> <name>instanceCustomIndex</name>:24</member>
+ <member><type>uint32_t</type> <name>mask</name>:8</member>
+ <member><type>uint32_t</type> <name>instanceShaderBindingTableRecordOffset</name>:24</member>
+ <member optional="true"><type>VkGeometryInstanceFlagsKHR</type> <name>flags</name>:8</member>
+ <member><type>uint64_t</type> <name>accelerationStructureReference</name></member>
+ </type>
+ <type category="struct" name="VkAccelerationStructureMatrixMotionInstanceNV">
+ <comment>The bitfields in this structure are non-normative since bitfield ordering is implementation-defined in C. The specification defines the normative layout.</comment>
+ <member><type>VkTransformMatrixKHR</type> <name>transformT0</name></member>
+ <member><type>VkTransformMatrixKHR</type> <name>transformT1</name></member>
+ <member><type>uint32_t</type> <name>instanceCustomIndex</name>:24</member>
+ <member><type>uint32_t</type> <name>mask</name>:8</member>
+ <member><type>uint32_t</type> <name>instanceShaderBindingTableRecordOffset</name>:24</member>
+ <member optional="true"><type>VkGeometryInstanceFlagsKHR</type> <name>flags</name>:8</member>
+ <member><type>uint64_t</type> <name>accelerationStructureReference</name></member>
+ </type>
+ <type category="union" name="VkAccelerationStructureMotionInstanceDataNV">
+ <member selection="VK_ACCELERATION_STRUCTURE_MOTION_INSTANCE_TYPE_STATIC_NV"><type>VkAccelerationStructureInstanceKHR</type> <name>staticInstance</name></member>
+ <member selection="VK_ACCELERATION_STRUCTURE_MOTION_INSTANCE_TYPE_MATRIX_MOTION_NV"><type>VkAccelerationStructureMatrixMotionInstanceNV</type> <name>matrixMotionInstance</name></member>
+ <member selection="VK_ACCELERATION_STRUCTURE_MOTION_INSTANCE_TYPE_SRT_MOTION_NV"><type>VkAccelerationStructureSRTMotionInstanceNV</type> <name>srtMotionInstance</name></member>
+ </type>
+ <type category="struct" name="VkAccelerationStructureMotionInstanceNV">
+ <member><type>VkAccelerationStructureMotionInstanceTypeNV</type> <name>type</name></member>
+ <member optional="true"><type>VkAccelerationStructureMotionInstanceFlagsNV</type> <name>flags</name></member>
+ <member selector="type"><type>VkAccelerationStructureMotionInstanceDataNV</type> <name>data</name></member>
+ </type>
+ <type category="basetype">typedef <type>void</type>* <name>VkRemoteAddressNV</name>;</type>
+ <type category="struct" name="VkMemoryGetRemoteAddressInfoNV">
+ <member values="VK_STRUCTURE_TYPE_MEMORY_GET_REMOTE_ADDRESS_INFO_NV"><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>VkExternalMemoryHandleTypeFlagBits</type> <name>handleType</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">
+ <enum type="uint32_t" value="256" name="VK_MAX_PHYSICAL_DEVICE_NAME_SIZE"/>
+ <enum type="uint32_t" value="16" name="VK_UUID_SIZE"/>
+ <enum type="uint32_t" value="8" name="VK_LUID_SIZE"/>
+ <enum name="VK_LUID_SIZE_KHR" alias="VK_LUID_SIZE"/>
+ <enum type="uint32_t" value="256" name="VK_MAX_EXTENSION_NAME_SIZE"/>
+ <enum type="uint32_t" value="256" name="VK_MAX_DESCRIPTION_SIZE"/>
+ <enum type="uint32_t" value="32" name="VK_MAX_MEMORY_TYPES"/>
+ <enum type="uint32_t" value="16" name="VK_MAX_MEMORY_HEAPS" comment="The maximum number of unique memory heaps, each of which supporting 1 or more memory types"/>
+ <enum type="float" value="1000.0F" name="VK_LOD_CLAMP_NONE"/>
+ <enum type="uint32_t" value="(~0U)" name="VK_REMAINING_MIP_LEVELS"/>
+ <enum type="uint32_t" value="(~0U)" name="VK_REMAINING_ARRAY_LAYERS"/>
+ <enum type="uint64_t" value="(~0ULL)" name="VK_WHOLE_SIZE"/>
+ <enum type="uint32_t" value="(~0U)" name="VK_ATTACHMENT_UNUSED"/>
+ <enum type="uint32_t" value="1" name="VK_TRUE"/>
+ <enum type="uint32_t" value="0" name="VK_FALSE"/>
+ <enum type="uint32_t" value="(~0U)" name="VK_QUEUE_FAMILY_IGNORED"/>
+ <enum type="uint32_t" value="(~1U)" name="VK_QUEUE_FAMILY_EXTERNAL"/>
+ <enum name="VK_QUEUE_FAMILY_EXTERNAL_KHR" alias="VK_QUEUE_FAMILY_EXTERNAL"/>
+ <enum type="uint32_t" value="(~2U)" name="VK_QUEUE_FAMILY_FOREIGN_EXT"/>
+ <enum type="uint32_t" value="(~0U)" name="VK_SUBPASS_EXTERNAL"/>
+ <enum type="uint32_t" value="32" name="VK_MAX_DEVICE_GROUP_SIZE"/>
+ <enum name="VK_MAX_DEVICE_GROUP_SIZE_KHR" alias="VK_MAX_DEVICE_GROUP_SIZE"/>
+ <enum type="uint32_t" value="256" name="VK_MAX_DRIVER_NAME_SIZE"/>
+ <enum name="VK_MAX_DRIVER_NAME_SIZE_KHR" alias="VK_MAX_DRIVER_NAME_SIZE"/>
+ <enum type="uint32_t" value="256" name="VK_MAX_DRIVER_INFO_SIZE"/>
+ <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"/>
+ </enums>
+
+ <comment>
+ Unlike OpenGL, most tokens in Vulkan are actual typed enumerants in
+ their own numeric namespaces. The "name" attribute is the C enum
+ type name, and is pulled in from a type tag definition above
+ (slightly clunky, but retains the type / enum distinction). "type"
+ attributes of "enum" or "bitmask" indicate that these values should
+ be generated inside an appropriate definition.
+ </comment>
+
+ <enums name="VkImageLayout" type="enum">
+ <enum value="0" name="VK_IMAGE_LAYOUT_UNDEFINED" comment="Implicit layout an image is when its contents are undefined due to various reasons (e.g. right after creation)"/>
+ <enum value="1" name="VK_IMAGE_LAYOUT_GENERAL" comment="General layout when image can be used for any kind of access"/>
+ <enum value="2" name="VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL" comment="Optimal layout when image is only used for color attachment read/write"/>
+ <enum value="3" name="VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL" comment="Optimal layout when image is only used for depth/stencil attachment read/write"/>
+ <enum value="4" name="VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL" comment="Optimal layout when image is used for read only depth/stencil attachment and shader access"/>
+ <enum value="5" name="VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL" comment="Optimal layout when image is used for read only shader access"/>
+ <enum value="6" name="VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL" comment="Optimal layout when image is used only as source of transfer operations"/>
+ <enum value="7" name="VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL" comment="Optimal layout when image is used only as destination of transfer operations"/>
+ <enum value="8" name="VK_IMAGE_LAYOUT_PREINITIALIZED" comment="Initial layout used when the data is populated by the CPU"/>
+ </enums>
+ <enums name="VkAttachmentLoadOp" type="enum">
+ <enum value="0" name="VK_ATTACHMENT_LOAD_OP_LOAD"/>
+ <enum value="1" name="VK_ATTACHMENT_LOAD_OP_CLEAR"/>
+ <enum value="2" name="VK_ATTACHMENT_LOAD_OP_DONT_CARE"/>
+ </enums>
+ <enums name="VkAttachmentStoreOp" type="enum">
+ <enum value="0" name="VK_ATTACHMENT_STORE_OP_STORE"/>
+ <enum value="1" name="VK_ATTACHMENT_STORE_OP_DONT_CARE"/>
+ </enums>
+ <enums name="VkImageType" type="enum">
+ <enum value="0" name="VK_IMAGE_TYPE_1D"/>
+ <enum value="1" name="VK_IMAGE_TYPE_2D"/>
+ <enum value="2" name="VK_IMAGE_TYPE_3D"/>
+ </enums>
+ <enums name="VkImageTiling" type="enum">
+ <enum value="0" name="VK_IMAGE_TILING_OPTIMAL"/>
+ <enum value="1" name="VK_IMAGE_TILING_LINEAR"/>
+ </enums>
+ <enums name="VkImageViewType" type="enum">
+ <enum value="0" name="VK_IMAGE_VIEW_TYPE_1D"/>
+ <enum value="1" name="VK_IMAGE_VIEW_TYPE_2D"/>
+ <enum value="2" name="VK_IMAGE_VIEW_TYPE_3D"/>
+ <enum value="3" name="VK_IMAGE_VIEW_TYPE_CUBE"/>
+ <enum value="4" name="VK_IMAGE_VIEW_TYPE_1D_ARRAY"/>
+ <enum value="5" name="VK_IMAGE_VIEW_TYPE_2D_ARRAY"/>
+ <enum value="6" name="VK_IMAGE_VIEW_TYPE_CUBE_ARRAY"/>
+ </enums>
+ <enums name="VkCommandBufferLevel" type="enum">
+ <enum value="0" name="VK_COMMAND_BUFFER_LEVEL_PRIMARY"/>
+ <enum value="1" name="VK_COMMAND_BUFFER_LEVEL_SECONDARY"/>
+ </enums>
+ <enums name="VkComponentSwizzle" type="enum">
+ <enum value="0" name="VK_COMPONENT_SWIZZLE_IDENTITY"/>
+ <enum value="1" name="VK_COMPONENT_SWIZZLE_ZERO"/>
+ <enum value="2" name="VK_COMPONENT_SWIZZLE_ONE"/>
+ <enum value="3" name="VK_COMPONENT_SWIZZLE_R"/>
+ <enum value="4" name="VK_COMPONENT_SWIZZLE_G"/>
+ <enum value="5" name="VK_COMPONENT_SWIZZLE_B"/>
+ <enum value="6" name="VK_COMPONENT_SWIZZLE_A"/>
+ </enums>
+ <enums name="VkDescriptorType" type="enum">
+ <enum value="0" name="VK_DESCRIPTOR_TYPE_SAMPLER"/>
+ <enum value="1" name="VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER"/>
+ <enum value="2" name="VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE"/>
+ <enum value="3" name="VK_DESCRIPTOR_TYPE_STORAGE_IMAGE"/>
+ <enum value="4" name="VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER"/>
+ <enum value="5" name="VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER"/>
+ <enum value="6" name="VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER"/>
+ <enum value="7" name="VK_DESCRIPTOR_TYPE_STORAGE_BUFFER"/>
+ <enum value="8" name="VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC"/>
+ <enum value="9" name="VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC"/>
+ <enum value="10" name="VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT"/>
+ </enums>
+ <enums name="VkQueryType" type="enum">
+ <enum value="0" name="VK_QUERY_TYPE_OCCLUSION"/>
+ <enum value="1" name="VK_QUERY_TYPE_PIPELINE_STATISTICS" comment="Optional"/>
+ <enum value="2" name="VK_QUERY_TYPE_TIMESTAMP"/>
+ </enums>
+ <enums name="VkBorderColor" type="enum">
+ <enum value="0" name="VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK"/>
+ <enum value="1" name="VK_BORDER_COLOR_INT_TRANSPARENT_BLACK"/>
+ <enum value="2" name="VK_BORDER_COLOR_FLOAT_OPAQUE_BLACK"/>
+ <enum value="3" name="VK_BORDER_COLOR_INT_OPAQUE_BLACK"/>
+ <enum value="4" name="VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE"/>
+ <enum value="5" name="VK_BORDER_COLOR_INT_OPAQUE_WHITE"/>
+ </enums>
+ <enums name="VkPipelineBindPoint" type="enum">
+ <enum value="0" name="VK_PIPELINE_BIND_POINT_GRAPHICS"/>
+ <enum value="1" name="VK_PIPELINE_BIND_POINT_COMPUTE"/>
+ </enums>
+ <enums name="VkPipelineCacheHeaderVersion" type="enum">
+ <enum value="1" name="VK_PIPELINE_CACHE_HEADER_VERSION_ONE"/>
+ </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"/>
+ <enum value="2" name="VK_PRIMITIVE_TOPOLOGY_LINE_STRIP"/>
+ <enum value="3" name="VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST"/>
+ <enum value="4" name="VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP"/>
+ <enum value="5" name="VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN"/>
+ <enum value="6" name="VK_PRIMITIVE_TOPOLOGY_LINE_LIST_WITH_ADJACENCY"/>
+ <enum value="7" name="VK_PRIMITIVE_TOPOLOGY_LINE_STRIP_WITH_ADJACENCY"/>
+ <enum value="8" name="VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST_WITH_ADJACENCY"/>
+ <enum value="9" name="VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP_WITH_ADJACENCY"/>
+ <enum value="10" name="VK_PRIMITIVE_TOPOLOGY_PATCH_LIST"/>
+ </enums>
+ <enums name="VkSharingMode" type="enum">
+ <enum value="0" name="VK_SHARING_MODE_EXCLUSIVE"/>
+ <enum value="1" name="VK_SHARING_MODE_CONCURRENT"/>
+ </enums>
+ <enums name="VkIndexType" type="enum">
+ <enum value="0" name="VK_INDEX_TYPE_UINT16"/>
+ <enum value="1" name="VK_INDEX_TYPE_UINT32"/>
+ </enums>
+ <enums name="VkFilter" type="enum">
+ <enum value="0" name="VK_FILTER_NEAREST"/>
+ <enum value="1" name="VK_FILTER_LINEAR"/>
+ </enums>
+ <enums name="VkSamplerMipmapMode" type="enum">
+ <enum value="0" name="VK_SAMPLER_MIPMAP_MODE_NEAREST" comment="Choose nearest mip level"/>
+ <enum value="1" name="VK_SAMPLER_MIPMAP_MODE_LINEAR" comment="Linear filter between mip levels"/>
+ </enums>
+ <enums name="VkSamplerAddressMode" type="enum">
+ <enum value="0" name="VK_SAMPLER_ADDRESS_MODE_REPEAT"/>
+ <enum value="1" name="VK_SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT"/>
+ <enum value="2" name="VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE"/>
+ <enum value="3" name="VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER"/>
+ <comment>
+ value="4" reserved for VK_KHR_sampler_mirror_clamp_to_edge
+ enum VK_SAMPLER_ADDRESS_MODE_MIRROR_CLAMP_TO_EDGE; do not
+ alias!
+ </comment>
+ </enums>
+ <enums name="VkCompareOp" type="enum">
+ <enum value="0" name="VK_COMPARE_OP_NEVER"/>
+ <enum value="1" name="VK_COMPARE_OP_LESS"/>
+ <enum value="2" name="VK_COMPARE_OP_EQUAL"/>
+ <enum value="3" name="VK_COMPARE_OP_LESS_OR_EQUAL"/>
+ <enum value="4" name="VK_COMPARE_OP_GREATER"/>
+ <enum value="5" name="VK_COMPARE_OP_NOT_EQUAL"/>
+ <enum value="6" name="VK_COMPARE_OP_GREATER_OR_EQUAL"/>
+ <enum value="7" name="VK_COMPARE_OP_ALWAYS"/>
+ </enums>
+ <enums name="VkPolygonMode" type="enum">
+ <enum value="0" name="VK_POLYGON_MODE_FILL"/>
+ <enum value="1" name="VK_POLYGON_MODE_LINE"/>
+ <enum value="2" name="VK_POLYGON_MODE_POINT"/>
+ </enums>
+ <enums name="VkFrontFace" type="enum">
+ <enum value="0" name="VK_FRONT_FACE_COUNTER_CLOCKWISE"/>
+ <enum value="1" name="VK_FRONT_FACE_CLOCKWISE"/>
+ </enums>
+ <enums name="VkBlendFactor" type="enum">
+ <enum value="0" name="VK_BLEND_FACTOR_ZERO"/>
+ <enum value="1" name="VK_BLEND_FACTOR_ONE"/>
+ <enum value="2" name="VK_BLEND_FACTOR_SRC_COLOR"/>
+ <enum value="3" name="VK_BLEND_FACTOR_ONE_MINUS_SRC_COLOR"/>
+ <enum value="4" name="VK_BLEND_FACTOR_DST_COLOR"/>
+ <enum value="5" name="VK_BLEND_FACTOR_ONE_MINUS_DST_COLOR"/>
+ <enum value="6" name="VK_BLEND_FACTOR_SRC_ALPHA"/>
+ <enum value="7" name="VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA"/>
+ <enum value="8" name="VK_BLEND_FACTOR_DST_ALPHA"/>
+ <enum value="9" name="VK_BLEND_FACTOR_ONE_MINUS_DST_ALPHA"/>
+ <enum value="10" name="VK_BLEND_FACTOR_CONSTANT_COLOR"/>
+ <enum value="11" name="VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_COLOR"/>
+ <enum value="12" name="VK_BLEND_FACTOR_CONSTANT_ALPHA"/>
+ <enum value="13" name="VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_ALPHA"/>
+ <enum value="14" name="VK_BLEND_FACTOR_SRC_ALPHA_SATURATE"/>
+ <enum value="15" name="VK_BLEND_FACTOR_SRC1_COLOR"/>
+ <enum value="16" name="VK_BLEND_FACTOR_ONE_MINUS_SRC1_COLOR"/>
+ <enum value="17" name="VK_BLEND_FACTOR_SRC1_ALPHA"/>
+ <enum value="18" name="VK_BLEND_FACTOR_ONE_MINUS_SRC1_ALPHA"/>
+ </enums>
+ <enums name="VkBlendOp" type="enum">
+ <enum value="0" name="VK_BLEND_OP_ADD"/>
+ <enum value="1" name="VK_BLEND_OP_SUBTRACT"/>
+ <enum value="2" name="VK_BLEND_OP_REVERSE_SUBTRACT"/>
+ <enum value="3" name="VK_BLEND_OP_MIN"/>
+ <enum value="4" name="VK_BLEND_OP_MAX"/>
+ </enums>
+ <enums name="VkStencilOp" type="enum">
+ <enum value="0" name="VK_STENCIL_OP_KEEP"/>
+ <enum value="1" name="VK_STENCIL_OP_ZERO"/>
+ <enum value="2" name="VK_STENCIL_OP_REPLACE"/>
+ <enum value="3" name="VK_STENCIL_OP_INCREMENT_AND_CLAMP"/>
+ <enum value="4" name="VK_STENCIL_OP_DECREMENT_AND_CLAMP"/>
+ <enum value="5" name="VK_STENCIL_OP_INVERT"/>
+ <enum value="6" name="VK_STENCIL_OP_INCREMENT_AND_WRAP"/>
+ <enum value="7" name="VK_STENCIL_OP_DECREMENT_AND_WRAP"/>
+ </enums>
+ <enums name="VkLogicOp" type="enum">
+ <enum value="0" name="VK_LOGIC_OP_CLEAR"/>
+ <enum value="1" name="VK_LOGIC_OP_AND"/>
+ <enum value="2" name="VK_LOGIC_OP_AND_REVERSE"/>
+ <enum value="3" name="VK_LOGIC_OP_COPY"/>
+ <enum value="4" name="VK_LOGIC_OP_AND_INVERTED"/>
+ <enum value="5" name="VK_LOGIC_OP_NO_OP"/>
+ <enum value="6" name="VK_LOGIC_OP_XOR"/>
+ <enum value="7" name="VK_LOGIC_OP_OR"/>
+ <enum value="8" name="VK_LOGIC_OP_NOR"/>
+ <enum value="9" name="VK_LOGIC_OP_EQUIVALENT"/>
+ <enum value="10" name="VK_LOGIC_OP_INVERT"/>
+ <enum value="11" name="VK_LOGIC_OP_OR_REVERSE"/>
+ <enum value="12" name="VK_LOGIC_OP_COPY_INVERTED"/>
+ <enum value="13" name="VK_LOGIC_OP_OR_INVERTED"/>
+ <enum value="14" name="VK_LOGIC_OP_NAND"/>
+ <enum value="15" name="VK_LOGIC_OP_SET"/>
+ </enums>
+ <enums name="VkInternalAllocationType" type="enum">
+ <enum value="0" name="VK_INTERNAL_ALLOCATION_TYPE_EXECUTABLE"/>
+ </enums>
+ <enums name="VkSystemAllocationScope" type="enum">
+ <enum value="0" name="VK_SYSTEM_ALLOCATION_SCOPE_COMMAND"/>
+ <enum value="1" name="VK_SYSTEM_ALLOCATION_SCOPE_OBJECT"/>
+ <enum value="2" name="VK_SYSTEM_ALLOCATION_SCOPE_CACHE"/>
+ <enum value="3" name="VK_SYSTEM_ALLOCATION_SCOPE_DEVICE"/>
+ <enum value="4" name="VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE"/>
+ </enums>
+ <enums name="VkPhysicalDeviceType" type="enum">
+ <enum value="0" name="VK_PHYSICAL_DEVICE_TYPE_OTHER"/>
+ <enum value="1" name="VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU"/>
+ <enum value="2" name="VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU"/>
+ <enum value="3" name="VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU"/>
+ <enum value="4" name="VK_PHYSICAL_DEVICE_TYPE_CPU"/>
+ </enums>
+ <enums name="VkVertexInputRate" type="enum">
+ <enum value="0" name="VK_VERTEX_INPUT_RATE_VERTEX"/>
+ <enum value="1" name="VK_VERTEX_INPUT_RATE_INSTANCE"/>
+ </enums>
+ <enums name="VkFormat" type="enum" comment="Vulkan format definitions">
+ <enum value="0" name="VK_FORMAT_UNDEFINED"/>
+ <enum value="1" name="VK_FORMAT_R4G4_UNORM_PACK8"/>
+ <enum value="2" name="VK_FORMAT_R4G4B4A4_UNORM_PACK16"/>
+ <enum value="3" name="VK_FORMAT_B4G4R4A4_UNORM_PACK16"/>
+ <enum value="4" name="VK_FORMAT_R5G6B5_UNORM_PACK16"/>
+ <enum value="5" name="VK_FORMAT_B5G6R5_UNORM_PACK16"/>
+ <enum value="6" name="VK_FORMAT_R5G5B5A1_UNORM_PACK16"/>
+ <enum value="7" name="VK_FORMAT_B5G5R5A1_UNORM_PACK16"/>
+ <enum value="8" name="VK_FORMAT_A1R5G5B5_UNORM_PACK16"/>
+ <enum value="9" name="VK_FORMAT_R8_UNORM"/>
+ <enum value="10" name="VK_FORMAT_R8_SNORM"/>
+ <enum value="11" name="VK_FORMAT_R8_USCALED"/>
+ <enum value="12" name="VK_FORMAT_R8_SSCALED"/>
+ <enum value="13" name="VK_FORMAT_R8_UINT"/>
+ <enum value="14" name="VK_FORMAT_R8_SINT"/>
+ <enum value="15" name="VK_FORMAT_R8_SRGB"/>
+ <enum value="16" name="VK_FORMAT_R8G8_UNORM"/>
+ <enum value="17" name="VK_FORMAT_R8G8_SNORM"/>
+ <enum value="18" name="VK_FORMAT_R8G8_USCALED"/>
+ <enum value="19" name="VK_FORMAT_R8G8_SSCALED"/>
+ <enum value="20" name="VK_FORMAT_R8G8_UINT"/>
+ <enum value="21" name="VK_FORMAT_R8G8_SINT"/>
+ <enum value="22" name="VK_FORMAT_R8G8_SRGB"/>
+ <enum value="23" name="VK_FORMAT_R8G8B8_UNORM"/>
+ <enum value="24" name="VK_FORMAT_R8G8B8_SNORM"/>
+ <enum value="25" name="VK_FORMAT_R8G8B8_USCALED"/>
+ <enum value="26" name="VK_FORMAT_R8G8B8_SSCALED"/>
+ <enum value="27" name="VK_FORMAT_R8G8B8_UINT"/>
+ <enum value="28" name="VK_FORMAT_R8G8B8_SINT"/>
+ <enum value="29" name="VK_FORMAT_R8G8B8_SRGB"/>
+ <enum value="30" name="VK_FORMAT_B8G8R8_UNORM"/>
+ <enum value="31" name="VK_FORMAT_B8G8R8_SNORM"/>
+ <enum value="32" name="VK_FORMAT_B8G8R8_USCALED"/>
+ <enum value="33" name="VK_FORMAT_B8G8R8_SSCALED"/>
+ <enum value="34" name="VK_FORMAT_B8G8R8_UINT"/>
+ <enum value="35" name="VK_FORMAT_B8G8R8_SINT"/>
+ <enum value="36" name="VK_FORMAT_B8G8R8_SRGB"/>
+ <enum value="37" name="VK_FORMAT_R8G8B8A8_UNORM"/>
+ <enum value="38" name="VK_FORMAT_R8G8B8A8_SNORM"/>
+ <enum value="39" name="VK_FORMAT_R8G8B8A8_USCALED"/>
+ <enum value="40" name="VK_FORMAT_R8G8B8A8_SSCALED"/>
+ <enum value="41" name="VK_FORMAT_R8G8B8A8_UINT"/>
+ <enum value="42" name="VK_FORMAT_R8G8B8A8_SINT"/>
+ <enum value="43" name="VK_FORMAT_R8G8B8A8_SRGB"/>
+ <enum value="44" name="VK_FORMAT_B8G8R8A8_UNORM"/>
+ <enum value="45" name="VK_FORMAT_B8G8R8A8_SNORM"/>
+ <enum value="46" name="VK_FORMAT_B8G8R8A8_USCALED"/>
+ <enum value="47" name="VK_FORMAT_B8G8R8A8_SSCALED"/>
+ <enum value="48" name="VK_FORMAT_B8G8R8A8_UINT"/>
+ <enum value="49" name="VK_FORMAT_B8G8R8A8_SINT"/>
+ <enum value="50" name="VK_FORMAT_B8G8R8A8_SRGB"/>
+ <enum value="51" name="VK_FORMAT_A8B8G8R8_UNORM_PACK32"/>
+ <enum value="52" name="VK_FORMAT_A8B8G8R8_SNORM_PACK32"/>
+ <enum value="53" name="VK_FORMAT_A8B8G8R8_USCALED_PACK32"/>
+ <enum value="54" name="VK_FORMAT_A8B8G8R8_SSCALED_PACK32"/>
+ <enum value="55" name="VK_FORMAT_A8B8G8R8_UINT_PACK32"/>
+ <enum value="56" name="VK_FORMAT_A8B8G8R8_SINT_PACK32"/>
+ <enum value="57" name="VK_FORMAT_A8B8G8R8_SRGB_PACK32"/>
+ <enum value="58" name="VK_FORMAT_A2R10G10B10_UNORM_PACK32"/>
+ <enum value="59" name="VK_FORMAT_A2R10G10B10_SNORM_PACK32"/>
+ <enum value="60" name="VK_FORMAT_A2R10G10B10_USCALED_PACK32"/>
+ <enum value="61" name="VK_FORMAT_A2R10G10B10_SSCALED_PACK32"/>
+ <enum value="62" name="VK_FORMAT_A2R10G10B10_UINT_PACK32"/>
+ <enum value="63" name="VK_FORMAT_A2R10G10B10_SINT_PACK32"/>
+ <enum value="64" name="VK_FORMAT_A2B10G10R10_UNORM_PACK32"/>
+ <enum value="65" name="VK_FORMAT_A2B10G10R10_SNORM_PACK32"/>
+ <enum value="66" name="VK_FORMAT_A2B10G10R10_USCALED_PACK32"/>
+ <enum value="67" name="VK_FORMAT_A2B10G10R10_SSCALED_PACK32"/>
+ <enum value="68" name="VK_FORMAT_A2B10G10R10_UINT_PACK32"/>
+ <enum value="69" name="VK_FORMAT_A2B10G10R10_SINT_PACK32"/>
+ <enum value="70" name="VK_FORMAT_R16_UNORM"/>
+ <enum value="71" name="VK_FORMAT_R16_SNORM"/>
+ <enum value="72" name="VK_FORMAT_R16_USCALED"/>
+ <enum value="73" name="VK_FORMAT_R16_SSCALED"/>
+ <enum value="74" name="VK_FORMAT_R16_UINT"/>
+ <enum value="75" name="VK_FORMAT_R16_SINT"/>
+ <enum value="76" name="VK_FORMAT_R16_SFLOAT"/>
+ <enum value="77" name="VK_FORMAT_R16G16_UNORM"/>
+ <enum value="78" name="VK_FORMAT_R16G16_SNORM"/>
+ <enum value="79" name="VK_FORMAT_R16G16_USCALED"/>
+ <enum value="80" name="VK_FORMAT_R16G16_SSCALED"/>
+ <enum value="81" name="VK_FORMAT_R16G16_UINT"/>
+ <enum value="82" name="VK_FORMAT_R16G16_SINT"/>
+ <enum value="83" name="VK_FORMAT_R16G16_SFLOAT"/>
+ <enum value="84" name="VK_FORMAT_R16G16B16_UNORM"/>
+ <enum value="85" name="VK_FORMAT_R16G16B16_SNORM"/>
+ <enum value="86" name="VK_FORMAT_R16G16B16_USCALED"/>
+ <enum value="87" name="VK_FORMAT_R16G16B16_SSCALED"/>
+ <enum value="88" name="VK_FORMAT_R16G16B16_UINT"/>
+ <enum value="89" name="VK_FORMAT_R16G16B16_SINT"/>
+ <enum value="90" name="VK_FORMAT_R16G16B16_SFLOAT"/>
+ <enum value="91" name="VK_FORMAT_R16G16B16A16_UNORM"/>
+ <enum value="92" name="VK_FORMAT_R16G16B16A16_SNORM"/>
+ <enum value="93" name="VK_FORMAT_R16G16B16A16_USCALED"/>
+ <enum value="94" name="VK_FORMAT_R16G16B16A16_SSCALED"/>
+ <enum value="95" name="VK_FORMAT_R16G16B16A16_UINT"/>
+ <enum value="96" name="VK_FORMAT_R16G16B16A16_SINT"/>
+ <enum value="97" name="VK_FORMAT_R16G16B16A16_SFLOAT"/>
+ <enum value="98" name="VK_FORMAT_R32_UINT"/>
+ <enum value="99" name="VK_FORMAT_R32_SINT"/>
+ <enum value="100" name="VK_FORMAT_R32_SFLOAT"/>
+ <enum value="101" name="VK_FORMAT_R32G32_UINT"/>
+ <enum value="102" name="VK_FORMAT_R32G32_SINT"/>
+ <enum value="103" name="VK_FORMAT_R32G32_SFLOAT"/>
+ <enum value="104" name="VK_FORMAT_R32G32B32_UINT"/>
+ <enum value="105" name="VK_FORMAT_R32G32B32_SINT"/>
+ <enum value="106" name="VK_FORMAT_R32G32B32_SFLOAT"/>
+ <enum value="107" name="VK_FORMAT_R32G32B32A32_UINT"/>
+ <enum value="108" name="VK_FORMAT_R32G32B32A32_SINT"/>
+ <enum value="109" name="VK_FORMAT_R32G32B32A32_SFLOAT"/>
+ <enum value="110" name="VK_FORMAT_R64_UINT"/>
+ <enum value="111" name="VK_FORMAT_R64_SINT"/>
+ <enum value="112" name="VK_FORMAT_R64_SFLOAT"/>
+ <enum value="113" name="VK_FORMAT_R64G64_UINT"/>
+ <enum value="114" name="VK_FORMAT_R64G64_SINT"/>
+ <enum value="115" name="VK_FORMAT_R64G64_SFLOAT"/>
+ <enum value="116" name="VK_FORMAT_R64G64B64_UINT"/>
+ <enum value="117" name="VK_FORMAT_R64G64B64_SINT"/>
+ <enum value="118" name="VK_FORMAT_R64G64B64_SFLOAT"/>
+ <enum value="119" name="VK_FORMAT_R64G64B64A64_UINT"/>
+ <enum value="120" name="VK_FORMAT_R64G64B64A64_SINT"/>
+ <enum value="121" name="VK_FORMAT_R64G64B64A64_SFLOAT"/>
+ <enum value="122" name="VK_FORMAT_B10G11R11_UFLOAT_PACK32"/>
+ <enum value="123" name="VK_FORMAT_E5B9G9R9_UFLOAT_PACK32"/>
+ <enum value="124" name="VK_FORMAT_D16_UNORM"/>
+ <enum value="125" name="VK_FORMAT_X8_D24_UNORM_PACK32"/>
+ <enum value="126" name="VK_FORMAT_D32_SFLOAT"/>
+ <enum value="127" name="VK_FORMAT_S8_UINT"/>
+ <enum value="128" name="VK_FORMAT_D16_UNORM_S8_UINT"/>
+ <enum value="129" name="VK_FORMAT_D24_UNORM_S8_UINT"/>
+ <enum value="130" name="VK_FORMAT_D32_SFLOAT_S8_UINT"/>
+ <enum value="131" name="VK_FORMAT_BC1_RGB_UNORM_BLOCK"/>
+ <enum value="132" name="VK_FORMAT_BC1_RGB_SRGB_BLOCK"/>
+ <enum value="133" name="VK_FORMAT_BC1_RGBA_UNORM_BLOCK"/>
+ <enum value="134" name="VK_FORMAT_BC1_RGBA_SRGB_BLOCK"/>
+ <enum value="135" name="VK_FORMAT_BC2_UNORM_BLOCK"/>
+ <enum value="136" name="VK_FORMAT_BC2_SRGB_BLOCK"/>
+ <enum value="137" name="VK_FORMAT_BC3_UNORM_BLOCK"/>
+ <enum value="138" name="VK_FORMAT_BC3_SRGB_BLOCK"/>
+ <enum value="139" name="VK_FORMAT_BC4_UNORM_BLOCK"/>
+ <enum value="140" name="VK_FORMAT_BC4_SNORM_BLOCK"/>
+ <enum value="141" name="VK_FORMAT_BC5_UNORM_BLOCK"/>
+ <enum value="142" name="VK_FORMAT_BC5_SNORM_BLOCK"/>
+ <enum value="143" name="VK_FORMAT_BC6H_UFLOAT_BLOCK"/>
+ <enum value="144" name="VK_FORMAT_BC6H_SFLOAT_BLOCK"/>
+ <enum value="145" name="VK_FORMAT_BC7_UNORM_BLOCK"/>
+ <enum value="146" name="VK_FORMAT_BC7_SRGB_BLOCK"/>
+ <enum value="147" name="VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK"/>
+ <enum value="148" name="VK_FORMAT_ETC2_R8G8B8_SRGB_BLOCK"/>
+ <enum value="149" name="VK_FORMAT_ETC2_R8G8B8A1_UNORM_BLOCK"/>
+ <enum value="150" name="VK_FORMAT_ETC2_R8G8B8A1_SRGB_BLOCK"/>
+ <enum value="151" name="VK_FORMAT_ETC2_R8G8B8A8_UNORM_BLOCK"/>
+ <enum value="152" name="VK_FORMAT_ETC2_R8G8B8A8_SRGB_BLOCK"/>
+ <enum value="153" name="VK_FORMAT_EAC_R11_UNORM_BLOCK"/>
+ <enum value="154" name="VK_FORMAT_EAC_R11_SNORM_BLOCK"/>
+ <enum value="155" name="VK_FORMAT_EAC_R11G11_UNORM_BLOCK"/>
+ <enum value="156" name="VK_FORMAT_EAC_R11G11_SNORM_BLOCK"/>
+ <enum value="157" name="VK_FORMAT_ASTC_4x4_UNORM_BLOCK"/>
+ <enum value="158" name="VK_FORMAT_ASTC_4x4_SRGB_BLOCK"/>
+ <enum value="159" name="VK_FORMAT_ASTC_5x4_UNORM_BLOCK"/>
+ <enum value="160" name="VK_FORMAT_ASTC_5x4_SRGB_BLOCK"/>
+ <enum value="161" name="VK_FORMAT_ASTC_5x5_UNORM_BLOCK"/>
+ <enum value="162" name="VK_FORMAT_ASTC_5x5_SRGB_BLOCK"/>
+ <enum value="163" name="VK_FORMAT_ASTC_6x5_UNORM_BLOCK"/>
+ <enum value="164" name="VK_FORMAT_ASTC_6x5_SRGB_BLOCK"/>
+ <enum value="165" name="VK_FORMAT_ASTC_6x6_UNORM_BLOCK"/>
+ <enum value="166" name="VK_FORMAT_ASTC_6x6_SRGB_BLOCK"/>
+ <enum value="167" name="VK_FORMAT_ASTC_8x5_UNORM_BLOCK"/>
+ <enum value="168" name="VK_FORMAT_ASTC_8x5_SRGB_BLOCK"/>
+ <enum value="169" name="VK_FORMAT_ASTC_8x6_UNORM_BLOCK"/>
+ <enum value="170" name="VK_FORMAT_ASTC_8x6_SRGB_BLOCK"/>
+ <enum value="171" name="VK_FORMAT_ASTC_8x8_UNORM_BLOCK"/>
+ <enum value="172" name="VK_FORMAT_ASTC_8x8_SRGB_BLOCK"/>
+ <enum value="173" name="VK_FORMAT_ASTC_10x5_UNORM_BLOCK"/>
+ <enum value="174" name="VK_FORMAT_ASTC_10x5_SRGB_BLOCK"/>
+ <enum value="175" name="VK_FORMAT_ASTC_10x6_UNORM_BLOCK"/>
+ <enum value="176" name="VK_FORMAT_ASTC_10x6_SRGB_BLOCK"/>
+ <enum value="177" name="VK_FORMAT_ASTC_10x8_UNORM_BLOCK"/>
+ <enum value="178" name="VK_FORMAT_ASTC_10x8_SRGB_BLOCK"/>
+ <enum value="179" name="VK_FORMAT_ASTC_10x10_UNORM_BLOCK"/>
+ <enum value="180" name="VK_FORMAT_ASTC_10x10_SRGB_BLOCK"/>
+ <enum value="181" name="VK_FORMAT_ASTC_12x10_UNORM_BLOCK"/>
+ <enum value="182" name="VK_FORMAT_ASTC_12x10_SRGB_BLOCK"/>
+ <enum value="183" name="VK_FORMAT_ASTC_12x12_UNORM_BLOCK"/>
+ <enum value="184" name="VK_FORMAT_ASTC_12x12_SRGB_BLOCK"/>
+ </enums>
+ <enums name="VkStructureType" type="enum" comment="Structure type enumerant">
+ <enum value="0" name="VK_STRUCTURE_TYPE_APPLICATION_INFO"/>
+ <enum value="1" name="VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO"/>
+ <enum value="2" name="VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO"/>
+ <enum value="3" name="VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO"/>
+ <enum value="4" name="VK_STRUCTURE_TYPE_SUBMIT_INFO"/>
+ <enum value="5" name="VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO"/>
+ <enum value="6" name="VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE"/>
+ <enum value="7" name="VK_STRUCTURE_TYPE_BIND_SPARSE_INFO"/>
+ <enum value="8" name="VK_STRUCTURE_TYPE_FENCE_CREATE_INFO"/>
+ <enum value="9" name="VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO"/>
+ <enum value="10" name="VK_STRUCTURE_TYPE_EVENT_CREATE_INFO"/>
+ <enum value="11" name="VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO"/>
+ <enum value="12" name="VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO"/>
+ <enum value="13" name="VK_STRUCTURE_TYPE_BUFFER_VIEW_CREATE_INFO"/>
+ <enum value="14" name="VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO"/>
+ <enum value="15" name="VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO"/>
+ <enum value="16" name="VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO"/>
+ <enum value="17" name="VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO"/>
+ <enum value="18" name="VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO"/>
+ <enum value="19" name="VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO"/>
+ <enum value="20" name="VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO"/>
+ <enum value="21" name="VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_STATE_CREATE_INFO"/>
+ <enum value="22" name="VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO"/>
+ <enum value="23" name="VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO"/>
+ <enum value="24" name="VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO"/>
+ <enum value="25" name="VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO"/>
+ <enum value="26" name="VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO"/>
+ <enum value="27" name="VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO"/>
+ <enum value="28" name="VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO"/>
+ <enum value="29" name="VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO"/>
+ <enum value="30" name="VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO"/>
+ <enum value="31" name="VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO"/>
+ <enum value="32" name="VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO"/>
+ <enum value="33" name="VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO"/>
+ <enum value="34" name="VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO"/>
+ <enum value="35" name="VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET"/>
+ <enum value="36" name="VK_STRUCTURE_TYPE_COPY_DESCRIPTOR_SET"/>
+ <enum value="37" name="VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO"/>
+ <enum value="38" name="VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO"/>
+ <enum value="39" name="VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO"/>
+ <enum value="40" name="VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO"/>
+ <enum value="41" name="VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO"/>
+ <enum value="42" name="VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO"/>
+ <enum value="43" name="VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO"/>
+ <enum value="44" name="VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER"/>
+ <enum value="45" name="VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER"/>
+ <enum value="46" name="VK_STRUCTURE_TYPE_MEMORY_BARRIER"/>
+ <enum value="47" name="VK_STRUCTURE_TYPE_LOADER_INSTANCE_CREATE_INFO" comment="Reserved for internal use by the loader, layers, and ICDs"/>
+ <enum value="48" name="VK_STRUCTURE_TYPE_LOADER_DEVICE_CREATE_INFO" comment="Reserved for internal use by the loader, layers, and ICDs"/>
+ </enums>
+ <enums name="VkSubpassContents" type="enum">
+ <enum value="0" name="VK_SUBPASS_CONTENTS_INLINE"/>
+ <enum value="1" name="VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS"/>
+ </enums>
+ <enums name="VkResult" type="enum" comment="API result codes">
+ <comment>Return codes (positive values)</comment>
+ <enum value="0" name="VK_SUCCESS" comment="Command completed successfully"/>
+ <enum value="1" name="VK_NOT_READY" comment="A fence or query has not yet completed"/>
+ <enum value="2" name="VK_TIMEOUT" comment="A wait operation has not completed in the specified time"/>
+ <enum value="3" name="VK_EVENT_SET" comment="An event is signaled"/>
+ <enum value="4" name="VK_EVENT_RESET" comment="An event is unsignaled"/>
+ <enum value="5" name="VK_INCOMPLETE" comment="A return array was too small for the result"/>
+ <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="-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"/>
+ <enum value="-7" name="VK_ERROR_EXTENSION_NOT_PRESENT" comment="Extension specified does not exist"/>
+ <enum value="-8" name="VK_ERROR_FEATURE_NOT_PRESENT" comment="Requested feature is not available on this device"/>
+ <enum value="-9" name="VK_ERROR_INCOMPATIBLE_DRIVER" comment="Unable to find a Vulkan driver"/>
+ <enum value="-10" name="VK_ERROR_TOO_MANY_OBJECTS" comment="Too many objects of the type have already been created"/>
+ <enum value="-11" name="VK_ERROR_FORMAT_NOT_SUPPORTED" comment="Requested format is not supported on this device"/>
+ <enum value="-12" name="VK_ERROR_FRAGMENTED_POOL" comment="A requested pool allocation has failed due to fragmentation of the pool's memory"/>
+ <enum value="-13" name="VK_ERROR_UNKNOWN" comment="An unknown error has occurred, due to an implementation or application bug"/>
+ <unused start="-14" comment="This is the next unused available error code (negative value)"/>
+ </enums>
+ <enums name="VkDynamicState" type="enum">
+ <enum value="0" name="VK_DYNAMIC_STATE_VIEWPORT"/>
+ <enum value="1" name="VK_DYNAMIC_STATE_SCISSOR"/>
+ <enum value="2" name="VK_DYNAMIC_STATE_LINE_WIDTH"/>
+ <enum value="3" name="VK_DYNAMIC_STATE_DEPTH_BIAS"/>
+ <enum value="4" name="VK_DYNAMIC_STATE_BLEND_CONSTANTS"/>
+ <enum value="5" name="VK_DYNAMIC_STATE_DEPTH_BOUNDS"/>
+ <enum value="6" name="VK_DYNAMIC_STATE_STENCIL_COMPARE_MASK"/>
+ <enum value="7" name="VK_DYNAMIC_STATE_STENCIL_WRITE_MASK"/>
+ <enum value="8" name="VK_DYNAMIC_STATE_STENCIL_REFERENCE"/>
+ </enums>
+ <enums name="VkDescriptorUpdateTemplateType" type="enum">
+ <enum value="0" name="VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_DESCRIPTOR_SET" comment="Create descriptor update template for descriptor set updates"/>
+ </enums>
+ <enums name="VkObjectType" type="enum" comment="Enums to track objects of various types - also see objtypeenum attributes on type tags">
+ <enum value="0" name="VK_OBJECT_TYPE_UNKNOWN"/>
+ <enum value="1" name="VK_OBJECT_TYPE_INSTANCE"/>
+ <enum value="2" name="VK_OBJECT_TYPE_PHYSICAL_DEVICE"/>
+ <enum value="3" name="VK_OBJECT_TYPE_DEVICE"/>
+ <enum value="4" name="VK_OBJECT_TYPE_QUEUE"/>
+ <enum value="5" name="VK_OBJECT_TYPE_SEMAPHORE"/>
+ <enum value="6" name="VK_OBJECT_TYPE_COMMAND_BUFFER"/>
+ <enum value="7" name="VK_OBJECT_TYPE_FENCE"/>
+ <enum value="8" name="VK_OBJECT_TYPE_DEVICE_MEMORY"/>
+ <enum value="9" name="VK_OBJECT_TYPE_BUFFER"/>
+ <enum value="10" name="VK_OBJECT_TYPE_IMAGE"/>
+ <enum value="11" name="VK_OBJECT_TYPE_EVENT"/>
+ <enum value="12" name="VK_OBJECT_TYPE_QUERY_POOL"/>
+ <enum value="13" name="VK_OBJECT_TYPE_BUFFER_VIEW"/>
+ <enum value="14" name="VK_OBJECT_TYPE_IMAGE_VIEW"/>
+ <enum value="15" name="VK_OBJECT_TYPE_SHADER_MODULE"/>
+ <enum value="16" name="VK_OBJECT_TYPE_PIPELINE_CACHE"/>
+ <enum value="17" name="VK_OBJECT_TYPE_PIPELINE_LAYOUT"/>
+ <enum value="18" name="VK_OBJECT_TYPE_RENDER_PASS"/>
+ <enum value="19" name="VK_OBJECT_TYPE_PIPELINE"/>
+ <enum value="20" name="VK_OBJECT_TYPE_DESCRIPTOR_SET_LAYOUT"/>
+ <enum value="21" name="VK_OBJECT_TYPE_SAMPLER"/>
+ <enum value="22" name="VK_OBJECT_TYPE_DESCRIPTOR_POOL"/>
+ <enum value="23" name="VK_OBJECT_TYPE_DESCRIPTOR_SET"/>
+ <enum value="24" name="VK_OBJECT_TYPE_FRAMEBUFFER"/>
+ <enum value="25" name="VK_OBJECT_TYPE_COMMAND_POOL"/>
+ </enums>
+
+ <comment>Flags</comment>
+ <enums name="VkQueueFlagBits" type="bitmask">
+ <enum bitpos="0" name="VK_QUEUE_GRAPHICS_BIT" comment="Queue supports graphics operations"/>
+ <enum bitpos="1" name="VK_QUEUE_COMPUTE_BIT" comment="Queue supports compute operations"/>
+ <enum bitpos="2" name="VK_QUEUE_TRANSFER_BIT" comment="Queue supports transfer operations"/>
+ <enum bitpos="3" name="VK_QUEUE_SPARSE_BINDING_BIT" comment="Queue supports sparse resource memory management operations"/>
+ </enums>
+ <enums name="VkCullModeFlagBits" type="bitmask">
+ <enum value="0" name="VK_CULL_MODE_NONE"/>
+ <enum bitpos="0" name="VK_CULL_MODE_FRONT_BIT"/>
+ <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="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"/>
+ <enum bitpos="2" name="VK_MEMORY_PROPERTY_HOST_COHERENT_BIT" comment="Memory will have i/o coherency. If not set, application may need to use vkFlushMappedMemoryRanges and vkInvalidateMappedMemoryRanges to flush/invalidate host cache"/>
+ <enum bitpos="3" name="VK_MEMORY_PROPERTY_HOST_CACHED_BIT" comment="Memory will be cached by the host"/>
+ <enum bitpos="4" name="VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT" comment="Memory may be allocated by the driver when it is required"/>
+ </enums>
+ <enums name="VkMemoryHeapFlagBits" type="bitmask">
+ <enum bitpos="0" name="VK_MEMORY_HEAP_DEVICE_LOCAL_BIT" comment="If set, heap represents device memory"/>
+ </enums>
+ <enums name="VkAccessFlagBits" type="bitmask">
+ <enum bitpos="0" name="VK_ACCESS_INDIRECT_COMMAND_READ_BIT" comment="Controls coherency of indirect command reads"/>
+ <enum bitpos="1" name="VK_ACCESS_INDEX_READ_BIT" comment="Controls coherency of index reads"/>
+ <enum bitpos="2" name="VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT" comment="Controls coherency of vertex attribute reads"/>
+ <enum bitpos="3" name="VK_ACCESS_UNIFORM_READ_BIT" comment="Controls coherency of uniform buffer reads"/>
+ <enum bitpos="4" name="VK_ACCESS_INPUT_ATTACHMENT_READ_BIT" comment="Controls coherency of input attachment reads"/>
+ <enum bitpos="5" name="VK_ACCESS_SHADER_READ_BIT" comment="Controls coherency of shader reads"/>
+ <enum bitpos="6" name="VK_ACCESS_SHADER_WRITE_BIT" comment="Controls coherency of shader writes"/>
+ <enum bitpos="7" name="VK_ACCESS_COLOR_ATTACHMENT_READ_BIT" comment="Controls coherency of color attachment reads"/>
+ <enum bitpos="8" name="VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT" comment="Controls coherency of color attachment writes"/>
+ <enum bitpos="9" name="VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT" comment="Controls coherency of depth/stencil attachment reads"/>
+ <enum bitpos="10" name="VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT" comment="Controls coherency of depth/stencil attachment writes"/>
+ <enum bitpos="11" name="VK_ACCESS_TRANSFER_READ_BIT" comment="Controls coherency of transfer reads"/>
+ <enum bitpos="12" name="VK_ACCESS_TRANSFER_WRITE_BIT" comment="Controls coherency of transfer writes"/>
+ <enum bitpos="13" name="VK_ACCESS_HOST_READ_BIT" comment="Controls coherency of host reads"/>
+ <enum bitpos="14" name="VK_ACCESS_HOST_WRITE_BIT" comment="Controls coherency of host writes"/>
+ <enum bitpos="15" name="VK_ACCESS_MEMORY_READ_BIT" comment="Controls coherency of memory reads"/>
+ <enum bitpos="16" name="VK_ACCESS_MEMORY_WRITE_BIT" comment="Controls coherency of memory writes"/>
+ </enums>
+ <enums name="VkBufferUsageFlagBits" type="bitmask">
+ <enum bitpos="0" name="VK_BUFFER_USAGE_TRANSFER_SRC_BIT" comment="Can be used as a source of transfer operations"/>
+ <enum bitpos="1" name="VK_BUFFER_USAGE_TRANSFER_DST_BIT" comment="Can be used as a destination of transfer operations"/>
+ <enum bitpos="2" name="VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT" comment="Can be used as TBO"/>
+ <enum bitpos="3" name="VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT" comment="Can be used as IBO"/>
+ <enum bitpos="4" name="VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT" comment="Can be used as UBO"/>
+ <enum bitpos="5" name="VK_BUFFER_USAGE_STORAGE_BUFFER_BIT" comment="Can be used as SSBO"/>
+ <enum bitpos="6" name="VK_BUFFER_USAGE_INDEX_BUFFER_BIT" comment="Can be used as source of fixed-function index fetch (index buffer)"/>
+ <enum bitpos="7" name="VK_BUFFER_USAGE_VERTEX_BUFFER_BIT" comment="Can be used as source of fixed-function vertex fetch (VBO)"/>
+ <enum bitpos="8" name="VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT" comment="Can be the source of indirect parameters (e.g. indirect buffer, parameter buffer)"/>
+ </enums>
+ <enums name="VkBufferCreateFlagBits" type="bitmask">
+ <enum bitpos="0" name="VK_BUFFER_CREATE_SPARSE_BINDING_BIT" comment="Buffer should support sparse backing"/>
+ <enum bitpos="1" name="VK_BUFFER_CREATE_SPARSE_RESIDENCY_BIT" comment="Buffer should support sparse backing with partial residency"/>
+ <enum bitpos="2" name="VK_BUFFER_CREATE_SPARSE_ALIASED_BIT" comment="Buffer should support constant data access to physical memory ranges mapped into multiple locations of sparse buffers"/>
+ </enums>
+ <enums name="VkShaderStageFlagBits" type="bitmask">
+ <enum bitpos="0" name="VK_SHADER_STAGE_VERTEX_BIT"/>
+ <enum bitpos="1" name="VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT"/>
+ <enum bitpos="2" name="VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT"/>
+ <enum bitpos="3" name="VK_SHADER_STAGE_GEOMETRY_BIT"/>
+ <enum bitpos="4" name="VK_SHADER_STAGE_FRAGMENT_BIT"/>
+ <enum bitpos="5" name="VK_SHADER_STAGE_COMPUTE_BIT"/>
+ <enum value="0x0000001F" name="VK_SHADER_STAGE_ALL_GRAPHICS"/>
+ <enum value="0x7FFFFFFF" name="VK_SHADER_STAGE_ALL"/>
+ </enums>
+ <enums name="VkImageUsageFlagBits" type="bitmask">
+ <enum bitpos="0" name="VK_IMAGE_USAGE_TRANSFER_SRC_BIT" comment="Can be used as a source of transfer operations"/>
+ <enum bitpos="1" name="VK_IMAGE_USAGE_TRANSFER_DST_BIT" comment="Can be used as a destination of transfer operations"/>
+ <enum bitpos="2" name="VK_IMAGE_USAGE_SAMPLED_BIT" comment="Can be sampled from (SAMPLED_IMAGE and COMBINED_IMAGE_SAMPLER descriptor types)"/>
+ <enum bitpos="3" name="VK_IMAGE_USAGE_STORAGE_BIT" comment="Can be used as storage image (STORAGE_IMAGE descriptor type)"/>
+ <enum bitpos="4" name="VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT" comment="Can be used as framebuffer color attachment"/>
+ <enum bitpos="5" name="VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT" comment="Can be used as framebuffer depth/stencil attachment"/>
+ <enum bitpos="6" name="VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT" comment="Image data not needed outside of rendering"/>
+ <enum bitpos="7" name="VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT" comment="Can be used as framebuffer input attachment"/>
+ </enums>
+ <enums name="VkImageCreateFlagBits" type="bitmask">
+ <enum bitpos="0" name="VK_IMAGE_CREATE_SPARSE_BINDING_BIT" comment="Image should support sparse backing"/>
+ <enum bitpos="1" name="VK_IMAGE_CREATE_SPARSE_RESIDENCY_BIT" comment="Image should support sparse backing with partial residency"/>
+ <enum bitpos="2" name="VK_IMAGE_CREATE_SPARSE_ALIASED_BIT" comment="Image should support constant data access to physical memory ranges mapped into multiple locations of sparse images"/>
+ <enum bitpos="3" name="VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT" comment="Allows image views to have different format than the base image"/>
+ <enum bitpos="4" name="VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT" comment="Allows creating image views with cube type from the created image"/>
+ </enums>
+ <enums name="VkImageViewCreateFlagBits" type="bitmask">
+ </enums>
+ <enums name="VkSamplerCreateFlagBits" type="bitmask">
+ </enums>
+ <enums name="VkPipelineCreateFlagBits" type="bitmask" comment="Note that the gap at bitpos 10 is unused, and can be reserved">
+ <enum bitpos="0" name="VK_PIPELINE_CREATE_DISABLE_OPTIMIZATION_BIT"/>
+ <enum bitpos="1" name="VK_PIPELINE_CREATE_ALLOW_DERIVATIVES_BIT"/>
+ <enum bitpos="2" name="VK_PIPELINE_CREATE_DERIVATIVE_BIT"/>
+ </enums>
+ <enums name="VkPipelineShaderStageCreateFlagBits" type="bitmask">
+ </enums>
+ <enums name="VkColorComponentFlagBits" type="bitmask">
+ <enum bitpos="0" name="VK_COLOR_COMPONENT_R_BIT"/>
+ <enum bitpos="1" name="VK_COLOR_COMPONENT_G_BIT"/>
+ <enum bitpos="2" name="VK_COLOR_COMPONENT_B_BIT"/>
+ <enum bitpos="3" name="VK_COLOR_COMPONENT_A_BIT"/>
+ </enums>
+ <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="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)"/>
+ <enum bitpos="2" name="VK_FORMAT_FEATURE_STORAGE_IMAGE_ATOMIC_BIT" comment="Format supports atomic operations in case it is used for storage images"/>
+ <enum bitpos="3" name="VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT" comment="Format can be used for uniform texel buffers (TBOs)"/>
+ <enum bitpos="4" name="VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT" comment="Format can be used for storage texel buffers (IBOs)"/>
+ <enum bitpos="5" name="VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_ATOMIC_BIT" comment="Format supports atomic operations in case it is used for storage texel buffers"/>
+ <enum bitpos="6" name="VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT" comment="Format can be used for vertex buffers (VBOs)"/>
+ <enum bitpos="7" name="VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT" comment="Format can be used for color attachment images"/>
+ <enum bitpos="8" name="VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT" comment="Format supports blending in case it is used for color attachment images"/>
+ <enum bitpos="9" name="VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT" comment="Format can be used for depth/stencil attachment images"/>
+ <enum bitpos="10" name="VK_FORMAT_FEATURE_BLIT_SRC_BIT" comment="Format can be used as the source image of blits with vkCmdBlitImage"/>
+ <enum bitpos="11" name="VK_FORMAT_FEATURE_BLIT_DST_BIT" comment="Format can be used as the destination image of blits with vkCmdBlitImage"/>
+ <enum bitpos="12" name="VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT" comment="Format can be filtered with VK_FILTER_LINEAR when being sampled"/>
+ </enums>
+ <enums name="VkQueryControlFlagBits" type="bitmask">
+ <enum bitpos="0" name="VK_QUERY_CONTROL_PRECISE_BIT" comment="Require precise results to be collected by the query"/>
+ </enums>
+ <enums name="VkQueryResultFlagBits" type="bitmask">
+ <enum bitpos="0" name="VK_QUERY_RESULT_64_BIT" comment="Results of the queries are written to the destination buffer as 64-bit values"/>
+ <enum bitpos="1" name="VK_QUERY_RESULT_WAIT_BIT" comment="Results of the queries are waited on before proceeding with the result copy"/>
+ <enum bitpos="2" name="VK_QUERY_RESULT_WITH_AVAILABILITY_BIT" comment="Besides the results of the query, the availability of the results is also written"/>
+ <enum bitpos="3" name="VK_QUERY_RESULT_PARTIAL_BIT" comment="Copy the partial results of the query even if the final results are not available"/>
+ </enums>
+ <enums name="VkCommandBufferUsageFlagBits" type="bitmask">
+ <enum bitpos="0" name="VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT"/>
+ <enum bitpos="1" name="VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT"/>
+ <enum bitpos="2" name="VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT" comment="Command buffer may be submitted/executed more than once simultaneously"/>
+ </enums>
+ <enums name="VkQueryPipelineStatisticFlagBits" type="bitmask">
+ <enum bitpos="0" name="VK_QUERY_PIPELINE_STATISTIC_INPUT_ASSEMBLY_VERTICES_BIT" comment="Optional"/>
+ <enum bitpos="1" name="VK_QUERY_PIPELINE_STATISTIC_INPUT_ASSEMBLY_PRIMITIVES_BIT" comment="Optional"/>
+ <enum bitpos="2" name="VK_QUERY_PIPELINE_STATISTIC_VERTEX_SHADER_INVOCATIONS_BIT" comment="Optional"/>
+ <enum bitpos="3" name="VK_QUERY_PIPELINE_STATISTIC_GEOMETRY_SHADER_INVOCATIONS_BIT" comment="Optional"/>
+ <enum bitpos="4" name="VK_QUERY_PIPELINE_STATISTIC_GEOMETRY_SHADER_PRIMITIVES_BIT" comment="Optional"/>
+ <enum bitpos="5" name="VK_QUERY_PIPELINE_STATISTIC_CLIPPING_INVOCATIONS_BIT" comment="Optional"/>
+ <enum bitpos="6" name="VK_QUERY_PIPELINE_STATISTIC_CLIPPING_PRIMITIVES_BIT" comment="Optional"/>
+ <enum bitpos="7" name="VK_QUERY_PIPELINE_STATISTIC_FRAGMENT_SHADER_INVOCATIONS_BIT" comment="Optional"/>
+ <enum bitpos="8" name="VK_QUERY_PIPELINE_STATISTIC_TESSELLATION_CONTROL_SHADER_PATCHES_BIT" comment="Optional"/>
+ <enum bitpos="9" name="VK_QUERY_PIPELINE_STATISTIC_TESSELLATION_EVALUATION_SHADER_INVOCATIONS_BIT" comment="Optional"/>
+ <enum bitpos="10" name="VK_QUERY_PIPELINE_STATISTIC_COMPUTE_SHADER_INVOCATIONS_BIT" comment="Optional"/>
+ </enums>
+ <enums name="VkImageAspectFlagBits" type="bitmask">
+ <enum bitpos="0" name="VK_IMAGE_ASPECT_COLOR_BIT"/>
+ <enum bitpos="1" name="VK_IMAGE_ASPECT_DEPTH_BIT"/>
+ <enum bitpos="2" name="VK_IMAGE_ASPECT_STENCIL_BIT"/>
+ <enum bitpos="3" name="VK_IMAGE_ASPECT_METADATA_BIT"/>
+ </enums>
+ <enums name="VkSparseImageFormatFlagBits" type="bitmask">
+ <enum bitpos="0" name="VK_SPARSE_IMAGE_FORMAT_SINGLE_MIPTAIL_BIT" comment="Image uses a single mip tail region for all array layers"/>
+ <enum bitpos="1" name="VK_SPARSE_IMAGE_FORMAT_ALIGNED_MIP_SIZE_BIT" comment="Image requires mip level dimensions to be an integer multiple of the sparse image block dimensions for non-tail mip levels."/>
+ <enum bitpos="2" name="VK_SPARSE_IMAGE_FORMAT_NONSTANDARD_BLOCK_SIZE_BIT" comment="Image uses a non-standard sparse image block dimensions"/>
+ </enums>
+ <enums name="VkSparseMemoryBindFlagBits" type="bitmask">
+ <enum bitpos="0" name="VK_SPARSE_MEMORY_BIND_METADATA_BIT" comment="Operation binds resource metadata to memory"/>
+ </enums>
+ <enums name="VkPipelineStageFlagBits" type="bitmask">
+ <enum bitpos="0" name="VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT" comment="Before subsequent commands are processed"/>
+ <enum bitpos="1" name="VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT" comment="Draw/DispatchIndirect command fetch"/>
+ <enum bitpos="2" name="VK_PIPELINE_STAGE_VERTEX_INPUT_BIT" comment="Vertex/index fetch"/>
+ <enum bitpos="3" name="VK_PIPELINE_STAGE_VERTEX_SHADER_BIT" comment="Vertex shading"/>
+ <enum bitpos="4" name="VK_PIPELINE_STAGE_TESSELLATION_CONTROL_SHADER_BIT" comment="Tessellation control shading"/>
+ <enum bitpos="5" name="VK_PIPELINE_STAGE_TESSELLATION_EVALUATION_SHADER_BIT" comment="Tessellation evaluation shading"/>
+ <enum bitpos="6" name="VK_PIPELINE_STAGE_GEOMETRY_SHADER_BIT" comment="Geometry shading"/>
+ <enum bitpos="7" name="VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT" comment="Fragment shading"/>
+ <enum bitpos="8" name="VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT" comment="Early fragment (depth and stencil) tests"/>
+ <enum bitpos="9" name="VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT" comment="Late fragment (depth and stencil) tests"/>
+ <enum bitpos="10" name="VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT" comment="Color attachment writes"/>
+ <enum bitpos="11" name="VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT" comment="Compute shading"/>
+ <enum bitpos="12" name="VK_PIPELINE_STAGE_TRANSFER_BIT" comment="Transfer/copy operations"/>
+ <enum bitpos="13" name="VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT" comment="After previous commands have completed"/>
+ <enum bitpos="14" name="VK_PIPELINE_STAGE_HOST_BIT" comment="Indicates host (CPU) is a source/sink of the dependency"/>
+ <enum bitpos="15" name="VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT" comment="All stages of the graphics pipeline"/>
+ <enum bitpos="16" name="VK_PIPELINE_STAGE_ALL_COMMANDS_BIT" comment="All stages supported on the queue"/>
+ </enums>
+ <enums name="VkCommandPoolCreateFlagBits" type="bitmask">
+ <enum bitpos="0" name="VK_COMMAND_POOL_CREATE_TRANSIENT_BIT" comment="Command buffers have a short lifetime"/>
+ <enum bitpos="1" name="VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT" comment="Command buffers may release their memory individually"/>
+ </enums>
+ <enums name="VkCommandPoolResetFlagBits" type="bitmask">
+ <enum bitpos="0" name="VK_COMMAND_POOL_RESET_RELEASE_RESOURCES_BIT" comment="Release resources owned by the pool"/>
+ </enums>
+ <enums name="VkCommandBufferResetFlagBits" type="bitmask">
+ <enum bitpos="0" name="VK_COMMAND_BUFFER_RESET_RELEASE_RESOURCES_BIT" comment="Release resources owned by the buffer"/>
+ </enums>
+ <enums name="VkSampleCountFlagBits" type="bitmask">
+ <enum bitpos="0" name="VK_SAMPLE_COUNT_1_BIT" comment="Sample count 1 supported"/>
+ <enum bitpos="1" name="VK_SAMPLE_COUNT_2_BIT" comment="Sample count 2 supported"/>
+ <enum bitpos="2" name="VK_SAMPLE_COUNT_4_BIT" comment="Sample count 4 supported"/>
+ <enum bitpos="3" name="VK_SAMPLE_COUNT_8_BIT" comment="Sample count 8 supported"/>
+ <enum bitpos="4" name="VK_SAMPLE_COUNT_16_BIT" comment="Sample count 16 supported"/>
+ <enum bitpos="5" name="VK_SAMPLE_COUNT_32_BIT" comment="Sample count 32 supported"/>
+ <enum bitpos="6" name="VK_SAMPLE_COUNT_64_BIT" comment="Sample count 64 supported"/>
+ </enums>
+ <enums name="VkAttachmentDescriptionFlagBits" type="bitmask">
+ <enum bitpos="0" name="VK_ATTACHMENT_DESCRIPTION_MAY_ALIAS_BIT" comment="The attachment may alias physical memory of another attachment in the same render pass"/>
+ </enums>
+ <enums name="VkStencilFaceFlagBits" type="bitmask">
+ <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"/>
+ </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"/>
+ </enums>
+ <enums name="VkDependencyFlagBits" type="bitmask">
+ <enum bitpos="0" name="VK_DEPENDENCY_BY_REGION_BIT" comment="Dependency is per pixel region "/>
+ </enums>
+ <enums name="VkSemaphoreType" type="enum">
+ <enum value="0" name="VK_SEMAPHORE_TYPE_BINARY"/>
+ <enum value="1" name="VK_SEMAPHORE_TYPE_TIMELINE"/>
+ </enums>
+ <enums name="VkSemaphoreWaitFlagBits" type="bitmask">
+ <enum bitpos="0" name="VK_SEMAPHORE_WAIT_ANY_BIT"/>
+ </enums>
+
+ <comment>WSI Extensions</comment>
+ <enums name="VkPresentModeKHR" type="enum">
+ <enum value="0" name="VK_PRESENT_MODE_IMMEDIATE_KHR"/>
+ <enum value="1" name="VK_PRESENT_MODE_MAILBOX_KHR"/>
+ <enum value="2" name="VK_PRESENT_MODE_FIFO_KHR"/>
+ <enum value="3" name="VK_PRESENT_MODE_FIFO_RELAXED_KHR"/>
+ </enums>
+ <enums name="VkColorSpaceKHR" type="enum">
+ <enum value="0" name="VK_COLOR_SPACE_SRGB_NONLINEAR_KHR"/>
+ <enum name="VK_COLORSPACE_SRGB_NONLINEAR_KHR" alias="VK_COLOR_SPACE_SRGB_NONLINEAR_KHR" comment="Backwards-compatible alias containing a typo"/>
+ </enums>
+ <enums name="VkDisplayPlaneAlphaFlagBitsKHR" type="bitmask">
+ <enum bitpos="0" name="VK_DISPLAY_PLANE_ALPHA_OPAQUE_BIT_KHR"/>
+ <enum bitpos="1" name="VK_DISPLAY_PLANE_ALPHA_GLOBAL_BIT_KHR"/>
+ <enum bitpos="2" name="VK_DISPLAY_PLANE_ALPHA_PER_PIXEL_BIT_KHR"/>
+ <enum bitpos="3" name="VK_DISPLAY_PLANE_ALPHA_PER_PIXEL_PREMULTIPLIED_BIT_KHR"/>
+ </enums>
+ <enums name="VkCompositeAlphaFlagBitsKHR" type="bitmask">
+ <enum bitpos="0" name="VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR"/>
+ <enum bitpos="1" name="VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR"/>
+ <enum bitpos="2" name="VK_COMPOSITE_ALPHA_POST_MULTIPLIED_BIT_KHR"/>
+ <enum bitpos="3" name="VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR"/>
+ </enums>
+ <enums name="VkSurfaceTransformFlagBitsKHR" type="bitmask">
+ <enum bitpos="0" name="VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR"/>
+ <enum bitpos="1" name="VK_SURFACE_TRANSFORM_ROTATE_90_BIT_KHR"/>
+ <enum bitpos="2" name="VK_SURFACE_TRANSFORM_ROTATE_180_BIT_KHR"/>
+ <enum bitpos="3" name="VK_SURFACE_TRANSFORM_ROTATE_270_BIT_KHR"/>
+ <enum bitpos="4" name="VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_BIT_KHR"/>
+ <enum bitpos="5" name="VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_90_BIT_KHR"/>
+ <enum bitpos="6" name="VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_180_BIT_KHR"/>
+ <enum bitpos="7" name="VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_270_BIT_KHR"/>
+ <enum bitpos="8" name="VK_SURFACE_TRANSFORM_INHERIT_BIT_KHR"/>
+ </enums>
+ <enums name="VkSwapchainImageUsageFlagBitsANDROID" type="bitmask">
+ <enum bitpos="0" name="VK_SWAPCHAIN_IMAGE_USAGE_SHARED_BIT_ANDROID"/>
+ </enums>
+ <enums name="VkTimeDomainEXT" type="enum">
+ <enum value="0" name="VK_TIME_DOMAIN_DEVICE_EXT"/>
+ <enum value="1" name="VK_TIME_DOMAIN_CLOCK_MONOTONIC_EXT"/>
+ <enum value="2" name="VK_TIME_DOMAIN_CLOCK_MONOTONIC_RAW_EXT"/>
+ <enum value="3" name="VK_TIME_DOMAIN_QUERY_PERFORMANCE_COUNTER_EXT"/>
+ </enums>
+ <enums name="VkDebugReportFlagBitsEXT" type="bitmask">
+ <enum bitpos="0" name="VK_DEBUG_REPORT_INFORMATION_BIT_EXT"/>
+ <enum bitpos="1" name="VK_DEBUG_REPORT_WARNING_BIT_EXT"/>
+ <enum bitpos="2" name="VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT"/>
+ <enum bitpos="3" name="VK_DEBUG_REPORT_ERROR_BIT_EXT"/>
+ <enum bitpos="4" name="VK_DEBUG_REPORT_DEBUG_BIT_EXT"/>
+ </enums>
+ <enums name="VkDebugReportObjectTypeEXT" type="enum">
+ <enum value="0" name="VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT"/>
+ <enum value="1" name="VK_DEBUG_REPORT_OBJECT_TYPE_INSTANCE_EXT"/>
+ <enum value="2" name="VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT"/>
+ <enum value="3" name="VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT"/>
+ <enum value="4" name="VK_DEBUG_REPORT_OBJECT_TYPE_QUEUE_EXT"/>
+ <enum value="5" name="VK_DEBUG_REPORT_OBJECT_TYPE_SEMAPHORE_EXT"/>
+ <enum value="6" name="VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT"/>
+ <enum value="7" name="VK_DEBUG_REPORT_OBJECT_TYPE_FENCE_EXT"/>
+ <enum value="8" name="VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT"/>
+ <enum value="9" name="VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT"/>
+ <enum value="10" name="VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT"/>
+ <enum value="11" name="VK_DEBUG_REPORT_OBJECT_TYPE_EVENT_EXT"/>
+ <enum value="12" name="VK_DEBUG_REPORT_OBJECT_TYPE_QUERY_POOL_EXT"/>
+ <enum value="13" name="VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_VIEW_EXT"/>
+ <enum value="14" name="VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_VIEW_EXT"/>
+ <enum value="15" name="VK_DEBUG_REPORT_OBJECT_TYPE_SHADER_MODULE_EXT"/>
+ <enum value="16" name="VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_CACHE_EXT"/>
+ <enum value="17" name="VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_LAYOUT_EXT"/>
+ <enum value="18" name="VK_DEBUG_REPORT_OBJECT_TYPE_RENDER_PASS_EXT"/>
+ <enum value="19" name="VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT"/>
+ <enum value="20" name="VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_LAYOUT_EXT"/>
+ <enum value="21" name="VK_DEBUG_REPORT_OBJECT_TYPE_SAMPLER_EXT"/>
+ <enum value="22" name="VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_POOL_EXT"/>
+ <enum value="23" name="VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT"/>
+ <enum value="24" name="VK_DEBUG_REPORT_OBJECT_TYPE_FRAMEBUFFER_EXT"/>
+ <enum value="25" name="VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_POOL_EXT"/>
+ <enum value="26" name="VK_DEBUG_REPORT_OBJECT_TYPE_SURFACE_KHR_EXT"/>
+ <enum value="27" name="VK_DEBUG_REPORT_OBJECT_TYPE_SWAPCHAIN_KHR_EXT"/>
+ <enum value="28" name="VK_DEBUG_REPORT_OBJECT_TYPE_DEBUG_REPORT_CALLBACK_EXT_EXT"/>
+ <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"/>-->
+ <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>
+ <enums name="VkDeviceMemoryReportEventTypeEXT" type="enum">
+ <enum value="0" name="VK_DEVICE_MEMORY_REPORT_EVENT_TYPE_ALLOCATE_EXT"/>
+ <enum value="1" name="VK_DEVICE_MEMORY_REPORT_EVENT_TYPE_FREE_EXT"/>
+ <enum value="2" name="VK_DEVICE_MEMORY_REPORT_EVENT_TYPE_IMPORT_EXT"/>
+ <enum value="3" name="VK_DEVICE_MEMORY_REPORT_EVENT_TYPE_UNIMPORT_EXT"/>
+ <enum value="4" name="VK_DEVICE_MEMORY_REPORT_EVENT_TYPE_ALLOCATION_FAILED_EXT"/>
+ </enums>
+ <enums name="VkRasterizationOrderAMD" type="enum">
+ <enum value="0" name="VK_RASTERIZATION_ORDER_STRICT_AMD"/>
+ <enum value="1" name="VK_RASTERIZATION_ORDER_RELAXED_AMD"/>
+ </enums>
+ <enums name="VkExternalMemoryHandleTypeFlagBitsNV" type="bitmask">
+ <enum bitpos="0" name="VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT_NV"/>
+ <enum bitpos="1" name="VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT_NV"/>
+ <enum bitpos="2" name="VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_IMAGE_BIT_NV"/>
+ <enum bitpos="3" name="VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_IMAGE_KMT_BIT_NV"/>
+ </enums>
+ <enums name="VkExternalMemoryFeatureFlagBitsNV" type="bitmask">
+ <enum bitpos="0" name="VK_EXTERNAL_MEMORY_FEATURE_DEDICATED_ONLY_BIT_NV"/>
+ <enum bitpos="1" name="VK_EXTERNAL_MEMORY_FEATURE_EXPORTABLE_BIT_NV"/>
+ <enum bitpos="2" name="VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT_NV"/>
+ </enums>
+ <enums name="VkValidationCheckEXT" type="enum">
+ <enum value="0" name="VK_VALIDATION_CHECK_ALL_EXT"/>
+ <enum value="1" name="VK_VALIDATION_CHECK_SHADERS_EXT"/>
+ </enums>
+ <enums name="VkValidationFeatureEnableEXT" type="enum">
+ <enum value="0" name="VK_VALIDATION_FEATURE_ENABLE_GPU_ASSISTED_EXT"/>
+ <enum value="1" name="VK_VALIDATION_FEATURE_ENABLE_GPU_ASSISTED_RESERVE_BINDING_SLOT_EXT"/>
+ <enum value="2" name="VK_VALIDATION_FEATURE_ENABLE_BEST_PRACTICES_EXT"/>
+ <enum value="3" name="VK_VALIDATION_FEATURE_ENABLE_DEBUG_PRINTF_EXT"/>
+ <enum value="4" name="VK_VALIDATION_FEATURE_ENABLE_SYNCHRONIZATION_VALIDATION_EXT"/>
+ </enums>
+ <enums name="VkValidationFeatureDisableEXT" type="enum">
+ <enum value="0" name="VK_VALIDATION_FEATURE_DISABLE_ALL_EXT"/>
+ <enum value="1" name="VK_VALIDATION_FEATURE_DISABLE_SHADERS_EXT"/>
+ <enum value="2" name="VK_VALIDATION_FEATURE_DISABLE_THREAD_SAFETY_EXT"/>
+ <enum value="3" name="VK_VALIDATION_FEATURE_DISABLE_API_PARAMETERS_EXT"/>
+ <enum value="4" name="VK_VALIDATION_FEATURE_DISABLE_OBJECT_LIFETIMES_EXT"/>
+ <enum value="5" name="VK_VALIDATION_FEATURE_DISABLE_CORE_CHECKS_EXT"/>
+ <enum value="6" name="VK_VALIDATION_FEATURE_DISABLE_UNIQUE_HANDLES_EXT"/>
+ <enum value="7" name="VK_VALIDATION_FEATURE_DISABLE_SHADER_VALIDATION_CACHE_EXT"/>
+ </enums>
+ <enums name="VkSubgroupFeatureFlagBits" type="bitmask">
+ <enum bitpos="0" name="VK_SUBGROUP_FEATURE_BASIC_BIT" comment="Basic subgroup operations"/>
+ <enum bitpos="1" name="VK_SUBGROUP_FEATURE_VOTE_BIT" comment="Vote subgroup operations"/>
+ <enum bitpos="2" name="VK_SUBGROUP_FEATURE_ARITHMETIC_BIT" comment="Arithmetic subgroup operations"/>
+ <enum bitpos="3" name="VK_SUBGROUP_FEATURE_BALLOT_BIT" comment="Ballot subgroup operations"/>
+ <enum bitpos="4" name="VK_SUBGROUP_FEATURE_SHUFFLE_BIT" comment="Shuffle subgroup operations"/>
+ <enum bitpos="5" name="VK_SUBGROUP_FEATURE_SHUFFLE_RELATIVE_BIT" comment="Shuffle relative subgroup operations"/>
+ <enum bitpos="6" name="VK_SUBGROUP_FEATURE_CLUSTERED_BIT" comment="Clustered subgroup operations"/>
+ <enum bitpos="7" name="VK_SUBGROUP_FEATURE_QUAD_BIT" comment="Quad subgroup operations"/>
+ </enums>
+ <enums name="VkIndirectCommandsLayoutUsageFlagBitsNV" type="bitmask">
+ <enum bitpos="0" name="VK_INDIRECT_COMMANDS_LAYOUT_USAGE_EXPLICIT_PREPROCESS_BIT_NV"/>
+ <enum bitpos="1" name="VK_INDIRECT_COMMANDS_LAYOUT_USAGE_INDEXED_SEQUENCES_BIT_NV"/>
+ <enum bitpos="2" name="VK_INDIRECT_COMMANDS_LAYOUT_USAGE_UNORDERED_SEQUENCES_BIT_NV"/>
+ </enums>
+ <enums name="VkIndirectStateFlagBitsNV" type="bitmask">
+ <enum bitpos="0" name="VK_INDIRECT_STATE_FLAG_FRONTFACE_BIT_NV"/>
+ </enums>
+ <enums name="VkIndirectCommandsTokenTypeNV" type="enum">
+ <enum value="0" name="VK_INDIRECT_COMMANDS_TOKEN_TYPE_SHADER_GROUP_NV"/>
+ <enum value="1" name="VK_INDIRECT_COMMANDS_TOKEN_TYPE_STATE_FLAGS_NV"/>
+ <enum value="2" name="VK_INDIRECT_COMMANDS_TOKEN_TYPE_INDEX_BUFFER_NV"/>
+ <enum value="3" name="VK_INDIRECT_COMMANDS_TOKEN_TYPE_VERTEX_BUFFER_NV"/>
+ <enum value="4" name="VK_INDIRECT_COMMANDS_TOKEN_TYPE_PUSH_CONSTANT_NV"/>
+ <enum value="5" name="VK_INDIRECT_COMMANDS_TOKEN_TYPE_DRAW_INDEXED_NV"/>
+ <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>
+ <enums name="VkDescriptorSetLayoutCreateFlagBits" type="bitmask">
+ </enums>
+ <enums name="VkExternalMemoryHandleTypeFlagBits" type="bitmask">
+ <enum bitpos="0" name="VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT"/>
+ <enum bitpos="1" name="VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT"/>
+ <enum bitpos="2" name="VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT"/>
+ <enum bitpos="3" name="VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_TEXTURE_BIT"/>
+ <enum bitpos="4" name="VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_TEXTURE_KMT_BIT"/>
+ <enum bitpos="5" name="VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D12_HEAP_BIT"/>
+ <enum bitpos="6" name="VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D12_RESOURCE_BIT"/>
+ </enums>
+ <enums name="VkExternalMemoryFeatureFlagBits" type="bitmask">
+ <enum bitpos="0" name="VK_EXTERNAL_MEMORY_FEATURE_DEDICATED_ONLY_BIT"/>
+ <enum bitpos="1" name="VK_EXTERNAL_MEMORY_FEATURE_EXPORTABLE_BIT"/>
+ <enum bitpos="2" name="VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT"/>
+ </enums>
+ <enums name="VkExternalSemaphoreHandleTypeFlagBits" type="bitmask">
+ <enum bitpos="0" name="VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT"/>
+ <enum bitpos="1" name="VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_BIT"/>
+ <enum bitpos="2" name="VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT"/>
+ <enum bitpos="3" name="VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_D3D12_FENCE_BIT"/>
+ <enum name="VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_D3D11_FENCE_BIT" alias="VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_D3D12_FENCE_BIT"/>
+ <enum bitpos="4" name="VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT"/>
+ </enums>
+ <enums name="VkExternalSemaphoreFeatureFlagBits" type="bitmask">
+ <enum bitpos="0" name="VK_EXTERNAL_SEMAPHORE_FEATURE_EXPORTABLE_BIT"/>
+ <enum bitpos="1" name="VK_EXTERNAL_SEMAPHORE_FEATURE_IMPORTABLE_BIT"/>
+ </enums>
+ <enums name="VkSemaphoreImportFlagBits" type="bitmask">
+ <enum bitpos="0" name="VK_SEMAPHORE_IMPORT_TEMPORARY_BIT"/>
+ </enums>
+ <enums name="VkExternalFenceHandleTypeFlagBits" type="bitmask">
+ <enum bitpos="0" name="VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_FD_BIT"/>
+ <enum bitpos="1" name="VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_WIN32_BIT"/>
+ <enum bitpos="2" name="VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT"/>
+ <enum bitpos="3" name="VK_EXTERNAL_FENCE_HANDLE_TYPE_SYNC_FD_BIT"/>
+ </enums>
+ <enums name="VkExternalFenceFeatureFlagBits" type="bitmask">
+ <enum bitpos="0" name="VK_EXTERNAL_FENCE_FEATURE_EXPORTABLE_BIT"/>
+ <enum bitpos="1" name="VK_EXTERNAL_FENCE_FEATURE_IMPORTABLE_BIT"/>
+ </enums>
+ <enums name="VkFenceImportFlagBits" type="bitmask">
+ <enum bitpos="0" name="VK_FENCE_IMPORT_TEMPORARY_BIT"/>
+ </enums>
+ <enums name="VkSurfaceCounterFlagBitsEXT" type="bitmask">
+ <enum bitpos="0" name="VK_SURFACE_COUNTER_VBLANK_BIT_EXT"/>
+ <enum name="VK_SURFACE_COUNTER_VBLANK_EXT" alias="VK_SURFACE_COUNTER_VBLANK_BIT_EXT" comment="Backwards-compatible alias containing a typo"/>
+ </enums>
+ <enums name="VkDisplayPowerStateEXT" type="enum">
+ <enum value="0" name="VK_DISPLAY_POWER_STATE_OFF_EXT"/>
+ <enum value="1" name="VK_DISPLAY_POWER_STATE_SUSPEND_EXT"/>
+ <enum value="2" name="VK_DISPLAY_POWER_STATE_ON_EXT"/>
+ </enums>
+ <enums name="VkDeviceEventTypeEXT" type="enum">
+ <enum value="0" name="VK_DEVICE_EVENT_TYPE_DISPLAY_HOTPLUG_EXT"/>
+ </enums>
+ <enums name="VkDisplayEventTypeEXT" type="enum">
+ <enum value="0" name="VK_DISPLAY_EVENT_TYPE_FIRST_PIXEL_OUT_EXT"/>
+ </enums>
+ <enums name="VkPeerMemoryFeatureFlagBits" type="bitmask">
+ <enum bitpos="0" name="VK_PEER_MEMORY_FEATURE_COPY_SRC_BIT" comment="Can read with vkCmdCopy commands"/>
+ <enum bitpos="1" name="VK_PEER_MEMORY_FEATURE_COPY_DST_BIT" comment="Can write with vkCmdCopy commands"/>
+ <enum bitpos="2" name="VK_PEER_MEMORY_FEATURE_GENERIC_SRC_BIT" comment="Can read with any access type/command"/>
+ <enum bitpos="3" name="VK_PEER_MEMORY_FEATURE_GENERIC_DST_BIT" comment="Can write with and access type/command"/>
+ </enums>
+ <enums name="VkMemoryAllocateFlagBits" type="bitmask">
+ <enum bitpos="0" name="VK_MEMORY_ALLOCATE_DEVICE_MASK_BIT" comment="Force allocation on specific devices"/>
+ </enums>
+ <enums name="VkDeviceGroupPresentModeFlagBitsKHR" type="bitmask">
+ <enum bitpos="0" name="VK_DEVICE_GROUP_PRESENT_MODE_LOCAL_BIT_KHR" comment="Present from local memory"/>
+ <enum bitpos="1" name="VK_DEVICE_GROUP_PRESENT_MODE_REMOTE_BIT_KHR" comment="Present from remote memory"/>
+ <enum bitpos="2" name="VK_DEVICE_GROUP_PRESENT_MODE_SUM_BIT_KHR" comment="Present sum of local and/or remote memory"/>
+ <enum bitpos="3" name="VK_DEVICE_GROUP_PRESENT_MODE_LOCAL_MULTI_DEVICE_BIT_KHR" comment="Each physical device presents from local memory"/>
+ </enums>
+ <enums name="VkSwapchainCreateFlagBitsKHR" type="bitmask">
+ </enums>
+ <enums name="VkViewportCoordinateSwizzleNV" type="enum">
+ <enum value="0" name="VK_VIEWPORT_COORDINATE_SWIZZLE_POSITIVE_X_NV"/>
+ <enum value="1" name="VK_VIEWPORT_COORDINATE_SWIZZLE_NEGATIVE_X_NV"/>
+ <enum value="2" name="VK_VIEWPORT_COORDINATE_SWIZZLE_POSITIVE_Y_NV"/>
+ <enum value="3" name="VK_VIEWPORT_COORDINATE_SWIZZLE_NEGATIVE_Y_NV"/>
+ <enum value="4" name="VK_VIEWPORT_COORDINATE_SWIZZLE_POSITIVE_Z_NV"/>
+ <enum value="5" name="VK_VIEWPORT_COORDINATE_SWIZZLE_NEGATIVE_Z_NV"/>
+ <enum value="6" name="VK_VIEWPORT_COORDINATE_SWIZZLE_POSITIVE_W_NV"/>
+ <enum value="7" name="VK_VIEWPORT_COORDINATE_SWIZZLE_NEGATIVE_W_NV"/>
+ </enums>
+ <enums name="VkDiscardRectangleModeEXT" type="enum">
+ <enum value="0" name="VK_DISCARD_RECTANGLE_MODE_INCLUSIVE_EXT"/>
+ <enum value="1" name="VK_DISCARD_RECTANGLE_MODE_EXCLUSIVE_EXT"/>
+ </enums>
+ <enums name="VkSubpassDescriptionFlagBits" type="bitmask">
+ </enums>
+ <enums name="VkPointClippingBehavior" type="enum">
+ <enum value="0" name="VK_POINT_CLIPPING_BEHAVIOR_ALL_CLIP_PLANES"/>
+ <enum value="1" name="VK_POINT_CLIPPING_BEHAVIOR_USER_CLIP_PLANES_ONLY"/>
+ </enums>
+ <enums name="VkSamplerReductionMode" type="enum">
+ <enum value="0" name="VK_SAMPLER_REDUCTION_MODE_WEIGHTED_AVERAGE"/>
+ <enum value="1" name="VK_SAMPLER_REDUCTION_MODE_MIN"/>
+ <enum value="2" name="VK_SAMPLER_REDUCTION_MODE_MAX"/>
+ </enums>
+ <enums name="VkTessellationDomainOrigin" type="enum">
+ <enum value="0" name="VK_TESSELLATION_DOMAIN_ORIGIN_UPPER_LEFT"/>
+ <enum value="1" name="VK_TESSELLATION_DOMAIN_ORIGIN_LOWER_LEFT"/>
+ </enums>
+ <enums name="VkSamplerYcbcrModelConversion" type="enum">
+ <enum value="0" name="VK_SAMPLER_YCBCR_MODEL_CONVERSION_RGB_IDENTITY"/>
+ <enum value="1" name="VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_IDENTITY" comment="just range expansion"/>
+ <enum value="2" name="VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_709" comment="aka HD YUV"/>
+ <enum value="3" name="VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_601" comment="aka SD YUV"/>
+ <enum value="4" name="VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_2020" comment="aka UHD YUV"/>
+ </enums>
+ <enums name="VkSamplerYcbcrRange" type="enum">
+ <enum value="0" name="VK_SAMPLER_YCBCR_RANGE_ITU_FULL" comment="Luma 0..1 maps to 0..255, chroma -0.5..0.5 to 1..255 (clamped)"/>
+ <enum value="1" name="VK_SAMPLER_YCBCR_RANGE_ITU_NARROW" comment="Luma 0..1 maps to 16..235, chroma -0.5..0.5 to 16..240"/>
+ </enums>
+ <enums name="VkChromaLocation" type="enum">
+ <enum value="0" name="VK_CHROMA_LOCATION_COSITED_EVEN"/>
+ <enum value="1" name="VK_CHROMA_LOCATION_MIDPOINT"/>
+ </enums>
+ <enums name="VkBlendOverlapEXT" type="enum">
+ <enum value="0" name="VK_BLEND_OVERLAP_UNCORRELATED_EXT"/>
+ <enum value="1" name="VK_BLEND_OVERLAP_DISJOINT_EXT"/>
+ <enum value="2" name="VK_BLEND_OVERLAP_CONJOINT_EXT"/>
+ </enums>
+ <enums name="VkCoverageModulationModeNV" type="enum">
+ <enum value="0" name="VK_COVERAGE_MODULATION_MODE_NONE_NV"/>
+ <enum value="1" name="VK_COVERAGE_MODULATION_MODE_RGB_NV"/>
+ <enum value="2" name="VK_COVERAGE_MODULATION_MODE_ALPHA_NV"/>
+ <enum value="3" name="VK_COVERAGE_MODULATION_MODE_RGBA_NV"/>
+ </enums>
+ <enums name="VkCoverageReductionModeNV" type="enum">
+ <enum value="0" name="VK_COVERAGE_REDUCTION_MODE_MERGE_NV"/>
+ <enum value="1" name="VK_COVERAGE_REDUCTION_MODE_TRUNCATE_NV"/>
+ </enums>
+ <enums name="VkValidationCacheHeaderVersionEXT" type="enum">
+ <enum value="1" name="VK_VALIDATION_CACHE_HEADER_VERSION_ONE_EXT"/>
+ </enums>
+ <enums name="VkShaderInfoTypeAMD" type="enum">
+ <enum value="0" name="VK_SHADER_INFO_TYPE_STATISTICS_AMD"/>
+ <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>
+ <enums name="VkDebugUtilsMessageSeverityFlagBitsEXT" type="bitmask">
+ <enum bitpos="0" name="VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT"/>
+ <enum bitpos="4" name="VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT"/>
+ <enum bitpos="8" name="VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT"/>
+ <enum bitpos="12" name="VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT"/>
+ </enums>
+ <enums name="VkDebugUtilsMessageTypeFlagBitsEXT" type="bitmask">
+ <enum bitpos="0" name="VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT"/>
+ <enum bitpos="1" name="VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT"/>
+ <enum bitpos="2" name="VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT"/>
+ </enums>
+ <enums name="VkConservativeRasterizationModeEXT" type="enum">
+ <enum value="0" name="VK_CONSERVATIVE_RASTERIZATION_MODE_DISABLED_EXT"/>
+ <enum value="1" name="VK_CONSERVATIVE_RASTERIZATION_MODE_OVERESTIMATE_EXT"/>
+ <enum value="2" name="VK_CONSERVATIVE_RASTERIZATION_MODE_UNDERESTIMATE_EXT"/>
+ </enums>
+ <enums name="VkDescriptorBindingFlagBits" type="bitmask">
+ <enum bitpos="0" name="VK_DESCRIPTOR_BINDING_UPDATE_AFTER_BIND_BIT"/>
+ <enum bitpos="1" name="VK_DESCRIPTOR_BINDING_UPDATE_UNUSED_WHILE_PENDING_BIT"/>
+ <enum bitpos="2" name="VK_DESCRIPTOR_BINDING_PARTIALLY_BOUND_BIT"/>
+ <enum bitpos="3" name="VK_DESCRIPTOR_BINDING_VARIABLE_DESCRIPTOR_COUNT_BIT"/>
+ </enums>
+ <enums name="VkVendorId" type="enum">
+ <comment>Vendor IDs are now represented as enums instead of the old
+ &lt;vendorids&gt; tag, allowing them to be included in the
+ API headers.</comment>
+ <enum value="0x10001" name="VK_VENDOR_ID_VIV" comment="Vivante vendor ID"/>
+ <enum value="0x10002" name="VK_VENDOR_ID_VSI" comment="VeriSilicon vendor ID"/>
+ <enum value="0x10003" name="VK_VENDOR_ID_KAZAN" comment="Kazan Software Renderer"/>
+ <enum value="0x10004" name="VK_VENDOR_ID_CODEPLAY" comment="Codeplay Software Ltd. vendor ID"/>
+ <enum value="0x10005" name="VK_VENDOR_ID_MESA" comment="Mesa vendor ID"/>
+ <enum value="0x10006" name="VK_VENDOR_ID_POCL" comment="PoCL vendor ID"/>
+ <unused start="0x10007" comment="This is the next unused available Khronos vendor ID"/>
+ </enums>
+ <enums name="VkDriverId" type="enum">
+ <comment>Driver IDs are now represented as enums instead of the old
+ &lt;driverids&gt; tag, allowing them to be included in the
+ API headers.</comment>
+ <enum value="1" name="VK_DRIVER_ID_AMD_PROPRIETARY" comment="Advanced Micro Devices, Inc."/>
+ <enum value="2" name="VK_DRIVER_ID_AMD_OPEN_SOURCE" comment="Advanced Micro Devices, Inc."/>
+ <enum value="3" name="VK_DRIVER_ID_MESA_RADV" comment="Mesa open source project"/>
+ <enum value="4" name="VK_DRIVER_ID_NVIDIA_PROPRIETARY" comment="NVIDIA Corporation"/>
+ <enum value="5" name="VK_DRIVER_ID_INTEL_PROPRIETARY_WINDOWS" comment="Intel Corporation"/>
+ <enum value="6" name="VK_DRIVER_ID_INTEL_OPEN_SOURCE_MESA" comment="Intel Corporation"/>
+ <enum value="7" name="VK_DRIVER_ID_IMAGINATION_PROPRIETARY" comment="Imagination Technologies"/>
+ <enum value="8" name="VK_DRIVER_ID_QUALCOMM_PROPRIETARY" comment="Qualcomm Technologies, Inc."/>
+ <enum value="9" name="VK_DRIVER_ID_ARM_PROPRIETARY" comment="Arm Limited"/>
+ <enum value="10" name="VK_DRIVER_ID_GOOGLE_SWIFTSHADER" comment="Google LLC"/>
+ <enum value="11" name="VK_DRIVER_ID_GGP_PROPRIETARY" comment="Google LLC"/>
+ <enum value="12" name="VK_DRIVER_ID_BROADCOM_PROPRIETARY" comment="Broadcom Inc."/>
+ <enum value="13" name="VK_DRIVER_ID_MESA_LLVMPIPE" comment="Mesa"/>
+ <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."/>
+ </enums>
+ <enums name="VkConditionalRenderingFlagBitsEXT" type="bitmask">
+ <enum bitpos="0" name="VK_CONDITIONAL_RENDERING_INVERTED_BIT_EXT"/>
+ </enums>
+ <enums name="VkResolveModeFlagBits" type="bitmask">
+ <enum value="0" name="VK_RESOLVE_MODE_NONE"/>
+ <enum bitpos="0" name="VK_RESOLVE_MODE_SAMPLE_ZERO_BIT"/>
+ <enum bitpos="1" name="VK_RESOLVE_MODE_AVERAGE_BIT"/>
+ <enum bitpos="2" name="VK_RESOLVE_MODE_MIN_BIT"/>
+ <enum bitpos="3" name="VK_RESOLVE_MODE_MAX_BIT"/>
+ </enums>
+ <enums name="VkShadingRatePaletteEntryNV" type="enum">
+ <enum value="0" name="VK_SHADING_RATE_PALETTE_ENTRY_NO_INVOCATIONS_NV"/>
+ <enum value="1" name="VK_SHADING_RATE_PALETTE_ENTRY_16_INVOCATIONS_PER_PIXEL_NV"/>
+ <enum value="2" name="VK_SHADING_RATE_PALETTE_ENTRY_8_INVOCATIONS_PER_PIXEL_NV"/>
+ <enum value="3" name="VK_SHADING_RATE_PALETTE_ENTRY_4_INVOCATIONS_PER_PIXEL_NV"/>
+ <enum value="4" name="VK_SHADING_RATE_PALETTE_ENTRY_2_INVOCATIONS_PER_PIXEL_NV"/>
+ <enum value="5" name="VK_SHADING_RATE_PALETTE_ENTRY_1_INVOCATION_PER_PIXEL_NV"/>
+ <enum value="6" name="VK_SHADING_RATE_PALETTE_ENTRY_1_INVOCATION_PER_2X1_PIXELS_NV"/>
+ <enum value="7" name="VK_SHADING_RATE_PALETTE_ENTRY_1_INVOCATION_PER_1X2_PIXELS_NV"/>
+ <enum value="8" name="VK_SHADING_RATE_PALETTE_ENTRY_1_INVOCATION_PER_2X2_PIXELS_NV"/>
+ <enum value="9" name="VK_SHADING_RATE_PALETTE_ENTRY_1_INVOCATION_PER_4X2_PIXELS_NV"/>
+ <enum value="10" name="VK_SHADING_RATE_PALETTE_ENTRY_1_INVOCATION_PER_2X4_PIXELS_NV"/>
+ <enum value="11" name="VK_SHADING_RATE_PALETTE_ENTRY_1_INVOCATION_PER_4X4_PIXELS_NV"/>
+ </enums>
+ <enums name="VkCoarseSampleOrderTypeNV" type="enum">
+ <enum value="0" name="VK_COARSE_SAMPLE_ORDER_TYPE_DEFAULT_NV"/>
+ <enum value="1" name="VK_COARSE_SAMPLE_ORDER_TYPE_CUSTOM_NV"/>
+ <enum value="2" name="VK_COARSE_SAMPLE_ORDER_TYPE_PIXEL_MAJOR_NV"/>
+ <enum value="3" name="VK_COARSE_SAMPLE_ORDER_TYPE_SAMPLE_MAJOR_NV"/>
+ </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="2" name="VK_GEOMETRY_INSTANCE_FORCE_OPAQUE_BIT_KHR"/>
+ <enum bitpos="3" name="VK_GEOMETRY_INSTANCE_FORCE_NO_OPAQUE_BIT_KHR"/>
+ </enums>
+ <enums name="VkGeometryFlagBitsKHR" type="bitmask">
+ <enum bitpos="0" name="VK_GEOMETRY_OPAQUE_BIT_KHR"/>
+ <enum bitpos="1" name="VK_GEOMETRY_NO_DUPLICATE_ANY_HIT_INVOCATION_BIT_KHR"/>
+ </enums>
+ <enums name="VkBuildAccelerationStructureFlagBitsKHR" type="bitmask">
+ <enum bitpos="0" name="VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_UPDATE_BIT_KHR"/>
+ <enum bitpos="1" name="VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_COMPACTION_BIT_KHR"/>
+ <enum bitpos="2" name="VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR"/>
+ <enum bitpos="3" name="VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_BUILD_BIT_KHR"/>
+ <enum bitpos="4" name="VK_BUILD_ACCELERATION_STRUCTURE_LOW_MEMORY_BIT_KHR"/>
+ </enums>
+ <enums name="VkAccelerationStructureCreateFlagBitsKHR" type="bitmask">
+ <enum bitpos="0" name="VK_ACCELERATION_STRUCTURE_CREATE_DEVICE_ADDRESS_CAPTURE_REPLAY_BIT_KHR"/>
+ </enums>
+ <enums name="VkCopyAccelerationStructureModeKHR" type="enum">
+ <enum value="0" name="VK_COPY_ACCELERATION_STRUCTURE_MODE_CLONE_KHR"/>
+ <enum value="1" name="VK_COPY_ACCELERATION_STRUCTURE_MODE_COMPACT_KHR"/>
+ <enum value="2" name="VK_COPY_ACCELERATION_STRUCTURE_MODE_SERIALIZE_KHR"/>
+ <enum value="3" name="VK_COPY_ACCELERATION_STRUCTURE_MODE_DESERIALIZE_KHR"/>
+ </enums>
+ <enums name="VkBuildAccelerationStructureModeKHR" type="enum">
+ <enum value="0" name="VK_BUILD_ACCELERATION_STRUCTURE_MODE_BUILD_KHR"/>
+ <enum value="1" name="VK_BUILD_ACCELERATION_STRUCTURE_MODE_UPDATE_KHR"/>
+ </enums>
+ <enums name="VkAccelerationStructureTypeKHR" type="enum">
+ <enum value="0" name="VK_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL_KHR"/>
+ <enum value="1" name="VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_KHR"/>
+ <enum value="2" name="VK_ACCELERATION_STRUCTURE_TYPE_GENERIC_KHR"/>
+ </enums>
+ <enums name="VkGeometryTypeKHR" type="enum">
+ <enum value="0" name="VK_GEOMETRY_TYPE_TRIANGLES_KHR"/>
+ <enum value="1" name="VK_GEOMETRY_TYPE_AABBS_KHR"/>
+ <enum value="2" name="VK_GEOMETRY_TYPE_INSTANCES_KHR"/>
+ </enums>
+ <enums name="VkAccelerationStructureMemoryRequirementsTypeNV" type="enum">
+ <enum value="0" name="VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_OBJECT_NV"/>
+ <enum value="1" name="VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_BUILD_SCRATCH_NV"/>
+ <enum value="2" name="VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_UPDATE_SCRATCH_NV"/>
+ </enums>
+ <enums name="VkAccelerationStructureBuildTypeKHR" type="enum">
+ <enum value="0" name="VK_ACCELERATION_STRUCTURE_BUILD_TYPE_HOST_KHR"/>
+ <enum value="1" name="VK_ACCELERATION_STRUCTURE_BUILD_TYPE_DEVICE_KHR"/>
+ <enum value="2" name="VK_ACCELERATION_STRUCTURE_BUILD_TYPE_HOST_OR_DEVICE_KHR"/>
+ </enums>
+ <enums name="VkRayTracingShaderGroupTypeKHR" type="enum">
+ <enum value="0" name="VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_KHR"/>
+ <enum value="1" name="VK_RAY_TRACING_SHADER_GROUP_TYPE_TRIANGLES_HIT_GROUP_KHR"/>
+ <enum value="2" name="VK_RAY_TRACING_SHADER_GROUP_TYPE_PROCEDURAL_HIT_GROUP_KHR"/>
+ </enums>
+ <enums name="VkAccelerationStructureCompatibilityKHR" type="enum">
+ <enum value="0" name="VK_ACCELERATION_STRUCTURE_COMPATIBILITY_COMPATIBLE_KHR"/>
+ <enum value="1" name="VK_ACCELERATION_STRUCTURE_COMPATIBILITY_INCOMPATIBLE_KHR"/>
+ </enums>
+ <enums name="VkShaderGroupShaderKHR" type="enum">
+ <enum value="0" name="VK_SHADER_GROUP_SHADER_GENERAL_KHR"/>
+ <enum value="1" name="VK_SHADER_GROUP_SHADER_CLOSEST_HIT_KHR"/>
+ <enum value="2" name="VK_SHADER_GROUP_SHADER_ANY_HIT_KHR"/>
+ <enum value="3" name="VK_SHADER_GROUP_SHADER_INTERSECTION_KHR"/>
+ </enums>
+ <enums name="VkMemoryOverallocationBehaviorAMD" type="enum">
+ <enum value="0" name="VK_MEMORY_OVERALLOCATION_BEHAVIOR_DEFAULT_AMD"/>
+ <enum value="1" name="VK_MEMORY_OVERALLOCATION_BEHAVIOR_ALLOWED_AMD"/>
+ <enum value="2" name="VK_MEMORY_OVERALLOCATION_BEHAVIOR_DISALLOWED_AMD"/>
+ </enums>
+ <enums name="VkFramebufferCreateFlagBits" type="bitmask">
+ </enums>
+ <enums name="VkScopeNV" type="enum">
+ <enum value="1" name="VK_SCOPE_DEVICE_NV"/>
+ <enum value="2" name="VK_SCOPE_WORKGROUP_NV"/>
+ <enum value="3" name="VK_SCOPE_SUBGROUP_NV"/>
+ <enum value="5" name="VK_SCOPE_QUEUE_FAMILY_NV"/>
+ </enums>
+ <enums name="VkComponentTypeNV" type="enum">
+ <enum value="0" name="VK_COMPONENT_TYPE_FLOAT16_NV"/>
+ <enum value="1" name="VK_COMPONENT_TYPE_FLOAT32_NV"/>
+ <enum value="2" name="VK_COMPONENT_TYPE_FLOAT64_NV"/>
+ <enum value="3" name="VK_COMPONENT_TYPE_SINT8_NV"/>
+ <enum value="4" name="VK_COMPONENT_TYPE_SINT16_NV"/>
+ <enum value="5" name="VK_COMPONENT_TYPE_SINT32_NV"/>
+ <enum value="6" name="VK_COMPONENT_TYPE_SINT64_NV"/>
+ <enum value="7" name="VK_COMPONENT_TYPE_UINT8_NV"/>
+ <enum value="8" name="VK_COMPONENT_TYPE_UINT16_NV"/>
+ <enum value="9" name="VK_COMPONENT_TYPE_UINT32_NV"/>
+ <enum value="10" name="VK_COMPONENT_TYPE_UINT64_NV"/>
+ </enums>
+ <enums name="VkDeviceDiagnosticsConfigFlagBitsNV" type="bitmask">
+ <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"/>
+ </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>
+ <enums name="VkFullScreenExclusiveEXT" type="enum">
+ <enum value="0" name="VK_FULL_SCREEN_EXCLUSIVE_DEFAULT_EXT"/>
+ <enum value="1" name="VK_FULL_SCREEN_EXCLUSIVE_ALLOWED_EXT"/>
+ <enum value="2" name="VK_FULL_SCREEN_EXCLUSIVE_DISALLOWED_EXT"/>
+ <enum value="3" name="VK_FULL_SCREEN_EXCLUSIVE_APPLICATION_CONTROLLED_EXT"/>
+ </enums>
+ <enums name="VkPerformanceCounterScopeKHR" type="enum">
+ <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"/>
+ </enums>
+ <enums name="VkPerformanceCounterUnitKHR" type="enum">
+ <enum value="0" name="VK_PERFORMANCE_COUNTER_UNIT_GENERIC_KHR"/>
+ <enum value="1" name="VK_PERFORMANCE_COUNTER_UNIT_PERCENTAGE_KHR"/>
+ <enum value="2" name="VK_PERFORMANCE_COUNTER_UNIT_NANOSECONDS_KHR"/>
+ <enum value="3" name="VK_PERFORMANCE_COUNTER_UNIT_BYTES_KHR"/>
+ <enum value="4" name="VK_PERFORMANCE_COUNTER_UNIT_BYTES_PER_SECOND_KHR"/>
+ <enum value="5" name="VK_PERFORMANCE_COUNTER_UNIT_KELVIN_KHR"/>
+ <enum value="6" name="VK_PERFORMANCE_COUNTER_UNIT_WATTS_KHR"/>
+ <enum value="7" name="VK_PERFORMANCE_COUNTER_UNIT_VOLTS_KHR"/>
+ <enum value="8" name="VK_PERFORMANCE_COUNTER_UNIT_AMPS_KHR"/>
+ <enum value="9" name="VK_PERFORMANCE_COUNTER_UNIT_HERTZ_KHR"/>
+ <enum value="10" name="VK_PERFORMANCE_COUNTER_UNIT_CYCLES_KHR"/>
+ </enums>
+ <enums name="VkPerformanceCounterStorageKHR" type="enum">
+ <enum value="0" name="VK_PERFORMANCE_COUNTER_STORAGE_INT32_KHR"/>
+ <enum value="1" name="VK_PERFORMANCE_COUNTER_STORAGE_INT64_KHR"/>
+ <enum value="2" name="VK_PERFORMANCE_COUNTER_STORAGE_UINT32_KHR"/>
+ <enum value="3" name="VK_PERFORMANCE_COUNTER_STORAGE_UINT64_KHR"/>
+ <enum value="4" name="VK_PERFORMANCE_COUNTER_STORAGE_FLOAT32_KHR"/>
+ <enum value="5" name="VK_PERFORMANCE_COUNTER_STORAGE_FLOAT64_KHR"/>
+ </enums>
+ <enums name="VkPerformanceCounterDescriptionFlagBitsKHR" type="bitmask">
+ <enum bitpos="0" name="VK_PERFORMANCE_COUNTER_DESCRIPTION_PERFORMANCE_IMPACTING_BIT_KHR"/>
+ <enum name="VK_PERFORMANCE_COUNTER_DESCRIPTION_PERFORMANCE_IMPACTING_KHR" alias="VK_PERFORMANCE_COUNTER_DESCRIPTION_PERFORMANCE_IMPACTING_BIT_KHR" comment="Backwards-compatible alias containing a typo"/>
+ <enum bitpos="1" name="VK_PERFORMANCE_COUNTER_DESCRIPTION_CONCURRENTLY_IMPACTED_BIT_KHR"/>
+ <enum name="VK_PERFORMANCE_COUNTER_DESCRIPTION_CONCURRENTLY_IMPACTED_KHR" alias="VK_PERFORMANCE_COUNTER_DESCRIPTION_CONCURRENTLY_IMPACTED_BIT_KHR" comment="Backwards-compatible alias containing a typo"/>
+ </enums>
+ <enums name="VkAcquireProfilingLockFlagBitsKHR" type="bitmask">
+ </enums>
+ <enums name="VkShaderCorePropertiesFlagBitsAMD" type="bitmask">
+ </enums>
+ <enums name="VkPerformanceConfigurationTypeINTEL" type="enum">
+ <enum value="0" name="VK_PERFORMANCE_CONFIGURATION_TYPE_COMMAND_QUEUE_METRICS_DISCOVERY_ACTIVATED_INTEL"/>
+ </enums>
+ <enums name="VkQueryPoolSamplingModeINTEL" type="enum">
+ <enum value="0" name="VK_QUERY_POOL_SAMPLING_MODE_MANUAL_INTEL"/>
+ </enums>
+ <enums name="VkPerformanceOverrideTypeINTEL" type="enum">
+ <enum value="0" name="VK_PERFORMANCE_OVERRIDE_TYPE_NULL_HARDWARE_INTEL"/>
+ <enum value="1" name="VK_PERFORMANCE_OVERRIDE_TYPE_FLUSH_GPU_CACHES_INTEL"/>
+ </enums>
+ <enums name="VkPerformanceParameterTypeINTEL" type="enum">
+ <enum value="0" name="VK_PERFORMANCE_PARAMETER_TYPE_HW_COUNTERS_SUPPORTED_INTEL"/>
+ <enum value="1" name="VK_PERFORMANCE_PARAMETER_TYPE_STREAM_MARKER_VALID_BITS_INTEL"/>
+ </enums>
+ <enums name="VkPerformanceValueTypeINTEL" type="enum">
+ <enum value="0" name="VK_PERFORMANCE_VALUE_TYPE_UINT32_INTEL"/>
+ <enum value="1" name="VK_PERFORMANCE_VALUE_TYPE_UINT64_INTEL"/>
+ <enum value="2" name="VK_PERFORMANCE_VALUE_TYPE_FLOAT_INTEL"/>
+ <enum value="3" name="VK_PERFORMANCE_VALUE_TYPE_BOOL_INTEL"/>
+ <enum value="4" name="VK_PERFORMANCE_VALUE_TYPE_STRING_INTEL"/>
+ </enums>
+ <enums name="VkShaderFloatControlsIndependence" type="enum">
+ <enum value="0" name="VK_SHADER_FLOAT_CONTROLS_INDEPENDENCE_32_BIT_ONLY"/>
+ <enum value="1" name="VK_SHADER_FLOAT_CONTROLS_INDEPENDENCE_ALL"/>
+ <enum value="2" name="VK_SHADER_FLOAT_CONTROLS_INDEPENDENCE_NONE"/>
+ </enums>
+ <enums name="VkPipelineExecutableStatisticFormatKHR" type="enum">
+ <enum value="0" name="VK_PIPELINE_EXECUTABLE_STATISTIC_FORMAT_BOOL32_KHR"/>
+ <enum value="1" name="VK_PIPELINE_EXECUTABLE_STATISTIC_FORMAT_INT64_KHR"/>
+ <enum value="2" name="VK_PIPELINE_EXECUTABLE_STATISTIC_FORMAT_UINT64_KHR"/>
+ <enum value="3" name="VK_PIPELINE_EXECUTABLE_STATISTIC_FORMAT_FLOAT64_KHR"/>
+ </enums>
+ <enums name="VkLineRasterizationModeEXT" type="enum">
+ <enum value="0" name="VK_LINE_RASTERIZATION_MODE_DEFAULT_EXT"/>
+ <enum value="1" name="VK_LINE_RASTERIZATION_MODE_RECTANGULAR_EXT"/>
+ <enum value="2" name="VK_LINE_RASTERIZATION_MODE_BRESENHAM_EXT"/>
+ <enum value="3" name="VK_LINE_RASTERIZATION_MODE_RECTANGULAR_SMOOTH_EXT"/>
+ </enums>
+ <enums name="VkShaderModuleCreateFlagBits" type="bitmask">
+ </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>
+ <enums name="VkFragmentShadingRateCombinerOpKHR" type="enum">
+ <enum value="0" name="VK_FRAGMENT_SHADING_RATE_COMBINER_OP_KEEP_KHR"/>
+ <enum value="1" name="VK_FRAGMENT_SHADING_RATE_COMBINER_OP_REPLACE_KHR"/>
+ <enum value="2" name="VK_FRAGMENT_SHADING_RATE_COMBINER_OP_MIN_KHR"/>
+ <enum value="3" name="VK_FRAGMENT_SHADING_RATE_COMBINER_OP_MAX_KHR"/>
+ <enum value="4" name="VK_FRAGMENT_SHADING_RATE_COMBINER_OP_MUL_KHR"/>
+ </enums>
+ <enums name="VkFragmentShadingRateNV" type="enum">
+ <enum value="0" name="VK_FRAGMENT_SHADING_RATE_1_INVOCATION_PER_PIXEL_NV"/>
+ <enum value="1" name="VK_FRAGMENT_SHADING_RATE_1_INVOCATION_PER_1X2_PIXELS_NV"/>
+ <enum value="4" name="VK_FRAGMENT_SHADING_RATE_1_INVOCATION_PER_2X1_PIXELS_NV"/>
+ <enum value="5" name="VK_FRAGMENT_SHADING_RATE_1_INVOCATION_PER_2X2_PIXELS_NV"/>
+ <enum value="6" name="VK_FRAGMENT_SHADING_RATE_1_INVOCATION_PER_2X4_PIXELS_NV"/>
+ <enum value="9" name="VK_FRAGMENT_SHADING_RATE_1_INVOCATION_PER_4X2_PIXELS_NV"/>
+ <enum value="10" name="VK_FRAGMENT_SHADING_RATE_1_INVOCATION_PER_4X4_PIXELS_NV"/>
+ <enum value="11" name="VK_FRAGMENT_SHADING_RATE_2_INVOCATIONS_PER_PIXEL_NV"/>
+ <enum value="12" name="VK_FRAGMENT_SHADING_RATE_4_INVOCATIONS_PER_PIXEL_NV"/>
+ <enum value="13" name="VK_FRAGMENT_SHADING_RATE_8_INVOCATIONS_PER_PIXEL_NV"/>
+ <enum value="14" name="VK_FRAGMENT_SHADING_RATE_16_INVOCATIONS_PER_PIXEL_NV"/>
+ <enum value="15" name="VK_FRAGMENT_SHADING_RATE_NO_INVOCATIONS_NV"/>
+ </enums>
+ <enums name="VkFragmentShadingRateTypeNV" type="enum">
+ <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>
+ <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>
+ <enums name="VkSubmitFlagBitsKHR" type="bitmask">
+ <enum bitpos="0" name="VK_SUBMIT_PROTECTED_BIT_KHR"/>
+ </enums>
+ <enums name="VkEventCreateFlagBits" type="bitmask">
+ </enums>
+ <enums name="VkPipelineLayoutCreateFlagBits" type="bitmask">
+ </enums>
+ <enums name="VkProvokingVertexModeEXT" type="enum">
+ <enum value="0" name="VK_PROVOKING_VERTEX_MODE_FIRST_VERTEX_EXT"/>
+ <enum value="1" name="VK_PROVOKING_VERTEX_MODE_LAST_VERTEX_EXT"/>
+ </enums>
+ <enums name="VkAccelerationStructureMotionInstanceTypeNV" type="enum">
+ <enum value="0" name="VK_ACCELERATION_STRUCTURE_MOTION_INSTANCE_TYPE_STATIC_NV"/>
+ <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="VkVideoCodecOperationFlagBitsKHR" type="bitmask">
+ <enum value="0" name="VK_VIDEO_CODEC_OPERATION_INVALID_BIT_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 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"/>
+ <enum bitpos="3" name="VK_VIDEO_CHROMA_SUBSAMPLING_444_BIT_KHR"/>
+ </enums>
+ <enums name="VkVideoComponentBitDepthFlagBitsKHR" type="bitmask" comment="Vulkan video component bit depth definitions">
+ <enum value="0" name="VK_VIDEO_COMPONENT_BIT_DEPTH_INVALID_KHR"/>
+ <enum bitpos="0" name="VK_VIDEO_COMPONENT_BIT_DEPTH_8_BIT_KHR"/>
+ <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>
+ <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>
+ <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">
+ <enum value="-1" name="VK_QUERY_RESULT_STATUS_ERROR_KHR"/>
+ <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>
+ <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>
+ <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>
+ <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>
+ <enums name="VkVideoEncodeH264InputModeFlagBitsEXT" type="bitmask">
+ <enum bitpos="0" name="VK_VIDEO_ENCODE_H264_INPUT_MODE_FRAME_BIT_EXT"/>
+ <enum bitpos="1" name="VK_VIDEO_ENCODE_H264_INPUT_MODE_SLICE_BIT_EXT"/>
+ <enum bitpos="2" name="VK_VIDEO_ENCODE_H264_INPUT_MODE_NON_VCL_BIT_EXT"/>
+ </enums>
+ <enums name="VkVideoEncodeH264OutputModeFlagBitsEXT" type="bitmask">
+ <enum bitpos="0" name="VK_VIDEO_ENCODE_H264_OUTPUT_MODE_FRAME_BIT_EXT"/>
+ <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>
+
+ <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>
+ <param>const <type>VkInstanceCreateInfo</type>* <name>pCreateInfo</name></param>
+ <param optional="true">const <type>VkAllocationCallbacks</type>* <name>pAllocator</name></param>
+ <param><type>VkInstance</type>* <name>pInstance</name></param>
+ </command>
+ <command>
+ <proto><type>void</type> <name>vkDestroyInstance</name></proto>
+ <param optional="true" externsync="true"><type>VkInstance</type> <name>instance</name></param>
+ <param optional="true">const <type>VkAllocationCallbacks</type>* <name>pAllocator</name></param>
+ <implicitexternsyncparams>
+ <param>all sname:VkPhysicalDevice objects enumerated from pname:instance</param>
+ </implicitexternsyncparams>
+ </command>
+ <command successcodes="VK_SUCCESS,VK_INCOMPLETE" errorcodes="VK_ERROR_OUT_OF_HOST_MEMORY,VK_ERROR_OUT_OF_DEVICE_MEMORY,VK_ERROR_INITIALIZATION_FAILED">
+ <proto><type>VkResult</type> <name>vkEnumeratePhysicalDevices</name></proto>
+ <param><type>VkInstance</type> <name>instance</name></param>
+ <param optional="false,true"><type>uint32_t</type>* <name>pPhysicalDeviceCount</name></param>
+ <param optional="true" len="pPhysicalDeviceCount"><type>VkPhysicalDevice</type>* <name>pPhysicalDevices</name></param>
+ </command>
+ <command>
+ <proto><type>PFN_vkVoidFunction</type> <name>vkGetDeviceProcAddr</name></proto>
+ <param><type>VkDevice</type> <name>device</name></param>
+ <param len="null-terminated">const <type>char</type>* <name>pName</name></param>
+ </command>
+ <command>
+ <proto><type>PFN_vkVoidFunction</type> <name>vkGetInstanceProcAddr</name></proto>
+ <param optional="true"><type>VkInstance</type> <name>instance</name></param>
+ <param len="null-terminated">const <type>char</type>* <name>pName</name></param>
+ </command>
+ <command>
+ <proto><type>void</type> <name>vkGetPhysicalDeviceProperties</name></proto>
+ <param><type>VkPhysicalDevice</type> <name>physicalDevice</name></param>
+ <param><type>VkPhysicalDeviceProperties</type>* <name>pProperties</name></param>
+ </command>
+ <command>
+ <proto><type>void</type> <name>vkGetPhysicalDeviceQueueFamilyProperties</name></proto>
+ <param><type>VkPhysicalDevice</type> <name>physicalDevice</name></param>
+ <param optional="false,true"><type>uint32_t</type>* <name>pQueueFamilyPropertyCount</name></param>
+ <param optional="true" len="pQueueFamilyPropertyCount"><type>VkQueueFamilyProperties</type>* <name>pQueueFamilyProperties</name></param>
+ </command>
+ <command>
+ <proto><type>void</type> <name>vkGetPhysicalDeviceMemoryProperties</name></proto>
+ <param><type>VkPhysicalDevice</type> <name>physicalDevice</name></param>
+ <param><type>VkPhysicalDeviceMemoryProperties</type>* <name>pMemoryProperties</name></param>
+ </command>
+ <command>
+ <proto><type>void</type> <name>vkGetPhysicalDeviceFeatures</name></proto>
+ <param><type>VkPhysicalDevice</type> <name>physicalDevice</name></param>
+ <param><type>VkPhysicalDeviceFeatures</type>* <name>pFeatures</name></param>
+ </command>
+ <command>
+ <proto><type>void</type> <name>vkGetPhysicalDeviceFormatProperties</name></proto>
+ <param><type>VkPhysicalDevice</type> <name>physicalDevice</name></param>
+ <param><type>VkFormat</type> <name>format</name></param>
+ <param><type>VkFormatProperties</type>* <name>pFormatProperties</name></param>
+ </command>
+ <command successcodes="VK_SUCCESS" errorcodes="VK_ERROR_OUT_OF_HOST_MEMORY,VK_ERROR_OUT_OF_DEVICE_MEMORY,VK_ERROR_FORMAT_NOT_SUPPORTED">
+ <proto><type>VkResult</type> <name>vkGetPhysicalDeviceImageFormatProperties</name></proto>
+ <param><type>VkPhysicalDevice</type> <name>physicalDevice</name></param>
+ <param><type>VkFormat</type> <name>format</name></param>
+ <param><type>VkImageType</type> <name>type</name></param>
+ <param><type>VkImageTiling</type> <name>tiling</name></param>
+ <param><type>VkImageUsageFlags</type> <name>usage</name></param>
+ <param optional="true"><type>VkImageCreateFlags</type> <name>flags</name></param>
+ <param><type>VkImageFormatProperties</type>* <name>pImageFormatProperties</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_EXTENSION_NOT_PRESENT,VK_ERROR_FEATURE_NOT_PRESENT,VK_ERROR_TOO_MANY_OBJECTS,VK_ERROR_DEVICE_LOST">
+ <proto><type>VkResult</type> <name>vkCreateDevice</name></proto>
+ <param><type>VkPhysicalDevice</type> <name>physicalDevice</name></param>
+ <param>const <type>VkDeviceCreateInfo</type>* <name>pCreateInfo</name></param>
+ <param optional="true">const <type>VkAllocationCallbacks</type>* <name>pAllocator</name></param>
+ <param><type>VkDevice</type>* <name>pDevice</name></param>
+ </command>
+ <command>
+ <proto><type>void</type> <name>vkDestroyDevice</name></proto>
+ <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>
+ </implicitexternsyncparams>
+ </command>
+ <command successcodes="VK_SUCCESS" errorcodes="VK_ERROR_OUT_OF_HOST_MEMORY">
+ <proto><type>VkResult</type> <name>vkEnumerateInstanceVersion</name></proto>
+ <param><type>uint32_t</type>* <name>pApiVersion</name></param>
+ </command>
+ <command successcodes="VK_SUCCESS,VK_INCOMPLETE" errorcodes="VK_ERROR_OUT_OF_HOST_MEMORY,VK_ERROR_OUT_OF_DEVICE_MEMORY">
+ <proto><type>VkResult</type> <name>vkEnumerateInstanceLayerProperties</name></proto>
+ <param optional="false,true"><type>uint32_t</type>* <name>pPropertyCount</name></param>
+ <param optional="true" len="pPropertyCount"><type>VkLayerProperties</type>* <name>pProperties</name></param>
+ </command>
+ <command successcodes="VK_SUCCESS,VK_INCOMPLETE" errorcodes="VK_ERROR_OUT_OF_HOST_MEMORY,VK_ERROR_OUT_OF_DEVICE_MEMORY,VK_ERROR_LAYER_NOT_PRESENT">
+ <proto><type>VkResult</type> <name>vkEnumerateInstanceExtensionProperties</name></proto>
+ <param optional="true" len="null-terminated">const <type>char</type>* <name>pLayerName</name></param>
+ <param optional="false,true"><type>uint32_t</type>* <name>pPropertyCount</name></param>
+ <param optional="true" len="pPropertyCount"><type>VkExtensionProperties</type>* <name>pProperties</name></param>
+ </command>
+ <command successcodes="VK_SUCCESS,VK_INCOMPLETE" errorcodes="VK_ERROR_OUT_OF_HOST_MEMORY,VK_ERROR_OUT_OF_DEVICE_MEMORY">
+ <proto><type>VkResult</type> <name>vkEnumerateDeviceLayerProperties</name></proto>
+ <param><type>VkPhysicalDevice</type> <name>physicalDevice</name></param>
+ <param optional="false,true"><type>uint32_t</type>* <name>pPropertyCount</name></param>
+ <param optional="true" len="pPropertyCount"><type>VkLayerProperties</type>* <name>pProperties</name></param>
+ </command>
+ <command successcodes="VK_SUCCESS,VK_INCOMPLETE" errorcodes="VK_ERROR_OUT_OF_HOST_MEMORY,VK_ERROR_OUT_OF_DEVICE_MEMORY,VK_ERROR_LAYER_NOT_PRESENT">
+ <proto><type>VkResult</type> <name>vkEnumerateDeviceExtensionProperties</name></proto>
+ <param><type>VkPhysicalDevice</type> <name>physicalDevice</name></param>
+ <param optional="true" len="null-terminated">const <type>char</type>* <name>pLayerName</name></param>
+ <param optional="false,true"><type>uint32_t</type>* <name>pPropertyCount</name></param>
+ <param optional="true" len="pPropertyCount"><type>VkExtensionProperties</type>* <name>pProperties</name></param>
+ </command>
+ <command>
+ <proto><type>void</type> <name>vkGetDeviceQueue</name></proto>
+ <param><type>VkDevice</type> <name>device</name></param>
+ <param><type>uint32_t</type> <name>queueFamilyIndex</name></param>
+ <param><type>uint32_t</type> <name>queueIndex</name></param>
+ <param><type>VkQueue</type>* <name>pQueue</name></param>
+ </command>
+ <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>vkQueueSubmit</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>VkSubmitInfo</type>* <name>pSubmits</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,VK_ERROR_DEVICE_LOST">
+ <proto><type>VkResult</type> <name>vkQueueWaitIdle</name></proto>
+ <param externsync="true"><type>VkQueue</type> <name>queue</name></param>
+ </command>
+ <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>vkDeviceWaitIdle</name></proto>
+ <param><type>VkDevice</type> <name>device</name></param>
+ <implicitexternsyncparams>
+ <param>all sname:VkQueue objects created from pname:device</param>
+ </implicitexternsyncparams>
+ </command>
+ <command successcodes="VK_SUCCESS" errorcodes="VK_ERROR_OUT_OF_HOST_MEMORY,VK_ERROR_OUT_OF_DEVICE_MEMORY,VK_ERROR_INVALID_EXTERNAL_HANDLE,VK_ERROR_INVALID_OPAQUE_CAPTURE_ADDRESS_KHR">
+ <proto><type>VkResult</type> <name>vkAllocateMemory</name></proto>
+ <param><type>VkDevice</type> <name>device</name></param>
+ <param>const <type>VkMemoryAllocateInfo</type>* <name>pAllocateInfo</name></param>
+ <param optional="true">const <type>VkAllocationCallbacks</type>* <name>pAllocator</name></param>
+ <param><type>VkDeviceMemory</type>* <name>pMemory</name></param>
+ </command>
+ <command>
+ <proto><type>void</type> <name>vkFreeMemory</name></proto>
+ <param><type>VkDevice</type> <name>device</name></param>
+ <param optional="true" externsync="true"><type>VkDeviceMemory</type> <name>memory</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_MEMORY_MAP_FAILED">
+ <proto><type>VkResult</type> <name>vkMapMemory</name></proto>
+ <param><type>VkDevice</type> <name>device</name></param>
+ <param externsync="true"><type>VkDeviceMemory</type> <name>memory</name></param>
+ <param><type>VkDeviceSize</type> <name>offset</name></param>
+ <param><type>VkDeviceSize</type> <name>size</name></param>
+ <param optional="true"><type>VkMemoryMapFlags</type> <name>flags</name></param>
+ <param optional="false,true"><type>void</type>** <name>ppData</name></param>
+ </command>
+ <command>
+ <proto><type>void</type> <name>vkUnmapMemory</name></proto>
+ <param><type>VkDevice</type> <name>device</name></param>
+ <param externsync="true"><type>VkDeviceMemory</type> <name>memory</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>vkFlushMappedMemoryRanges</name></proto>
+ <param><type>VkDevice</type> <name>device</name></param>
+ <param><type>uint32_t</type> <name>memoryRangeCount</name></param>
+ <param len="memoryRangeCount">const <type>VkMappedMemoryRange</type>* <name>pMemoryRanges</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>vkInvalidateMappedMemoryRanges</name></proto>
+ <param><type>VkDevice</type> <name>device</name></param>
+ <param><type>uint32_t</type> <name>memoryRangeCount</name></param>
+ <param len="memoryRangeCount">const <type>VkMappedMemoryRange</type>* <name>pMemoryRanges</name></param>
+ </command>
+ <command>
+ <proto><type>void</type> <name>vkGetDeviceMemoryCommitment</name></proto>
+ <param><type>VkDevice</type> <name>device</name></param>
+ <param><type>VkDeviceMemory</type> <name>memory</name></param>
+ <param><type>VkDeviceSize</type>* <name>pCommittedMemoryInBytes</name></param>
+ </command>
+ <command>
+ <proto><type>void</type> <name>vkGetBufferMemoryRequirements</name></proto>
+ <param><type>VkDevice</type> <name>device</name></param>
+ <param><type>VkBuffer</type> <name>buffer</name></param>
+ <param><type>VkMemoryRequirements</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_INVALID_OPAQUE_CAPTURE_ADDRESS_KHR">
+ <proto><type>VkResult</type> <name>vkBindBufferMemory</name></proto>
+ <param><type>VkDevice</type> <name>device</name></param>
+ <param externsync="true"><type>VkBuffer</type> <name>buffer</name></param>
+ <param><type>VkDeviceMemory</type> <name>memory</name></param>
+ <param><type>VkDeviceSize</type> <name>memoryOffset</name></param>
+ </command>
+ <command>
+ <proto><type>void</type> <name>vkGetImageMemoryRequirements</name></proto>
+ <param><type>VkDevice</type> <name>device</name></param>
+ <param><type>VkImage</type> <name>image</name></param>
+ <param><type>VkMemoryRequirements</type>* <name>pMemoryRequirements</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>vkBindImageMemory</name></proto>
+ <param><type>VkDevice</type> <name>device</name></param>
+ <param externsync="true"><type>VkImage</type> <name>image</name></param>
+ <param><type>VkDeviceMemory</type> <name>memory</name></param>
+ <param><type>VkDeviceSize</type> <name>memoryOffset</name></param>
+ </command>
+ <command>
+ <proto><type>void</type> <name>vkGetImageSparseMemoryRequirements</name></proto>
+ <param><type>VkDevice</type> <name>device</name></param>
+ <param><type>VkImage</type> <name>image</name></param>
+ <param optional="false,true"><type>uint32_t</type>* <name>pSparseMemoryRequirementCount</name></param>
+ <param optional="true" len="pSparseMemoryRequirementCount"><type>VkSparseImageMemoryRequirements</type>* <name>pSparseMemoryRequirements</name></param>
+ </command>
+ <command>
+ <proto><type>void</type> <name>vkGetPhysicalDeviceSparseImageFormatProperties</name></proto>
+ <param><type>VkPhysicalDevice</type> <name>physicalDevice</name></param>
+ <param><type>VkFormat</type> <name>format</name></param>
+ <param><type>VkImageType</type> <name>type</name></param>
+ <param><type>VkSampleCountFlagBits</type> <name>samples</name></param>
+ <param><type>VkImageUsageFlags</type> <name>usage</name></param>
+ <param><type>VkImageTiling</type> <name>tiling</name></param>
+ <param optional="false,true"><type>uint32_t</type>* <name>pPropertyCount</name></param>
+ <param optional="true" len="pPropertyCount"><type>VkSparseImageFormatProperties</type>* <name>pProperties</name></param>
+ </command>
+ <command queues="sparse_binding" 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>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 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">
+ <proto><type>VkResult</type> <name>vkCreateFence</name></proto>
+ <param><type>VkDevice</type> <name>device</name></param>
+ <param>const <type>VkFenceCreateInfo</type>* <name>pCreateInfo</name></param>
+ <param optional="true">const <type>VkAllocationCallbacks</type>* <name>pAllocator</name></param>
+ <param><type>VkFence</type>* <name>pFence</name></param>
+ </command>
+ <command>
+ <proto><type>void</type> <name>vkDestroyFence</name></proto>
+ <param><type>VkDevice</type> <name>device</name></param>
+ <param optional="true" externsync="true"><type>VkFence</type> <name>fence</name></param>
+ <param optional="true">const <type>VkAllocationCallbacks</type>* <name>pAllocator</name></param>
+ </command>
+ <command successcodes="VK_SUCCESS" errorcodes="VK_ERROR_OUT_OF_DEVICE_MEMORY">
+ <proto><type>VkResult</type> <name>vkResetFences</name></proto>
+ <param><type>VkDevice</type> <name>device</name></param>
+ <param><type>uint32_t</type> <name>fenceCount</name></param>
+ <param len="fenceCount" externsync="true">const <type>VkFence</type>* <name>pFences</name></param>
+ </command>
+ <command successcodes="VK_SUCCESS,VK_NOT_READY" errorcodes="VK_ERROR_OUT_OF_HOST_MEMORY,VK_ERROR_OUT_OF_DEVICE_MEMORY,VK_ERROR_DEVICE_LOST">
+ <proto><type>VkResult</type> <name>vkGetFenceStatus</name></proto>
+ <param><type>VkDevice</type> <name>device</name></param>
+ <param><type>VkFence</type> <name>fence</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>vkWaitForFences</name></proto>
+ <param><type>VkDevice</type> <name>device</name></param>
+ <param><type>uint32_t</type> <name>fenceCount</name></param>
+ <param len="fenceCount">const <type>VkFence</type>* <name>pFences</name></param>
+ <param><type>VkBool32</type> <name>waitAll</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_OUT_OF_DEVICE_MEMORY">
+ <proto><type>VkResult</type> <name>vkCreateSemaphore</name></proto>
+ <param><type>VkDevice</type> <name>device</name></param>
+ <param>const <type>VkSemaphoreCreateInfo</type>* <name>pCreateInfo</name></param>
+ <param optional="true">const <type>VkAllocationCallbacks</type>* <name>pAllocator</name></param>
+ <param><type>VkSemaphore</type>* <name>pSemaphore</name></param>
+ </command>
+ <command>
+ <proto><type>void</type> <name>vkDestroySemaphore</name></proto>
+ <param><type>VkDevice</type> <name>device</name></param>
+ <param optional="true" externsync="true"><type>VkSemaphore</type> <name>semaphore</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">
+ <proto><type>VkResult</type> <name>vkCreateEvent</name></proto>
+ <param><type>VkDevice</type> <name>device</name></param>
+ <param>const <type>VkEventCreateInfo</type>* <name>pCreateInfo</name></param>
+ <param optional="true">const <type>VkAllocationCallbacks</type>* <name>pAllocator</name></param>
+ <param><type>VkEvent</type>* <name>pEvent</name></param>
+ </command>
+ <command>
+ <proto><type>void</type> <name>vkDestroyEvent</name></proto>
+ <param><type>VkDevice</type> <name>device</name></param>
+ <param optional="true" externsync="true"><type>VkEvent</type> <name>event</name></param>
+ <param optional="true">const <type>VkAllocationCallbacks</type>* <name>pAllocator</name></param>
+ </command>
+ <command successcodes="VK_EVENT_SET,VK_EVENT_RESET" errorcodes="VK_ERROR_OUT_OF_HOST_MEMORY,VK_ERROR_OUT_OF_DEVICE_MEMORY,VK_ERROR_DEVICE_LOST">
+ <proto><type>VkResult</type> <name>vkGetEventStatus</name></proto>
+ <param><type>VkDevice</type> <name>device</name></param>
+ <param><type>VkEvent</type> <name>event</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>vkSetEvent</name></proto>
+ <param><type>VkDevice</type> <name>device</name></param>
+ <param externsync="true"><type>VkEvent</type> <name>event</name></param>
+ </command>
+ <command successcodes="VK_SUCCESS" errorcodes="VK_ERROR_OUT_OF_DEVICE_MEMORY">
+ <proto><type>VkResult</type> <name>vkResetEvent</name></proto>
+ <param><type>VkDevice</type> <name>device</name></param>
+ <param externsync="true"><type>VkEvent</type> <name>event</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>vkCreateQueryPool</name></proto>
+ <param><type>VkDevice</type> <name>device</name></param>
+ <param>const <type>VkQueryPoolCreateInfo</type>* <name>pCreateInfo</name></param>
+ <param optional="true">const <type>VkAllocationCallbacks</type>* <name>pAllocator</name></param>
+ <param><type>VkQueryPool</type>* <name>pQueryPool</name></param>
+ </command>
+ <command>
+ <proto><type>void</type> <name>vkDestroyQueryPool</name></proto>
+ <param><type>VkDevice</type> <name>device</name></param>
+ <param optional="true" externsync="true"><type>VkQueryPool</type> <name>queryPool</name></param>
+ <param optional="true">const <type>VkAllocationCallbacks</type>* <name>pAllocator</name></param>
+ </command>
+ <command successcodes="VK_SUCCESS,VK_NOT_READY" errorcodes="VK_ERROR_OUT_OF_HOST_MEMORY,VK_ERROR_OUT_OF_DEVICE_MEMORY,VK_ERROR_DEVICE_LOST">
+ <proto><type>VkResult</type> <name>vkGetQueryPoolResults</name></proto>
+ <param><type>VkDevice</type> <name>device</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>
+ <param><type>size_t</type> <name>dataSize</name></param>
+ <param len="dataSize"><type>void</type>* <name>pData</name></param>
+ <param><type>VkDeviceSize</type> <name>stride</name></param>
+ <param optional="true"><type>VkQueryResultFlags</type> <name>flags</name></param>
+ </command>
+ <command>
+ <proto><type>void</type> <name>vkResetQueryPool</name></proto>
+ <param><type>VkDevice</type> <name>device</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 name="vkResetQueryPoolEXT" alias="vkResetQueryPool"/>
+ <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>vkCreateBuffer</name></proto>
+ <param><type>VkDevice</type> <name>device</name></param>
+ <param>const <type>VkBufferCreateInfo</type>* <name>pCreateInfo</name></param>
+ <param optional="true">const <type>VkAllocationCallbacks</type>* <name>pAllocator</name></param>
+ <param><type>VkBuffer</type>* <name>pBuffer</name></param>
+ </command>
+ <command>
+ <proto><type>void</type> <name>vkDestroyBuffer</name></proto>
+ <param><type>VkDevice</type> <name>device</name></param>
+ <param optional="true" externsync="true"><type>VkBuffer</type> <name>buffer</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">
+ <proto><type>VkResult</type> <name>vkCreateBufferView</name></proto>
+ <param><type>VkDevice</type> <name>device</name></param>
+ <param>const <type>VkBufferViewCreateInfo</type>* <name>pCreateInfo</name></param>
+ <param optional="true">const <type>VkAllocationCallbacks</type>* <name>pAllocator</name></param>
+ <param><type>VkBufferView</type>* <name>pView</name></param>
+ </command>
+ <command>
+ <proto><type>void</type> <name>vkDestroyBufferView</name></proto>
+ <param><type>VkDevice</type> <name>device</name></param>
+ <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">
+ <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>
+ <param optional="true">const <type>VkAllocationCallbacks</type>* <name>pAllocator</name></param>
+ <param><type>VkImage</type>* <name>pImage</name></param>
+ </command>
+ <command>
+ <proto><type>void</type> <name>vkDestroyImage</name></proto>
+ <param><type>VkDevice</type> <name>device</name></param>
+ <param optional="true" externsync="true"><type>VkImage</type> <name>image</name></param>
+ <param optional="true">const <type>VkAllocationCallbacks</type>* <name>pAllocator</name></param>
+ </command>
+ <command>
+ <proto><type>void</type> <name>vkGetImageSubresourceLayout</name></proto>
+ <param><type>VkDevice</type> <name>device</name></param>
+ <param><type>VkImage</type> <name>image</name></param>
+ <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">
+ <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>
+ <param optional="true">const <type>VkAllocationCallbacks</type>* <name>pAllocator</name></param>
+ <param><type>VkImageView</type>* <name>pView</name></param>
+ </command>
+ <command>
+ <proto><type>void</type> <name>vkDestroyImageView</name></proto>
+ <param><type>VkDevice</type> <name>device</name></param>
+ <param optional="true" externsync="true"><type>VkImageView</type> <name>imageView</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_INVALID_SHADER_NV">
+ <proto><type>VkResult</type> <name>vkCreateShaderModule</name></proto>
+ <param><type>VkDevice</type> <name>device</name></param>
+ <param>const <type>VkShaderModuleCreateInfo</type>* <name>pCreateInfo</name></param>
+ <param optional="true">const <type>VkAllocationCallbacks</type>* <name>pAllocator</name></param>
+ <param><type>VkShaderModule</type>* <name>pShaderModule</name></param>
+ </command>
+ <command>
+ <proto><type>void</type> <name>vkDestroyShaderModule</name></proto>
+ <param><type>VkDevice</type> <name>device</name></param>
+ <param optional="true" externsync="true"><type>VkShaderModule</type> <name>shaderModule</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">
+ <proto><type>VkResult</type> <name>vkCreatePipelineCache</name></proto>
+ <param><type>VkDevice</type> <name>device</name></param>
+ <param>const <type>VkPipelineCacheCreateInfo</type>* <name>pCreateInfo</name></param>
+ <param optional="true">const <type>VkAllocationCallbacks</type>* <name>pAllocator</name></param>
+ <param><type>VkPipelineCache</type>* <name>pPipelineCache</name></param>
+ </command>
+ <command>
+ <proto><type>void</type> <name>vkDestroyPipelineCache</name></proto>
+ <param><type>VkDevice</type> <name>device</name></param>
+ <param optional="true" externsync="true"><type>VkPipelineCache</type> <name>pipelineCache</name></param>
+ <param optional="true">const <type>VkAllocationCallbacks</type>* <name>pAllocator</name></param>
+ </command>
+ <command successcodes="VK_SUCCESS,VK_INCOMPLETE" errorcodes="VK_ERROR_OUT_OF_HOST_MEMORY,VK_ERROR_OUT_OF_DEVICE_MEMORY">
+ <proto><type>VkResult</type> <name>vkGetPipelineCacheData</name></proto>
+ <param><type>VkDevice</type> <name>device</name></param>
+ <param><type>VkPipelineCache</type> <name>pipelineCache</name></param>
+ <param optional="false,true"><type>size_t</type>* <name>pDataSize</name></param>
+ <param optional="true" len="pDataSize"><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>vkMergePipelineCaches</name></proto>
+ <param><type>VkDevice</type> <name>device</name></param>
+ <param externsync="true"><type>VkPipelineCache</type> <name>dstCache</name></param>
+ <param><type>uint32_t</type> <name>srcCacheCount</name></param>
+ <param len="srcCacheCount">const <type>VkPipelineCache</type>* <name>pSrcCaches</name></param>
+ </command>
+ <command successcodes="VK_SUCCESS,VK_PIPELINE_COMPILE_REQUIRED_EXT" errorcodes="VK_ERROR_OUT_OF_HOST_MEMORY,VK_ERROR_OUT_OF_DEVICE_MEMORY,VK_ERROR_INVALID_SHADER_NV">
+ <proto><type>VkResult</type> <name>vkCreateGraphicsPipelines</name></proto>
+ <param><type>VkDevice</type> <name>device</name></param>
+ <param optional="true"><type>VkPipelineCache</type> <name>pipelineCache</name></param>
+ <param><type>uint32_t</type> <name>createInfoCount</name></param>
+ <param len="createInfoCount">const <type>VkGraphicsPipelineCreateInfo</type>* <name>pCreateInfos</name></param>
+ <param optional="true">const <type>VkAllocationCallbacks</type>* <name>pAllocator</name></param>
+ <param len="createInfoCount"><type>VkPipeline</type>* <name>pPipelines</name></param>
+ </command>
+ <command successcodes="VK_SUCCESS,VK_PIPELINE_COMPILE_REQUIRED_EXT" errorcodes="VK_ERROR_OUT_OF_HOST_MEMORY,VK_ERROR_OUT_OF_DEVICE_MEMORY,VK_ERROR_INVALID_SHADER_NV">
+ <proto><type>VkResult</type> <name>vkCreateComputePipelines</name></proto>
+ <param><type>VkDevice</type> <name>device</name></param>
+ <param optional="true"><type>VkPipelineCache</type> <name>pipelineCache</name></param>
+ <param><type>uint32_t</type> <name>createInfoCount</name></param>
+ <param len="createInfoCount">const <type>VkComputePipelineCreateInfo</type>* <name>pCreateInfos</name></param>
+ <param optional="true">const <type>VkAllocationCallbacks</type>* <name>pAllocator</name></param>
+ <param len="createInfoCount"><type>VkPipeline</type>* <name>pPipelines</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>vkGetDeviceSubpassShadingMaxWorkgroupSizeHUAWEI</name></proto>
+ <param><type>VkDevice</type> <name>device</name></param>
+ <param><type>VkRenderPass</type> <name>renderpass</name></param>
+ <param><type>VkExtent2D</type>* <name>pMaxWorkgroupSize</name></param>
+ </command>
+ <command>
+ <proto><type>void</type> <name>vkDestroyPipeline</name></proto>
+ <param><type>VkDevice</type> <name>device</name></param>
+ <param optional="true" externsync="true"><type>VkPipeline</type> <name>pipeline</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">
+ <proto><type>VkResult</type> <name>vkCreatePipelineLayout</name></proto>
+ <param><type>VkDevice</type> <name>device</name></param>
+ <param>const <type>VkPipelineLayoutCreateInfo</type>* <name>pCreateInfo</name></param>
+ <param optional="true">const <type>VkAllocationCallbacks</type>* <name>pAllocator</name></param>
+ <param><type>VkPipelineLayout</type>* <name>pPipelineLayout</name></param>
+ </command>
+ <command>
+ <proto><type>void</type> <name>vkDestroyPipelineLayout</name></proto>
+ <param><type>VkDevice</type> <name>device</name></param>
+ <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">
+ <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>
+ <param optional="true">const <type>VkAllocationCallbacks</type>* <name>pAllocator</name></param>
+ <param><type>VkSampler</type>* <name>pSampler</name></param>
+ </command>
+ <command>
+ <proto><type>void</type> <name>vkDestroySampler</name></proto>
+ <param><type>VkDevice</type> <name>device</name></param>
+ <param optional="true" externsync="true"><type>VkSampler</type> <name>sampler</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">
+ <proto><type>VkResult</type> <name>vkCreateDescriptorSetLayout</name></proto>
+ <param><type>VkDevice</type> <name>device</name></param>
+ <param>const <type>VkDescriptorSetLayoutCreateInfo</type>* <name>pCreateInfo</name></param>
+ <param optional="true">const <type>VkAllocationCallbacks</type>* <name>pAllocator</name></param>
+ <param><type>VkDescriptorSetLayout</type>* <name>pSetLayout</name></param>
+ </command>
+ <command>
+ <proto><type>void</type> <name>vkDestroyDescriptorSetLayout</name></proto>
+ <param><type>VkDevice</type> <name>device</name></param>
+ <param optional="true" externsync="true"><type>VkDescriptorSetLayout</type> <name>descriptorSetLayout</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_FRAGMENTATION_EXT">
+ <proto><type>VkResult</type> <name>vkCreateDescriptorPool</name></proto>
+ <param><type>VkDevice</type> <name>device</name></param>
+ <param>const <type>VkDescriptorPoolCreateInfo</type>* <name>pCreateInfo</name></param>
+ <param optional="true">const <type>VkAllocationCallbacks</type>* <name>pAllocator</name></param>
+ <param><type>VkDescriptorPool</type>* <name>pDescriptorPool</name></param>
+ </command>
+ <command>
+ <proto><type>void</type> <name>vkDestroyDescriptorPool</name></proto>
+ <param><type>VkDevice</type> <name>device</name></param>
+ <param optional="true" externsync="true"><type>VkDescriptorPool</type> <name>descriptorPool</name></param>
+ <param optional="true">const <type>VkAllocationCallbacks</type>* <name>pAllocator</name></param>
+ </command>
+ <command successcodes="VK_SUCCESS">
+ <proto><type>VkResult</type> <name>vkResetDescriptorPool</name></proto>
+ <param><type>VkDevice</type> <name>device</name></param>
+ <param externsync="true"><type>VkDescriptorPool</type> <name>descriptorPool</name></param>
+ <param optional="true"><type>VkDescriptorPoolResetFlags</type> <name>flags</name></param>
+ <implicitexternsyncparams>
+ <param>any sname:VkDescriptorSet objects allocated from pname:descriptorPool</param>
+ </implicitexternsyncparams>
+ </command>
+ <command successcodes="VK_SUCCESS" errorcodes="VK_ERROR_OUT_OF_HOST_MEMORY,VK_ERROR_OUT_OF_DEVICE_MEMORY,VK_ERROR_FRAGMENTED_POOL,VK_ERROR_OUT_OF_POOL_MEMORY">
+ <proto><type>VkResult</type> <name>vkAllocateDescriptorSets</name></proto>
+ <param><type>VkDevice</type> <name>device</name></param>
+ <param externsync="pAllocateInfo-&gt;descriptorPool">const <type>VkDescriptorSetAllocateInfo</type>* <name>pAllocateInfo</name></param>
+ <param len="pAllocateInfo-&gt;descriptorSetCount"><type>VkDescriptorSet</type>* <name>pDescriptorSets</name></param>
+ </command>
+ <command successcodes="VK_SUCCESS">
+ <proto><type>VkResult</type> <name>vkFreeDescriptorSets</name></proto>
+ <param><type>VkDevice</type> <name>device</name></param>
+ <param externsync="true"><type>VkDescriptorPool</type> <name>descriptorPool</name></param>
+ <param><type>uint32_t</type> <name>descriptorSetCount</name></param>
+ <param noautovalidity="true" externsync="true" len="descriptorSetCount">const <type>VkDescriptorSet</type>* <name>pDescriptorSets</name></param>
+ </command>
+ <command>
+ <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 optional="true"><type>uint32_t</type> <name>descriptorCopyCount</name></param>
+ <param len="descriptorCopyCount" externsync="pDescriptorCopies[].dstSet">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>
+ <param><type>VkDevice</type> <name>device</name></param>
+ <param>const <type>VkFramebufferCreateInfo</type>* <name>pCreateInfo</name></param>
+ <param optional="true">const <type>VkAllocationCallbacks</type>* <name>pAllocator</name></param>
+ <param><type>VkFramebuffer</type>* <name>pFramebuffer</name></param>
+ </command>
+ <command>
+ <proto><type>void</type> <name>vkDestroyFramebuffer</name></proto>
+ <param><type>VkDevice</type> <name>device</name></param>
+ <param optional="true" externsync="true"><type>VkFramebuffer</type> <name>framebuffer</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">
+ <proto><type>VkResult</type> <name>vkCreateRenderPass</name></proto>
+ <param><type>VkDevice</type> <name>device</name></param>
+ <param>const <type>VkRenderPassCreateInfo</type>* <name>pCreateInfo</name></param>
+ <param optional="true">const <type>VkAllocationCallbacks</type>* <name>pAllocator</name></param>
+ <param><type>VkRenderPass</type>* <name>pRenderPass</name></param>
+ </command>
+ <command>
+ <proto><type>void</type> <name>vkDestroyRenderPass</name></proto>
+ <param><type>VkDevice</type> <name>device</name></param>
+ <param optional="true" externsync="true"><type>VkRenderPass</type> <name>renderPass</name></param>
+ <param optional="true">const <type>VkAllocationCallbacks</type>* <name>pAllocator</name></param>
+ </command>
+ <command>
+ <proto><type>void</type> <name>vkGetRenderAreaGranularity</name></proto>
+ <param><type>VkDevice</type> <name>device</name></param>
+ <param><type>VkRenderPass</type> <name>renderPass</name></param>
+ <param><type>VkExtent2D</type>* <name>pGranularity</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>vkCreateCommandPool</name></proto>
+ <param><type>VkDevice</type> <name>device</name></param>
+ <param>const <type>VkCommandPoolCreateInfo</type>* <name>pCreateInfo</name></param>
+ <param optional="true">const <type>VkAllocationCallbacks</type>* <name>pAllocator</name></param>
+ <param><type>VkCommandPool</type>* <name>pCommandPool</name></param>
+ </command>
+ <command>
+ <proto><type>void</type> <name>vkDestroyCommandPool</name></proto>
+ <param><type>VkDevice</type> <name>device</name></param>
+ <param optional="true" externsync="true"><type>VkCommandPool</type> <name>commandPool</name></param>
+ <param optional="true">const <type>VkAllocationCallbacks</type>* <name>pAllocator</name></param>
+ </command>
+ <command successcodes="VK_SUCCESS" errorcodes="VK_ERROR_OUT_OF_DEVICE_MEMORY">
+ <proto><type>VkResult</type> <name>vkResetCommandPool</name></proto>
+ <param><type>VkDevice</type> <name>device</name></param>
+ <param externsync="true"><type>VkCommandPool</type> <name>commandPool</name></param>
+ <param optional="true"><type>VkCommandPoolResetFlags</type> <name>flags</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>vkAllocateCommandBuffers</name></proto>
+ <param><type>VkDevice</type> <name>device</name></param>
+ <param externsync="pAllocateInfo-&gt;commandPool">const <type>VkCommandBufferAllocateInfo</type>* <name>pAllocateInfo</name></param>
+ <param len="pAllocateInfo-&gt;commandBufferCount"><type>VkCommandBuffer</type>* <name>pCommandBuffers</name></param>
+ </command>
+ <command>
+ <proto><type>void</type> <name>vkFreeCommandBuffers</name></proto>
+ <param><type>VkDevice</type> <name>device</name></param>
+ <param externsync="true"><type>VkCommandPool</type> <name>commandPool</name></param>
+ <param><type>uint32_t</type> <name>commandBufferCount</name></param>
+ <param noautovalidity="true" externsync="true" len="commandBufferCount">const <type>VkCommandBuffer</type>* <name>pCommandBuffers</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>vkBeginCommandBuffer</name></proto>
+ <param externsync="true"><type>VkCommandBuffer</type> <name>commandBuffer</name></param>
+ <param>const <type>VkCommandBufferBeginInfo</type>* <name>pBeginInfo</name></param>
+ <implicitexternsyncparams>
+ <param>the sname:VkCommandPool that pname:commandBuffer was allocated from</param>
+ </implicitexternsyncparams>
+ </command>
+ <command successcodes="VK_SUCCESS" errorcodes="VK_ERROR_OUT_OF_HOST_MEMORY,VK_ERROR_OUT_OF_DEVICE_MEMORY">
+ <proto><type>VkResult</type> <name>vkEndCommandBuffer</name></proto>
+ <param externsync="true"><type>VkCommandBuffer</type> <name>commandBuffer</name></param>
+ <implicitexternsyncparams>
+ <param>the sname:VkCommandPool that pname:commandBuffer was allocated from</param>
+ </implicitexternsyncparams>
+ </command>
+ <command successcodes="VK_SUCCESS" errorcodes="VK_ERROR_OUT_OF_DEVICE_MEMORY">
+ <proto><type>VkResult</type> <name>vkResetCommandBuffer</name></proto>
+ <param externsync="true"><type>VkCommandBuffer</type> <name>commandBuffer</name></param>
+ <param optional="true"><type>VkCommandBufferResetFlags</type> <name>flags</name></param>
+ <implicitexternsyncparams>
+ <param>the sname:VkCommandPool that pname:commandBuffer was allocated from</param>
+ </implicitexternsyncparams>
+ </command>
+ <command queues="graphics,compute" renderpass="both" cmdbufferlevel="primary,secondary">
+ <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">
+ <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">
+ <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">
+ <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">
+ <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">
+ <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">
+ <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">
+ <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">
+ <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">
+ <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">
+ <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 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">
+ <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">
+ <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>
+ <param><type>uint32_t</type> <name>bindingCount</name></param>
+ <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">
+ <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>
+ <param><type>uint32_t</type> <name>instanceCount</name></param>
+ <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">
+ <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>
+ <param><type>uint32_t</type> <name>instanceCount</name></param>
+ <param><type>uint32_t</type> <name>firstIndex</name></param>
+ <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">
+ <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><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">
+ <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><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">
+ <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>
+ <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">
+ <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>
+ <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="compute" renderpass="outside" cmdbufferlevel="primary,secondary">
+ <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">
+ <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">
+ <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">
+ <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>
+ <param><type>VkBuffer</type> <name>dstBuffer</name></param>
+ <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">
+ <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>
+ <param><type>VkImageLayout</type> <name>srcImageLayout</name></param>
+ <param><type>VkImage</type> <name>dstImage</name></param>
+ <param><type>VkImageLayout</type> <name>dstImageLayout</name></param>
+ <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">
+ <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>
+ <param><type>VkImageLayout</type> <name>srcImageLayout</name></param>
+ <param><type>VkImage</type> <name>dstImage</name></param>
+ <param><type>VkImageLayout</type> <name>dstImageLayout</name></param>
+ <param><type>uint32_t</type> <name>regionCount</name></param>
+ <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">
+ <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>
+ <param><type>VkImage</type> <name>dstImage</name></param>
+ <param><type>VkImageLayout</type> <name>dstImageLayout</name></param>
+ <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">
+ <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>
+ <param><type>VkImageLayout</type> <name>srcImageLayout</name></param>
+ <param><type>VkBuffer</type> <name>dstBuffer</name></param>
+ <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">
+ <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>
+ <param><type>VkDeviceSize</type> <name>dstOffset</name></param>
+ <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">
+ <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>
+ <param><type>VkDeviceSize</type> <name>dstOffset</name></param>
+ <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">
+ <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>
+ <param><type>VkImageLayout</type> <name>imageLayout</name></param>
+ <param noautovalidity="true">const <type>VkClearColorValue</type>* <name>pColor</name></param>
+ <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">
+ <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>
+ <param><type>VkImageLayout</type> <name>imageLayout</name></param>
+ <param>const <type>VkClearDepthStencilValue</type>* <name>pDepthStencil</name></param>
+ <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">
+ <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>
+ <param len="attachmentCount">const <type>VkClearAttachment</type>* <name>pAttachments</name></param>
+ <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">
+ <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>
+ <param><type>VkImageLayout</type> <name>srcImageLayout</name></param>
+ <param><type>VkImage</type> <name>dstImage</name></param>
+ <param><type>VkImageLayout</type> <name>dstImageLayout</name></param>
+ <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">
+ <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">
+ <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">
+ <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>
+ <param len="eventCount">const <type>VkEvent</type>* <name>pEvents</name></param>
+ <param optional="true"><type>VkPipelineStageFlags</type> <name>srcStageMask</name></param>
+ <param optional="true"><type>VkPipelineStageFlags</type> <name>dstStageMask</name></param>
+ <param optional="true"><type>uint32_t</type> <name>memoryBarrierCount</name></param>
+ <param len="memoryBarrierCount">const <type>VkMemoryBarrier</type>* <name>pMemoryBarriers</name></param>
+ <param optional="true"><type>uint32_t</type> <name>bufferMemoryBarrierCount</name></param>
+ <param len="bufferMemoryBarrierCount">const <type>VkBufferMemoryBarrier</type>* <name>pBufferMemoryBarriers</name></param>
+ <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">
+ <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>
+ <param optional="true"><type>VkPipelineStageFlags</type> <name>dstStageMask</name></param>
+ <param optional="true"><type>VkDependencyFlags</type> <name>dependencyFlags</name></param>
+ <param optional="true"><type>uint32_t</type> <name>memoryBarrierCount</name></param>
+ <param len="memoryBarrierCount">const <type>VkMemoryBarrier</type>* <name>pMemoryBarriers</name></param>
+ <param optional="true"><type>uint32_t</type> <name>bufferMemoryBarrierCount</name></param>
+ <param len="bufferMemoryBarrierCount">const <type>VkBufferMemoryBarrier</type>* <name>pBufferMemoryBarriers</name></param>
+ <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">
+ <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">
+ <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">
+ <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">
+ <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">
+ <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">
+ <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">
+ <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>
+ <param><type>uint32_t</type> <name>firstQuery</name></param>
+ <param><type>uint32_t</type> <name>queryCount</name></param>
+ <param><type>VkBuffer</type> <name>dstBuffer</name></param>
+ <param><type>VkDeviceSize</type> <name>dstOffset</name></param>
+ <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">
+ <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>
+ <param><type>VkShaderStageFlags</type> <name>stageFlags</name></param>
+ <param><type>uint32_t</type> <name>offset</name></param>
+ <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">
+ <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">
+ <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">
+ <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">
+ <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>
+ <param len="commandBufferCount">const <type>VkCommandBuffer</type>* <name>pCommandBuffers</name></param>
+ </command>
+ <command successcodes="VK_SUCCESS" errorcodes="VK_ERROR_OUT_OF_HOST_MEMORY,VK_ERROR_OUT_OF_DEVICE_MEMORY,VK_ERROR_NATIVE_WINDOW_IN_USE_KHR">
+ <proto><type>VkResult</type> <name>vkCreateAndroidSurfaceKHR</name></proto>
+ <param><type>VkInstance</type> <name>instance</name></param>
+ <param>const <type>VkAndroidSurfaceCreateInfoKHR</type>* <name>pCreateInfo</name></param>
+ <param optional="true">const <type>VkAllocationCallbacks</type>* <name>pAllocator</name></param>
+ <param><type>VkSurfaceKHR</type>* <name>pSurface</name></param>
+ </command>
+ <command successcodes="VK_SUCCESS,VK_INCOMPLETE" errorcodes="VK_ERROR_OUT_OF_HOST_MEMORY,VK_ERROR_OUT_OF_DEVICE_MEMORY">
+ <proto><type>VkResult</type> <name>vkGetPhysicalDeviceDisplayPropertiesKHR</name></proto>
+ <param><type>VkPhysicalDevice</type> <name>physicalDevice</name></param>
+ <param optional="false,true"><type>uint32_t</type>* <name>pPropertyCount</name></param>
+ <param optional="true" len="pPropertyCount"><type>VkDisplayPropertiesKHR</type>* <name>pProperties</name></param>
+ </command>
+ <command successcodes="VK_SUCCESS,VK_INCOMPLETE" errorcodes="VK_ERROR_OUT_OF_HOST_MEMORY,VK_ERROR_OUT_OF_DEVICE_MEMORY">
+ <proto><type>VkResult</type> <name>vkGetPhysicalDeviceDisplayPlanePropertiesKHR</name></proto>
+ <param><type>VkPhysicalDevice</type> <name>physicalDevice</name></param>
+ <param optional="false,true"><type>uint32_t</type>* <name>pPropertyCount</name></param>
+ <param optional="true" len="pPropertyCount"><type>VkDisplayPlanePropertiesKHR</type>* <name>pProperties</name></param>
+ </command>
+ <command successcodes="VK_SUCCESS,VK_INCOMPLETE" errorcodes="VK_ERROR_OUT_OF_HOST_MEMORY,VK_ERROR_OUT_OF_DEVICE_MEMORY">
+ <proto><type>VkResult</type> <name>vkGetDisplayPlaneSupportedDisplaysKHR</name></proto>
+ <param><type>VkPhysicalDevice</type> <name>physicalDevice</name></param>
+ <param><type>uint32_t</type> <name>planeIndex</name></param>
+ <param optional="false,true"><type>uint32_t</type>* <name>pDisplayCount</name></param>
+ <param optional="true" len="pDisplayCount"><type>VkDisplayKHR</type>* <name>pDisplays</name></param>
+ </command>
+ <command successcodes="VK_SUCCESS,VK_INCOMPLETE" errorcodes="VK_ERROR_OUT_OF_HOST_MEMORY,VK_ERROR_OUT_OF_DEVICE_MEMORY">
+ <proto><type>VkResult</type> <name>vkGetDisplayModePropertiesKHR</name></proto>
+ <param><type>VkPhysicalDevice</type> <name>physicalDevice</name></param>
+ <param><type>VkDisplayKHR</type> <name>display</name></param>
+ <param optional="false,true"><type>uint32_t</type>* <name>pPropertyCount</name></param>
+ <param optional="true" len="pPropertyCount"><type>VkDisplayModePropertiesKHR</type>* <name>pProperties</name></param>
+ </command>
+ <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>vkCreateDisplayModeKHR</name></proto>
+ <param><type>VkPhysicalDevice</type> <name>physicalDevice</name></param>
+ <param externsync="true"><type>VkDisplayKHR</type> <name>display</name></param>
+ <param>const <type>VkDisplayModeCreateInfoKHR</type>* <name>pCreateInfo</name></param>
+ <param optional="true">const <type>VkAllocationCallbacks</type>* <name>pAllocator</name></param>
+ <param><type>VkDisplayModeKHR</type>* <name>pMode</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>vkGetDisplayPlaneCapabilitiesKHR</name></proto>
+ <param><type>VkPhysicalDevice</type> <name>physicalDevice</name></param>
+ <param externsync="true"><type>VkDisplayModeKHR</type> <name>mode</name></param>
+ <param><type>uint32_t</type> <name>planeIndex</name></param>
+ <param><type>VkDisplayPlaneCapabilitiesKHR</type>* <name>pCapabilities</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>vkCreateDisplayPlaneSurfaceKHR</name></proto>
+ <param><type>VkInstance</type> <name>instance</name></param>
+ <param>const <type>VkDisplaySurfaceCreateInfoKHR</type>* <name>pCreateInfo</name></param>
+ <param optional="true">const <type>VkAllocationCallbacks</type>* <name>pAllocator</name></param>
+ <param><type>VkSurfaceKHR</type>* <name>pSurface</name></param>
+ </command>
+ <command successcodes="VK_SUCCESS" errorcodes="VK_ERROR_OUT_OF_HOST_MEMORY,VK_ERROR_OUT_OF_DEVICE_MEMORY,VK_ERROR_INCOMPATIBLE_DISPLAY_KHR,VK_ERROR_DEVICE_LOST,VK_ERROR_SURFACE_LOST_KHR">
+ <proto><type>VkResult</type> <name>vkCreateSharedSwapchainsKHR</name></proto>
+ <param><type>VkDevice</type> <name>device</name></param>
+ <param><type>uint32_t</type> <name>swapchainCount</name></param>
+ <param len="swapchainCount" externsync="pCreateInfos[].surface,pCreateInfos[].oldSwapchain">const <type>VkSwapchainCreateInfoKHR</type>* <name>pCreateInfos</name></param>
+ <param optional="true">const <type>VkAllocationCallbacks</type>* <name>pAllocator</name></param>
+ <param len="swapchainCount"><type>VkSwapchainKHR</type>* <name>pSwapchains</name></param>
+ </command>
+ <command>
+ <proto><type>void</type> <name>vkDestroySurfaceKHR</name></proto>
+ <param><type>VkInstance</type> <name>instance</name></param>
+ <param optional="true" externsync="true"><type>VkSurfaceKHR</type> <name>surface</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_SURFACE_LOST_KHR">
+ <proto><type>VkResult</type> <name>vkGetPhysicalDeviceSurfaceSupportKHR</name></proto>
+ <param><type>VkPhysicalDevice</type> <name>physicalDevice</name></param>
+ <param><type>uint32_t</type> <name>queueFamilyIndex</name></param>
+ <param><type>VkSurfaceKHR</type> <name>surface</name></param>
+ <param><type>VkBool32</type>* <name>pSupported</name></param>
+ </command>
+ <command successcodes="VK_SUCCESS" errorcodes="VK_ERROR_OUT_OF_HOST_MEMORY,VK_ERROR_OUT_OF_DEVICE_MEMORY,VK_ERROR_SURFACE_LOST_KHR">
+ <proto><type>VkResult</type> <name>vkGetPhysicalDeviceSurfaceCapabilitiesKHR</name></proto>
+ <param><type>VkPhysicalDevice</type> <name>physicalDevice</name></param>
+ <param><type>VkSurfaceKHR</type> <name>surface</name></param>
+ <param><type>VkSurfaceCapabilitiesKHR</type>* <name>pSurfaceCapabilities</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>vkGetPhysicalDeviceSurfaceFormatsKHR</name></proto>
+ <param><type>VkPhysicalDevice</type> <name>physicalDevice</name></param>
+ <param><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="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">
+ <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>
+ <param optional="true">const <type>VkAllocationCallbacks</type>* <name>pAllocator</name></param>
+ <param><type>VkSwapchainKHR</type>* <name>pSwapchain</name></param>
+ </command>
+ <command>
+ <proto><type>void</type> <name>vkDestroySwapchainKHR</name></proto>
+ <param><type>VkDevice</type> <name>device</name></param>
+ <param optional="true" externsync="true"><type>VkSwapchainKHR</type> <name>swapchain</name></param>
+ <param optional="true">const <type>VkAllocationCallbacks</type>* <name>pAllocator</name></param>
+ </command>
+ <command successcodes="VK_SUCCESS,VK_INCOMPLETE" errorcodes="VK_ERROR_OUT_OF_HOST_MEMORY,VK_ERROR_OUT_OF_DEVICE_MEMORY">
+ <proto><type>VkResult</type> <name>vkGetSwapchainImagesKHR</name></proto>
+ <param><type>VkDevice</type> <name>device</name></param>
+ <param><type>VkSwapchainKHR</type> <name>swapchain</name></param>
+ <param optional="false,true"><type>uint32_t</type>* <name>pSwapchainImageCount</name></param>
+ <param optional="true" len="pSwapchainImageCount"><type>VkImage</type>* <name>pSwapchainImages</name></param>
+ </command>
+ <command successcodes="VK_SUCCESS,VK_TIMEOUT,VK_NOT_READY,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>vkAcquireNextImageKHR</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>timeout</name></param>
+ <param optional="true" externsync="true"><type>VkSemaphore</type> <name>semaphore</name></param>
+ <param optional="true" externsync="true"><type>VkFence</type> <name>fence</name></param>
+ <param><type>uint32_t</type>* <name>pImageIndex</name></param>
+ </command>
+ <command successcodes="VK_SUCCESS,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>vkQueuePresentKHR</name></proto>
+ <param externsync="true"><type>VkQueue</type> <name>queue</name></param>
+ <param externsync="pPresentInfo-&gt;pWaitSemaphores[],pPresentInfo-&gt;pSwapchains[]">const <type>VkPresentInfoKHR</type>* <name>pPresentInfo</name></param>
+ </command>
+ <command successcodes="VK_SUCCESS" errorcodes="VK_ERROR_OUT_OF_HOST_MEMORY,VK_ERROR_OUT_OF_DEVICE_MEMORY,VK_ERROR_NATIVE_WINDOW_IN_USE_KHR">
+ <proto><type>VkResult</type> <name>vkCreateViSurfaceNN</name></proto>
+ <param><type>VkInstance</type> <name>instance</name></param>
+ <param>const <type>VkViSurfaceCreateInfoNN</type>* <name>pCreateInfo</name></param>
+ <param optional="true">const <type>VkAllocationCallbacks</type>* <name>pAllocator</name></param>
+ <param><type>VkSurfaceKHR</type>* <name>pSurface</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>vkCreateWaylandSurfaceKHR</name></proto>
+ <param><type>VkInstance</type> <name>instance</name></param>
+ <param>const <type>VkWaylandSurfaceCreateInfoKHR</type>* <name>pCreateInfo</name></param>
+ <param optional="true">const <type>VkAllocationCallbacks</type>* <name>pAllocator</name></param>
+ <param><type>VkSurfaceKHR</type>* <name>pSurface</name></param>
+ </command>
+ <command>
+ <proto><type>VkBool32</type> <name>vkGetPhysicalDeviceWaylandPresentationSupportKHR</name></proto>
+ <param><type>VkPhysicalDevice</type> <name>physicalDevice</name></param>
+ <param><type>uint32_t</type> <name>queueFamilyIndex</name></param>
+ <param>struct <type>wl_display</type>* <name>display</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>vkCreateWin32SurfaceKHR</name></proto>
+ <param><type>VkInstance</type> <name>instance</name></param>
+ <param>const <type>VkWin32SurfaceCreateInfoKHR</type>* <name>pCreateInfo</name></param>
+ <param optional="true">const <type>VkAllocationCallbacks</type>* <name>pAllocator</name></param>
+ <param><type>VkSurfaceKHR</type>* <name>pSurface</name></param>
+ </command>
+ <command>
+ <proto><type>VkBool32</type> <name>vkGetPhysicalDeviceWin32PresentationSupportKHR</name></proto>
+ <param><type>VkPhysicalDevice</type> <name>physicalDevice</name></param>
+ <param><type>uint32_t</type> <name>queueFamilyIndex</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>vkCreateXlibSurfaceKHR</name></proto>
+ <param><type>VkInstance</type> <name>instance</name></param>
+ <param>const <type>VkXlibSurfaceCreateInfoKHR</type>* <name>pCreateInfo</name></param>
+ <param optional="true">const <type>VkAllocationCallbacks</type>* <name>pAllocator</name></param>
+ <param><type>VkSurfaceKHR</type>* <name>pSurface</name></param>
+ </command>
+ <command>
+ <proto><type>VkBool32</type> <name>vkGetPhysicalDeviceXlibPresentationSupportKHR</name></proto>
+ <param><type>VkPhysicalDevice</type> <name>physicalDevice</name></param>
+ <param><type>uint32_t</type> <name>queueFamilyIndex</name></param>
+ <param><type>Display</type>* <name>dpy</name></param>
+ <param><type>VisualID</type> <name>visualID</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>vkCreateXcbSurfaceKHR</name></proto>
+ <param><type>VkInstance</type> <name>instance</name></param>
+ <param>const <type>VkXcbSurfaceCreateInfoKHR</type>* <name>pCreateInfo</name></param>
+ <param optional="true">const <type>VkAllocationCallbacks</type>* <name>pAllocator</name></param>
+ <param><type>VkSurfaceKHR</type>* <name>pSurface</name></param>
+ </command>
+ <command>
+ <proto><type>VkBool32</type> <name>vkGetPhysicalDeviceXcbPresentationSupportKHR</name></proto>
+ <param><type>VkPhysicalDevice</type> <name>physicalDevice</name></param>
+ <param><type>uint32_t</type> <name>queueFamilyIndex</name></param>
+ <param><type>xcb_connection_t</type>* <name>connection</name></param>
+ <param><type>xcb_visualid_t</type> <name>visual_id</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>vkCreateDirectFBSurfaceEXT</name></proto>
+ <param><type>VkInstance</type> <name>instance</name></param>
+ <param>const <type>VkDirectFBSurfaceCreateInfoEXT</type>* <name>pCreateInfo</name></param>
+ <param optional="true">const <type>VkAllocationCallbacks</type>* <name>pAllocator</name></param>
+ <param><type>VkSurfaceKHR</type>* <name>pSurface</name></param>
+ </command>
+ <command>
+ <proto><type>VkBool32</type> <name>vkGetPhysicalDeviceDirectFBPresentationSupportEXT</name></proto>
+ <param><type>VkPhysicalDevice</type> <name>physicalDevice</name></param>
+ <param><type>uint32_t</type> <name>queueFamilyIndex</name></param>
+ <param><type>IDirectFB</type>* <name>dfb</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>vkCreateImagePipeSurfaceFUCHSIA</name></proto>
+ <param><type>VkInstance</type> <name>instance</name></param>
+ <param>const <type>VkImagePipeSurfaceCreateInfoFUCHSIA</type>* <name>pCreateInfo</name></param>
+ <param optional="true">const <type>VkAllocationCallbacks</type>* <name>pAllocator</name></param>
+ <param><type>VkSurfaceKHR</type>* <name>pSurface</name></param>
+ </command>
+ <command successcodes="VK_SUCCESS" errorcodes="VK_ERROR_OUT_OF_HOST_MEMORY,VK_ERROR_OUT_OF_DEVICE_MEMORY,VK_ERROR_NATIVE_WINDOW_IN_USE_KHR">
+ <proto><type>VkResult</type> <name>vkCreateStreamDescriptorSurfaceGGP</name></proto>
+ <param><type>VkInstance</type> <name>instance</name></param>
+ <param>const <type>VkStreamDescriptorSurfaceCreateInfoGGP</type>* <name>pCreateInfo</name></param>
+ <param optional="true">const <type>VkAllocationCallbacks</type>* <name>pAllocator</name></param>
+ <param><type>VkSurfaceKHR</type>* <name>pSurface</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>vkCreateScreenSurfaceQNX</name></proto>
+ <param><type>VkInstance</type> <name>instance</name></param>
+ <param>const <type>VkScreenSurfaceCreateInfoQNX</type>* <name>pCreateInfo</name></param>
+ <param optional="true">const <type>VkAllocationCallbacks</type>* <name>pAllocator</name></param>
+ <param><type>VkSurfaceKHR</type>* <name>pSurface</name></param>
+ </command>
+ <command>
+ <proto><type>VkBool32</type> <name>vkGetPhysicalDeviceScreenPresentationSupportQNX</name></proto>
+ <param><type>VkPhysicalDevice</type> <name>physicalDevice</name></param>
+ <param><type>uint32_t</type> <name>queueFamilyIndex</name></param>
+ <param>struct <type>_screen_window</type>* <name>window</name></param>
+ </command>
+ <command successcodes="VK_SUCCESS" errorcodes="VK_ERROR_OUT_OF_HOST_MEMORY">
+ <proto><type>VkResult</type> <name>vkCreateDebugReportCallbackEXT</name></proto>
+ <param><type>VkInstance</type> <name>instance</name></param>
+ <param>const <type>VkDebugReportCallbackCreateInfoEXT</type>* <name>pCreateInfo</name></param>
+ <param optional="true">const <type>VkAllocationCallbacks</type>* <name>pAllocator</name></param>
+ <param><type>VkDebugReportCallbackEXT</type>* <name>pCallback</name></param>
+ </command>
+ <command>
+ <proto><type>void</type> <name>vkDestroyDebugReportCallbackEXT</name></proto>
+ <param><type>VkInstance</type> <name>instance</name></param>
+ <param optional="true" externsync="true"><type>VkDebugReportCallbackEXT</type> <name>callback</name></param>
+ <param optional="true">const <type>VkAllocationCallbacks</type>* <name>pAllocator</name></param>
+ </command>
+ <command>
+ <proto><type>void</type> <name>vkDebugReportMessageEXT</name></proto>
+ <param><type>VkInstance</type> <name>instance</name></param>
+ <param><type>VkDebugReportFlagsEXT</type> <name>flags</name></param>
+ <param><type>VkDebugReportObjectTypeEXT</type> <name>objectType</name></param>
+ <param objecttype="objectType"><type>uint64_t</type> <name>object</name></param>
+ <param><type>size_t</type> <name>location</name></param>
+ <param><type>int32_t</type> <name>messageCode</name></param>
+ <param len="null-terminated">const <type>char</type>* <name>pLayerPrefix</name></param>
+ <param len="null-terminated">const <type>char</type>* <name>pMessage</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>vkDebugMarkerSetObjectNameEXT</name></proto>
+ <param><type>VkDevice</type> <name>device</name></param>
+ <param externsync="pNameInfo-&gt;object">const <type>VkDebugMarkerObjectNameInfoEXT</type>* <name>pNameInfo</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>vkDebugMarkerSetObjectTagEXT</name></proto>
+ <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">
+ <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">
+ <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">
+ <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>
+ </command>
+ <command successcodes="VK_SUCCESS" errorcodes="VK_ERROR_OUT_OF_HOST_MEMORY,VK_ERROR_OUT_OF_DEVICE_MEMORY,VK_ERROR_FORMAT_NOT_SUPPORTED">
+ <proto><type>VkResult</type> <name>vkGetPhysicalDeviceExternalImageFormatPropertiesNV</name></proto>
+ <param><type>VkPhysicalDevice</type> <name>physicalDevice</name></param>
+ <param><type>VkFormat</type> <name>format</name></param>
+ <param><type>VkImageType</type> <name>type</name></param>
+ <param><type>VkImageTiling</type> <name>tiling</name></param>
+ <param><type>VkImageUsageFlags</type> <name>usage</name></param>
+ <param optional="true"><type>VkImageCreateFlags</type> <name>flags</name></param>
+ <param optional="true"><type>VkExternalMemoryHandleTypeFlagsNV</type> <name>externalHandleType</name></param>
+ <param><type>VkExternalImageFormatPropertiesNV</type>* <name>pExternalImageFormatProperties</name></param>
+ </command>
+ <command successcodes="VK_SUCCESS" errorcodes="VK_ERROR_TOO_MANY_OBJECTS,VK_ERROR_OUT_OF_HOST_MEMORY">
+ <proto><type>VkResult</type> <name>vkGetMemoryWin32HandleNV</name></proto>
+ <param><type>VkDevice</type> <name>device</name></param>
+ <param><type>VkDeviceMemory</type> <name>memory</name></param>
+ <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">
+ <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">
+ <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">
+ <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>
+ <param><type>VkPipeline</type> <name>pipeline</name></param>
+ <param><type>uint32_t</type> <name>groupIndex</name></param>
+ </command>
+ <command>
+ <proto><type>void</type> <name>vkGetGeneratedCommandsMemoryRequirementsNV</name></proto>
+ <param><type>VkDevice</type> <name>device</name></param>
+ <param>const <type>VkGeneratedCommandsMemoryRequirementsInfoNV</type>* <name>pInfo</name></param>
+ <param><type>VkMemoryRequirements2</type>* <name>pMemoryRequirements</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>vkCreateIndirectCommandsLayoutNV</name></proto>
+ <param><type>VkDevice</type> <name>device</name></param>
+ <param>const <type>VkIndirectCommandsLayoutCreateInfoNV</type>* <name>pCreateInfo</name></param>
+ <param optional="true">const <type>VkAllocationCallbacks</type>* <name>pAllocator</name></param>
+ <param><type>VkIndirectCommandsLayoutNV</type>* <name>pIndirectCommandsLayout</name></param>
+ </command>
+ <command>
+ <proto><type>void</type> <name>vkDestroyIndirectCommandsLayoutNV</name></proto>
+ <param><type>VkDevice</type> <name>device</name></param>
+ <param optional="true" externsync="true"><type>VkIndirectCommandsLayoutNV</type> <name>indirectCommandsLayout</name></param>
+ <param optional="true">const <type>VkAllocationCallbacks</type>* <name>pAllocator</name></param>
+ </command>
+ <command>
+ <proto><type>void</type> <name>vkGetPhysicalDeviceFeatures2</name></proto>
+ <param><type>VkPhysicalDevice</type> <name>physicalDevice</name></param>
+ <param><type>VkPhysicalDeviceFeatures2</type>* <name>pFeatures</name></param>
+ </command>
+ <command name="vkGetPhysicalDeviceFeatures2KHR" alias="vkGetPhysicalDeviceFeatures2"/>
+ <command>
+ <proto><type>void</type> <name>vkGetPhysicalDeviceProperties2</name></proto>
+ <param><type>VkPhysicalDevice</type> <name>physicalDevice</name></param>
+ <param><type>VkPhysicalDeviceProperties2</type>* <name>pProperties</name></param>
+ </command>
+ <command name="vkGetPhysicalDeviceProperties2KHR" alias="vkGetPhysicalDeviceProperties2"/>
+ <command>
+ <proto><type>void</type> <name>vkGetPhysicalDeviceFormatProperties2</name></proto>
+ <param><type>VkPhysicalDevice</type> <name>physicalDevice</name></param>
+ <param><type>VkFormat</type> <name>format</name></param>
+ <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">
+ <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>
+ <param><type>VkImageFormatProperties2</type>* <name>pImageFormatProperties</name></param>
+ </command>
+ <command name="vkGetPhysicalDeviceImageFormatProperties2KHR" alias="vkGetPhysicalDeviceImageFormatProperties2"/>
+ <command>
+ <proto><type>void</type> <name>vkGetPhysicalDeviceQueueFamilyProperties2</name></proto>
+ <param><type>VkPhysicalDevice</type> <name>physicalDevice</name></param>
+ <param optional="false,true"><type>uint32_t</type>* <name>pQueueFamilyPropertyCount</name></param>
+ <param optional="true" len="pQueueFamilyPropertyCount"><type>VkQueueFamilyProperties2</type>* <name>pQueueFamilyProperties</name></param>
+ </command>
+ <command name="vkGetPhysicalDeviceQueueFamilyProperties2KHR" alias="vkGetPhysicalDeviceQueueFamilyProperties2"/>
+ <command>
+ <proto><type>void</type> <name>vkGetPhysicalDeviceMemoryProperties2</name></proto>
+ <param><type>VkPhysicalDevice</type> <name>physicalDevice</name></param>
+ <param><type>VkPhysicalDeviceMemoryProperties2</type>* <name>pMemoryProperties</name></param>
+ </command>
+ <command name="vkGetPhysicalDeviceMemoryProperties2KHR" alias="vkGetPhysicalDeviceMemoryProperties2"/>
+ <command>
+ <proto><type>void</type> <name>vkGetPhysicalDeviceSparseImageFormatProperties2</name></proto>
+ <param><type>VkPhysicalDevice</type> <name>physicalDevice</name></param>
+ <param>const <type>VkPhysicalDeviceSparseImageFormatInfo2</type>* <name>pFormatInfo</name></param>
+ <param optional="false,true"><type>uint32_t</type>* <name>pPropertyCount</name></param>
+ <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">
+ <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>
+ <param><type>VkPipelineLayout</type> <name>layout</name></param>
+ <param><type>uint32_t</type> <name>set</name></param>
+ <param><type>uint32_t</type> <name>descriptorWriteCount</name></param>
+ <param len="descriptorWriteCount">const <type>VkWriteDescriptorSet</type>* <name>pDescriptorWrites</name></param>
+ </command>
+ <command>
+ <proto><type>void</type> <name>vkTrimCommandPool</name></proto>
+ <param><type>VkDevice</type> <name>device</name></param>
+ <param externsync="true"><type>VkCommandPool</type> <name>commandPool</name></param>
+ <param optional="true"><type>VkCommandPoolTrimFlags</type> <name>flags</name></param>
+ </command>
+ <command name="vkTrimCommandPoolKHR" alias="vkTrimCommandPool"/>
+ <command>
+ <proto><type>void</type> <name>vkGetPhysicalDeviceExternalBufferProperties</name></proto>
+ <param><type>VkPhysicalDevice</type> <name>physicalDevice</name></param>
+ <param>const <type>VkPhysicalDeviceExternalBufferInfo</type>* <name>pExternalBufferInfo</name></param>
+ <param><type>VkExternalBufferProperties</type>* <name>pExternalBufferProperties</name></param>
+ </command>
+ <command name="vkGetPhysicalDeviceExternalBufferPropertiesKHR" alias="vkGetPhysicalDeviceExternalBufferProperties"/>
+ <command successcodes="VK_SUCCESS" errorcodes="VK_ERROR_TOO_MANY_OBJECTS,VK_ERROR_OUT_OF_HOST_MEMORY">
+ <proto><type>VkResult</type> <name>vkGetMemoryWin32HandleKHR</name></proto>
+ <param><type>VkDevice</type> <name>device</name></param>
+ <param>const <type>VkMemoryGetWin32HandleInfoKHR</type>* <name>pGetWin32HandleInfo</name></param>
+ <param><type>HANDLE</type>* <name>pHandle</name></param>
+ </command>
+ <command successcodes="VK_SUCCESS" errorcodes="VK_ERROR_OUT_OF_HOST_MEMORY,VK_ERROR_INVALID_EXTERNAL_HANDLE">
+ <proto><type>VkResult</type> <name>vkGetMemoryWin32HandlePropertiesKHR</name></proto>
+ <param><type>VkDevice</type> <name>device</name></param>
+ <param><type>VkExternalMemoryHandleTypeFlagBits</type> <name>handleType</name></param>
+ <param><type>HANDLE</type> <name>handle</name></param>
+ <param><type>VkMemoryWin32HandlePropertiesKHR</type>* <name>pMemoryWin32HandleProperties</name></param>
+ </command>
+ <command successcodes="VK_SUCCESS" errorcodes="VK_ERROR_TOO_MANY_OBJECTS,VK_ERROR_OUT_OF_HOST_MEMORY">
+ <proto><type>VkResult</type> <name>vkGetMemoryFdKHR</name></proto>
+ <param><type>VkDevice</type> <name>device</name></param>
+ <param>const <type>VkMemoryGetFdInfoKHR</type>* <name>pGetFdInfo</name></param>
+ <param><type>int</type>* <name>pFd</name></param>
+ </command>
+ <command successcodes="VK_SUCCESS" errorcodes="VK_ERROR_OUT_OF_HOST_MEMORY,VK_ERROR_INVALID_EXTERNAL_HANDLE">
+ <proto><type>VkResult</type> <name>vkGetMemoryFdPropertiesKHR</name></proto>
+ <param><type>VkDevice</type> <name>device</name></param>
+ <param><type>VkExternalMemoryHandleTypeFlagBits</type> <name>handleType</name></param>
+ <param><type>int</type> <name>fd</name></param>
+ <param><type>VkMemoryFdPropertiesKHR</type>* <name>pMemoryFdProperties</name></param>
+ </command>
+ <command successcodes="VK_SUCCESS" errorcodes="VK_ERROR_TOO_MANY_OBJECTS,VK_ERROR_OUT_OF_HOST_MEMORY">
+ <proto><type>VkResult</type> <name>vkGetMemoryZirconHandleFUCHSIA</name></proto>
+ <param><type>VkDevice</type> <name>device</name></param>
+ <param>const <type>VkMemoryGetZirconHandleInfoFUCHSIA</type>* <name>pGetZirconHandleInfo</name></param>
+ <param><type>zx_handle_t</type>* <name>pZirconHandle</name></param>
+ </command>
+ <command successcodes="VK_SUCCESS" errorcodes="VK_ERROR_INVALID_EXTERNAL_HANDLE">
+ <proto><type>VkResult</type> <name>vkGetMemoryZirconHandlePropertiesFUCHSIA</name></proto>
+ <param><type>VkDevice</type> <name>device</name></param>
+ <param><type>VkExternalMemoryHandleTypeFlagBits</type> <name>handleType</name></param>
+ <param><type>zx_handle_t</type> <name>zirconHandle</name></param>
+ <param><type>VkMemoryZirconHandlePropertiesFUCHSIA</type>* <name>pMemoryZirconHandleProperties</name></param>
+ </command>
+ <command successcodes="VK_SUCCESS" errorcodes="VK_ERROR_INVALID_EXTERNAL_HANDLE">
+ <proto><type>VkResult</type> <name>vkGetMemoryRemoteAddressNV</name></proto>
+ <param><type>VkDevice</type> <name>device</name></param>
+ <param>const <type>VkMemoryGetRemoteAddressInfoNV</type>* <name>pMemoryGetRemoteAddressInfo</name></param>
+ <param><type>VkRemoteAddressNV</type>* <name>pAddress</name></param>
+ </command>
+ <command>
+ <proto><type>void</type> <name>vkGetPhysicalDeviceExternalSemaphoreProperties</name></proto>
+ <param><type>VkPhysicalDevice</type> <name>physicalDevice</name></param>
+ <param>const <type>VkPhysicalDeviceExternalSemaphoreInfo</type>* <name>pExternalSemaphoreInfo</name></param>
+ <param><type>VkExternalSemaphoreProperties</type>* <name>pExternalSemaphoreProperties</name></param>
+ </command>
+ <command name="vkGetPhysicalDeviceExternalSemaphorePropertiesKHR" alias="vkGetPhysicalDeviceExternalSemaphoreProperties"/>
+ <command successcodes="VK_SUCCESS" errorcodes="VK_ERROR_TOO_MANY_OBJECTS,VK_ERROR_OUT_OF_HOST_MEMORY">
+ <proto><type>VkResult</type> <name>vkGetSemaphoreWin32HandleKHR</name></proto>
+ <param><type>VkDevice</type> <name>device</name></param>
+ <param>const <type>VkSemaphoreGetWin32HandleInfoKHR</type>* <name>pGetWin32HandleInfo</name></param>
+ <param><type>HANDLE</type>* <name>pHandle</name></param>
+ </command>
+ <command successcodes="VK_SUCCESS" errorcodes="VK_ERROR_OUT_OF_HOST_MEMORY,VK_ERROR_INVALID_EXTERNAL_HANDLE">
+ <proto><type>VkResult</type> <name>vkImportSemaphoreWin32HandleKHR</name></proto>
+ <param><type>VkDevice</type> <name>device</name></param>
+ <param>const <type>VkImportSemaphoreWin32HandleInfoKHR</type>* <name>pImportSemaphoreWin32HandleInfo</name></param>
+ </command>
+ <command successcodes="VK_SUCCESS" errorcodes="VK_ERROR_TOO_MANY_OBJECTS,VK_ERROR_OUT_OF_HOST_MEMORY">
+ <proto><type>VkResult</type> <name>vkGetSemaphoreFdKHR</name></proto>
+ <param><type>VkDevice</type> <name>device</name></param>
+ <param>const <type>VkSemaphoreGetFdInfoKHR</type>* <name>pGetFdInfo</name></param>
+ <param><type>int</type>* <name>pFd</name></param>
+ </command>
+ <command successcodes="VK_SUCCESS" errorcodes="VK_ERROR_OUT_OF_HOST_MEMORY,VK_ERROR_INVALID_EXTERNAL_HANDLE">
+ <proto><type>VkResult</type> <name>vkImportSemaphoreFdKHR</name></proto>
+ <param><type>VkDevice</type> <name>device</name></param>
+ <param>const <type>VkImportSemaphoreFdInfoKHR</type>* <name>pImportSemaphoreFdInfo</name></param>
+ </command>
+ <command successcodes="VK_SUCCESS" errorcodes="VK_ERROR_TOO_MANY_OBJECTS,VK_ERROR_OUT_OF_HOST_MEMORY">
+ <proto><type>VkResult</type> <name>vkGetSemaphoreZirconHandleFUCHSIA</name></proto>
+ <param><type>VkDevice</type> <name>device</name></param>
+ <param>const <type>VkSemaphoreGetZirconHandleInfoFUCHSIA</type>* <name>pGetZirconHandleInfo</name></param>
+ <param><type>zx_handle_t</type>* <name>pZirconHandle</name></param>
+ </command>
+ <command successcodes="VK_SUCCESS" errorcodes="VK_ERROR_OUT_OF_HOST_MEMORY,VK_ERROR_INVALID_EXTERNAL_HANDLE">
+ <proto><type>VkResult</type> <name>vkImportSemaphoreZirconHandleFUCHSIA</name></proto>
+ <param><type>VkDevice</type> <name>device</name></param>
+ <param>const <type>VkImportSemaphoreZirconHandleInfoFUCHSIA</type>* <name>pImportSemaphoreZirconHandleInfo</name></param>
+ </command>
+ <command>
+ <proto><type>void</type> <name>vkGetPhysicalDeviceExternalFenceProperties</name></proto>
+ <param><type>VkPhysicalDevice</type> <name>physicalDevice</name></param>
+ <param>const <type>VkPhysicalDeviceExternalFenceInfo</type>* <name>pExternalFenceInfo</name></param>
+ <param><type>VkExternalFenceProperties</type>* <name>pExternalFenceProperties</name></param>
+ </command>
+ <command name="vkGetPhysicalDeviceExternalFencePropertiesKHR" alias="vkGetPhysicalDeviceExternalFenceProperties"/>
+ <command successcodes="VK_SUCCESS" errorcodes="VK_ERROR_TOO_MANY_OBJECTS,VK_ERROR_OUT_OF_HOST_MEMORY">
+ <proto><type>VkResult</type> <name>vkGetFenceWin32HandleKHR</name></proto>
+ <param><type>VkDevice</type> <name>device</name></param>
+ <param>const <type>VkFenceGetWin32HandleInfoKHR</type>* <name>pGetWin32HandleInfo</name></param>
+ <param><type>HANDLE</type>* <name>pHandle</name></param>
+ </command>
+ <command successcodes="VK_SUCCESS" errorcodes="VK_ERROR_OUT_OF_HOST_MEMORY,VK_ERROR_INVALID_EXTERNAL_HANDLE">
+ <proto><type>VkResult</type> <name>vkImportFenceWin32HandleKHR</name></proto>
+ <param><type>VkDevice</type> <name>device</name></param>
+ <param>const <type>VkImportFenceWin32HandleInfoKHR</type>* <name>pImportFenceWin32HandleInfo</name></param>
+ </command>
+ <command successcodes="VK_SUCCESS" errorcodes="VK_ERROR_TOO_MANY_OBJECTS,VK_ERROR_OUT_OF_HOST_MEMORY">
+ <proto><type>VkResult</type> <name>vkGetFenceFdKHR</name></proto>
+ <param><type>VkDevice</type> <name>device</name></param>
+ <param>const <type>VkFenceGetFdInfoKHR</type>* <name>pGetFdInfo</name></param>
+ <param><type>int</type>* <name>pFd</name></param>
+ </command>
+ <command successcodes="VK_SUCCESS" errorcodes="VK_ERROR_OUT_OF_HOST_MEMORY,VK_ERROR_INVALID_EXTERNAL_HANDLE">
+ <proto><type>VkResult</type> <name>vkImportFenceFdKHR</name></proto>
+ <param><type>VkDevice</type> <name>device</name></param>
+ <param>const <type>VkImportFenceFdInfoKHR</type>* <name>pImportFenceFdInfo</name></param>
+ </command>
+ <command successcodes="VK_SUCCESS">
+ <proto><type>VkResult</type> <name>vkReleaseDisplayEXT</name></proto>
+ <param><type>VkPhysicalDevice</type> <name>physicalDevice</name></param>
+ <param><type>VkDisplayKHR</type> <name>display</name></param>
+ </command>
+ <command successcodes="VK_SUCCESS" errorcodes="VK_ERROR_OUT_OF_HOST_MEMORY,VK_ERROR_INITIALIZATION_FAILED">
+ <proto><type>VkResult</type> <name>vkAcquireXlibDisplayEXT</name></proto>
+ <param><type>VkPhysicalDevice</type> <name>physicalDevice</name></param>
+ <param><type>Display</type>* <name>dpy</name></param>
+ <param><type>VkDisplayKHR</type> <name>display</name></param>
+ </command>
+ <command successcodes="VK_SUCCESS" errorcodes="VK_ERROR_OUT_OF_HOST_MEMORY">
+ <proto><type>VkResult</type> <name>vkGetRandROutputDisplayEXT</name></proto>
+ <param><type>VkPhysicalDevice</type> <name>physicalDevice</name></param>
+ <param><type>Display</type>* <name>dpy</name></param>
+ <param><type>RROutput</type> <name>rrOutput</name></param>
+ <param><type>VkDisplayKHR</type>* <name>pDisplay</name></param>
+ </command>
+ <command successcodes="VK_SUCCESS" errorcodes="VK_ERROR_OUT_OF_HOST_MEMORY,VK_ERROR_DEVICE_LOST,VK_ERROR_INITIALIZATION_FAILED">
+ <proto><type>VkResult</type> <name>vkAcquireWinrtDisplayNV</name></proto>
+ <param><type>VkPhysicalDevice</type> <name>physicalDevice</name></param>
+ <param><type>VkDisplayKHR</type> <name>display</name></param>
+ </command>
+ <command successcodes="VK_SUCCESS" errorcodes="VK_ERROR_OUT_OF_HOST_MEMORY,VK_ERROR_DEVICE_LOST,VK_ERROR_INITIALIZATION_FAILED">
+ <proto><type>VkResult</type> <name>vkGetWinrtDisplayNV</name></proto>
+ <param><type>VkPhysicalDevice</type> <name>physicalDevice</name></param>
+ <param><type>uint32_t</type> <name>deviceRelativeId</name></param>
+ <param><type>VkDisplayKHR</type>* <name>pDisplay</name></param>
+ </command>
+ <command successcodes="VK_SUCCESS" errorcodes="VK_ERROR_OUT_OF_HOST_MEMORY">
+ <proto><type>VkResult</type> <name>vkDisplayPowerControlEXT</name></proto>
+ <param><type>VkDevice</type> <name>device</name></param>
+ <param><type>VkDisplayKHR</type> <name>display</name></param>
+ <param>const <type>VkDisplayPowerInfoEXT</type>* <name>pDisplayPowerInfo</name></param>
+ </command>
+ <command successcodes="VK_SUCCESS" errorcodes="VK_ERROR_OUT_OF_HOST_MEMORY">
+ <proto><type>VkResult</type> <name>vkRegisterDeviceEventEXT</name></proto>
+ <param><type>VkDevice</type> <name>device</name></param>
+ <param>const <type>VkDeviceEventInfoEXT</type>* <name>pDeviceEventInfo</name></param>
+ <param optional="true">const <type>VkAllocationCallbacks</type>* <name>pAllocator</name></param>
+ <param><type>VkFence</type>* <name>pFence</name></param>
+ </command>
+ <command successcodes="VK_SUCCESS" errorcodes="VK_ERROR_OUT_OF_HOST_MEMORY">
+ <proto><type>VkResult</type> <name>vkRegisterDisplayEventEXT</name></proto>
+ <param><type>VkDevice</type> <name>device</name></param>
+ <param><type>VkDisplayKHR</type> <name>display</name></param>
+ <param>const <type>VkDisplayEventInfoEXT</type>* <name>pDisplayEventInfo</name></param>
+ <param optional="true">const <type>VkAllocationCallbacks</type>* <name>pAllocator</name></param>
+ <param><type>VkFence</type>* <name>pFence</name></param>
+ </command>
+ <command successcodes="VK_SUCCESS" errorcodes="VK_ERROR_OUT_OF_HOST_MEMORY,VK_ERROR_DEVICE_LOST,VK_ERROR_OUT_OF_DATE_KHR">
+ <proto><type>VkResult</type> <name>vkGetSwapchainCounterEXT</name></proto>
+ <param><type>VkDevice</type> <name>device</name></param>
+ <param><type>VkSwapchainKHR</type> <name>swapchain</name></param>
+ <param><type>VkSurfaceCounterFlagBitsEXT</type> <name>counter</name></param>
+ <param><type>uint64_t</type>* <name>pCounterValue</name></param>
+ </command>
+ <command successcodes="VK_SUCCESS" errorcodes="VK_ERROR_OUT_OF_HOST_MEMORY,VK_ERROR_OUT_OF_DEVICE_MEMORY,VK_ERROR_SURFACE_LOST_KHR">
+ <proto><type>VkResult</type> <name>vkGetPhysicalDeviceSurfaceCapabilities2EXT</name></proto>
+ <param><type>VkPhysicalDevice</type> <name>physicalDevice</name></param>
+ <param><type>VkSurfaceKHR</type> <name>surface</name></param>
+ <param><type>VkSurfaceCapabilities2EXT</type>* <name>pSurfaceCapabilities</name></param>
+ </command>
+ <command successcodes="VK_SUCCESS,VK_INCOMPLETE" errorcodes="VK_ERROR_OUT_OF_HOST_MEMORY,VK_ERROR_OUT_OF_DEVICE_MEMORY,VK_ERROR_INITIALIZATION_FAILED">
+ <proto><type>VkResult</type> <name>vkEnumeratePhysicalDeviceGroups</name></proto>
+ <param><type>VkInstance</type> <name>instance</name></param>
+ <param optional="false,true"><type>uint32_t</type>* <name>pPhysicalDeviceGroupCount</name></param>
+ <param optional="true" len="pPhysicalDeviceGroupCount"><type>VkPhysicalDeviceGroupProperties</type>* <name>pPhysicalDeviceGroupProperties</name></param>
+ </command>
+ <command name="vkEnumeratePhysicalDeviceGroupsKHR" alias="vkEnumeratePhysicalDeviceGroups"/>
+ <command>
+ <proto><type>void</type> <name>vkGetDeviceGroupPeerMemoryFeatures</name></proto>
+ <param><type>VkDevice</type> <name>device</name></param>
+ <param><type>uint32_t</type> <name>heapIndex</name></param>
+ <param><type>uint32_t</type> <name>localDeviceIndex</name></param>
+ <param><type>uint32_t</type> <name>remoteDeviceIndex</name></param>
+ <param><type>VkPeerMemoryFeatureFlags</type>* <name>pPeerMemoryFeatures</name></param>
+ </command>
+ <command name="vkGetDeviceGroupPeerMemoryFeaturesKHR" alias="vkGetDeviceGroupPeerMemoryFeatures"/>
+ <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>vkBindBufferMemory2</name></proto>
+ <param><type>VkDevice</type> <name>device</name></param>
+ <param><type>uint32_t</type> <name>bindInfoCount</name></param>
+ <param len="bindInfoCount">const <type>VkBindBufferMemoryInfo</type>* <name>pBindInfos</name></param>
+ </command>
+ <command name="vkBindBufferMemory2KHR" alias="vkBindBufferMemory2"/>
+ <command successcodes="VK_SUCCESS" errorcodes="VK_ERROR_OUT_OF_HOST_MEMORY,VK_ERROR_OUT_OF_DEVICE_MEMORY">
+ <proto><type>VkResult</type> <name>vkBindImageMemory2</name></proto>
+ <param><type>VkDevice</type> <name>device</name></param>
+ <param><type>uint32_t</type> <name>bindInfoCount</name></param>
+ <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">
+ <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>
+ </command>
+ <command name="vkCmdSetDeviceMaskKHR" alias="vkCmdSetDeviceMask"/>
+ <command successcodes="VK_SUCCESS" errorcodes="VK_ERROR_OUT_OF_HOST_MEMORY,VK_ERROR_OUT_OF_DEVICE_MEMORY">
+ <proto><type>VkResult</type> <name>vkGetDeviceGroupPresentCapabilitiesKHR</name></proto>
+ <param><type>VkDevice</type> <name>device</name></param>
+ <param><type>VkDeviceGroupPresentCapabilitiesKHR</type>* <name>pDeviceGroupPresentCapabilities</name></param>
+ </command>
+ <command successcodes="VK_SUCCESS" errorcodes="VK_ERROR_OUT_OF_HOST_MEMORY,VK_ERROR_OUT_OF_DEVICE_MEMORY,VK_ERROR_SURFACE_LOST_KHR">
+ <proto><type>VkResult</type> <name>vkGetDeviceGroupSurfacePresentModesKHR</name></proto>
+ <param><type>VkDevice</type> <name>device</name></param>
+ <param externsync="true"><type>VkSurfaceKHR</type> <name>surface</name></param>
+ <param optional="false,true"><type>VkDeviceGroupPresentModeFlagsKHR</type>* <name>pModes</name></param>
+ </command>
+ <command successcodes="VK_SUCCESS,VK_TIMEOUT,VK_NOT_READY,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>vkAcquireNextImage2KHR</name></proto>
+ <param><type>VkDevice</type> <name>device</name></param>
+ <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">
+ <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>
+ <param><type>uint32_t</type> <name>baseGroupY</name></param>
+ <param><type>uint32_t</type> <name>baseGroupZ</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 name="vkCmdDispatchBaseKHR" alias="vkCmdDispatchBase"/>
+ <command successcodes="VK_SUCCESS,VK_INCOMPLETE" errorcodes="VK_ERROR_OUT_OF_HOST_MEMORY,VK_ERROR_OUT_OF_DEVICE_MEMORY">
+ <proto><type>VkResult</type> <name>vkGetPhysicalDevicePresentRectanglesKHR</name></proto>
+ <param><type>VkPhysicalDevice</type> <name>physicalDevice</name></param>
+ <param externsync="true"><type>VkSurfaceKHR</type> <name>surface</name></param>
+ <param optional="false,true"><type>uint32_t</type>* <name>pRectCount</name></param>
+ <param optional="true" len="pRectCount"><type>VkRect2D</type>* <name>pRects</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>vkCreateDescriptorUpdateTemplate</name></proto>
+ <param><type>VkDevice</type> <name>device</name></param>
+ <param>const <type>VkDescriptorUpdateTemplateCreateInfo</type>* <name>pCreateInfo</name></param>
+ <param optional="true">const <type>VkAllocationCallbacks</type>* <name>pAllocator</name></param>
+ <param><type>VkDescriptorUpdateTemplate</type>* <name>pDescriptorUpdateTemplate</name></param>
+ </command>
+ <command name="vkCreateDescriptorUpdateTemplateKHR" alias="vkCreateDescriptorUpdateTemplate"/>
+ <command>
+ <proto><type>void</type> <name>vkDestroyDescriptorUpdateTemplate</name></proto>
+ <param><type>VkDevice</type> <name>device</name></param>
+ <param optional="true" externsync="true"><type>VkDescriptorUpdateTemplate</type> <name>descriptorUpdateTemplate</name></param>
+ <param optional="true">const <type>VkAllocationCallbacks</type>* <name>pAllocator</name></param>
+ </command>
+ <command name="vkDestroyDescriptorUpdateTemplateKHR" alias="vkDestroyDescriptorUpdateTemplate"/>
+ <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>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">
+ <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>
+ <param><type>VkPipelineLayout</type> <name>layout</name></param>
+ <param><type>uint32_t</type> <name>set</name></param>
+ <param noautovalidity="true">const <type>void</type>* <name>pData</name></param>
+ </command>
+ <command>
+ <proto><type>void</type> <name>vkSetHdrMetadataEXT</name></proto>
+ <param><type>VkDevice</type> <name>device</name></param>
+ <param><type>uint32_t</type> <name>swapchainCount</name></param>
+ <param len="swapchainCount">const <type>VkSwapchainKHR</type>* <name>pSwapchains</name></param>
+ <param len="swapchainCount">const <type>VkHdrMetadataEXT</type>* <name>pMetadata</name></param>
+ </command>
+ <command successcodes="VK_SUCCESS,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>vkGetSwapchainStatusKHR</name></proto>
+ <param><type>VkDevice</type> <name>device</name></param>
+ <param externsync="true"><type>VkSwapchainKHR</type> <name>swapchain</name></param>
+ </command>
+ <command successcodes="VK_SUCCESS" errorcodes="VK_ERROR_OUT_OF_HOST_MEMORY,VK_ERROR_DEVICE_LOST,VK_ERROR_SURFACE_LOST_KHR">
+ <proto><type>VkResult</type> <name>vkGetRefreshCycleDurationGOOGLE</name></proto>
+ <param><type>VkDevice</type> <name>device</name></param>
+ <param externsync="true"><type>VkSwapchainKHR</type> <name>swapchain</name></param>
+ <param><type>VkRefreshCycleDurationGOOGLE</type>* <name>pDisplayTimingProperties</name></param>
+ </command>
+ <command successcodes="VK_SUCCESS,VK_INCOMPLETE" errorcodes="VK_ERROR_OUT_OF_HOST_MEMORY,VK_ERROR_DEVICE_LOST,VK_ERROR_OUT_OF_DATE_KHR,VK_ERROR_SURFACE_LOST_KHR">
+ <proto><type>VkResult</type> <name>vkGetPastPresentationTimingGOOGLE</name></proto>
+ <param><type>VkDevice</type> <name>device</name></param>
+ <param externsync="true"><type>VkSwapchainKHR</type> <name>swapchain</name></param>
+ <param optional="false,true"><type>uint32_t</type>* <name>pPresentationTimingCount</name></param>
+ <param optional="true" len="pPresentationTimingCount"><type>VkPastPresentationTimingGOOGLE</type>* <name>pPresentationTimings</name></param>
+ </command>
+ <command successcodes="VK_SUCCESS" errorcodes="VK_ERROR_OUT_OF_HOST_MEMORY,VK_ERROR_OUT_OF_DEVICE_MEMORY,VK_ERROR_NATIVE_WINDOW_IN_USE_KHR">
+ <proto><type>VkResult</type> <name>vkCreateIOSSurfaceMVK</name></proto>
+ <param><type>VkInstance</type> <name>instance</name></param>
+ <param>const <type>VkIOSSurfaceCreateInfoMVK</type>* <name>pCreateInfo</name></param>
+ <param optional="true">const <type>VkAllocationCallbacks</type>* <name>pAllocator</name></param>
+ <param><type>VkSurfaceKHR</type>* <name>pSurface</name></param>
+ </command>
+ <command successcodes="VK_SUCCESS" errorcodes="VK_ERROR_OUT_OF_HOST_MEMORY,VK_ERROR_OUT_OF_DEVICE_MEMORY,VK_ERROR_NATIVE_WINDOW_IN_USE_KHR">
+ <proto><type>VkResult</type> <name>vkCreateMacOSSurfaceMVK</name></proto>
+ <param><type>VkInstance</type> <name>instance</name></param>
+ <param>const <type>VkMacOSSurfaceCreateInfoMVK</type>* <name>pCreateInfo</name></param>
+ <param optional="true">const <type>VkAllocationCallbacks</type>* <name>pAllocator</name></param>
+ <param><type>VkSurfaceKHR</type>* <name>pSurface</name></param>
+ </command>
+ <command successcodes="VK_SUCCESS" errorcodes="VK_ERROR_OUT_OF_HOST_MEMORY,VK_ERROR_OUT_OF_DEVICE_MEMORY,VK_ERROR_NATIVE_WINDOW_IN_USE_KHR">
+ <proto><type>VkResult</type> <name>vkCreateMetalSurfaceEXT</name></proto>
+ <param><type>VkInstance</type> <name>instance</name></param>
+ <param>const <type>VkMetalSurfaceCreateInfoEXT</type>* <name>pCreateInfo</name></param>
+ <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">
+ <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">
+ <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">
+ <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>
+ </command>
+ <command>
+ <proto><type>void</type> <name>vkGetPhysicalDeviceMultisamplePropertiesEXT</name></proto>
+ <param><type>VkPhysicalDevice</type> <name>physicalDevice</name></param>
+ <param><type>VkSampleCountFlagBits</type> <name>samples</name></param>
+ <param><type>VkMultisamplePropertiesEXT</type>* <name>pMultisampleProperties</name></param>
+ </command>
+ <command successcodes="VK_SUCCESS" errorcodes="VK_ERROR_OUT_OF_HOST_MEMORY,VK_ERROR_OUT_OF_DEVICE_MEMORY,VK_ERROR_SURFACE_LOST_KHR">
+ <proto><type>VkResult</type> <name>vkGetPhysicalDeviceSurfaceCapabilities2KHR</name></proto>
+ <param><type>VkPhysicalDevice</type> <name>physicalDevice</name></param>
+ <param>const <type>VkPhysicalDeviceSurfaceInfo2KHR</type>* <name>pSurfaceInfo</name></param>
+ <param><type>VkSurfaceCapabilities2KHR</type>* <name>pSurfaceCapabilities</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>vkGetPhysicalDeviceSurfaceFormats2KHR</name></proto>
+ <param><type>VkPhysicalDevice</type> <name>physicalDevice</name></param>
+ <param>const <type>VkPhysicalDeviceSurfaceInfo2KHR</type>* <name>pSurfaceInfo</name></param>
+ <param optional="false,true"><type>uint32_t</type>* <name>pSurfaceFormatCount</name></param>
+ <param optional="true" len="pSurfaceFormatCount"><type>VkSurfaceFormat2KHR</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">
+ <proto><type>VkResult</type> <name>vkGetPhysicalDeviceDisplayProperties2KHR</name></proto>
+ <param><type>VkPhysicalDevice</type> <name>physicalDevice</name></param>
+ <param optional="false,true"><type>uint32_t</type>* <name>pPropertyCount</name></param>
+ <param optional="true" len="pPropertyCount"><type>VkDisplayProperties2KHR</type>* <name>pProperties</name></param>
+ </command>
+ <command successcodes="VK_SUCCESS,VK_INCOMPLETE" errorcodes="VK_ERROR_OUT_OF_HOST_MEMORY,VK_ERROR_OUT_OF_DEVICE_MEMORY">
+ <proto><type>VkResult</type> <name>vkGetPhysicalDeviceDisplayPlaneProperties2KHR</name></proto>
+ <param><type>VkPhysicalDevice</type> <name>physicalDevice</name></param>
+ <param optional="false,true"><type>uint32_t</type>* <name>pPropertyCount</name></param>
+ <param optional="true" len="pPropertyCount"><type>VkDisplayPlaneProperties2KHR</type>* <name>pProperties</name></param>
+ </command>
+ <command successcodes="VK_SUCCESS,VK_INCOMPLETE" errorcodes="VK_ERROR_OUT_OF_HOST_MEMORY,VK_ERROR_OUT_OF_DEVICE_MEMORY">
+ <proto><type>VkResult</type> <name>vkGetDisplayModeProperties2KHR</name></proto>
+ <param><type>VkPhysicalDevice</type> <name>physicalDevice</name></param>
+ <param><type>VkDisplayKHR</type> <name>display</name></param>
+ <param optional="false,true"><type>uint32_t</type>* <name>pPropertyCount</name></param>
+ <param optional="true" len="pPropertyCount"><type>VkDisplayModeProperties2KHR</type>* <name>pProperties</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>vkGetDisplayPlaneCapabilities2KHR</name></proto>
+ <param><type>VkPhysicalDevice</type> <name>physicalDevice</name></param>
+ <param>const <type>VkDisplayPlaneInfo2KHR</type>* <name>pDisplayPlaneInfo</name></param>
+ <param><type>VkDisplayPlaneCapabilities2KHR</type>* <name>pCapabilities</name></param>
+ </command>
+ <command>
+ <proto><type>void</type> <name>vkGetBufferMemoryRequirements2</name></proto>
+ <param><type>VkDevice</type> <name>device</name></param>
+ <param>const <type>VkBufferMemoryRequirementsInfo2</type>* <name>pInfo</name></param>
+ <param><type>VkMemoryRequirements2</type>* <name>pMemoryRequirements</name></param>
+ </command>
+ <command name="vkGetBufferMemoryRequirements2KHR" alias="vkGetBufferMemoryRequirements2"/>
+ <command>
+ <proto><type>void</type> <name>vkGetImageMemoryRequirements2</name></proto>
+ <param><type>VkDevice</type> <name>device</name></param>
+ <param>const <type>VkImageMemoryRequirementsInfo2</type>* <name>pInfo</name></param>
+ <param><type>VkMemoryRequirements2</type>* <name>pMemoryRequirements</name></param>
+ </command>
+ <command name="vkGetImageMemoryRequirements2KHR" alias="vkGetImageMemoryRequirements2"/>
+ <command>
+ <proto><type>void</type> <name>vkGetImageSparseMemoryRequirements2</name></proto>
+ <param><type>VkDevice</type> <name>device</name></param>
+ <param>const <type>VkImageSparseMemoryRequirementsInfo2</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="vkGetImageSparseMemoryRequirements2KHR" alias="vkGetImageSparseMemoryRequirements2"/>
+ <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>
+ <param>const <type>VkSamplerYcbcrConversionCreateInfo</type>* <name>pCreateInfo</name></param>
+ <param optional="true">const <type>VkAllocationCallbacks</type>* <name>pAllocator</name></param>
+ <param><type>VkSamplerYcbcrConversion</type>* <name>pYcbcrConversion</name></param>
+ </command>
+ <command name="vkCreateSamplerYcbcrConversionKHR" alias="vkCreateSamplerYcbcrConversion"/>
+ <command>
+ <proto><type>void</type> <name>vkDestroySamplerYcbcrConversion</name></proto>
+ <param><type>VkDevice</type> <name>device</name></param>
+ <param optional="true" externsync="true"><type>VkSamplerYcbcrConversion</type> <name>ycbcrConversion</name></param>
+ <param optional="true">const <type>VkAllocationCallbacks</type>* <name>pAllocator</name></param>
+ </command>
+ <command name="vkDestroySamplerYcbcrConversionKHR" alias="vkDestroySamplerYcbcrConversion"/>
+ <command>
+ <proto><type>void</type> <name>vkGetDeviceQueue2</name></proto>
+ <param><type>VkDevice</type> <name>device</name></param>
+ <param>const <type>VkDeviceQueueInfo2</type>* <name>pQueueInfo</name></param>
+ <param><type>VkQueue</type>* <name>pQueue</name></param>
+ </command>
+ <command successcodes="VK_SUCCESS" errorcodes="VK_ERROR_OUT_OF_HOST_MEMORY">
+ <proto><type>VkResult</type> <name>vkCreateValidationCacheEXT</name></proto>
+ <param><type>VkDevice</type> <name>device</name></param>
+ <param>const <type>VkValidationCacheCreateInfoEXT</type>* <name>pCreateInfo</name></param>
+ <param optional="true">const <type>VkAllocationCallbacks</type>* <name>pAllocator</name></param>
+ <param><type>VkValidationCacheEXT</type>* <name>pValidationCache</name></param>
+ </command>
+ <command>
+ <proto><type>void</type> <name>vkDestroyValidationCacheEXT</name></proto>
+ <param><type>VkDevice</type> <name>device</name></param>
+ <param optional="true" externsync="true"><type>VkValidationCacheEXT</type> <name>validationCache</name></param>
+ <param optional="true">const <type>VkAllocationCallbacks</type>* <name>pAllocator</name></param>
+ </command>
+ <command successcodes="VK_SUCCESS,VK_INCOMPLETE" errorcodes="VK_ERROR_OUT_OF_HOST_MEMORY,VK_ERROR_OUT_OF_DEVICE_MEMORY">
+ <proto><type>VkResult</type> <name>vkGetValidationCacheDataEXT</name></proto>
+ <param><type>VkDevice</type> <name>device</name></param>
+ <param><type>VkValidationCacheEXT</type> <name>validationCache</name></param>
+ <param optional="false,true"><type>size_t</type>* <name>pDataSize</name></param>
+ <param optional="true" len="pDataSize"><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>vkMergeValidationCachesEXT</name></proto>
+ <param><type>VkDevice</type> <name>device</name></param>
+ <param externsync="true"><type>VkValidationCacheEXT</type> <name>dstCache</name></param>
+ <param><type>uint32_t</type> <name>srcCacheCount</name></param>
+ <param len="srcCacheCount">const <type>VkValidationCacheEXT</type>* <name>pSrcCaches</name></param>
+ </command>
+ <command>
+ <proto><type>void</type> <name>vkGetDescriptorSetLayoutSupport</name></proto>
+ <param><type>VkDevice</type> <name>device</name></param>
+ <param>const <type>VkDescriptorSetLayoutCreateInfo</type>* <name>pCreateInfo</name></param>
+ <param><type>VkDescriptorSetLayoutSupport</type>* <name>pSupport</name></param>
+ </command>
+ <command name="vkGetDescriptorSetLayoutSupportKHR" alias="vkGetDescriptorSetLayoutSupport"/>
+ <command>
+ <proto><type>VkResult</type> <name>vkGetSwapchainGrallocUsageANDROID</name></proto>
+ <param><type>VkDevice</type> <name>device</name></param>
+ <param><type>VkFormat</type> <name>format</name></param>
+ <param><type>VkImageUsageFlags</type> <name>imageUsage</name></param>
+ <param><type>int</type>* <name>grallocUsage</name></param>
+ </command>
+ <command>
+ <proto><type>VkResult</type> <name>vkGetSwapchainGrallocUsage2ANDROID</name></proto>
+ <param><type>VkDevice</type> <name>device</name></param>
+ <param><type>VkFormat</type> <name>format</name></param>
+ <param><type>VkImageUsageFlags</type> <name>imageUsage</name></param>
+ <param><type>VkSwapchainImageUsageFlagsANDROID</type> <name>swapchainImageUsage</name></param>
+ <param><type>uint64_t</type>* <name>grallocConsumerUsage</name></param>
+ <param><type>uint64_t</type>* <name>grallocProducerUsage</name></param>
+ </command>
+ <command>
+ <proto><type>VkResult</type> <name>vkAcquireImageANDROID</name></proto>
+ <param><type>VkDevice</type> <name>device</name></param>
+ <param><type>VkImage</type> <name>image</name></param>
+ <param><type>int</type> <name>nativeFenceFd</name></param>
+ <param><type>VkSemaphore</type> <name>semaphore</name></param>
+ <param><type>VkFence</type> <name>fence</name></param>
+ </command>
+ <command>
+ <proto><type>VkResult</type> <name>vkQueueSignalReleaseImageANDROID</name></proto>
+ <param><type>VkQueue</type> <name>queue</name></param>
+ <param><type>uint32_t</type> <name>waitSemaphoreCount</name></param>
+ <param len="waitSemaphoreCount">const <type>VkSemaphore</type>* <name>pWaitSemaphores</name></param>
+ <param><type>VkImage</type> <name>image</name></param>
+ <param><type>int</type>* <name>pNativeFenceFd</name></param>
+ </command>
+ <command successcodes="VK_SUCCESS,VK_INCOMPLETE" errorcodes="VK_ERROR_FEATURE_NOT_PRESENT,VK_ERROR_OUT_OF_HOST_MEMORY">
+ <proto><type>VkResult</type> <name>vkGetShaderInfoAMD</name></proto>
+ <param><type>VkDevice</type> <name>device</name></param>
+ <param><type>VkPipeline</type> <name>pipeline</name></param>
+ <param><type>VkShaderStageFlagBits</type> <name>shaderStage</name></param>
+ <param><type>VkShaderInfoTypeAMD</type> <name>infoType</name></param>
+ <param optional="false,true"><type>size_t</type>* <name>pInfoSize</name></param>
+ <param optional="true" len="pInfoSize"><type>void</type>* <name>pInfo</name></param>
+ </command>
+ <command>
+ <proto><type>void</type> <name>vkSetLocalDimmingAMD</name></proto>
+ <param><type>VkDevice</type> <name>device</name></param>
+ <param><type>VkSwapchainKHR</type> <name>swapChain</name></param>
+ <param><type>VkBool32</type> <name>localDimmingEnable</name></param>
+ </command>
+ <command successcodes="VK_SUCCESS,VK_INCOMPLETE" errorcodes="VK_ERROR_OUT_OF_HOST_MEMORY,VK_ERROR_OUT_OF_DEVICE_MEMORY">
+ <proto><type>VkResult</type> <name>vkGetPhysicalDeviceCalibrateableTimeDomainsEXT</name></proto>
+ <param><type>VkPhysicalDevice</type> <name>physicalDevice</name></param>
+ <param optional="false,true"><type>uint32_t</type>* <name>pTimeDomainCount</name></param>
+ <param optional="true" len="pTimeDomainCount"><type>VkTimeDomainEXT</type>* <name>pTimeDomains</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>vkGetCalibratedTimestampsEXT</name></proto>
+ <param><type>VkDevice</type> <name>device</name></param>
+ <param><type>uint32_t</type> <name>timestampCount</name></param>
+ <param len="timestampCount">const <type>VkCalibratedTimestampInfoEXT</type>* <name>pTimestampInfos</name></param>
+ <param len="timestampCount"><type>uint64_t</type>* <name>pTimestamps</name></param>
+ <param><type>uint64_t</type>* <name>pMaxDeviation</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>vkSetDebugUtilsObjectNameEXT</name></proto>
+ <param><type>VkDevice</type> <name>device</name></param>
+ <param externsync="pNameInfo-&gt;objectHandle">const <type>VkDebugUtilsObjectNameInfoEXT</type>* <name>pNameInfo</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>vkSetDebugUtilsObjectTagEXT</name></proto>
+ <param><type>VkDevice</type> <name>device</name></param>
+ <param externsync="pTagInfo-&gt;objectHandle">const <type>VkDebugUtilsObjectTagInfoEXT</type>* <name>pTagInfo</name></param>
+ </command>
+ <command>
+ <proto><type>void</type> <name>vkQueueBeginDebugUtilsLabelEXT</name></proto>
+ <param><type>VkQueue</type> <name>queue</name></param>
+ <param>const <type>VkDebugUtilsLabelEXT</type>* <name>pLabelInfo</name></param>
+ </command>
+ <command>
+ <proto><type>void</type> <name>vkQueueEndDebugUtilsLabelEXT</name></proto>
+ <param><type>VkQueue</type> <name>queue</name></param>
+ </command>
+ <command>
+ <proto><type>void</type> <name>vkQueueInsertDebugUtilsLabelEXT</name></proto>
+ <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">
+ <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">
+ <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">
+ <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>
+ </command>
+ <command successcodes="VK_SUCCESS" errorcodes="VK_ERROR_OUT_OF_HOST_MEMORY">
+ <proto><type>VkResult</type> <name>vkCreateDebugUtilsMessengerEXT</name></proto>
+ <param><type>VkInstance</type> <name>instance</name></param>
+ <param>const <type>VkDebugUtilsMessengerCreateInfoEXT</type>* <name>pCreateInfo</name></param>
+ <param optional="true">const <type>VkAllocationCallbacks</type>* <name>pAllocator</name></param>
+ <param><type>VkDebugUtilsMessengerEXT</type>* <name>pMessenger</name></param>
+ </command>
+ <command>
+ <proto><type>void</type> <name>vkDestroyDebugUtilsMessengerEXT</name></proto>
+ <param><type>VkInstance</type> <name>instance</name></param>
+ <param optional="true" externsync="true"><type>VkDebugUtilsMessengerEXT</type> <name>messenger</name></param>
+ <param optional="true">const <type>VkAllocationCallbacks</type>* <name>pAllocator</name></param>
+ </command>
+ <command>
+ <proto><type>void</type> <name>vkSubmitDebugUtilsMessageEXT</name></proto>
+ <param><type>VkInstance</type> <name>instance</name></param>
+ <param><type>VkDebugUtilsMessageSeverityFlagBitsEXT</type> <name>messageSeverity</name></param>
+ <param><type>VkDebugUtilsMessageTypeFlagsEXT</type> <name>messageTypes</name></param>
+ <param>const <type>VkDebugUtilsMessengerCallbackDataEXT</type>* <name>pCallbackData</name></param>
+ </command>
+ <command successcodes="VK_SUCCESS" errorcodes="VK_ERROR_OUT_OF_HOST_MEMORY,VK_ERROR_INVALID_EXTERNAL_HANDLE">
+ <proto><type>VkResult</type> <name>vkGetMemoryHostPointerPropertiesEXT</name></proto>
+ <param><type>VkDevice</type> <name>device</name></param>
+ <param><type>VkExternalMemoryHandleTypeFlagBits</type> <name>handleType</name></param>
+ <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">
+ <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><type>VkBuffer</type> <name>dstBuffer</name></param>
+ <param><type>VkDeviceSize</type> <name>dstOffset</name></param>
+ <param><type>uint32_t</type> <name>marker</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>vkCreateRenderPass2</name></proto>
+ <param><type>VkDevice</type> <name>device</name></param>
+ <param>const <type>VkRenderPassCreateInfo2</type>* <name>pCreateInfo</name></param>
+ <param optional="true">const <type>VkAllocationCallbacks</type>* <name>pAllocator</name></param>
+ <param><type>VkRenderPass</type>* <name>pRenderPass</name></param>
+ </command>
+ <command name="vkCreateRenderPass2KHR" alias="vkCreateRenderPass2"/>
+ <command queues="graphics" renderpass="outside" cmdbufferlevel="primary">
+ <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">
+ <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">
+ <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>
+ </command>
+ <command name="vkCmdEndRenderPass2KHR" alias="vkCmdEndRenderPass2"/>
+ <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>vkGetSemaphoreCounterValue</name></proto>
+ <param><type>VkDevice</type> <name>device</name></param>
+ <param><type>VkSemaphore</type> <name>semaphore</name></param>
+ <param><type>uint64_t</type>* <name>pValue</name></param>
+ </command>
+ <command name="vkGetSemaphoreCounterValueKHR" alias="vkGetSemaphoreCounterValue"/>
+ <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>vkWaitSemaphores</name></proto>
+ <param><type>VkDevice</type> <name>device</name></param>
+ <param>const <type>VkSemaphoreWaitInfo</type>* <name>pWaitInfo</name></param>
+ <param><type>uint64_t</type> <name>timeout</name></param>
+ </command>
+ <command name="vkWaitSemaphoresKHR" alias="vkWaitSemaphores"/>
+ <command successcodes="VK_SUCCESS" errorcodes="VK_ERROR_OUT_OF_HOST_MEMORY,VK_ERROR_OUT_OF_DEVICE_MEMORY">
+ <proto><type>VkResult</type> <name>vkSignalSemaphore</name></proto>
+ <param><type>VkDevice</type> <name>device</name></param>
+ <param>const <type>VkSemaphoreSignalInfo</type>* <name>pSignalInfo</name></param>
+ </command>
+ <command name="vkSignalSemaphoreKHR" alias="vkSignalSemaphore"/>
+ <command successcodes="VK_SUCCESS" errorcodes="VK_ERROR_OUT_OF_HOST_MEMORY,VK_ERROR_INVALID_EXTERNAL_HANDLE_KHR">
+ <proto><type>VkResult</type> <name>vkGetAndroidHardwareBufferPropertiesANDROID</name></proto>
+ <param><type>VkDevice</type> <name>device</name></param>
+ <param>const struct <type>AHardwareBuffer</type>* <name>buffer</name></param>
+ <param><type>VkAndroidHardwareBufferPropertiesANDROID</type>* <name>pProperties</name></param>
+ </command>
+ <command successcodes="VK_SUCCESS" errorcodes="VK_ERROR_TOO_MANY_OBJECTS,VK_ERROR_OUT_OF_HOST_MEMORY">
+ <proto><type>VkResult</type> <name>vkGetMemoryAndroidHardwareBufferANDROID</name></proto>
+ <param><type>VkDevice</type> <name>device</name></param>
+ <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">
+ <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>
+ <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 name="vkCmdDrawIndirectCountKHR" alias="vkCmdDrawIndirectCount"/>
+ <command name="vkCmdDrawIndirectCountAMD" alias="vkCmdDrawIndirectCount"/>
+ <command queues="graphics" renderpass="inside" cmdbufferlevel="primary,secondary">
+ <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>
+ <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 name="vkCmdDrawIndexedIndirectCountKHR" alias="vkCmdDrawIndexedIndirectCount"/>
+ <command name="vkCmdDrawIndexedIndirectCountAMD" alias="vkCmdDrawIndexedIndirectCount"/>
+ <command queues="graphics,compute,transfer" renderpass="both" cmdbufferlevel="primary,secondary">
+ <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>
+ </command>
+ <command>
+ <proto><type>void</type> <name>vkGetQueueCheckpointDataNV</name></proto>
+ <param><type>VkQueue</type> <name>queue</name></param>
+ <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">
+ <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>
+ <param><type>uint32_t</type> <name>bindingCount</name></param>
+ <param len="bindingCount">const <type>VkBuffer</type>* <name>pBuffers</name></param>
+ <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">
+ <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>
+ <param optional="true"><type>uint32_t</type> <name>counterBufferCount</name></param>
+ <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">
+ <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>
+ <param optional="true"><type>uint32_t</type> <name>counterBufferCount</name></param>
+ <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">
+ <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>
+ <param><type>uint32_t</type> <name>query</name></param>
+ <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">
+ <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">
+ <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>
+ <param><type>uint32_t</type> <name>firstInstance</name></param>
+ <param><type>VkBuffer</type> <name>counterBuffer</name></param>
+ <param><type>VkDeviceSize</type> <name>counterBufferOffset</name></param>
+ <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">
+ <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">
+ <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">
+ <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">
+ <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">
+ <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">
+ <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>
+ <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">
+ <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>
+ <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>
+ <param><type>VkPipeline</type> <name>pipeline</name></param>
+ <param><type>uint32_t</type> <name>shader</name></param>
+ </command>
+ <command successcodes="VK_SUCCESS" errorcodes="VK_ERROR_OUT_OF_HOST_MEMORY">
+ <proto><type>VkResult</type> <name>vkCreateAccelerationStructureNV</name></proto>
+ <param><type>VkDevice</type> <name>device</name></param>
+ <param>const <type>VkAccelerationStructureCreateInfoNV</type>* <name>pCreateInfo</name></param>
+ <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">
+ <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>
+ <param><type>VkImageLayout</type> <name>imageLayout</name></param>
+ </command>
+ <command>
+ <proto><type>void</type> <name>vkDestroyAccelerationStructureKHR</name></proto>
+ <param><type>VkDevice</type> <name>device</name></param>
+ <param optional="true" externsync="true"><type>VkAccelerationStructureKHR</type> <name>accelerationStructure</name></param>
+ <param optional="true">const <type>VkAllocationCallbacks</type>* <name>pAllocator</name></param>
+ </command>
+ <command>
+ <proto><type>void</type> <name>vkDestroyAccelerationStructureNV</name></proto>
+ <param><type>VkDevice</type> <name>device</name></param>
+ <param optional="true" externsync="true"><type>VkAccelerationStructureNV</type> <name>accelerationStructure</name></param>
+ <param optional="true">const <type>VkAllocationCallbacks</type>* <name>pAllocator</name></param>
+ </command>
+ <command>
+ <proto><type>void</type> <name>vkGetAccelerationStructureMemoryRequirementsNV</name></proto>
+ <param><type>VkDevice</type> <name>device</name></param>
+ <param>const <type>VkAccelerationStructureMemoryRequirementsInfoNV</type>* <name>pInfo</name></param>
+ <param><type>VkMemoryRequirements2KHR</type>* <name>pMemoryRequirements</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>vkBindAccelerationStructureMemoryNV</name></proto>
+ <param><type>VkDevice</type> <name>device</name></param>
+ <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">
+ <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">
+ <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>
+ </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>vkCopyAccelerationStructureKHR</name></proto>
+ <param><type>VkDevice</type> <name>device</name></param>
+ <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">
+ <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>
+ </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>vkCopyAccelerationStructureToMemoryKHR</name></proto>
+ <param><type>VkDevice</type> <name>device</name></param>
+ <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">
+ <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>
+ </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>vkCopyMemoryToAccelerationStructureKHR</name></proto>
+ <param><type>VkDevice</type> <name>device</name></param>
+ <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">
+ <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>
+ <param len="accelerationStructureCount">const <type>VkAccelerationStructureKHR</type>* <name>pAccelerationStructures</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 queues="compute" renderpass="outside" cmdbufferlevel="primary,secondary">
+ <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>
+ <param len="accelerationStructureCount">const <type>VkAccelerationStructureNV</type>* <name>pAccelerationStructures</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 queues="compute" renderpass="outside" cmdbufferlevel="primary,secondary">
+ <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>
+ <param optional="true"><type>VkBuffer</type> <name>instanceData</name></param>
+ <param><type>VkDeviceSize</type> <name>instanceOffset</name></param>
+ <param><type>VkBool32</type> <name>update</name></param>
+ <param><type>VkAccelerationStructureNV</type> <name>dst</name></param>
+ <param optional="true"><type>VkAccelerationStructureNV</type> <name>src</name></param>
+ <param><type>VkBuffer</type> <name>scratch</name></param>
+ <param><type>VkDeviceSize</type> <name>scratchOffset</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>vkWriteAccelerationStructuresPropertiesKHR</name></proto>
+ <param><type>VkDevice</type> <name>device</name></param>
+ <param><type>uint32_t</type> <name>accelerationStructureCount</name></param>
+ <param len="accelerationStructureCount">const <type>VkAccelerationStructureKHR</type>* <name>pAccelerationStructures</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 queues="compute" renderpass="outside" cmdbufferlevel="primary,secondary">
+ <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>
+ <param>const <type>VkStridedDeviceAddressRegionKHR</type>* <name>pMissShaderBindingTable</name></param>
+ <param>const <type>VkStridedDeviceAddressRegionKHR</type>* <name>pHitShaderBindingTable</name></param>
+ <param>const <type>VkStridedDeviceAddressRegionKHR</type>* <name>pCallableShaderBindingTable</name></param>
+ <param><type>uint32_t</type> <name>width</name></param>
+ <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">
+ <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>
+ <param><type>VkDeviceSize</type> <name>raygenShaderBindingOffset</name></param>
+ <param optional="true"><type>VkBuffer</type> <name>missShaderBindingTableBuffer</name></param>
+ <param><type>VkDeviceSize</type> <name>missShaderBindingOffset</name></param>
+ <param><type>VkDeviceSize</type> <name>missShaderBindingStride</name></param>
+ <param optional="true"><type>VkBuffer</type> <name>hitShaderBindingTableBuffer</name></param>
+ <param><type>VkDeviceSize</type> <name>hitShaderBindingOffset</name></param>
+ <param><type>VkDeviceSize</type> <name>hitShaderBindingStride</name></param>
+ <param optional="true"><type>VkBuffer</type> <name>callableShaderBindingTableBuffer</name></param>
+ <param><type>VkDeviceSize</type> <name>callableShaderBindingOffset</name></param>
+ <param><type>VkDeviceSize</type> <name>callableShaderBindingStride</name></param>
+ <param><type>uint32_t</type> <name>width</name></param>
+ <param><type>uint32_t</type> <name>height</name></param>
+ <param><type>uint32_t</type> <name>depth</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>vkGetRayTracingShaderGroupHandlesKHR</name></proto>
+ <param><type>VkDevice</type> <name>device</name></param>
+ <param><type>VkPipeline</type> <name>pipeline</name></param>
+ <param><type>uint32_t</type> <name>firstGroup</name></param>
+ <param><type>uint32_t</type> <name>groupCount</name></param>
+ <param><type>size_t</type> <name>dataSize</name></param>
+ <param len="dataSize"><type>void</type>* <name>pData</name></param>
+ </command>
+ <command name="vkGetRayTracingShaderGroupHandlesNV" alias="vkGetRayTracingShaderGroupHandlesKHR"/>
+ <command successcodes="VK_SUCCESS" errorcodes="VK_ERROR_OUT_OF_HOST_MEMORY,VK_ERROR_OUT_OF_DEVICE_MEMORY">
+ <proto><type>VkResult</type> <name>vkGetRayTracingCaptureReplayShaderGroupHandlesKHR</name></proto>
+ <param><type>VkDevice</type> <name>device</name></param>
+ <param><type>VkPipeline</type> <name>pipeline</name></param>
+ <param><type>uint32_t</type> <name>firstGroup</name></param>
+ <param><type>uint32_t</type> <name>groupCount</name></param>
+ <param><type>size_t</type> <name>dataSize</name></param>
+ <param len="dataSize"><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>vkGetAccelerationStructureHandleNV</name></proto>
+ <param><type>VkDevice</type> <name>device</name></param>
+ <param><type>VkAccelerationStructureNV</type> <name>accelerationStructure</name></param>
+ <param><type>size_t</type> <name>dataSize</name></param>
+ <param len="dataSize"><type>void</type>* <name>pData</name></param>
+ </command>
+ <command successcodes="VK_SUCCESS,VK_PIPELINE_COMPILE_REQUIRED_EXT" errorcodes="VK_ERROR_OUT_OF_HOST_MEMORY,VK_ERROR_OUT_OF_DEVICE_MEMORY,VK_ERROR_INVALID_SHADER_NV">
+ <proto><type>VkResult</type> <name>vkCreateRayTracingPipelinesNV</name></proto>
+ <param><type>VkDevice</type> <name>device</name></param>
+ <param optional="true"><type>VkPipelineCache</type> <name>pipelineCache</name></param>
+ <param><type>uint32_t</type> <name>createInfoCount</name></param>
+ <param len="createInfoCount">const <type>VkRayTracingPipelineCreateInfoNV</type>* <name>pCreateInfos</name></param>
+ <param optional="true">const <type>VkAllocationCallbacks</type>* <name>pAllocator</name></param>
+ <param len="createInfoCount"><type>VkPipeline</type>* <name>pPipelines</name></param>
+ </command>
+ <command successcodes="VK_SUCCESS,VK_OPERATION_DEFERRED_KHR,VK_OPERATION_NOT_DEFERRED_KHR,VK_PIPELINE_COMPILE_REQUIRED_EXT" errorcodes="VK_ERROR_OUT_OF_HOST_MEMORY,VK_ERROR_OUT_OF_DEVICE_MEMORY,VK_ERROR_INVALID_OPAQUE_CAPTURE_ADDRESS">
+ <proto><type>VkResult</type> <name>vkCreateRayTracingPipelinesKHR</name></proto>
+ <param><type>VkDevice</type> <name>device</name></param>
+ <param optional="true"><type>VkDeferredOperationKHR</type> <name>deferredOperation</name></param>
+ <param optional="true"><type>VkPipelineCache</type> <name>pipelineCache</name></param>
+ <param><type>uint32_t</type> <name>createInfoCount</name></param>
+ <param len="createInfoCount">const <type>VkRayTracingPipelineCreateInfoKHR</type>* <name>pCreateInfos</name></param>
+ <param optional="true">const <type>VkAllocationCallbacks</type>* <name>pAllocator</name></param>
+ <param len="createInfoCount"><type>VkPipeline</type>* <name>pPipelines</name></param>
+ </command>
+ <command successcodes="VK_SUCCESS,VK_INCOMPLETE" errorcodes="VK_ERROR_OUT_OF_HOST_MEMORY,VK_ERROR_OUT_OF_DEVICE_MEMORY">
+ <proto><type>VkResult</type> <name>vkGetPhysicalDeviceCooperativeMatrixPropertiesNV</name></proto>
+ <param><type>VkPhysicalDevice</type> <name>physicalDevice</name></param>
+ <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">
+ <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>
+ <param>const <type>VkStridedDeviceAddressRegionKHR</type>* <name>pMissShaderBindingTable</name></param>
+ <param>const <type>VkStridedDeviceAddressRegionKHR</type>* <name>pHitShaderBindingTable</name></param>
+ <param>const <type>VkStridedDeviceAddressRegionKHR</type>* <name>pCallableShaderBindingTable</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>
+ <param>const <type>VkAccelerationStructureVersionInfoKHR</type>* <name>pVersionInfo</name></param>
+ <param><type>VkAccelerationStructureCompatibilityKHR</type>* <name>pCompatibility</name></param>
+ </command>
+ <command>
+ <proto><type>VkDeviceSize</type> <name>vkGetRayTracingShaderGroupStackSizeKHR</name></proto>
+ <param><type>VkDevice</type> <name>device</name></param>
+ <param><type>VkPipeline</type> <name>pipeline</name></param>
+ <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">
+ <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>
+ </command>
+ <command>
+ <proto><type>uint32_t</type> <name>vkGetImageViewHandleNVX</name></proto>
+ <param><type>VkDevice</type> <name>device</name></param>
+ <param>const <type>VkImageViewHandleInfoNVX</type>* <name>pInfo</name></param>
+ </command>
+ <command successcodes="VK_SUCCESS" errorcodes="VK_ERROR_OUT_OF_HOST_MEMORY,VK_ERROR_UNKNOWN">
+ <proto><type>VkResult</type> <name>vkGetImageViewAddressNVX</name></proto>
+ <param><type>VkDevice</type> <name>device</name></param>
+ <param><type>VkImageView</type> <name>imageView</name></param>
+ <param><type>VkImageViewAddressPropertiesNVX</type>* <name>pProperties</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>vkGetPhysicalDeviceSurfacePresentModes2EXT</name></proto>
+ <param><type>VkPhysicalDevice</type> <name>physicalDevice</name></param>
+ <param>const <type>VkPhysicalDeviceSurfaceInfo2KHR</type>* <name>pSurfaceInfo</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_SURFACE_LOST_KHR">
+ <proto><type>VkResult</type> <name>vkGetDeviceGroupSurfacePresentModes2EXT</name></proto>
+ <param><type>VkDevice</type> <name>device</name></param>
+ <param>const <type>VkPhysicalDeviceSurfaceInfo2KHR</type>* <name>pSurfaceInfo</name></param>
+ <param optional="false,true"><type>VkDeviceGroupPresentModeFlagsKHR</type>* <name>pModes</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_SURFACE_LOST_KHR">
+ <proto><type>VkResult</type> <name>vkAcquireFullScreenExclusiveModeEXT</name></proto>
+ <param><type>VkDevice</type> <name>device</name></param>
+ <param><type>VkSwapchainKHR</type> <name>swapchain</name></param>
+ </command>
+ <command successcodes="VK_SUCCESS" errorcodes="VK_ERROR_OUT_OF_HOST_MEMORY,VK_ERROR_OUT_OF_DEVICE_MEMORY,VK_ERROR_SURFACE_LOST_KHR">
+ <proto><type>VkResult</type> <name>vkReleaseFullScreenExclusiveModeEXT</name></proto>
+ <param><type>VkDevice</type> <name>device</name></param>
+ <param><type>VkSwapchainKHR</type> <name>swapchain</name></param>
+ </command>
+ <command successcodes="VK_SUCCESS,VK_INCOMPLETE" errorcodes="VK_ERROR_OUT_OF_HOST_MEMORY,VK_ERROR_OUT_OF_DEVICE_MEMORY,VK_ERROR_INITIALIZATION_FAILED">
+ <proto><type>VkResult</type> <name>vkEnumeratePhysicalDeviceQueueFamilyPerformanceQueryCountersKHR</name></proto>
+ <param><type>VkPhysicalDevice</type> <name>physicalDevice</name></param>
+ <param><type>uint32_t</type> <name>queueFamilyIndex</name></param>
+ <param optional="false,true"><type>uint32_t</type>* <name>pCounterCount</name></param>
+ <param optional="true" len="pCounterCount"><type>VkPerformanceCounterKHR</type>* <name>pCounters</name></param>
+ <param optional="true" len="pCounterCount"><type>VkPerformanceCounterDescriptionKHR</type>* <name>pCounterDescriptions</name></param>
+ </command>
+ <command>
+ <proto><type>void</type> <name>vkGetPhysicalDeviceQueueFamilyPerformanceQueryPassesKHR</name></proto>
+ <param><type>VkPhysicalDevice</type> <name>physicalDevice</name></param>
+ <param>const <type>VkQueryPoolPerformanceCreateInfoKHR</type>* <name>pPerformanceQueryCreateInfo</name></param>
+ <param><type>uint32_t</type>* <name>pNumPasses</name></param>
+ </command>
+ <command successcodes="VK_SUCCESS" errorcodes="VK_ERROR_OUT_OF_HOST_MEMORY,VK_TIMEOUT">
+ <proto><type>VkResult</type> <name>vkAcquireProfilingLockKHR</name></proto>
+ <param><type>VkDevice</type> <name>device</name></param>
+ <param>const <type>VkAcquireProfilingLockInfoKHR</type>* <name>pInfo</name></param>
+ </command>
+ <command>
+ <proto><type>void</type> <name>vkReleaseProfilingLockKHR</name></proto>
+ <param><type>VkDevice</type> <name>device</name></param>
+ </command>
+ <command successcodes="VK_SUCCESS" errorcodes="VK_ERROR_OUT_OF_HOST_MEMORY">
+ <proto><type>VkResult</type> <name>vkGetImageDrmFormatModifierPropertiesEXT</name></proto>
+ <param><type>VkDevice</type> <name>device</name></param>
+ <param><type>VkImage</type> <name>image</name></param>
+ <param><type>VkImageDrmFormatModifierPropertiesEXT</type>* <name>pProperties</name></param>
+ </command>
+ <command>
+ <proto><type>uint64_t</type> <name>vkGetBufferOpaqueCaptureAddress</name></proto>
+ <param><type>VkDevice</type> <name>device</name></param>
+ <param>const <type>VkBufferDeviceAddressInfo</type>* <name>pInfo</name></param>
+ </command>
+ <command name="vkGetBufferOpaqueCaptureAddressKHR" alias="vkGetBufferOpaqueCaptureAddress"/>
+ <command>
+ <proto><type>VkDeviceAddress</type> <name>vkGetBufferDeviceAddress</name></proto>
+ <param><type>VkDevice</type> <name>device</name></param>
+ <param>const <type>VkBufferDeviceAddressInfo</type>* <name>pInfo</name></param>
+ </command>
+ <command name="vkGetBufferDeviceAddressKHR" alias="vkGetBufferDeviceAddress"/>
+ <command name="vkGetBufferDeviceAddressEXT" alias="vkGetBufferDeviceAddress"/>
+ <command successcodes="VK_SUCCESS" errorcodes="VK_ERROR_OUT_OF_HOST_MEMORY,VK_ERROR_OUT_OF_DEVICE_MEMORY">
+ <proto><type>VkResult</type> <name>vkCreateHeadlessSurfaceEXT</name></proto>
+ <param><type>VkInstance</type> <name>instance</name></param>
+ <param>const <type>VkHeadlessSurfaceCreateInfoEXT</type>* <name>pCreateInfo</name></param>
+ <param optional="true">const <type>VkAllocationCallbacks</type>* <name>pAllocator</name></param>
+ <param><type>VkSurfaceKHR</type>* <name>pSurface</name></param>
+ </command>
+ <command successcodes="VK_SUCCESS,VK_INCOMPLETE" errorcodes="VK_ERROR_OUT_OF_HOST_MEMORY,VK_ERROR_OUT_OF_DEVICE_MEMORY">
+ <proto><type>VkResult</type> <name>vkGetPhysicalDeviceSupportedFramebufferMixedSamplesCombinationsNV</name></proto>
+ <param><type>VkPhysicalDevice</type> <name>physicalDevice</name></param>
+ <param optional="false,true"><type>uint32_t</type>* <name>pCombinationCount</name></param>
+ <param optional="true" len="pCombinationCount"><type>VkFramebufferMixedSamplesCombinationNV</type>* <name>pCombinations</name></param>
+ </command>
+ <command successcodes="VK_SUCCESS" errorcodes="VK_ERROR_TOO_MANY_OBJECTS,VK_ERROR_OUT_OF_HOST_MEMORY">
+ <proto><type>VkResult</type> <name>vkInitializePerformanceApiINTEL</name></proto>
+ <param><type>VkDevice</type> <name>device</name></param>
+ <param>const <type>VkInitializePerformanceApiInfoINTEL</type>* <name>pInitializeInfo</name></param>
+ </command>
+ <command>
+ <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">
+ <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">
+ <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">
+ <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>
+ </command>
+ <command successcodes="VK_SUCCESS" errorcodes="VK_ERROR_TOO_MANY_OBJECTS,VK_ERROR_OUT_OF_HOST_MEMORY">
+ <proto><type>VkResult</type> <name>vkAcquirePerformanceConfigurationINTEL</name></proto>
+ <param><type>VkDevice</type> <name>device</name></param>
+ <param>const <type>VkPerformanceConfigurationAcquireInfoINTEL</type>* <name>pAcquireInfo</name></param>
+ <param><type>VkPerformanceConfigurationINTEL</type>* <name>pConfiguration</name></param>
+ </command>
+ <command successcodes="VK_SUCCESS" errorcodes="VK_ERROR_TOO_MANY_OBJECTS,VK_ERROR_OUT_OF_HOST_MEMORY">
+ <proto><type>VkResult</type> <name>vkReleasePerformanceConfigurationINTEL</name></proto>
+ <param><type>VkDevice</type> <name>device</name></param>
+ <param optional="true" externsync="true"><type>VkPerformanceConfigurationINTEL</type> <name>configuration</name></param>
+ </command>
+ <command successcodes="VK_SUCCESS" errorcodes="VK_ERROR_TOO_MANY_OBJECTS,VK_ERROR_OUT_OF_HOST_MEMORY">
+ <proto><type>VkResult</type> <name>vkQueueSetPerformanceConfigurationINTEL</name></proto>
+ <param><type>VkQueue</type> <name>queue</name></param>
+ <param><type>VkPerformanceConfigurationINTEL</type> <name>configuration</name></param>
+ </command>
+ <command successcodes="VK_SUCCESS" errorcodes="VK_ERROR_TOO_MANY_OBJECTS,VK_ERROR_OUT_OF_HOST_MEMORY">
+ <proto><type>VkResult</type> <name>vkGetPerformanceParameterINTEL</name></proto>
+ <param><type>VkDevice</type> <name>device</name></param>
+ <param><type>VkPerformanceParameterTypeINTEL</type> <name>parameter</name></param>
+ <param><type>VkPerformanceValueINTEL</type>* <name>pValue</name></param>
+ </command>
+ <command>
+ <proto><type>uint64_t</type> <name>vkGetDeviceMemoryOpaqueCaptureAddress</name></proto>
+ <param><type>VkDevice</type> <name>device</name></param>
+ <param>const <type>VkDeviceMemoryOpaqueCaptureAddressInfo</type>* <name>pInfo</name></param>
+ </command>
+ <command name="vkGetDeviceMemoryOpaqueCaptureAddressKHR" alias="vkGetDeviceMemoryOpaqueCaptureAddress"/>
+ <command successcodes="VK_SUCCESS,VK_INCOMPLETE" errorcodes="VK_ERROR_OUT_OF_HOST_MEMORY,VK_ERROR_OUT_OF_DEVICE_MEMORY">
+ <proto><type>VkResult</type> <name>vkGetPipelineExecutablePropertiesKHR</name></proto>
+ <param><type>VkDevice</type> <name>device</name></param>
+ <param>const <type>VkPipelineInfoKHR</type>* <name>pPipelineInfo</name></param>
+ <param optional="false,true"><type>uint32_t</type>* <name>pExecutableCount</name></param>
+ <param optional="true" len="pExecutableCount"><type>VkPipelineExecutablePropertiesKHR</type>* <name>pProperties</name></param>
+ </command>
+ <command successcodes="VK_SUCCESS,VK_INCOMPLETE" errorcodes="VK_ERROR_OUT_OF_HOST_MEMORY,VK_ERROR_OUT_OF_DEVICE_MEMORY">
+ <proto><type>VkResult</type> <name>vkGetPipelineExecutableStatisticsKHR</name></proto>
+ <param><type>VkDevice</type> <name>device</name></param>
+ <param>const <type>VkPipelineExecutableInfoKHR</type>* <name>pExecutableInfo</name></param>
+ <param optional="false,true"><type>uint32_t</type>* <name>pStatisticCount</name></param>
+ <param optional="true" len="pStatisticCount"><type>VkPipelineExecutableStatisticKHR</type>* <name>pStatistics</name></param>
+ </command>
+ <command successcodes="VK_SUCCESS,VK_INCOMPLETE" errorcodes="VK_ERROR_OUT_OF_HOST_MEMORY,VK_ERROR_OUT_OF_DEVICE_MEMORY">
+ <proto><type>VkResult</type> <name>vkGetPipelineExecutableInternalRepresentationsKHR</name></proto>
+ <param><type>VkDevice</type> <name>device</name></param>
+ <param>const <type>VkPipelineExecutableInfoKHR</type>* <name>pExecutableInfo</name></param>
+ <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">
+ <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>
+ <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>
+ </command>
+ <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>
+ <param>const <type>VkAccelerationStructureCreateInfoKHR</type>* <name>pCreateInfo</name></param>
+ <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">
+ <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">
+ <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>
+ <param len="infoCount">const <type>VkAccelerationStructureBuildGeometryInfoKHR</type>* <name>pInfos</name></param>
+ <param len="infoCount">const <type>VkDeviceAddress</type>* <name>pIndirectDeviceAddresses</name></param>
+ <param len="infoCount">const <type>uint32_t</type>* <name>pIndirectStrides</name></param>
+ <param len="infoCount">const <type>uint32_t</type>* const* <name>ppMaxPrimitiveCounts</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>vkBuildAccelerationStructuresKHR</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>VkAccelerationStructureBuildGeometryInfoKHR</type>* <name>pInfos</name></param>
+ <param len="infoCount">const <type>VkAccelerationStructureBuildRangeInfoKHR</type>* const* <name>ppBuildRangeInfos</name></param>
+ </command>
+ <command>
+ <proto><type>VkDeviceAddress</type> <name>vkGetAccelerationStructureDeviceAddressKHR</name></proto>
+ <param><type>VkDevice</type> <name>device</name></param>
+ <param>const <type>VkAccelerationStructureDeviceAddressInfoKHR</type>* <name>pInfo</name></param>
+ </command>
+ <command successcodes="VK_SUCCESS" errorcodes="VK_ERROR_OUT_OF_HOST_MEMORY">
+ <proto><type>VkResult</type> <name>vkCreateDeferredOperationKHR</name></proto>
+ <param><type>VkDevice</type> <name>device</name></param>
+ <param optional="true">const <type>VkAllocationCallbacks</type>* <name>pAllocator</name></param>
+ <param><type>VkDeferredOperationKHR</type>* <name>pDeferredOperation</name></param>
+ </command>
+ <command>
+ <proto><type>void</type> <name>vkDestroyDeferredOperationKHR</name></proto>
+ <param><type>VkDevice</type> <name>device</name></param>
+ <param optional="true" externsync="true"><type>VkDeferredOperationKHR</type> <name>operation</name></param>
+ <param optional="true">const <type>VkAllocationCallbacks</type>* <name>pAllocator</name></param>
+ </command>
+ <command>
+ <proto><type>uint32_t</type> <name>vkGetDeferredOperationMaxConcurrencyKHR</name></proto>
+ <param><type>VkDevice</type> <name>device</name></param>
+ <param><type>VkDeferredOperationKHR</type> <name>operation</name></param>
+ </command>
+ <command successcodes="VK_SUCCESS,VK_NOT_READY">
+ <proto><type>VkResult</type> <name>vkGetDeferredOperationResultKHR</name></proto>
+ <param><type>VkDevice</type> <name>device</name></param>
+ <param><type>VkDeferredOperationKHR</type> <name>operation</name></param>
+ </command>
+ <command successcodes="VK_SUCCESS,VK_THREAD_DONE_KHR,VK_THREAD_IDLE_KHR" errorcodes="VK_ERROR_OUT_OF_HOST_MEMORY,VK_ERROR_OUT_OF_DEVICE_MEMORY">
+ <proto><type>VkResult</type> <name>vkDeferredOperationJoinKHR</name></proto>
+ <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>
+ <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>
+ <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>
+ <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>
+ <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>
+ <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>
+ <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>
+ <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>
+ <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>
+ <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>
+ <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>
+ <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>
+ <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>
+ <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>
+ <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>
+ <param><type>VkStencilOp</type> <name>passOp</name></param>
+ <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">
+ <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>
+ <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>
+ <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">
+ <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>
+ <param externsync="true"><type>VkCommandBuffer</type> <name>commandBuffer</name></param>
+ <param><type>VkBool32</type> <name>primitiveRestartEnable</name></param>
+ </command>
+ <command successcodes="VK_SUCCESS" errorcodes="VK_ERROR_OUT_OF_HOST_MEMORY">
+ <proto><type>VkResult</type> <name>vkCreatePrivateDataSlotEXT</name></proto>
+ <param><type>VkDevice</type> <name>device</name></param>
+ <param>const <type>VkPrivateDataSlotCreateInfoEXT</type>* <name>pCreateInfo</name></param>
+ <param optional="true">const <type>VkAllocationCallbacks</type>* <name>pAllocator</name></param>
+ <param><type>VkPrivateDataSlotEXT</type>* <name>pPrivateDataSlot</name></param>
+ </command>
+ <command>
+ <proto><type>void</type> <name>vkDestroyPrivateDataSlotEXT</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">const <type>VkAllocationCallbacks</type>* <name>pAllocator</name></param>
+ </command>
+ <command successcodes="VK_SUCCESS" errorcodes="VK_ERROR_OUT_OF_HOST_MEMORY">
+ <proto><type>VkResult</type> <name>vkSetPrivateDataEXT</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>uint64_t</type> <name>data</name></param>
+ </command>
+ <command>
+ <proto><type>void</type> <name>vkGetPrivateDataEXT</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>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>
+ <param externsync="true"><type>VkCommandBuffer</type> <name>commandBuffer</name></param>
+ <param>const <type>VkCopyBufferInfo2KHR</type>* <name>pCopyBufferInfo</name></param>
+ </command>
+ <command queues="transfer,graphics,compute" renderpass="outside" cmdbufferlevel="primary,secondary">
+ <proto><type>void</type> <name>vkCmdCopyImage2KHR</name></proto>
+ <param externsync="true"><type>VkCommandBuffer</type> <name>commandBuffer</name></param>
+ <param>const <type>VkCopyImageInfo2KHR</type>* <name>pCopyImageInfo</name></param>
+ </command>
+ <command queues="graphics" renderpass="outside" cmdbufferlevel="primary,secondary">
+ <proto><type>void</type> <name>vkCmdBlitImage2KHR</name></proto>
+ <param externsync="true"><type>VkCommandBuffer</type> <name>commandBuffer</name></param>
+ <param>const <type>VkBlitImageInfo2KHR</type>* <name>pBlitImageInfo</name></param>
+ </command>
+ <command queues="transfer,graphics,compute" renderpass="outside" cmdbufferlevel="primary,secondary">
+ <proto><type>void</type> <name>vkCmdCopyBufferToImage2KHR</name></proto>
+ <param externsync="true"><type>VkCommandBuffer</type> <name>commandBuffer</name></param>
+ <param>const <type>VkCopyBufferToImageInfo2KHR</type>* <name>pCopyBufferToImageInfo</name></param>
+ </command>
+ <command queues="transfer,graphics,compute" renderpass="outside" cmdbufferlevel="primary,secondary">
+ <proto><type>void</type> <name>vkCmdCopyImageToBuffer2KHR</name></proto>
+ <param externsync="true"><type>VkCommandBuffer</type> <name>commandBuffer</name></param>
+ <param>const <type>VkCopyImageToBufferInfo2KHR</type>* <name>pCopyImageToBufferInfo</name></param>
+ </command>
+ <command queues="graphics" renderpass="outside" cmdbufferlevel="primary,secondary">
+ <proto><type>void</type> <name>vkCmdResolveImage2KHR</name></proto>
+ <param externsync="true"><type>VkCommandBuffer</type> <name>commandBuffer</name></param>
+ <param>const <type>VkResolveImageInfo2KHR</type>* <name>pResolveImageInfo</name></param>
+ </command>
+ <command queues="graphics" renderpass="both" cmdbufferlevel="primary,secondary">
+ <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>
+ <param>const <type>VkFragmentShadingRateCombinerOpKHR</type> <name>combinerOps</name>[2]</param>
+ </command>
+ <command successcodes="VK_SUCCESS,VK_INCOMPLETE" errorcodes="VK_ERROR_OUT_OF_HOST_MEMORY">
+ <proto><type>VkResult</type> <name>vkGetPhysicalDeviceFragmentShadingRatesKHR</name></proto>
+ <param><type>VkPhysicalDevice</type> <name>physicalDevice</name></param>
+ <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">
+ <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>
+ <param>const <type>VkFragmentShadingRateCombinerOpKHR</type> <name>combinerOps</name>[2]</param>
+ </command>
+ <command>
+ <proto><type>void</type> <name>vkGetAccelerationStructureBuildSizesKHR</name></proto>
+ <param><type>VkDevice</type> <name>device</name></param>
+ <param><type>VkAccelerationStructureBuildTypeKHR</type> <name>buildType</name></param>
+ <param>const <type>VkAccelerationStructureBuildGeometryInfoKHR</type>* <name>pBuildInfo</name></param>
+ <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">
+ <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>
+ <param len="vertexBindingDescriptionCount">const <type>VkVertexInputBindingDescription2EXT</type>* <name>pVertexBindingDescriptions</name></param>
+ <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">
+ <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>
+ <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>
+ </command>
+ <command queues="graphics,compute" renderpass="outside" cmdbufferlevel="primary,secondary">
+ <proto><type>void</type> <name>vkCmdResetEvent2KHR</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>
+ </command>
+ <command queues="graphics,compute" renderpass="both" cmdbufferlevel="primary,secondary">
+ <proto><type>void</type> <name>vkCmdWaitEvents2KHR</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>
+ </command>
+ <command queues="transfer,graphics,compute" renderpass="both" cmdbufferlevel="primary,secondary">
+ <proto><type>void</type> <name>vkCmdPipelineBarrier2KHR</name></proto>
+ <param externsync="true"><type>VkCommandBuffer</type> <name>commandBuffer</name></param>
+ <param>const <type>VkDependencyInfoKHR</type>* <name>pDependencyInfo</name></param>
+ </command>
+ <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>
+ <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 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>
+ <param externsync="true"><type>VkCommandBuffer</type> <name>commandBuffer</name></param>
+ <param><type>VkPipelineStageFlags2KHR</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">
+ <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><type>VkBuffer</type> <name>dstBuffer</name></param>
+ <param><type>VkDeviceSize</type> <name>dstOffset</name></param>
+ <param><type>uint32_t</type> <name>marker</name></param>
+ </command>
+ <command>
+ <proto><type>void</type> <name>vkGetQueueCheckpointData2NV</name></proto>
+ <param><type>VkQueue</type> <name>queue</name></param>
+ <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">
+ <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><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">
+ <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">
+ <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>
+ <param optional="true">const <type>VkAllocationCallbacks</type>* <name>pAllocator</name></param>
+ <param><type>VkVideoSessionKHR</type>* <name>pVideoSession</name></param>
+ </command>
+ <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">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">
+ <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">
+ <proto><type>VkResult</type> <name>vkUpdateVideoSessionParametersKHR</name></proto>
+ <param><type>VkDevice</type> <name>device</name></param>
+ <param><type>VkVideoSessionParametersKHR</type> <name>videoSessionParameters</name></param>
+ <param>const <type>VkVideoSessionParametersUpdateInfoKHR</type>* <name>pUpdateInfo</name></param>
+ </command>
+ <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">const <type>VkAllocationCallbacks</type>* <name>pAllocator</name></param>
+ </command>
+ <command successcodes="VK_SUCCESS,VK_INCOMPLETE" errorcodes="VK_ERROR_INITIALIZATION_FAILED">
+ <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>
+ </command>
+ <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>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>
+ </command>
+ <command queues="decode" renderpass="outside" cmdbufferlevel="primary">
+ <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>
+ </command>
+ <command queues="decode,encode" renderpass="outside" cmdbufferlevel="primary">
+ <proto><type>void</type> <name>vkCmdBeginVideoCodingKHR</name></proto>
+ <param><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">
+ <proto><type>void</type> <name>vkCmdControlVideoCodingKHR</name></proto>
+ <param><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">
+ <proto><type>void</type> <name>vkCmdEndVideoCodingKHR</name></proto>
+ <param><type>VkCommandBuffer</type> <name>commandBuffer</name></param>
+ <param>const <type>VkVideoEndCodingInfoKHR</type>* <name>pEndCodingInfo</name></param>
+ </command>
+ <command queues="encode" renderpass="outside" cmdbufferlevel="primary">
+ <proto><type>void</type> <name>vkCmdEncodeVideoKHR</name></proto>
+ <param><type>VkCommandBuffer</type> <name>commandBuffer</name></param>
+ <param>const <type>VkVideoEncodeInfoKHR</type>* <name>pEncodeInfo</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>
+ <param>const <type>VkCuModuleCreateInfoNVX</type>* <name>pCreateInfo</name></param>
+ <param optional="true">const <type>VkAllocationCallbacks</type>* <name>pAllocator</name></param>
+ <param><type>VkCuModuleNVX</type>* <name>pModule</name></param>
+ </command>
+ <command successcodes="VK_SUCCESS" errorcodes="VK_ERROR_OUT_OF_HOST_MEMORY,VK_ERROR_INITIALIZATION_FAILED">
+ <proto><type>VkResult</type> <name>vkCreateCuFunctionNVX</name></proto>
+ <param><type>VkDevice</type> <name>device</name></param>
+ <param>const <type>VkCuFunctionCreateInfoNVX</type>* <name>pCreateInfo</name></param>
+ <param optional="true">const <type>VkAllocationCallbacks</type>* <name>pAllocator</name></param>
+ <param><type>VkCuFunctionNVX</type>* <name>pFunction</name></param>
+ </command>
+ <command>
+ <proto><type>void</type> <name>vkDestroyCuModuleNVX</name></proto>
+ <param><type>VkDevice</type> <name>device</name></param>
+ <param><type>VkCuModuleNVX</type> <name>module</name></param>
+ <param optional="true">const <type>VkAllocationCallbacks</type>* <name>pAllocator</name></param>
+ </command>
+ <command>
+ <proto><type>void</type> <name>vkDestroyCuFunctionNVX</name></proto>
+ <param><type>VkDevice</type> <name>device</name></param>
+ <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">
+ <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 successcodes="VK_SUCCESS" errorcodes="VK_ERROR_INITIALIZATION_FAILED">
+ <proto><type>VkResult</type> <name>vkAcquireDrmDisplayEXT</name></proto>
+ <param><type>VkPhysicalDevice</type> <name>physicalDevice</name></param>
+ <param><type>int32_t</type> <name>drmFd</name></param>
+ <param><type>VkDisplayKHR</type> <name>display</name></param>
+ </command>
+ <command successcodes="VK_SUCCESS" errorcodes="VK_ERROR_INITIALIZATION_FAILED,VK_ERROR_OUT_OF_HOST_MEMORY">
+ <proto><type>VkResult</type> <name>vkGetDrmDisplayEXT</name></proto>
+ <param><type>VkPhysicalDevice</type> <name>physicalDevice</name></param>
+ <param><type>int32_t</type> <name>drmFd</name></param>
+ <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>
+ </commands>
+
+ <feature api="vulkan" name="VK_VERSION_1_0" number="1.0" comment="Vulkan core API interface definitions">
+ <require comment="Header boilerplate">
+ <type name="vk_platform"/>
+ <type name="VK_DEFINE_HANDLE"/>
+ <type name="VK_USE_64_BIT_PTR_DEFINES"/>
+ <type name="VK_DEFINE_NON_DISPATCHABLE_HANDLE"/>
+ <type name="VK_NULL_HANDLE"/>
+ </require>
+ <require comment="Fundamental types used by many commands and structures">
+ <type name="VkBool32"/>
+ <type name="VkDeviceAddress"/>
+ <type name="VkDeviceSize"/>
+ <type name="VkExtent2D"/>
+ <type name="VkExtent3D"/>
+ <type name="VkFlags"/>
+ <type name="VkOffset2D"/>
+ <type name="VkOffset3D"/>
+ <type name="VkRect2D"/>
+ <type name="VkResult"/>
+ <type name="VkStructureType"/>
+ </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"/>
+ <type name="VkBufferMemoryBarrier"/>
+ <type name="VkDispatchIndirectCommand"/>
+ <type name="VkDrawIndexedIndirectCommand"/>
+ <type name="VkDrawIndirectCommand"/>
+ <type name="VkImageMemoryBarrier"/>
+ <type name="VkMemoryBarrier"/>
+ <type name="VkObjectType"/>
+ <type name="VkPipelineCacheHeaderVersionOne"/>
+ <type name="VkVendorId"/>
+ </require>
+ <require comment="API version macros">
+ <type name="VK_API_VERSION"/>
+ <type name="VK_API_VERSION_1_0"/>
+ <type name="VK_HEADER_VERSION"/>
+ <type name="VK_HEADER_VERSION_COMPLETE"/>
+ <type name="VK_MAKE_VERSION"/>
+ <type name="VK_VERSION_MAJOR"/>
+ <type name="VK_VERSION_MINOR"/>
+ <type name="VK_VERSION_PATCH"/>
+ <type name="VK_MAKE_API_VERSION"/>
+ <type name="VK_API_VERSION_VARIANT"/>
+ <type name="VK_API_VERSION_MAJOR"/>
+ <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"/>
+ <type name="PFN_vkInternalAllocationNotification"/>
+ <type name="PFN_vkInternalFreeNotification"/>
+ <type name="PFN_vkReallocationFunction"/>
+ <type name="PFN_vkVoidFunction"/>
+ <type name="VkAllocationCallbacks"/>
+ <type name="VkApplicationInfo"/>
+ <type name="VkFormat"/>
+ <type name="VkFormatFeatureFlagBits"/>
+ <type name="VkFormatFeatureFlags"/>
+ <type name="VkFormatProperties"/>
+ <type name="VkImageCreateFlagBits"/>
+ <type name="VkImageCreateFlags"/>
+ <type name="VkImageFormatProperties"/>
+ <type name="VkImageTiling"/>
+ <type name="VkImageType"/>
+ <type name="VkImageUsageFlagBits"/>
+ <type name="VkImageUsageFlags"/>
+ <type name="VkInstance"/>
+ <type name="VkInstanceCreateFlags"/>
+ <type name="VkInstanceCreateInfo"/>
+ <type name="VkInternalAllocationType"/>
+ <type name="VkMemoryHeap"/>
+ <type name="VkMemoryHeapFlagBits"/>
+ <type name="VkMemoryHeapFlags"/>
+ <type name="VkMemoryPropertyFlagBits"/>
+ <type name="VkMemoryPropertyFlags"/>
+ <type name="VkMemoryType"/>
+ <type name="VkPhysicalDevice"/>
+ <type name="VkPhysicalDeviceFeatures"/>
+ <type name="VkPhysicalDeviceLimits"/>
+ <type name="VkPhysicalDeviceMemoryProperties"/>
+ <type name="VkPhysicalDeviceProperties"/>
+ <type name="VkPhysicalDeviceSparseProperties"/>
+ <type name="VkPhysicalDeviceType"/>
+ <type name="VkQueueFamilyProperties"/>
+ <type name="VkQueueFlagBits"/>
+ <type name="VkQueueFlags"/>
+ <type name="VkSampleCountFlagBits"/>
+ <type name="VkSampleCountFlags"/>
+ <type name="VkSystemAllocationScope"/>
+ <command name="vkCreateInstance"/>
+ <command name="vkDestroyInstance"/>
+ <command name="vkEnumeratePhysicalDevices"/>
+ <command name="vkGetPhysicalDeviceFeatures"/>
+ <command name="vkGetPhysicalDeviceFormatProperties"/>
+ <command name="vkGetPhysicalDeviceImageFormatProperties"/>
+ <command name="vkGetPhysicalDeviceProperties"/>
+ <command name="vkGetPhysicalDeviceQueueFamilyProperties"/>
+ <command name="vkGetPhysicalDeviceMemoryProperties"/>
+ <command name="vkGetInstanceProcAddr"/>
+ <command name="vkGetDeviceProcAddr"/>
+ </require>
+ <require comment="Device commands">
+ <type name="VkDevice"/>
+ <type name="VkDeviceCreateFlags"/>
+ <type name="VkDeviceCreateInfo"/>
+ <type name="VkDeviceQueueCreateFlagBits"/>
+ <type name="VkDeviceQueueCreateFlags"/>
+ <type name="VkDeviceQueueCreateInfo"/>
+ <command name="vkCreateDevice"/>
+ <command name="vkDestroyDevice"/>
+ </require>
+ <require comment="Extension discovery commands">
+ <type name="VkExtensionProperties"/>
+ <command name="vkEnumerateInstanceExtensionProperties"/>
+ <command name="vkEnumerateDeviceExtensionProperties"/>
+ </require>
+ <require comment="Layer discovery commands">
+ <type name="VkLayerProperties"/>
+ <command name="vkEnumerateInstanceLayerProperties"/>
+ <command name="vkEnumerateDeviceLayerProperties"/>
+ </require>
+ <require comment="Queue commands">
+ <type name="VkPipelineStageFlagBits"/>
+ <type name="VkPipelineStageFlags"/>
+ <type name="VkQueue"/>
+ <type name="VkSubmitInfo"/>
+ <command name="vkGetDeviceQueue"/>
+ <command name="vkQueueSubmit"/>
+ <command name="vkQueueWaitIdle"/>
+ <command name="vkDeviceWaitIdle"/>
+ </require>
+ <require comment="Memory commands">
+ <type name="VkMappedMemoryRange"/>
+ <type name="VkMemoryAllocateInfo"/>
+ <type name="VkMemoryMapFlags"/>
+ <command name="vkAllocateMemory"/>
+ <command name="vkFreeMemory"/>
+ <command name="vkMapMemory"/>
+ <command name="vkUnmapMemory"/>
+ <command name="vkFlushMappedMemoryRanges"/>
+ <command name="vkInvalidateMappedMemoryRanges"/>
+ <command name="vkGetDeviceMemoryCommitment"/>
+ </require>
+ <require comment="Memory management API commands">
+ <type name="VkDeviceMemory"/>
+ <type name="VkMemoryRequirements"/>
+ <command name="vkBindBufferMemory"/>
+ <command name="vkBindImageMemory"/>
+ <command name="vkGetBufferMemoryRequirements"/>
+ <command name="vkGetImageMemoryRequirements"/>
+ </require>
+ <require comment="Sparse resource memory management API commands">
+ <type name="VkBindSparseInfo"/>
+ <type name="VkImageAspectFlagBits"/>
+ <type name="VkImageAspectFlags"/>
+ <type name="VkImageSubresource"/>
+ <type name="VkSparseBufferMemoryBindInfo"/>
+ <type name="VkSparseImageFormatFlagBits"/>
+ <type name="VkSparseImageFormatFlags"/>
+ <type name="VkSparseImageFormatProperties"/>
+ <type name="VkSparseImageMemoryBind"/>
+ <type name="VkSparseImageMemoryBindInfo"/>
+ <type name="VkSparseImageMemoryRequirements"/>
+ <type name="VkSparseImageOpaqueMemoryBindInfo"/>
+ <type name="VkSparseMemoryBind"/>
+ <type name="VkSparseMemoryBindFlagBits"/>
+ <type name="VkSparseMemoryBindFlags"/>
+ <command name="vkGetImageSparseMemoryRequirements"/>
+ <command name="vkGetPhysicalDeviceSparseImageFormatProperties"/>
+ <command name="vkQueueBindSparse"/>
+ </require>
+ <require comment="Fence commands">
+ <type name="VkFence"/>
+ <type name="VkFenceCreateFlagBits"/>
+ <type name="VkFenceCreateFlags"/>
+ <type name="VkFenceCreateInfo"/>
+ <command name="vkCreateFence"/>
+ <command name="vkDestroyFence"/>
+ <command name="vkResetFences"/>
+ <command name="vkGetFenceStatus"/>
+ <command name="vkWaitForFences"/>
+ </require>
+ <require comment="Queue semaphore commands">
+ <type name="VkSemaphore"/>
+ <type name="VkSemaphoreCreateFlags"/>
+ <type name="VkSemaphoreCreateInfo"/>
+ <command name="vkCreateSemaphore"/>
+ <command name="vkDestroySemaphore"/>
+ </require>
+ <require comment="Event commands">
+ <type name="VkEvent"/>
+ <type name="VkEventCreateFlags"/>
+ <type name="VkEventCreateFlagBits"/>
+ <type name="VkEventCreateInfo"/>
+ <command name="vkCreateEvent"/>
+ <command name="vkDestroyEvent"/>
+ <command name="vkGetEventStatus"/>
+ <command name="vkSetEvent"/>
+ <command name="vkResetEvent"/>
+ </require>
+ <require comment="Query commands">
+ <type name="VkQueryPipelineStatisticFlagBits"/>
+ <type name="VkQueryPipelineStatisticFlags"/>
+ <type name="VkQueryPool"/>
+ <type name="VkQueryPoolCreateFlags"/>
+ <type name="VkQueryPoolCreateInfo"/>
+ <type name="VkQueryResultFlagBits"/>
+ <type name="VkQueryResultFlags"/>
+ <type name="VkQueryType"/>
+ <command name="vkCreateQueryPool"/>
+ <command name="vkDestroyQueryPool"/>
+ <command name="vkGetQueryPoolResults"/>
+ </require>
+ <require comment="Buffer commands">
+ <type name="VkBuffer"/>
+ <type name="VkBufferCreateFlagBits"/>
+ <type name="VkBufferCreateFlags"/>
+ <type name="VkBufferCreateInfo"/>
+ <type name="VkBufferUsageFlagBits"/>
+ <type name="VkBufferUsageFlags"/>
+ <type name="VkSharingMode"/>
+ <command name="vkCreateBuffer"/>
+ <command name="vkDestroyBuffer"/>
+ </require>
+ <require comment="Buffer view commands">
+ <type name="VkBufferView"/>
+ <type name="VkBufferViewCreateFlags" comment="Will need FlagBits type eventually"/>
+ <type name="VkBufferViewCreateInfo"/>
+ <command name="vkCreateBufferView"/>
+ <command name="vkDestroyBufferView"/>
+ </require>
+ <require comment="Image commands">
+ <type name="VkImage"/>
+ <type name="VkImageCreateInfo"/>
+ <type name="VkImageLayout"/>
+ <type name="VkSubresourceLayout"/>
+ <command name="vkCreateImage"/>
+ <command name="vkDestroyImage"/>
+ <command name="vkGetImageSubresourceLayout"/>
+ </require>
+ <require comment="Image view commands">
+ <type name="VkComponentMapping"/>
+ <type name="VkComponentSwizzle"/>
+ <type name="VkImageSubresourceRange"/>
+ <type name="VkImageView"/>
+ <type name="VkImageViewCreateFlagBits"/>
+ <type name="VkImageViewCreateFlags"/>
+ <type name="VkImageViewCreateInfo"/>
+ <type name="VkImageViewType"/>
+ <command name="vkCreateImageView"/>
+ <command name="vkDestroyImageView"/>
+ </require>
+ <require comment="Shader commands">
+ <type name="VkShaderModule"/>
+ <type name="VkShaderModuleCreateFlagBits"/>
+ <type name="VkShaderModuleCreateFlags"/>
+ <type name="VkShaderModuleCreateInfo"/>
+ <command name="vkCreateShaderModule"/>
+ <command name="vkDestroyShaderModule"/>
+ </require>
+ <require comment="Pipeline Cache commands">
+ <type name="VkPipelineCache"/>
+ <type name="VkPipelineCacheCreateFlagBits"/>
+ <type name="VkPipelineCacheCreateFlags"/>
+ <type name="VkPipelineCacheCreateInfo"/>
+ <command name="vkCreatePipelineCache"/>
+ <command name="vkDestroyPipelineCache"/>
+ <command name="vkGetPipelineCacheData"/>
+ <command name="vkMergePipelineCaches"/>
+ </require>
+ <require comment="Pipeline commands">
+ <type name="VkBlendFactor"/>
+ <type name="VkBlendOp"/>
+ <type name="VkColorComponentFlagBits"/>
+ <type name="VkColorComponentFlags"/>
+ <type name="VkCompareOp"/>
+ <type name="VkComputePipelineCreateInfo"/>
+ <type name="VkCullModeFlagBits"/>
+ <type name="VkCullModeFlags"/>
+ <type name="VkDynamicState"/>
+ <type name="VkFrontFace"/>
+ <type name="VkGraphicsPipelineCreateInfo"/>
+ <type name="VkLogicOp"/>
+ <type name="VkPipeline"/>
+ <type name="VkPipelineColorBlendAttachmentState"/>
+ <type name="VkPipelineColorBlendStateCreateFlags" comment="Will need FlagBits type eventually"/>
+ <type name="VkPipelineColorBlendStateCreateInfo"/>
+ <type name="VkPipelineCreateFlagBits"/>
+ <type name="VkPipelineCreateFlags"/>
+ <type name="VkPipelineDepthStencilStateCreateFlags" comment="Will need FlagBits type eventually"/>
+ <type name="VkPipelineDepthStencilStateCreateInfo"/>
+ <type name="VkPipelineDynamicStateCreateFlags" comment="Will need FlagBits type eventually"/>
+ <type name="VkPipelineDynamicStateCreateInfo"/>
+ <type name="VkPipelineInputAssemblyStateCreateFlags" comment="Will need FlagBits type eventually"/>
+ <type name="VkPipelineInputAssemblyStateCreateInfo"/>
+ <type name="VkPipelineLayoutCreateFlags" comment="Will need FlagBits type eventually"/>
+ <type name="VkPipelineMultisampleStateCreateFlags" comment="Will need FlagBits type eventually"/>
+ <type name="VkPipelineMultisampleStateCreateInfo"/>
+ <type name="VkPipelineRasterizationStateCreateFlags" comment="Will need FlagBits type eventually"/>
+ <type name="VkPipelineRasterizationStateCreateInfo"/>
+ <type name="VkPipelineShaderStageCreateFlagBits"/>
+ <type name="VkPipelineShaderStageCreateFlags"/>
+ <type name="VkPipelineShaderStageCreateInfo"/>
+ <type name="VkPipelineTessellationStateCreateFlags" comment="Will need FlagBits type eventually"/>
+ <type name="VkPipelineTessellationStateCreateInfo"/>
+ <type name="VkPipelineVertexInputStateCreateFlags" comment="Will need FlagBits type eventually"/>
+ <type name="VkPipelineVertexInputStateCreateInfo"/>
+ <type name="VkPipelineViewportStateCreateFlags" comment="Will need FlagBits type eventually"/>
+ <type name="VkPipelineViewportStateCreateInfo"/>
+ <type name="VkPolygonMode"/>
+ <type name="VkPrimitiveTopology"/>
+ <type name="VkSampleMask"/>
+ <type name="VkShaderStageFlagBits"/>
+ <type name="VkShaderStageFlags"/>
+ <type name="VkSpecializationInfo"/>
+ <type name="VkSpecializationMapEntry"/>
+ <type name="VkStencilOp"/>
+ <type name="VkStencilOpState"/>
+ <type name="VkVertexInputAttributeDescription"/>
+ <type name="VkVertexInputBindingDescription"/>
+ <type name="VkVertexInputRate"/>
+ <type name="VkViewport"/>
+ <command name="vkCreateGraphicsPipelines"/>
+ <command name="vkCreateComputePipelines"/>
+ <command name="vkDestroyPipeline"/>
+ </require>
+ <require comment="Pipeline layout commands">
+ <type name="VkPipelineLayout"/>
+ <type name="VkPipelineLayoutCreateInfo"/>
+ <type name="VkPushConstantRange"/>
+ <command name="vkCreatePipelineLayout"/>
+ <command name="vkDestroyPipelineLayout"/>
+ </require>
+ <require comment="Sampler commands">
+ <type name="VkBorderColor"/>
+ <type name="VkFilter"/>
+ <type name="VkSampler"/>
+ <type name="VkSamplerAddressMode"/>
+ <type name="VkSamplerCreateFlagBits"/>
+ <type name="VkSamplerCreateFlags"/>
+ <type name="VkSamplerCreateInfo"/>
+ <type name="VkSamplerMipmapMode"/>
+ <command name="vkCreateSampler"/>
+ <command name="vkDestroySampler"/>
+ </require>
+ <require comment="Descriptor set commands">
+ <type name="VkCopyDescriptorSet"/>
+ <type name="VkDescriptorBufferInfo"/>
+ <type name="VkDescriptorImageInfo"/>
+ <type name="VkDescriptorPool"/>
+ <type name="VkDescriptorPoolCreateFlagBits"/>
+ <type name="VkDescriptorPoolCreateFlags"/>
+ <type name="VkDescriptorPoolCreateInfo"/>
+ <type name="VkDescriptorPoolResetFlags"/>
+ <type name="VkDescriptorPoolSize"/>
+ <type name="VkDescriptorSet"/>
+ <type name="VkDescriptorSetAllocateInfo"/>
+ <type name="VkDescriptorSetLayout"/>
+ <type name="VkDescriptorSetLayoutBinding"/>
+ <type name="VkDescriptorSetLayoutCreateFlagBits"/>
+ <type name="VkDescriptorSetLayoutCreateFlags"/>
+ <type name="VkDescriptorSetLayoutCreateInfo"/>
+ <type name="VkDescriptorType"/>
+ <type name="VkWriteDescriptorSet"/>
+ <command name="vkCreateDescriptorSetLayout"/>
+ <command name="vkDestroyDescriptorSetLayout"/>
+ <command name="vkCreateDescriptorPool"/>
+ <command name="vkDestroyDescriptorPool"/>
+ <command name="vkResetDescriptorPool"/>
+ <command name="vkAllocateDescriptorSets"/>
+ <command name="vkFreeDescriptorSets"/>
+ <command name="vkUpdateDescriptorSets"/>
+ </require>
+ <require comment="Pass commands">
+ <type name="VkAccessFlagBits"/>
+ <type name="VkAccessFlags"/>
+ <type name="VkAttachmentDescription"/>
+ <type name="VkAttachmentDescriptionFlagBits"/>
+ <type name="VkAttachmentDescriptionFlags"/>
+ <type name="VkAttachmentLoadOp"/>
+ <type name="VkAttachmentReference"/>
+ <type name="VkAttachmentStoreOp"/>
+ <type name="VkDependencyFlagBits"/>
+ <type name="VkDependencyFlags"/>
+ <type name="VkFramebuffer"/>
+ <type name="VkFramebufferCreateFlagBits"/>
+ <type name="VkFramebufferCreateFlags"/>
+ <type name="VkFramebufferCreateInfo"/>
+ <type name="VkPipelineBindPoint"/>
+ <type name="VkRenderPass"/>
+ <type name="VkRenderPassCreateFlagBits"/>
+ <type name="VkRenderPassCreateFlags"/>
+ <type name="VkRenderPassCreateInfo"/>
+ <type name="VkSubpassDependency"/>
+ <type name="VkSubpassDescription"/>
+ <type name="VkSubpassDescriptionFlagBits"/>
+ <type name="VkSubpassDescriptionFlags"/>
+ <command name="vkCreateFramebuffer"/>
+ <command name="vkDestroyFramebuffer"/>
+ <command name="vkCreateRenderPass"/>
+ <command name="vkDestroyRenderPass"/>
+ <command name="vkGetRenderAreaGranularity"/>
+ </require>
+ <require comment="Command pool commands">
+ <type name="VkCommandPool"/>
+ <type name="VkCommandPoolCreateFlagBits"/>
+ <type name="VkCommandPoolCreateFlags"/>
+ <type name="VkCommandPoolCreateInfo"/>
+ <type name="VkCommandPoolResetFlagBits"/>
+ <type name="VkCommandPoolResetFlags"/>
+ <command name="vkCreateCommandPool"/>
+ <command name="vkDestroyCommandPool"/>
+ <command name="vkResetCommandPool"/>
+ </require>
+ <require comment="Command buffer commands">
+ <type name="VkCommandBuffer"/>
+ <type name="VkCommandBufferAllocateInfo"/>
+ <type name="VkCommandBufferBeginInfo"/>
+ <type name="VkCommandBufferInheritanceInfo"/>
+ <type name="VkCommandBufferLevel"/>
+ <type name="VkCommandBufferResetFlagBits"/>
+ <type name="VkCommandBufferResetFlags"/>
+ <type name="VkCommandBufferUsageFlagBits"/>
+ <type name="VkCommandBufferUsageFlags"/>
+ <type name="VkQueryControlFlagBits"/>
+ <type name="VkQueryControlFlags"/>
+ <command name="vkAllocateCommandBuffers"/>
+ <command name="vkFreeCommandBuffers"/>
+ <command name="vkBeginCommandBuffer"/>
+ <command name="vkEndCommandBuffer"/>
+ <command name="vkResetCommandBuffer"/>
+ </require>
+ <require comment="Command buffer building commands">
+ <type name="VkBufferCopy"/>
+ <type name="VkBufferImageCopy"/>
+ <type name="VkClearAttachment"/>
+ <type name="VkClearColorValue"/>
+ <type name="VkClearDepthStencilValue"/>
+ <type name="VkClearRect"/>
+ <type name="VkClearValue"/>
+ <type name="VkImageBlit"/>
+ <type name="VkImageCopy"/>
+ <type name="VkImageResolve"/>
+ <type name="VkImageSubresourceLayers"/>
+ <type name="VkIndexType"/>
+ <type name="VkRenderPassBeginInfo"/>
+ <type name="VkStencilFaceFlagBits"/>
+ <type name="VkStencilFaceFlags"/>
+ <type name="VkSubpassContents"/>
+ <command name="vkCmdBindPipeline"/>
+ <command name="vkCmdSetViewport"/>
+ <command name="vkCmdSetScissor"/>
+ <command name="vkCmdSetLineWidth"/>
+ <command name="vkCmdSetDepthBias"/>
+ <command name="vkCmdSetBlendConstants"/>
+ <command name="vkCmdSetDepthBounds"/>
+ <command name="vkCmdSetStencilCompareMask"/>
+ <command name="vkCmdSetStencilWriteMask"/>
+ <command name="vkCmdSetStencilReference"/>
+ <command name="vkCmdBindDescriptorSets"/>
+ <command name="vkCmdBindIndexBuffer"/>
+ <command name="vkCmdBindVertexBuffers"/>
+ <command name="vkCmdDraw"/>
+ <command name="vkCmdDrawIndexed"/>
+ <command name="vkCmdDrawIndirect"/>
+ <command name="vkCmdDrawIndexedIndirect"/>
+ <command name="vkCmdDispatch"/>
+ <command name="vkCmdDispatchIndirect"/>
+ <command name="vkCmdCopyBuffer"/>
+ <command name="vkCmdCopyImage"/>
+ <command name="vkCmdBlitImage"/>
+ <command name="vkCmdCopyBufferToImage"/>
+ <command name="vkCmdCopyImageToBuffer"/>
+ <command name="vkCmdUpdateBuffer"/>
+ <command name="vkCmdFillBuffer"/>
+ <command name="vkCmdClearColorImage"/>
+ <command name="vkCmdClearDepthStencilImage"/>
+ <command name="vkCmdClearAttachments"/>
+ <command name="vkCmdResolveImage"/>
+ <command name="vkCmdSetEvent"/>
+ <command name="vkCmdResetEvent"/>
+ <command name="vkCmdWaitEvents"/>
+ <command name="vkCmdPipelineBarrier"/>
+ <command name="vkCmdBeginQuery"/>
+ <command name="vkCmdEndQuery"/>
+ <command name="vkCmdResetQueryPool"/>
+ <command name="vkCmdWriteTimestamp"/>
+ <command name="vkCmdCopyQueryPoolResults"/>
+ <command name="vkCmdPushConstants"/>
+ <command name="vkCmdBeginRenderPass"/>
+ <command name="vkCmdNextSubpass"/>
+ <command name="vkCmdEndRenderPass"/>
+ <command name="vkCmdExecuteCommands"/>
+ </require>
+ </feature>
+ <feature api="vulkan" name="VK_VERSION_1_1" number="1.1" comment="Vulkan 1.1 core API interface definitions.">
+ <require>
+ <type name="VK_API_VERSION_1_1"/>
+ </require>
+ <require comment="Device Initialization">
+ <command name="vkEnumerateInstanceVersion"/>
+ </require>
+ <require comment="Promoted from VK_KHR_relaxed_block_layout, which has no API"/>
+ <require comment="Promoted from VK_KHR_storage_buffer_storage_class, which has no API"/>
+ <require comment="Originally based on VK_KHR_subgroup (extension 94), but the actual enum block used was, incorrectly, that of extension 95">
+ <enum extends="VkStructureType" extnumber="95" offset="0" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_PROPERTIES"/>
+ <type name="VkPhysicalDeviceSubgroupProperties"/>
+ <type name="VkSubgroupFeatureFlags"/>
+ <type name="VkSubgroupFeatureFlagBits"/>
+ </require>
+ <require comment="Promoted from VK_KHR_bind_memory2">
+ <command name="vkBindBufferMemory2"/>
+ <command name="vkBindImageMemory2"/>
+ <enum extends="VkStructureType" extnumber="158" offset="0" name="VK_STRUCTURE_TYPE_BIND_BUFFER_MEMORY_INFO"/>
+ <enum extends="VkStructureType" extnumber="158" offset="1" name="VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_INFO"/>
+ <enum bitpos="10" extends="VkImageCreateFlagBits" name="VK_IMAGE_CREATE_ALIAS_BIT"/>
+ <type name="VkBindBufferMemoryInfo"/>
+ <type name="VkBindImageMemoryInfo"/>
+ </require>
+ <require comment="Promoted from VK_KHR_16bit_storage">
+ <enum extends="VkStructureType" extnumber="84" offset="0" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_16BIT_STORAGE_FEATURES"/>
+ <type name="VkPhysicalDevice16BitStorageFeatures"/>
+ </require>
+ <require comment="Promoted from VK_KHR_dedicated_allocation">
+ <enum extends="VkStructureType" extnumber="128" offset="0" name="VK_STRUCTURE_TYPE_MEMORY_DEDICATED_REQUIREMENTS"/>
+ <enum extends="VkStructureType" extnumber="128" offset="1" name="VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO"/>
+ <type name="VkMemoryDedicatedRequirements"/>
+ <type name="VkMemoryDedicatedAllocateInfo"/>
+ </require>
+ <require comment="Promoted from VK_KHR_device_group">
+ <enum extends="VkStructureType" extnumber="61" offset="0" name="VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_FLAGS_INFO"/>
+ <comment>offset 1 reserved for the old VK_STRUCTURE_TYPE_BIND_BUFFER_MEMORY_INFO_KHX enum</comment>
+ <comment>offset 2 reserved for the old VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_INFO_KHX enum</comment>
+ <enum extends="VkStructureType" extnumber="61" offset="3" name="VK_STRUCTURE_TYPE_DEVICE_GROUP_RENDER_PASS_BEGIN_INFO"/>
+ <enum extends="VkStructureType" extnumber="61" offset="4" name="VK_STRUCTURE_TYPE_DEVICE_GROUP_COMMAND_BUFFER_BEGIN_INFO"/>
+ <enum extends="VkStructureType" extnumber="61" offset="5" name="VK_STRUCTURE_TYPE_DEVICE_GROUP_SUBMIT_INFO"/>
+ <enum extends="VkStructureType" extnumber="61" offset="6" name="VK_STRUCTURE_TYPE_DEVICE_GROUP_BIND_SPARSE_INFO"/>
+ <type name="VkPeerMemoryFeatureFlags"/>
+ <type name="VkPeerMemoryFeatureFlagBits"/>
+ <type name="VkMemoryAllocateFlags"/>
+ <type name="VkMemoryAllocateFlagBits"/>
+ <type name="VkMemoryAllocateFlagsInfo"/>
+ <type name="VkDeviceGroupRenderPassBeginInfo"/>
+ <type name="VkDeviceGroupCommandBufferBeginInfo"/>
+ <type name="VkDeviceGroupSubmitInfo"/>
+ <type name="VkDeviceGroupBindSparseInfo"/>
+ <command name="vkGetDeviceGroupPeerMemoryFeatures"/>
+ <command name="vkCmdSetDeviceMask"/>
+ <command name="vkCmdDispatchBase"/>
+ <enum bitpos="3" extends="VkPipelineCreateFlagBits" name="VK_PIPELINE_CREATE_VIEW_INDEX_FROM_DEVICE_INDEX_BIT"/>
+ <enum bitpos="4" extends="VkPipelineCreateFlagBits" name="VK_PIPELINE_CREATE_DISPATCH_BASE_BIT"/>
+ <enum extends="VkPipelineCreateFlagBits" name="VK_PIPELINE_CREATE_DISPATCH_BASE" alias="VK_PIPELINE_CREATE_DISPATCH_BASE_BIT"/>
+ <enum bitpos="2" extends="VkDependencyFlagBits" name="VK_DEPENDENCY_DEVICE_GROUP_BIT" comment="Dependency is across devices"/>
+ </require>
+ <require comment="Promoted from VK_KHR_device_group + VK_KHR_bind_memory2">
+ <enum extends="VkStructureType" extnumber="61" offset="13" name="VK_STRUCTURE_TYPE_BIND_BUFFER_MEMORY_DEVICE_GROUP_INFO"/>
+ <enum extends="VkStructureType" extnumber="61" offset="14" name="VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_DEVICE_GROUP_INFO"/>
+ <type name="VkBindBufferMemoryDeviceGroupInfo"/>
+ <type name="VkBindImageMemoryDeviceGroupInfo"/>
+ <enum bitpos="6" extends="VkImageCreateFlagBits" name="VK_IMAGE_CREATE_SPLIT_INSTANCE_BIND_REGIONS_BIT" comment="Allows using VkBindImageMemoryDeviceGroupInfo::pSplitInstanceBindRegions when binding memory to the image"/>
+ </require>
+ <require comment="Promoted from VK_KHR_device_group_creation">
+ <enum extends="VkStructureType" extnumber="71" offset="0" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_GROUP_PROPERTIES"/>
+ <enum extends="VkStructureType" extnumber="71" offset="1" name="VK_STRUCTURE_TYPE_DEVICE_GROUP_DEVICE_CREATE_INFO"/>
+ <enum name="VK_MAX_DEVICE_GROUP_SIZE"/>
+ <type name="VkPhysicalDeviceGroupProperties"/>
+ <type name="VkDeviceGroupDeviceCreateInfo"/>
+ <command name="vkEnumeratePhysicalDeviceGroups"/>
+ <enum bitpos="1" extends="VkMemoryHeapFlagBits" name="VK_MEMORY_HEAP_MULTI_INSTANCE_BIT" comment="If set, heap allocations allocate multiple instances by default"/>
+ </require>
+ <require comment="Promoted from VK_KHR_get_memory_requirements2">
+ <enum extends="VkStructureType" extnumber="147" offset="0" name="VK_STRUCTURE_TYPE_BUFFER_MEMORY_REQUIREMENTS_INFO_2"/>
+ <enum extends="VkStructureType" extnumber="147" offset="1" name="VK_STRUCTURE_TYPE_IMAGE_MEMORY_REQUIREMENTS_INFO_2"/>
+ <enum extends="VkStructureType" extnumber="147" offset="2" name="VK_STRUCTURE_TYPE_IMAGE_SPARSE_MEMORY_REQUIREMENTS_INFO_2"/>
+ <enum extends="VkStructureType" extnumber="147" offset="3" name="VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2"/>
+ <enum extends="VkStructureType" extnumber="147" offset="4" name="VK_STRUCTURE_TYPE_SPARSE_IMAGE_MEMORY_REQUIREMENTS_2"/>
+ <type name="VkBufferMemoryRequirementsInfo2"/>
+ <type name="VkImageMemoryRequirementsInfo2"/>
+ <type name="VkImageSparseMemoryRequirementsInfo2"/>
+ <type name="VkMemoryRequirements2"/>
+ <type name="VkSparseImageMemoryRequirements2"/>
+ <command name="vkGetImageMemoryRequirements2"/>
+ <command name="vkGetBufferMemoryRequirements2"/>
+ <command name="vkGetImageSparseMemoryRequirements2"/>
+ </require>
+ <require comment="Promoted from VK_KHR_get_physical_device_properties2">
+ <enum extends="VkStructureType" extnumber="60" offset="0" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2"/>
+ <enum extends="VkStructureType" extnumber="60" offset="1" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2"/>
+ <enum extends="VkStructureType" extnumber="60" offset="2" name="VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2"/>
+ <enum extends="VkStructureType" extnumber="60" offset="3" name="VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2"/>
+ <enum extends="VkStructureType" extnumber="60" offset="4" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2"/>
+ <enum extends="VkStructureType" extnumber="60" offset="5" name="VK_STRUCTURE_TYPE_QUEUE_FAMILY_PROPERTIES_2"/>
+ <enum extends="VkStructureType" extnumber="60" offset="6" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_PROPERTIES_2"/>
+ <enum extends="VkStructureType" extnumber="60" offset="7" name="VK_STRUCTURE_TYPE_SPARSE_IMAGE_FORMAT_PROPERTIES_2"/>
+ <enum extends="VkStructureType" extnumber="60" offset="8" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SPARSE_IMAGE_FORMAT_INFO_2"/>
+ <type name="VkPhysicalDeviceFeatures2"/>
+ <type name="VkPhysicalDeviceProperties2"/>
+ <type name="VkFormatProperties2"/>
+ <type name="VkImageFormatProperties2"/>
+ <type name="VkPhysicalDeviceImageFormatInfo2"/>
+ <type name="VkQueueFamilyProperties2"/>
+ <type name="VkPhysicalDeviceMemoryProperties2"/>
+ <type name="VkSparseImageFormatProperties2"/>
+ <type name="VkPhysicalDeviceSparseImageFormatInfo2"/>
+ <command name="vkGetPhysicalDeviceFeatures2"/>
+ <command name="vkGetPhysicalDeviceProperties2"/>
+ <command name="vkGetPhysicalDeviceFormatProperties2"/>
+ <command name="vkGetPhysicalDeviceImageFormatProperties2"/>
+ <command name="vkGetPhysicalDeviceQueueFamilyProperties2"/>
+ <command name="vkGetPhysicalDeviceMemoryProperties2"/>
+ <command name="vkGetPhysicalDeviceSparseImageFormatProperties2"/>
+ </require>
+ <require comment="Promoted from VK_KHR_maintenance1">
+ <enum extends="VkResult" extnumber="70" offset="0" dir="-" name="VK_ERROR_OUT_OF_POOL_MEMORY"/>
+ <enum bitpos="14" extends="VkFormatFeatureFlagBits" name="VK_FORMAT_FEATURE_TRANSFER_SRC_BIT" comment="Format can be used as the source image of image transfer commands"/>
+ <enum bitpos="15" extends="VkFormatFeatureFlagBits" name="VK_FORMAT_FEATURE_TRANSFER_DST_BIT" comment="Format can be used as the destination image of image transfer commands"/>
+ <enum bitpos="5" extends="VkImageCreateFlagBits" name="VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT" comment="The 3D image can be viewed as a 2D or 2D array image"/>
+ <command name="vkTrimCommandPool"/>
+ <comment>Additional dependent types / tokens extending enumerants, not explicitly mentioned</comment>
+ <type name="VkCommandPoolTrimFlags"/>
+ </require>
+ <require comment="Promoted from VK_KHR_maintenance2">
+ <enum bitpos="7" extends="VkImageCreateFlagBits" name="VK_IMAGE_CREATE_BLOCK_TEXEL_VIEW_COMPATIBLE_BIT"/>
+ <enum bitpos="8" extends="VkImageCreateFlagBits" name="VK_IMAGE_CREATE_EXTENDED_USAGE_BIT"/>
+ <enum extends="VkStructureType" extnumber="118" offset="0" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_POINT_CLIPPING_PROPERTIES"/>
+ <enum extends="VkStructureType" extnumber="118" offset="1" name="VK_STRUCTURE_TYPE_RENDER_PASS_INPUT_ATTACHMENT_ASPECT_CREATE_INFO"/>
+ <enum extends="VkStructureType" extnumber="118" offset="2" name="VK_STRUCTURE_TYPE_IMAGE_VIEW_USAGE_CREATE_INFO"/>
+ <enum extends="VkStructureType" extnumber="118" offset="3" name="VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_DOMAIN_ORIGIN_STATE_CREATE_INFO"/>
+ <enum extends="VkImageLayout" extnumber="118" offset="0" name="VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL"/>
+ <enum extends="VkImageLayout" extnumber="118" offset="1" name="VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL"/>
+ <type name="VkPhysicalDevicePointClippingProperties"/>
+ <type name="VkPointClippingBehavior"/>
+ <type name="VkRenderPassInputAttachmentAspectCreateInfo"/>
+ <type name="VkInputAttachmentAspectReference"/>
+ <type name="VkImageViewUsageCreateInfo"/>
+ <type name="VkTessellationDomainOrigin"/>
+ <type name="VkPipelineTessellationDomainOriginStateCreateInfo"/>
+ </require>
+ <require comment="Promoted from VK_KHR_multiview">
+ <enum extends="VkStructureType" extnumber="54" offset="0" name="VK_STRUCTURE_TYPE_RENDER_PASS_MULTIVIEW_CREATE_INFO"/>
+ <enum extends="VkStructureType" extnumber="54" offset="1" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_FEATURES"/>
+ <enum extends="VkStructureType" extnumber="54" offset="2" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_PROPERTIES"/>
+ <enum bitpos="1" extends="VkDependencyFlagBits" name="VK_DEPENDENCY_VIEW_LOCAL_BIT"/>
+ <type name="VkRenderPassMultiviewCreateInfo"/>
+ <type name="VkPhysicalDeviceMultiviewFeatures"/>
+ <type name="VkPhysicalDeviceMultiviewProperties"/>
+ </require>
+ <require comment="Promoted from VK_KHR_variable_pointers">
+ <enum extends="VkStructureType" extnumber="121" offset="0" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VARIABLE_POINTERS_FEATURES"/>
+ <enum extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VARIABLE_POINTER_FEATURES" alias="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VARIABLE_POINTERS_FEATURES"/>
+ <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.">
+ <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"/>
+ <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"/>
+ <enum bitpos="2" extends="VkCommandPoolCreateFlagBits" name="VK_COMMAND_POOL_CREATE_PROTECTED_BIT" comment="Command buffers allocated from pool are protected command buffers"/>
+ <type name="VkPhysicalDeviceProtectedMemoryFeatures"/>
+ <type name="VkPhysicalDeviceProtectedMemoryProperties"/>
+ <type name="VkDeviceQueueInfo2"/>
+ <type name="VkProtectedSubmitInfo"/>
+ <command name="vkGetDeviceQueue2"/>
+ </require>
+ <require comment="Promoted from VK_KHR_sampler_ycbcr_conversion">
+ <enum extends="VkStructureType" extnumber="157" offset="0" name="VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_CREATE_INFO"/>
+ <enum extends="VkStructureType" extnumber="157" offset="1" name="VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_INFO"/>
+ <enum extends="VkStructureType" extnumber="157" offset="2" name="VK_STRUCTURE_TYPE_BIND_IMAGE_PLANE_MEMORY_INFO"/>
+ <enum extends="VkStructureType" extnumber="157" offset="3" name="VK_STRUCTURE_TYPE_IMAGE_PLANE_MEMORY_REQUIREMENTS_INFO"/>
+ <enum extends="VkStructureType" extnumber="157" offset="4" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLER_YCBCR_CONVERSION_FEATURES"/>
+ <enum extends="VkStructureType" extnumber="157" offset="5" name="VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_IMAGE_FORMAT_PROPERTIES"/>
+ <enum extends="VkObjectType" extnumber="157" offset="0" name="VK_OBJECT_TYPE_SAMPLER_YCBCR_CONVERSION"/>
+ <enum extends="VkFormat" extnumber="157" offset="0" name="VK_FORMAT_G8B8G8R8_422_UNORM"/>
+ <enum extends="VkFormat" extnumber="157" offset="1" name="VK_FORMAT_B8G8R8G8_422_UNORM"/>
+ <enum extends="VkFormat" extnumber="157" offset="2" name="VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM"/>
+ <enum extends="VkFormat" extnumber="157" offset="3" name="VK_FORMAT_G8_B8R8_2PLANE_420_UNORM"/>
+ <enum extends="VkFormat" extnumber="157" offset="4" name="VK_FORMAT_G8_B8_R8_3PLANE_422_UNORM"/>
+ <enum extends="VkFormat" extnumber="157" offset="5" name="VK_FORMAT_G8_B8R8_2PLANE_422_UNORM"/>
+ <enum extends="VkFormat" extnumber="157" offset="6" name="VK_FORMAT_G8_B8_R8_3PLANE_444_UNORM"/>
+ <enum extends="VkFormat" extnumber="157" offset="7" name="VK_FORMAT_R10X6_UNORM_PACK16"/>
+ <enum extends="VkFormat" extnumber="157" offset="8" name="VK_FORMAT_R10X6G10X6_UNORM_2PACK16"/>
+ <enum extends="VkFormat" extnumber="157" offset="9" name="VK_FORMAT_R10X6G10X6B10X6A10X6_UNORM_4PACK16"/>
+ <enum extends="VkFormat" extnumber="157" offset="10" name="VK_FORMAT_G10X6B10X6G10X6R10X6_422_UNORM_4PACK16"/>
+ <enum extends="VkFormat" extnumber="157" offset="11" name="VK_FORMAT_B10X6G10X6R10X6G10X6_422_UNORM_4PACK16"/>
+ <enum extends="VkFormat" extnumber="157" offset="12" name="VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_420_UNORM_3PACK16"/>
+ <enum extends="VkFormat" extnumber="157" offset="13" name="VK_FORMAT_G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16"/>
+ <enum extends="VkFormat" extnumber="157" offset="14" name="VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_422_UNORM_3PACK16"/>
+ <enum extends="VkFormat" extnumber="157" offset="15" name="VK_FORMAT_G10X6_B10X6R10X6_2PLANE_422_UNORM_3PACK16"/>
+ <enum extends="VkFormat" extnumber="157" offset="16" name="VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_444_UNORM_3PACK16"/>
+ <enum extends="VkFormat" extnumber="157" offset="17" name="VK_FORMAT_R12X4_UNORM_PACK16"/>
+ <enum extends="VkFormat" extnumber="157" offset="18" name="VK_FORMAT_R12X4G12X4_UNORM_2PACK16"/>
+ <enum extends="VkFormat" extnumber="157" offset="19" name="VK_FORMAT_R12X4G12X4B12X4A12X4_UNORM_4PACK16"/>
+ <enum extends="VkFormat" extnumber="157" offset="20" name="VK_FORMAT_G12X4B12X4G12X4R12X4_422_UNORM_4PACK16"/>
+ <enum extends="VkFormat" extnumber="157" offset="21" name="VK_FORMAT_B12X4G12X4R12X4G12X4_422_UNORM_4PACK16"/>
+ <enum extends="VkFormat" extnumber="157" offset="22" name="VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_420_UNORM_3PACK16"/>
+ <enum extends="VkFormat" extnumber="157" offset="23" name="VK_FORMAT_G12X4_B12X4R12X4_2PLANE_420_UNORM_3PACK16"/>
+ <enum extends="VkFormat" extnumber="157" offset="24" name="VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_422_UNORM_3PACK16"/>
+ <enum extends="VkFormat" extnumber="157" offset="25" name="VK_FORMAT_G12X4_B12X4R12X4_2PLANE_422_UNORM_3PACK16"/>
+ <enum extends="VkFormat" extnumber="157" offset="26" name="VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_444_UNORM_3PACK16"/>
+ <enum extends="VkFormat" extnumber="157" offset="27" name="VK_FORMAT_G16B16G16R16_422_UNORM"/>
+ <enum extends="VkFormat" extnumber="157" offset="28" name="VK_FORMAT_B16G16R16G16_422_UNORM"/>
+ <enum extends="VkFormat" extnumber="157" offset="29" name="VK_FORMAT_G16_B16_R16_3PLANE_420_UNORM"/>
+ <enum extends="VkFormat" extnumber="157" offset="30" name="VK_FORMAT_G16_B16R16_2PLANE_420_UNORM"/>
+ <enum extends="VkFormat" extnumber="157" offset="31" name="VK_FORMAT_G16_B16_R16_3PLANE_422_UNORM"/>
+ <enum extends="VkFormat" extnumber="157" offset="32" name="VK_FORMAT_G16_B16R16_2PLANE_422_UNORM"/>
+ <enum extends="VkFormat" extnumber="157" offset="33" name="VK_FORMAT_G16_B16_R16_3PLANE_444_UNORM"/>
+ <enum bitpos="4" extends="VkImageAspectFlagBits" name="VK_IMAGE_ASPECT_PLANE_0_BIT"/>
+ <enum bitpos="5" extends="VkImageAspectFlagBits" name="VK_IMAGE_ASPECT_PLANE_1_BIT"/>
+ <enum bitpos="6" extends="VkImageAspectFlagBits" name="VK_IMAGE_ASPECT_PLANE_2_BIT"/>
+ <enum bitpos="9" extends="VkImageCreateFlagBits" name="VK_IMAGE_CREATE_DISJOINT_BIT"/>
+ <enum bitpos="17" extends="VkFormatFeatureFlagBits" name="VK_FORMAT_FEATURE_MIDPOINT_CHROMA_SAMPLES_BIT" comment="Format can have midpoint rather than cosited chroma samples"/>
+ <enum bitpos="18" extends="VkFormatFeatureFlagBits" name="VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_LINEAR_FILTER_BIT" comment="Format can be used with linear filtering whilst color conversion is enabled"/>
+ <enum bitpos="19" extends="VkFormatFeatureFlagBits" name="VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_SEPARATE_RECONSTRUCTION_FILTER_BIT" comment="Format can have different chroma, min and mag filters"/>
+ <enum bitpos="20" extends="VkFormatFeatureFlagBits" name="VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_CHROMA_RECONSTRUCTION_EXPLICIT_BIT"/>
+ <enum bitpos="21" extends="VkFormatFeatureFlagBits" name="VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_CHROMA_RECONSTRUCTION_EXPLICIT_FORCEABLE_BIT"/>
+ <enum bitpos="22" extends="VkFormatFeatureFlagBits" name="VK_FORMAT_FEATURE_DISJOINT_BIT" comment="Format supports disjoint planes"/>
+ <enum bitpos="23" extends="VkFormatFeatureFlagBits" name="VK_FORMAT_FEATURE_COSITED_CHROMA_SAMPLES_BIT" comment="Format can have cosited rather than midpoint chroma samples"/>
+ <type name="VkSamplerYcbcrConversionCreateInfo"/>
+ <type name="VkSamplerYcbcrConversionInfo"/>
+ <type name="VkBindImagePlaneMemoryInfo"/>
+ <type name="VkImagePlaneMemoryRequirementsInfo"/>
+ <type name="VkPhysicalDeviceSamplerYcbcrConversionFeatures"/>
+ <type name="VkSamplerYcbcrConversionImageFormatProperties"/>
+ <command name="vkCreateSamplerYcbcrConversion"/>
+ <command name="vkDestroySamplerYcbcrConversion"/>
+ <comment>Additional dependent types / tokens extending enumerants, not explicitly mentioned</comment>
+ <type name="VkSamplerYcbcrConversion"/>
+ <type name="VkSamplerYcbcrModelConversion"/>
+ <type name="VkSamplerYcbcrRange"/>
+ <type name="VkChromaLocation"/>
+ </require>
+ <require comment="Promoted from VK_KHR_descriptor_update_template">
+ <enum extends="VkStructureType" extnumber="86" offset="0" name="VK_STRUCTURE_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_CREATE_INFO"/>
+ <enum extends="VkObjectType" extnumber="86" offset="0" name="VK_OBJECT_TYPE_DESCRIPTOR_UPDATE_TEMPLATE"/>
+ <command name="vkCreateDescriptorUpdateTemplate"/>
+ <command name="vkDestroyDescriptorUpdateTemplate"/>
+ <command name="vkUpdateDescriptorSetWithTemplate"/>
+ <type name="VkDescriptorUpdateTemplate"/>
+ <type name="VkDescriptorUpdateTemplateCreateFlags"/>
+ <type name="VkDescriptorUpdateTemplateType"/>
+ <type name="VkDescriptorUpdateTemplateEntry"/>
+ <type name="VkDescriptorUpdateTemplateCreateInfo"/>
+ </require>
+ <require comment="Promoted from VK_KHR_external_memory_capabilities">
+ <enum extends="VkStructureType" extnumber="72" offset="0" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_IMAGE_FORMAT_INFO"/>
+ <enum extends="VkStructureType" extnumber="72" offset="1" name="VK_STRUCTURE_TYPE_EXTERNAL_IMAGE_FORMAT_PROPERTIES"/>
+ <enum extends="VkStructureType" extnumber="72" offset="2" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_BUFFER_INFO"/>
+ <enum extends="VkStructureType" extnumber="72" offset="3" name="VK_STRUCTURE_TYPE_EXTERNAL_BUFFER_PROPERTIES"/>
+ <enum extends="VkStructureType" extnumber="72" offset="4" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ID_PROPERTIES"/>
+ <enum name="VK_LUID_SIZE"/>
+ <type name="VkExternalMemoryHandleTypeFlags"/>
+ <type name="VkExternalMemoryHandleTypeFlagBits"/>
+ <type name="VkExternalMemoryFeatureFlags"/>
+ <type name="VkExternalMemoryFeatureFlagBits"/>
+ <type name="VkExternalMemoryProperties"/>
+ <type name="VkPhysicalDeviceExternalImageFormatInfo"/>
+ <type name="VkExternalImageFormatProperties"/>
+ <type name="VkPhysicalDeviceExternalBufferInfo"/>
+ <type name="VkExternalBufferProperties"/>
+ <type name="VkPhysicalDeviceIDProperties"/>
+ <command name="vkGetPhysicalDeviceExternalBufferProperties"/>
+ </require>
+ <require comment="Promoted from VK_KHR_external_memory">
+ <enum extends="VkStructureType" extnumber="73" offset="0" name="VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_BUFFER_CREATE_INFO"/>
+ <enum extends="VkStructureType" extnumber="73" offset="1" name="VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO"/>
+ <enum extends="VkStructureType" extnumber="73" offset="2" name="VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO"/>
+ <enum extends="VkResult" extnumber="73" offset="3" dir="-" name="VK_ERROR_INVALID_EXTERNAL_HANDLE"/>
+ <enum name="VK_QUEUE_FAMILY_EXTERNAL"/>
+ <type name="VkExternalMemoryImageCreateInfo"/>
+ <type name="VkExternalMemoryBufferCreateInfo"/>
+ <type name="VkExportMemoryAllocateInfo"/>
+ </require>
+ <require comment="Promoted from VK_KHR_external_fence_capabilities">
+ <enum extends="VkStructureType" extnumber="113" offset="0" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_FENCE_INFO"/>
+ <enum extends="VkStructureType" extnumber="113" offset="1" name="VK_STRUCTURE_TYPE_EXTERNAL_FENCE_PROPERTIES"/>
+ <type name="VkExternalFenceHandleTypeFlags"/>
+ <type name="VkExternalFenceHandleTypeFlagBits"/>
+ <type name="VkExternalFenceFeatureFlags"/>
+ <type name="VkExternalFenceFeatureFlagBits"/>
+ <type name="VkPhysicalDeviceExternalFenceInfo"/>
+ <type name="VkExternalFenceProperties"/>
+ <command name="vkGetPhysicalDeviceExternalFenceProperties"/>
+ </require>
+ <require comment="Promoted from VK_KHR_external_fence">
+ <enum extends="VkStructureType" extnumber="114" offset="0" name="VK_STRUCTURE_TYPE_EXPORT_FENCE_CREATE_INFO"/>
+ <type name="VkFenceImportFlags"/>
+ <type name="VkFenceImportFlagBits"/>
+ <type name="VkExportFenceCreateInfo"/>
+ </require>
+ <require comment="Promoted from VK_KHR_external_semaphore">
+ <enum extends="VkStructureType" extnumber="78" offset="0" name="VK_STRUCTURE_TYPE_EXPORT_SEMAPHORE_CREATE_INFO"/>
+ <type name="VkSemaphoreImportFlags"/>
+ <type name="VkSemaphoreImportFlagBits"/>
+ <type name="VkExportSemaphoreCreateInfo"/>
+ </require>
+ <require comment="Promoted from VK_KHR_external_semaphore_capabilities">
+ <enum extends="VkStructureType" extnumber="77" offset="0" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_SEMAPHORE_INFO"/>
+ <enum extends="VkStructureType" extnumber="77" offset="1" name="VK_STRUCTURE_TYPE_EXTERNAL_SEMAPHORE_PROPERTIES"/>
+ <type name="VkExternalSemaphoreHandleTypeFlags"/>
+ <type name="VkExternalSemaphoreHandleTypeFlagBits"/>
+ <type name="VkExternalSemaphoreFeatureFlags"/>
+ <type name="VkExternalSemaphoreFeatureFlagBits"/>
+ <type name="VkPhysicalDeviceExternalSemaphoreInfo"/>
+ <type name="VkExternalSemaphoreProperties"/>
+ <command name="vkGetPhysicalDeviceExternalSemaphoreProperties"/>
+ </require>
+ <require comment="Promoted from VK_KHR_maintenance3">
+ <enum extends="VkStructureType" extnumber="169" offset="0" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_3_PROPERTIES"/>
+ <enum extends="VkStructureType" extnumber="169" offset="1" name="VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_SUPPORT"/>
+ <type name="VkPhysicalDeviceMaintenance3Properties"/>
+ <type name="VkDescriptorSetLayoutSupport"/>
+ <command name="vkGetDescriptorSetLayoutSupport"/>
+ </require>
+ <require comment="Promoted from VK_KHR_shader_draw_parameters, with a feature support query added">
+ <enum extends="VkStructureType" extnumber="64" offset="0" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_DRAW_PARAMETERS_FEATURES"/>
+ <enum extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_DRAW_PARAMETER_FEATURES" alias="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_DRAW_PARAMETERS_FEATURES"/>
+ <type name="VkPhysicalDeviceShaderDrawParameterFeatures"/>
+ <type name="VkPhysicalDeviceShaderDrawParametersFeatures"/>
+ </require>
+ </feature>
+ <feature api="vulkan" name="VK_VERSION_1_2" number="1.2" comment="Vulkan 1.2 core API interface definitions.">
+ <require>
+ <type name="VK_API_VERSION_1_2"/>
+ </require>
+ <require>
+ <enum extends="VkStructureType" value="49" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_1_FEATURES"/>
+ <enum extends="VkStructureType" value="50" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_1_PROPERTIES"/>
+ <enum extends="VkStructureType" value="51" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_FEATURES"/>
+ <enum extends="VkStructureType" value="52" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_PROPERTIES"/>
+ <type name="VkPhysicalDeviceVulkan11Features"/>
+ <type name="VkPhysicalDeviceVulkan11Properties"/>
+ <type name="VkPhysicalDeviceVulkan12Features"/>
+ <type name="VkPhysicalDeviceVulkan12Properties"/>
+ </require>
+ <require comment="Promoted from VK_KHR_image_format_list (extension 148)">
+ <enum offset="0" extends="VkStructureType" extnumber="148" name="VK_STRUCTURE_TYPE_IMAGE_FORMAT_LIST_CREATE_INFO"/>
+ <type name="VkImageFormatListCreateInfo"/>
+ </require>
+ <require comment="Promoted from VK_KHR_sampler_mirror_clamp_to_edge (extension 15)">
+ <enum value="4" extends="VkSamplerAddressMode" name="VK_SAMPLER_ADDRESS_MODE_MIRROR_CLAMP_TO_EDGE" comment="No need to add an extnumber attribute, since this uses a core enum value"/>
+ </require>
+ <require comment="Promoted from VK_KHR_draw_indirect_count (extension 170)">
+ <command name="vkCmdDrawIndirectCount"/>
+ <command name="vkCmdDrawIndexedIndirectCount"/>
+ </require>
+ <require comment="Promoted from VK_KHR_create_renderpass2 (extension 110)">
+ <enum offset="0" extends="VkStructureType" extnumber="110" name="VK_STRUCTURE_TYPE_ATTACHMENT_DESCRIPTION_2"/>
+ <enum offset="1" extends="VkStructureType" extnumber="110" name="VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2"/>
+ <enum offset="2" extends="VkStructureType" extnumber="110" name="VK_STRUCTURE_TYPE_SUBPASS_DESCRIPTION_2"/>
+ <enum offset="3" extends="VkStructureType" extnumber="110" name="VK_STRUCTURE_TYPE_SUBPASS_DEPENDENCY_2"/>
+ <enum offset="4" extends="VkStructureType" extnumber="110" name="VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO_2"/>
+ <enum offset="5" extends="VkStructureType" extnumber="110" name="VK_STRUCTURE_TYPE_SUBPASS_BEGIN_INFO"/>
+ <enum offset="6" extends="VkStructureType" extnumber="110" name="VK_STRUCTURE_TYPE_SUBPASS_END_INFO"/>
+ <command name="vkCreateRenderPass2"/>
+ <command name="vkCmdBeginRenderPass2"/>
+ <command name="vkCmdNextSubpass2"/>
+ <command name="vkCmdEndRenderPass2"/>
+ <type name="VkRenderPassCreateInfo2"/>
+ <type name="VkAttachmentDescription2"/>
+ <type name="VkAttachmentReference2"/>
+ <type name="VkSubpassDescription2"/>
+ <type name="VkSubpassDependency2"/>
+ <type name="VkSubpassBeginInfo"/>
+ <type name="VkSubpassEndInfo"/>
+ </require>
+ <require comment="Promoted from VK_KHR_8bit_storage (extension 178)">
+ <enum offset="0" extends="VkStructureType" extnumber="178" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_8BIT_STORAGE_FEATURES"/>
+ <type name="VkPhysicalDevice8BitStorageFeatures"/>
+ </require>
+ <require comment="Promoted from VK_KHR_driver_properties (extension 197)">
+ <enum offset="0" extends="VkStructureType" extnumber="197" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DRIVER_PROPERTIES"/>
+ <enum name="VK_MAX_DRIVER_NAME_SIZE"/>
+ <enum name="VK_MAX_DRIVER_INFO_SIZE"/>
+ <type name="VkDriverId"/>
+ <type name="VkConformanceVersion"/>
+ <type name="VkPhysicalDeviceDriverProperties"/>
+ </require>
+ <require comment="Promoted from VK_KHR_shader_atomic_int64 (extension 181)">
+ <enum offset="0" extends="VkStructureType" extnumber="181" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_ATOMIC_INT64_FEATURES"/>
+ <type name="VkPhysicalDeviceShaderAtomicInt64Features"/>
+ </require>
+ <require comment="Promoted from VK_KHR_shader_float16_int8 (extension 83)">
+ <enum offset="0" extends="VkStructureType" extnumber="83" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_FLOAT16_INT8_FEATURES"/>
+ <type name="VkPhysicalDeviceShaderFloat16Int8Features"/>
+ </require>
+ <require comment="Promoted from VK_KHR_shader_float_controls (extension 198)">
+ <enum offset="0" extends="VkStructureType" extnumber="198" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FLOAT_CONTROLS_PROPERTIES"/>
+ <type name="VkPhysicalDeviceFloatControlsProperties"/>
+ <type name="VkShaderFloatControlsIndependence"/>
+ </require>
+ <require comment="Promoted from VK_EXT_descriptor_indexing (extension 162)">
+ <enum offset="0" extends="VkStructureType" extnumber="162" name="VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_BINDING_FLAGS_CREATE_INFO"/>
+ <enum offset="1" extends="VkStructureType" extnumber="162" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_INDEXING_FEATURES"/>
+ <enum offset="2" extends="VkStructureType" extnumber="162" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_INDEXING_PROPERTIES"/>
+ <enum offset="3" extends="VkStructureType" extnumber="162" name="VK_STRUCTURE_TYPE_DESCRIPTOR_SET_VARIABLE_DESCRIPTOR_COUNT_ALLOCATE_INFO"/>
+ <enum offset="4" extends="VkStructureType" extnumber="162" name="VK_STRUCTURE_TYPE_DESCRIPTOR_SET_VARIABLE_DESCRIPTOR_COUNT_LAYOUT_SUPPORT"/>
+ <enum bitpos="1" extends="VkDescriptorPoolCreateFlagBits" name="VK_DESCRIPTOR_POOL_CREATE_UPDATE_AFTER_BIND_BIT"/>
+ <enum bitpos="1" extends="VkDescriptorSetLayoutCreateFlagBits" name="VK_DESCRIPTOR_SET_LAYOUT_CREATE_UPDATE_AFTER_BIND_POOL_BIT"/>
+ <enum offset="0" dir="-" extends="VkResult" extnumber="162" name="VK_ERROR_FRAGMENTATION"/>
+ <type name="VkDescriptorSetLayoutBindingFlagsCreateInfo"/>
+ <type name="VkPhysicalDeviceDescriptorIndexingFeatures"/>
+ <type name="VkPhysicalDeviceDescriptorIndexingProperties"/>
+ <type name="VkDescriptorSetVariableDescriptorCountAllocateInfo"/>
+ <type name="VkDescriptorSetVariableDescriptorCountLayoutSupport"/>
+ <type name="VkDescriptorBindingFlagBits"/>
+ <type name="VkDescriptorBindingFlags"/>
+ </require>
+ <require comment="Promoted from VK_KHR_depth_stencil_resolve (extension 200)">
+ <enum offset="0" extends="VkStructureType" extnumber="200" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEPTH_STENCIL_RESOLVE_PROPERTIES"/>
+ <enum offset="1" extends="VkStructureType" extnumber="200" name="VK_STRUCTURE_TYPE_SUBPASS_DESCRIPTION_DEPTH_STENCIL_RESOLVE"/>
+ <type name="VkSubpassDescriptionDepthStencilResolve"/>
+ <type name="VkPhysicalDeviceDepthStencilResolveProperties"/>
+ <type name="VkResolveModeFlagBits"/>
+ <type name="VkResolveModeFlags"/>
+ </require>
+ <require comment="Promoted from VK_EXT_scalar_block_layout (extension 222))">
+ <type name="VkPhysicalDeviceScalarBlockLayoutFeatures"/>
+ <enum offset="0" extends="VkStructureType" extnumber="222" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SCALAR_BLOCK_LAYOUT_FEATURES"/>
+ </require>
+ <require comment="Promoted from VK_EXT_shader_viewport_index_layer, which has no API (extension 163)"/>
+ <require comment="Promoted from VK_EXT_separate_stencil_usage (extension 247)">
+ <enum offset="0" extends="VkStructureType" extnumber="247" name="VK_STRUCTURE_TYPE_IMAGE_STENCIL_USAGE_CREATE_INFO"/>
+ <type name="VkImageStencilUsageCreateInfo"/>
+ </require>
+ <require comment="Promoted from VK_EXT_sampler_filter_minmax (extension 131)">
+ <enum offset="0" extends="VkStructureType" extnumber="131" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLER_FILTER_MINMAX_PROPERTIES"/>
+ <enum offset="1" extends="VkStructureType" extnumber="131" name="VK_STRUCTURE_TYPE_SAMPLER_REDUCTION_MODE_CREATE_INFO"/>
+ <enum bitpos="16" extends="VkFormatFeatureFlagBits" name="VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_MINMAX_BIT" comment="Format can be used with min/max reduction filtering"/>
+ <type name="VkSamplerReductionMode"/>
+ <type name="VkSamplerReductionModeCreateInfo"/>
+ <type name="VkPhysicalDeviceSamplerFilterMinmaxProperties"/>
+ </require>
+ <require comment="Promoted from VK_KHR_vulkan_memory_model (extension 212)">
+ <enum offset="0" extends="VkStructureType" extnumber="212" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_MEMORY_MODEL_FEATURES"/>
+ <type name="VkPhysicalDeviceVulkanMemoryModelFeatures"/>
+ </require>
+ <require comment="Promoted from VK_KHR_imageless_framebuffer (extension 109)">
+ <type name="VkPhysicalDeviceImagelessFramebufferFeatures"/>
+ <type name="VkFramebufferAttachmentsCreateInfo"/>
+ <type name="VkFramebufferAttachmentImageInfo"/>
+ <type name="VkRenderPassAttachmentBeginInfo"/>
+ <enum offset="0" extends="VkStructureType" extnumber="109" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGELESS_FRAMEBUFFER_FEATURES"/>
+ <enum offset="1" extends="VkStructureType" extnumber="109" name="VK_STRUCTURE_TYPE_FRAMEBUFFER_ATTACHMENTS_CREATE_INFO"/>
+ <enum offset="2" extends="VkStructureType" extnumber="109" name="VK_STRUCTURE_TYPE_FRAMEBUFFER_ATTACHMENT_IMAGE_INFO"/>
+ <enum offset="3" extends="VkStructureType" extnumber="109" name="VK_STRUCTURE_TYPE_RENDER_PASS_ATTACHMENT_BEGIN_INFO"/>
+ <enum bitpos="0" extends="VkFramebufferCreateFlagBits" name="VK_FRAMEBUFFER_CREATE_IMAGELESS_BIT"/>
+ </require>
+ <require comment="Promoted from VK_KHR_uniform_buffer_standard_layout (extension 254)">
+ <type name="VkPhysicalDeviceUniformBufferStandardLayoutFeatures"/>
+ <enum offset="0" extends="VkStructureType" extnumber="254" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_UNIFORM_BUFFER_STANDARD_LAYOUT_FEATURES"/>
+ </require>
+ <require comment="Promoted from VK_KHR_shader_subgroup_extended_types (extension 176)">
+ <enum offset="0" extends="VkStructureType" extnumber="176" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_SUBGROUP_EXTENDED_TYPES_FEATURES"/>
+ <type name="VkPhysicalDeviceShaderSubgroupExtendedTypesFeatures"/>
+ </require>
+ <require comment="Promoted from VK_KHR_spirv_1_4 (extension 237)">
+ </require>
+ <require comment="Promoted from VK_KHR_separate_depth_stencil_layouts (extension 242)">
+ <enum offset="0" extends="VkStructureType" extnumber="242" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SEPARATE_DEPTH_STENCIL_LAYOUTS_FEATURES"/>
+ <enum offset="1" extends="VkStructureType" extnumber="242" name="VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_STENCIL_LAYOUT"/>
+ <enum offset="2" extends="VkStructureType" extnumber="242" name="VK_STRUCTURE_TYPE_ATTACHMENT_DESCRIPTION_STENCIL_LAYOUT"/>
+ <enum offset="0" extends="VkImageLayout" extnumber="242" name="VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL"/>
+ <enum offset="1" extends="VkImageLayout" extnumber="242" name="VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_OPTIMAL"/>
+ <enum offset="2" extends="VkImageLayout" extnumber="242" name="VK_IMAGE_LAYOUT_STENCIL_ATTACHMENT_OPTIMAL"/>
+ <enum offset="3" extends="VkImageLayout" extnumber="242" name="VK_IMAGE_LAYOUT_STENCIL_READ_ONLY_OPTIMAL"/>
+ <type name="VkPhysicalDeviceSeparateDepthStencilLayoutsFeatures"/>
+ <type name="VkAttachmentReferenceStencilLayout"/>
+ <type name="VkAttachmentDescriptionStencilLayout"/>
+ </require>
+ <require comment="Promoted from VK_EXT_host_query_reset (extension 262)">
+ <enum offset="0" extends="VkStructureType" extnumber="262" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_HOST_QUERY_RESET_FEATURES"/>
+ <type name="VkPhysicalDeviceHostQueryResetFeatures"/>
+ <command name="vkResetQueryPool"/>
+ </require>
+ <require comment="Promoted from VK_KHR_timeline_semaphore (extension 208)">
+ <enum offset="0" extends="VkStructureType" extnumber="208" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TIMELINE_SEMAPHORE_FEATURES"/>
+ <enum offset="1" extends="VkStructureType" extnumber="208" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TIMELINE_SEMAPHORE_PROPERTIES"/>
+ <enum offset="2" extends="VkStructureType" extnumber="208" name="VK_STRUCTURE_TYPE_SEMAPHORE_TYPE_CREATE_INFO"/>
+ <enum offset="3" extends="VkStructureType" extnumber="208" name="VK_STRUCTURE_TYPE_TIMELINE_SEMAPHORE_SUBMIT_INFO"/>
+ <enum offset="4" extends="VkStructureType" extnumber="208" name="VK_STRUCTURE_TYPE_SEMAPHORE_WAIT_INFO"/>
+ <enum offset="5" extends="VkStructureType" extnumber="208" name="VK_STRUCTURE_TYPE_SEMAPHORE_SIGNAL_INFO"/>
+ <type name="VkSemaphoreType"/>
+ <type name="VkPhysicalDeviceTimelineSemaphoreFeatures"/>
+ <type name="VkPhysicalDeviceTimelineSemaphoreProperties"/>
+ <type name="VkSemaphoreTypeCreateInfo"/>
+ <type name="VkTimelineSemaphoreSubmitInfo"/>
+ <type name="VkSemaphoreWaitFlagBits"/>
+ <type name="VkSemaphoreWaitFlags"/>
+ <type name="VkSemaphoreWaitInfo"/>
+ <type name="VkSemaphoreSignalInfo"/>
+ <command name="vkGetSemaphoreCounterValue"/>
+ <command name="vkWaitSemaphores"/>
+ <command name="vkSignalSemaphore"/>
+ </require>
+ <require comment="Promoted from VK_KHR_buffer_device_address (extension 258)">
+ <enum offset="0" extends="VkStructureType" extnumber="258" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BUFFER_DEVICE_ADDRESS_FEATURES"/>
+ <enum offset="1" extends="VkStructureType" extnumber="245" name="VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO"/>
+ <enum offset="2" extends="VkStructureType" extnumber="258" name="VK_STRUCTURE_TYPE_BUFFER_OPAQUE_CAPTURE_ADDRESS_CREATE_INFO"/>
+ <enum offset="3" extends="VkStructureType" extnumber="258" name="VK_STRUCTURE_TYPE_MEMORY_OPAQUE_CAPTURE_ADDRESS_ALLOCATE_INFO"/>
+ <enum offset="4" extends="VkStructureType" extnumber="258" name="VK_STRUCTURE_TYPE_DEVICE_MEMORY_OPAQUE_CAPTURE_ADDRESS_INFO"/>
+ <enum bitpos="17" extends="VkBufferUsageFlagBits" name="VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT"/>
+ <enum bitpos="4" extends="VkBufferCreateFlagBits" name="VK_BUFFER_CREATE_DEVICE_ADDRESS_CAPTURE_REPLAY_BIT"/>
+ <enum bitpos="1" extends="VkMemoryAllocateFlagBits" name="VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT"/>
+ <enum bitpos="2" extends="VkMemoryAllocateFlagBits" name="VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_CAPTURE_REPLAY_BIT"/>
+ <enum offset="0" dir="-" extends="VkResult" extnumber="258" name="VK_ERROR_INVALID_OPAQUE_CAPTURE_ADDRESS"/>
+ <type name="VkPhysicalDeviceBufferDeviceAddressFeatures"/>
+ <type name="VkBufferDeviceAddressInfo"/>
+ <type name="VkBufferOpaqueCaptureAddressCreateInfo"/>
+ <type name="VkMemoryOpaqueCaptureAddressAllocateInfo"/>
+ <type name="VkDeviceMemoryOpaqueCaptureAddressInfo"/>
+ <command name="vkGetBufferDeviceAddress"/>
+ <command name="vkGetBufferOpaqueCaptureAddress"/>
+ <command name="vkGetDeviceMemoryOpaqueCaptureAddress"/>
+ </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">
+ <require>
+ <enum value="25" name="VK_KHR_SURFACE_SPEC_VERSION"/>
+ <enum value="&quot;VK_KHR_surface&quot;" name="VK_KHR_SURFACE_EXTENSION_NAME"/>
+ <enum offset="0" extends="VkResult" dir="-" name="VK_ERROR_SURFACE_LOST_KHR"/>
+ <enum offset="1" extends="VkResult" dir="-" name="VK_ERROR_NATIVE_WINDOW_IN_USE_KHR"/>
+ <enum offset="0" extends="VkObjectType" name="VK_OBJECT_TYPE_SURFACE_KHR"/>
+ <type name="VkSurfaceKHR"/>
+ <type name="VkSurfaceTransformFlagBitsKHR"/>
+ <type name="VkPresentModeKHR"/>
+ <type name="VkColorSpaceKHR"/>
+ <type name="VkCompositeAlphaFlagBitsKHR"/>
+ <type name="VkCompositeAlphaFlagsKHR"/>
+ <type name="VkSurfaceCapabilitiesKHR"/>
+ <type name="VkSurfaceFormatKHR"/>
+ <command name="vkDestroySurfaceKHR"/>
+ <command name="vkGetPhysicalDeviceSurfaceSupportKHR"/>
+ <command name="vkGetPhysicalDeviceSurfaceCapabilitiesKHR"/>
+ <command name="vkGetPhysicalDeviceSurfaceFormatsKHR"/>
+ <command name="vkGetPhysicalDeviceSurfacePresentModesKHR"/>
+ </require>
+ </extension>
+ <extension name="VK_KHR_swapchain" number="2" type="device" requires="VK_KHR_surface" author="KHR" contact="James Jones @cubanismo,Ian Elliott @ianelliottus" supported="vulkan">
+ <require>
+ <enum value="70" name="VK_KHR_SWAPCHAIN_SPEC_VERSION"/>
+ <enum value="&quot;VK_KHR_swapchain&quot;" name="VK_KHR_SWAPCHAIN_EXTENSION_NAME"/>
+ <enum offset="0" extends="VkStructureType" name="VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR"/>
+ <enum offset="1" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PRESENT_INFO_KHR"/>
+ <enum offset="2" extends="VkImageLayout" name="VK_IMAGE_LAYOUT_PRESENT_SRC_KHR"/>
+ <enum offset="3" extends="VkResult" name="VK_SUBOPTIMAL_KHR"/>
+ <enum offset="4" extends="VkResult" dir="-" name="VK_ERROR_OUT_OF_DATE_KHR"/>
+ <enum offset="0" extends="VkObjectType" name="VK_OBJECT_TYPE_SWAPCHAIN_KHR"/>
+ <type name="VkSwapchainCreateFlagBitsKHR"/>
+ <type name="VkSwapchainCreateFlagsKHR"/>
+ <type name="VkSwapchainCreateInfoKHR"/>
+ <type name="VkSwapchainKHR"/>
+ <type name="VkPresentInfoKHR"/>
+ <command name="vkCreateSwapchainKHR"/>
+ <command name="vkDestroySwapchainKHR"/>
+ <command name="vkGetSwapchainImagesKHR"/>
+ <command name="vkAcquireNextImageKHR"/>
+ <command name="vkQueuePresentKHR"/>
+ </require>
+ <require feature="VK_VERSION_1_1">
+ <comment>This duplicates definitions in VK_KHR_device_group below</comment>
+ <enum extends="VkStructureType" extnumber="61" offset="7" name="VK_STRUCTURE_TYPE_DEVICE_GROUP_PRESENT_CAPABILITIES_KHR"/>
+ <enum extends="VkStructureType" extnumber="61" offset="8" name="VK_STRUCTURE_TYPE_IMAGE_SWAPCHAIN_CREATE_INFO_KHR"/>
+ <enum extends="VkStructureType" extnumber="61" offset="9" name="VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_SWAPCHAIN_INFO_KHR"/>
+ <enum extends="VkStructureType" extnumber="61" offset="10" name="VK_STRUCTURE_TYPE_ACQUIRE_NEXT_IMAGE_INFO_KHR"/>
+ <enum extends="VkStructureType" extnumber="61" offset="11" name="VK_STRUCTURE_TYPE_DEVICE_GROUP_PRESENT_INFO_KHR"/>
+ <enum extends="VkStructureType" extnumber="61" offset="12" name="VK_STRUCTURE_TYPE_DEVICE_GROUP_SWAPCHAIN_CREATE_INFO_KHR"/>
+ <enum bitpos="0" extends="VkSwapchainCreateFlagBitsKHR" name="VK_SWAPCHAIN_CREATE_SPLIT_INSTANCE_BIND_REGIONS_BIT_KHR" comment="Allow images with VK_IMAGE_CREATE_SPLIT_INSTANCE_BIND_REGIONS_BIT"/>
+ <type name="VkImageSwapchainCreateInfoKHR"/>
+ <type name="VkBindImageMemorySwapchainInfoKHR"/>
+ <type name="VkAcquireNextImageInfoKHR"/>
+ <type name="VkDeviceGroupPresentModeFlagBitsKHR"/>
+ <type name="VkDeviceGroupPresentModeFlagsKHR"/>
+ <type name="VkDeviceGroupPresentCapabilitiesKHR"/>
+ <type name="VkDeviceGroupPresentInfoKHR"/>
+ <type name="VkDeviceGroupSwapchainCreateInfoKHR"/>
+ <command name="vkGetDeviceGroupPresentCapabilitiesKHR"/>
+ <command name="vkGetDeviceGroupSurfacePresentModesKHR"/>
+ <command name="vkGetPhysicalDevicePresentRectanglesKHR"/>
+ <command name="vkAcquireNextImage2KHR"/>
+ <enum bitpos="1" extends="VkSwapchainCreateFlagBitsKHR" name="VK_SWAPCHAIN_CREATE_PROTECTED_BIT_KHR" comment="Swapchain is protected"/>
+ </require>
+ </extension>
+ <extension name="VK_KHR_display" number="3" type="instance" requires="VK_KHR_surface" author="KHR" contact="James Jones @cubanismo,Norbert Nopper @FslNopper" supported="vulkan">
+ <require>
+ <enum value="23" name="VK_KHR_DISPLAY_SPEC_VERSION"/>
+ <enum value="&quot;VK_KHR_display&quot;" name="VK_KHR_DISPLAY_EXTENSION_NAME"/>
+ <enum offset="0" extends="VkStructureType" name="VK_STRUCTURE_TYPE_DISPLAY_MODE_CREATE_INFO_KHR"/>
+ <enum offset="1" extends="VkStructureType" name="VK_STRUCTURE_TYPE_DISPLAY_SURFACE_CREATE_INFO_KHR"/>
+ <enum offset="0" extends="VkObjectType" name="VK_OBJECT_TYPE_DISPLAY_KHR"/>
+ <enum offset="1" extends="VkObjectType" name="VK_OBJECT_TYPE_DISPLAY_MODE_KHR"/>
+ <type name="VkDisplayKHR"/>
+ <type name="VkDisplayModeCreateFlagsKHR"/>
+ <type name="VkDisplayModeCreateInfoKHR"/>
+ <type name="VkDisplayModeKHR"/>
+ <type name="VkDisplayModeParametersKHR"/>
+ <type name="VkDisplayModePropertiesKHR"/>
+ <type name="VkDisplayPlaneAlphaFlagBitsKHR"/>
+ <type name="VkDisplayPlaneAlphaFlagsKHR"/>
+ <type name="VkDisplayPlaneCapabilitiesKHR"/>
+ <type name="VkDisplayPlanePropertiesKHR"/>
+ <type name="VkDisplayPropertiesKHR"/>
+ <type name="VkDisplaySurfaceCreateFlagsKHR"/>
+ <type name="VkDisplaySurfaceCreateInfoKHR"/>
+ <type name="VkSurfaceTransformFlagsKHR"/>
+ <command name="vkGetPhysicalDeviceDisplayPropertiesKHR"/>
+ <command name="vkGetPhysicalDeviceDisplayPlanePropertiesKHR"/>
+ <command name="vkGetDisplayPlaneSupportedDisplaysKHR"/>
+ <command name="vkGetDisplayModePropertiesKHR"/>
+ <command name="vkCreateDisplayModeKHR"/>
+ <command name="vkGetDisplayPlaneCapabilitiesKHR"/>
+ <command name="vkCreateDisplayPlaneSurfaceKHR"/>
+ </require>
+ </extension>
+ <extension name="VK_KHR_display_swapchain" number="4" type="device" requires="VK_KHR_swapchain,VK_KHR_display" author="KHR" contact="James Jones @cubanismo" supported="vulkan">
+ <require>
+ <enum value="10" name="VK_KHR_DISPLAY_SWAPCHAIN_SPEC_VERSION"/>
+ <enum value="&quot;VK_KHR_display_swapchain&quot;" name="VK_KHR_DISPLAY_SWAPCHAIN_EXTENSION_NAME"/>
+ <enum offset="0" extends="VkStructureType" name="VK_STRUCTURE_TYPE_DISPLAY_PRESENT_INFO_KHR"/>
+ <enum offset="1" extends="VkResult" dir="-" name="VK_ERROR_INCOMPATIBLE_DISPLAY_KHR"/>
+ <type name="VkDisplayPresentInfoKHR"/>
+ <command name="vkCreateSharedSwapchainsKHR"/>
+ </require>
+ </extension>
+ <extension name="VK_KHR_xlib_surface" number="5" type="instance" requires="VK_KHR_surface" platform="xlib" author="KHR" contact="Jesse Hall @critsec,Ian Elliott @ianelliottus" supported="vulkan">
+ <require>
+ <enum value="6" name="VK_KHR_XLIB_SURFACE_SPEC_VERSION"/>
+ <enum value="&quot;VK_KHR_xlib_surface&quot;" name="VK_KHR_XLIB_SURFACE_EXTENSION_NAME"/>
+ <enum offset="0" extends="VkStructureType" name="VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR"/>
+ <type name="VkXlibSurfaceCreateFlagsKHR"/>
+ <type name="VkXlibSurfaceCreateInfoKHR"/>
+ <command name="vkCreateXlibSurfaceKHR"/>
+ <command name="vkGetPhysicalDeviceXlibPresentationSupportKHR"/>
+ </require>
+ </extension>
+ <extension name="VK_KHR_xcb_surface" number="6" type="instance" requires="VK_KHR_surface" platform="xcb" author="KHR" contact="Jesse Hall @critsec,Ian Elliott @ianelliottus" supported="vulkan">
+ <require>
+ <enum value="6" name="VK_KHR_XCB_SURFACE_SPEC_VERSION"/>
+ <enum value="&quot;VK_KHR_xcb_surface&quot;" name="VK_KHR_XCB_SURFACE_EXTENSION_NAME"/>
+ <enum offset="0" extends="VkStructureType" name="VK_STRUCTURE_TYPE_XCB_SURFACE_CREATE_INFO_KHR"/>
+ <type name="VkXcbSurfaceCreateFlagsKHR"/>
+ <type name="VkXcbSurfaceCreateInfoKHR"/>
+ <command name="vkCreateXcbSurfaceKHR"/>
+ <command name="vkGetPhysicalDeviceXcbPresentationSupportKHR"/>
+ </require>
+ </extension>
+ <extension name="VK_KHR_wayland_surface" number="7" type="instance" requires="VK_KHR_surface" platform="wayland" author="KHR" contact="Jesse Hall @critsec,Ian Elliott @ianelliottus" supported="vulkan">
+ <require>
+ <enum value="6" name="VK_KHR_WAYLAND_SURFACE_SPEC_VERSION"/>
+ <enum value="&quot;VK_KHR_wayland_surface&quot;" name="VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME"/>
+ <enum offset="0" extends="VkStructureType" name="VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR"/>
+ <type name="VkWaylandSurfaceCreateFlagsKHR"/>
+ <type name="VkWaylandSurfaceCreateInfoKHR"/>
+ <command name="vkCreateWaylandSurfaceKHR"/>
+ <command name="vkGetPhysicalDeviceWaylandPresentationSupportKHR"/>
+ </require>
+ </extension>
+ <extension name="VK_KHR_mir_surface" number="8" type="instance" requires="VK_KHR_surface" author="KHR" supported="disabled" comment="Extension permanently disabled. Extension number should not be reused">
+ <require>
+ <enum value="4" name="VK_KHR_MIR_SURFACE_SPEC_VERSION"/>
+ <enum value="&quot;VK_KHR_mir_surface&quot;" name="VK_KHR_MIR_SURFACE_EXTENSION_NAME"/>
+ </require>
+ </extension>
+ <extension name="VK_KHR_android_surface" number="9" type="instance" requires="VK_KHR_surface" platform="android" author="KHR" contact="Jesse Hall @critsec" supported="vulkan">
+ <require>
+ <enum value="6" name="VK_KHR_ANDROID_SURFACE_SPEC_VERSION"/>
+ <enum value="&quot;VK_KHR_android_surface&quot;" name="VK_KHR_ANDROID_SURFACE_EXTENSION_NAME"/>
+ <type name="ANativeWindow"/>
+ <enum offset="0" extends="VkStructureType" name="VK_STRUCTURE_TYPE_ANDROID_SURFACE_CREATE_INFO_KHR"/>
+ <type name="VkAndroidSurfaceCreateFlagsKHR"/>
+ <type name="VkAndroidSurfaceCreateInfoKHR"/>
+ <command name="vkCreateAndroidSurfaceKHR"/>
+ </require>
+ </extension>
+ <extension name="VK_KHR_win32_surface" number="10" type="instance" requires="VK_KHR_surface" platform="win32" author="KHR" contact="Jesse Hall @critsec,Ian Elliott @ianelliottus" supported="vulkan">
+ <require>
+ <enum value="6" name="VK_KHR_WIN32_SURFACE_SPEC_VERSION"/>
+ <enum value="&quot;VK_KHR_win32_surface&quot;" name="VK_KHR_WIN32_SURFACE_EXTENSION_NAME"/>
+ <enum offset="0" extends="VkStructureType" name="VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR"/>
+ <type name="VkWin32SurfaceCreateFlagsKHR"/>
+ <type name="VkWin32SurfaceCreateInfoKHR"/>
+ <command name="vkCreateWin32SurfaceKHR"/>
+ <command name="vkGetPhysicalDeviceWin32PresentationSupportKHR"/>
+ </require>
+ </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>
+ <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 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"/>
+ <type name="VkNativeBufferANDROID"/>
+ <type name="VkSwapchainImageCreateInfoANDROID"/>
+ <type name="VkPhysicalDevicePresentationPropertiesANDROID"/>
+ <type name="VkNativeBufferUsage2ANDROID"/>
+ <type name="VkSwapchainImageUsageFlagBitsANDROID"/>
+ <type name="VkSwapchainImageUsageFlagsANDROID"/>
+ <command name="vkGetSwapchainGrallocUsageANDROID"/>
+ <command name="vkAcquireImageANDROID"/>
+ <command name="vkQueueSignalReleaseImageANDROID"/>
+ <command name="vkGetSwapchainGrallocUsage2ANDROID"/>
+ </require>
+ </extension>
+ <extension name="VK_EXT_debug_report" number="12" type="instance" author="GOOGLE" contact="Courtney Goeltzenleuchter @courtney-g" specialuse="debugging" supported="vulkan" deprecatedby="VK_EXT_debug_utils">
+ <require>
+ <enum value="10" name="VK_EXT_DEBUG_REPORT_SPEC_VERSION"/>
+ <enum value="&quot;VK_EXT_debug_report&quot;" name="VK_EXT_DEBUG_REPORT_EXTENSION_NAME"/>
+ <enum offset="0" extends="VkStructureType" name="VK_STRUCTURE_TYPE_DEBUG_REPORT_CALLBACK_CREATE_INFO_EXT"/>
+ <enum alias="VK_STRUCTURE_TYPE_DEBUG_REPORT_CALLBACK_CREATE_INFO_EXT" extends="VkStructureType" name="VK_STRUCTURE_TYPE_DEBUG_REPORT_CREATE_INFO_EXT" comment="Backwards-compatible alias containing a typo"/>
+ <enum offset="1" extends="VkResult" dir="-" name="VK_ERROR_VALIDATION_FAILED_EXT"/>
+ <enum offset="0" extends="VkObjectType" name="VK_OBJECT_TYPE_DEBUG_REPORT_CALLBACK_EXT"/>
+ <type name="VkDebugReportCallbackEXT"/>
+ <type name="PFN_vkDebugReportCallbackEXT"/>
+ <type name="VkDebugReportFlagBitsEXT"/>
+ <type name="VkDebugReportFlagsEXT"/>
+ <type name="VkDebugReportObjectTypeEXT"/>
+ <type name="VkDebugReportCallbackCreateInfoEXT"/>
+ <command name="vkCreateDebugReportCallbackEXT"/>
+ <command name="vkDestroyDebugReportCallbackEXT"/>
+ <command name="vkDebugReportMessageEXT"/>
+ </require>
+ <require feature="VK_VERSION_1_1">
+ <comment>This duplicates definitions in other extensions, below</comment>
+ <enum extends="VkDebugReportObjectTypeEXT" extnumber="157" offset="0" name="VK_DEBUG_REPORT_OBJECT_TYPE_SAMPLER_YCBCR_CONVERSION_EXT"/>
+ <enum extends="VkDebugReportObjectTypeEXT" extnumber="86" offset="0" name="VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_EXT"/>
+ </require>
+ </extension>
+ <extension name="VK_NV_glsl_shader" number="13" type="device" author="NV" contact="Piers Daniell @pdaniell-nv" supported="vulkan" deprecatedby="">
+ <require>
+ <enum value="1" name="VK_NV_GLSL_SHADER_SPEC_VERSION"/>
+ <enum value="&quot;VK_NV_glsl_shader&quot;" name="VK_NV_GLSL_SHADER_EXTENSION_NAME"/>
+ <enum offset="0" extends="VkResult" dir="-" name="VK_ERROR_INVALID_SHADER_NV"/>
+ </require>
+ </extension>
+ <extension name="VK_EXT_depth_range_unrestricted" type="device" number="14" author="NV" contact="Piers Daniell @pdaniell-nv" supported="vulkan">
+ <require>
+ <enum value="1" name="VK_EXT_DEPTH_RANGE_UNRESTRICTED_SPEC_VERSION"/>
+ <enum value="&quot;VK_EXT_depth_range_unrestricted&quot;" name="VK_EXT_DEPTH_RANGE_UNRESTRICTED_EXTENSION_NAME"/>
+ </require>
+ </extension>
+ <extension name="VK_KHR_sampler_mirror_clamp_to_edge" type="device" number="15" author="KHR" contact="Tobias Hector @tobski" supported="vulkan" promotedto="VK_VERSION_1_2">
+ <require>
+ <enum value="3" name="VK_KHR_SAMPLER_MIRROR_CLAMP_TO_EDGE_SPEC_VERSION"/>
+ <enum value="&quot;VK_KHR_sampler_mirror_clamp_to_edge&quot;" name="VK_KHR_SAMPLER_MIRROR_CLAMP_TO_EDGE_EXTENSION_NAME"/>
+ <enum value="4" extends="VkSamplerAddressMode" name="VK_SAMPLER_ADDRESS_MODE_MIRROR_CLAMP_TO_EDGE" comment="Note that this defines what was previously a core enum, and so uses the 'value' attribute rather than 'offset', and does not have a suffix. This is a special case, and should not be repeated"/>
+ <enum extends="VkSamplerAddressMode" name="VK_SAMPLER_ADDRESS_MODE_MIRROR_CLAMP_TO_EDGE_KHR" alias="VK_SAMPLER_ADDRESS_MODE_MIRROR_CLAMP_TO_EDGE" comment="Alias introduced for consistency with extension suffixing rules"/>
+ </require>
+ </extension>
+ <extension name="VK_IMG_filter_cubic" number="16" type="device" author="IMG" contact="Tobias Hector @tobski" supported="vulkan">
+ <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"/>
+ </require>
+ </extension>
+ <extension name="VK_AMD_extension_17" number="17" author="AMD" contact="Daniel Rakos @drakos-amd" supported="disabled">
+ <require>
+ <enum value="0" name="VK_AMD_EXTENSION_17_SPEC_VERSION"/>
+ <enum value="&quot;VK_AMD_extension_17&quot;" name="VK_AMD_EXTENSION_17_EXTENSION_NAME"/>
+ </require>
+ </extension>
+ <extension name="VK_AMD_extension_18" number="18" author="AMD" contact="Daniel Rakos @drakos-amd" supported="disabled">
+ <require>
+ <enum value="0" name="VK_AMD_EXTENSION_18_SPEC_VERSION"/>
+ <enum value="&quot;VK_AMD_extension_18&quot;" name="VK_AMD_EXTENSION_18_EXTENSION_NAME"/>
+ </require>
+ </extension>
+ <extension name="VK_AMD_rasterization_order" number="19" type="device" author="AMD" contact="Daniel Rakos @drakos-amd" supported="vulkan">
+ <require>
+ <enum value="1" name="VK_AMD_RASTERIZATION_ORDER_SPEC_VERSION"/>
+ <enum value="&quot;VK_AMD_rasterization_order&quot;" name="VK_AMD_RASTERIZATION_ORDER_EXTENSION_NAME"/>
+ <enum offset="0" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_RASTERIZATION_ORDER_AMD"/>
+ <type name="VkRasterizationOrderAMD"/>
+ <type name="VkPipelineRasterizationStateRasterizationOrderAMD"/>
+ </require>
+ </extension>
+ <extension name="VK_AMD_extension_20" number="20" author="AMD" contact="Daniel Rakos @drakos-amd" supported="disabled">
+ <require>
+ <enum value="0" name="VK_AMD_EXTENSION_20_SPEC_VERSION"/>
+ <enum value="&quot;VK_AMD_extension_20&quot;" name="VK_AMD_EXTENSION_20_EXTENSION_NAME"/>
+ </require>
+ </extension>
+ <extension name="VK_AMD_shader_trinary_minmax" number="21" type="device" author="AMD" contact="Qun Lin @linqun" supported="vulkan">
+ <require>
+ <enum value="1" name="VK_AMD_SHADER_TRINARY_MINMAX_SPEC_VERSION"/>
+ <enum value="&quot;VK_AMD_shader_trinary_minmax&quot;" name="VK_AMD_SHADER_TRINARY_MINMAX_EXTENSION_NAME"/>
+ </require>
+ </extension>
+ <extension name="VK_AMD_shader_explicit_vertex_parameter" number="22" type="device" author="AMD" contact="Qun Lin @linqun" supported="vulkan">
+ <require>
+ <enum value="1" name="VK_AMD_SHADER_EXPLICIT_VERTEX_PARAMETER_SPEC_VERSION"/>
+ <enum value="&quot;VK_AMD_shader_explicit_vertex_parameter&quot;" name="VK_AMD_SHADER_EXPLICIT_VERTEX_PARAMETER_EXTENSION_NAME"/>
+ </require>
+ </extension>
+ <extension name="VK_EXT_debug_marker" number="23" type="device" requires="VK_EXT_debug_report" author="Baldur Karlsson" contact="Baldur Karlsson @baldurk" specialuse="debugging" supported="vulkan" promotedto="VK_EXT_debug_utils">
+ <require>
+ <enum value="4" name="VK_EXT_DEBUG_MARKER_SPEC_VERSION"/>
+ <enum value="&quot;VK_EXT_debug_marker&quot;" name="VK_EXT_DEBUG_MARKER_EXTENSION_NAME"/>
+ <enum offset="0" extends="VkStructureType" name="VK_STRUCTURE_TYPE_DEBUG_MARKER_OBJECT_NAME_INFO_EXT"/>
+ <enum offset="1" extends="VkStructureType" name="VK_STRUCTURE_TYPE_DEBUG_MARKER_OBJECT_TAG_INFO_EXT"/>
+ <enum offset="2" extends="VkStructureType" name="VK_STRUCTURE_TYPE_DEBUG_MARKER_MARKER_INFO_EXT"/>
+ <type name="VkDebugReportObjectTypeEXT"/>
+ <type name="VkDebugMarkerObjectNameInfoEXT"/>
+ <type name="VkDebugMarkerObjectTagInfoEXT"/>
+ <type name="VkDebugMarkerMarkerInfoEXT"/>
+ <command name="vkDebugMarkerSetObjectTagEXT"/>
+ <command name="vkDebugMarkerSetObjectNameEXT"/>
+ <command name="vkCmdDebugMarkerBeginEXT"/>
+ <command name="vkCmdDebugMarkerEndEXT"/>
+ <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">
+ <require>
+ <enum value="1" 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="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="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"/>
+
+ <type name="VkVideoSessionKHR"/>
+ <type name="VkVideoSessionParametersKHR"/>
+
+ <type name="VkVideoCodecOperationFlagBitsKHR"/>
+ <type name="VkVideoCodecOperationFlagsKHR"/>
+ <type name="VkVideoChromaSubsamplingFlagBitsKHR"/>
+ <type name="VkVideoChromaSubsamplingFlagsKHR"/>
+ <type name="VkVideoComponentBitDepthFlagBitsKHR"/>
+ <type name="VkVideoComponentBitDepthFlagsKHR"/>
+ <type name="VkVideoCapabilitiesFlagBitsKHR"/>
+ <type name="VkVideoCapabilitiesFlagsKHR"/>
+ <type name="VkVideoSessionCreateFlagBitsKHR"/>
+ <type name="VkVideoSessionCreateFlagsKHR"/>
+ <type name="VkVideoBeginCodingFlagsKHR"/>
+ <type name="VkVideoEndCodingFlagsKHR"/>
+ <type name="VkVideoCodingControlFlagBitsKHR"/>
+ <type name="VkVideoCodingControlFlagsKHR"/>
+ <type name="VkVideoCodingQualityPresetFlagBitsKHR"/>
+ <type name="VkVideoCodingQualityPresetFlagsKHR"/>
+
+ <type name="VkQueryResultStatusKHR"/>
+
+ <type name="VkVideoQueueFamilyProperties2KHR"/>
+ <type name="VkVideoProfileKHR"/>
+ <type name="VkVideoProfilesKHR"/>
+ <type name="VkVideoCapabilitiesKHR"/>
+ <type name="VkPhysicalDeviceVideoFormatInfoKHR"/>
+ <type name="VkVideoFormatPropertiesKHR"/>
+ <type name="VkVideoPictureResourceKHR"/>
+ <type name="VkVideoReferenceSlotKHR"/>
+ <type name="VkVideoGetMemoryPropertiesKHR"/>
+ <type name="VkVideoBindMemoryKHR"/>
+ <type name="VkVideoSessionCreateInfoKHR"/>
+ <type name="VkVideoSessionParametersCreateInfoKHR"/>
+ <type name="VkVideoSessionParametersUpdateInfoKHR"/>
+ <type name="VkVideoBeginCodingInfoKHR"/>
+ <type name="VkVideoEndCodingInfoKHR"/>
+ <type name="VkVideoCodingControlInfoKHR"/>
+
+ <command name="vkGetPhysicalDeviceVideoCapabilitiesKHR"/>
+ <command name="vkGetPhysicalDeviceVideoFormatPropertiesKHR"/>
+
+ <command name="vkCreateVideoSessionKHR"/>
+ <command name="vkDestroyVideoSessionKHR"/>
+ <command name="vkGetVideoSessionMemoryRequirementsKHR"/>
+ <command name="vkBindVideoSessionMemoryKHR"/>
+ <command name="vkCreateVideoSessionParametersKHR"/>
+ <command name="vkUpdateVideoSessionParametersKHR"/>
+ <command name="vkDestroyVideoSessionParametersKHR"/>
+ <command name="vkCmdBeginVideoCodingKHR"/>
+ <command name="vkCmdEndVideoCodingKHR"/>
+ <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">
+ <require>
+ <enum value="1" 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"/>
+
+ <type name="VkVideoDecodeFlagBitsKHR"/>
+ <type name="VkVideoDecodeFlagsKHR"/>
+
+ <type name="VkVideoDecodeInfoKHR"/>
+ <command name="vkCmdDecodeVideoKHR"/>
+ </require>
+ </extension>
+ <extension name="VK_AMD_gcn_shader" number="26" type="device" author="AMD" contact="Dominik Witczak @dominikwitczakamd" supported="vulkan">
+ <require>
+ <enum value="1" name="VK_AMD_GCN_SHADER_SPEC_VERSION"/>
+ <enum value="&quot;VK_AMD_gcn_shader&quot;" name="VK_AMD_GCN_SHADER_EXTENSION_NAME"/>
+ </require>
+ </extension>
+ <extension name="VK_NV_dedicated_allocation" number="27" type="device" author="NV" contact="Jeff Bolz @jeffbolznv" supported="vulkan" deprecatedby="VK_KHR_dedicated_allocation">
+ <require>
+ <enum value="1" name="VK_NV_DEDICATED_ALLOCATION_SPEC_VERSION"/>
+ <enum value="&quot;VK_NV_dedicated_allocation&quot;" name="VK_NV_DEDICATED_ALLOCATION_EXTENSION_NAME"/>
+ <enum offset="0" extends="VkStructureType" name="VK_STRUCTURE_TYPE_DEDICATED_ALLOCATION_IMAGE_CREATE_INFO_NV"/>
+ <enum offset="1" extends="VkStructureType" name="VK_STRUCTURE_TYPE_DEDICATED_ALLOCATION_BUFFER_CREATE_INFO_NV"/>
+ <enum offset="2" extends="VkStructureType" name="VK_STRUCTURE_TYPE_DEDICATED_ALLOCATION_MEMORY_ALLOCATE_INFO_NV"/>
+ <type name="VkDedicatedAllocationImageCreateInfoNV"/>
+ <type name="VkDedicatedAllocationBufferCreateInfoNV"/>
+ <type name="VkDedicatedAllocationMemoryAllocateInfoNV"/>
+ </require>
+ </extension>
+ <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"/>
+ </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">
+ <require>
+ <enum value="1" name="VK_EXT_TRANSFORM_FEEDBACK_SPEC_VERSION"/>
+ <enum value="&quot;VK_EXT_transform_feedback&quot;" name="VK_EXT_TRANSFORM_FEEDBACK_EXTENSION_NAME"/>
+ <command name="vkCmdBindTransformFeedbackBuffersEXT"/>
+ <command name="vkCmdBeginTransformFeedbackEXT"/>
+ <command name="vkCmdEndTransformFeedbackEXT"/>
+ <command name="vkCmdBeginQueryIndexedEXT"/>
+ <command name="vkCmdEndQueryIndexedEXT"/>
+ <command name="vkCmdDrawIndirectByteCountEXT"/>
+
+ <enum offset="0" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TRANSFORM_FEEDBACK_FEATURES_EXT"/>
+ <enum offset="1" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TRANSFORM_FEEDBACK_PROPERTIES_EXT"/>
+ <enum offset="2" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_STREAM_CREATE_INFO_EXT"/>
+
+ <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="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"/>
+ <enum bitpos="27" extends="VkAccessFlagBits" name="VK_ACCESS_TRANSFORM_FEEDBACK_COUNTER_WRITE_BIT_EXT"/>
+
+ <enum bitpos="24" extends="VkPipelineStageFlagBits" name="VK_PIPELINE_STAGE_TRANSFORM_FEEDBACK_BIT_EXT"/>
+
+ <type name="VkPhysicalDeviceTransformFeedbackFeaturesEXT"/>
+ <type name="VkPhysicalDeviceTransformFeedbackPropertiesEXT"/>
+ <type name="VkPipelineRasterizationStateStreamCreateInfoEXT"/>
+
+ <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">
+ <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"/>
+ <enum offset="0" extends="VkStructureType" name="VK_STRUCTURE_TYPE_CU_MODULE_CREATE_INFO_NVX"/>
+ <enum offset="1" extends="VkStructureType" name="VK_STRUCTURE_TYPE_CU_FUNCTION_CREATE_INFO_NVX"/>
+ <enum offset="2" extends="VkStructureType" name="VK_STRUCTURE_TYPE_CU_LAUNCH_INFO_NVX"/>
+ <enum offset="0" extends="VkObjectType" name="VK_OBJECT_TYPE_CU_MODULE_NVX"/>
+ <enum offset="1" extends="VkObjectType" name="VK_OBJECT_TYPE_CU_FUNCTION_NVX"/>
+ <enum offset="0" extends="VkDebugReportObjectTypeEXT" name="VK_DEBUG_REPORT_OBJECT_TYPE_CU_MODULE_NVX_EXT"/>
+ <enum offset="1" extends="VkDebugReportObjectTypeEXT" name="VK_DEBUG_REPORT_OBJECT_TYPE_CU_FUNCTION_NVX_EXT"/>
+ <type name="VkCuModuleNVX"/>
+ <type name="VkCuFunctionNVX"/>
+ <type name="VkCuModuleCreateInfoNVX"/>
+ <type name="VkCuFunctionCreateInfoNVX"/>
+ <type name="VkCuLaunchInfoNVX"/>
+ <command name="vkCreateCuModuleNVX"/>
+ <command name="vkCreateCuFunctionNVX"/>
+ <command name="vkDestroyCuModuleNVX"/>
+ <command name="vkDestroyCuFunctionNVX"/>
+ <command name="vkCmdCuLaunchKernelNVX"/>
+ </require>
+ </extension>
+ <extension name="VK_NVX_image_view_handle" number="31" type="device" author="NVX" contact="Eric Werness @ewerness" 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"/>
+ <enum offset="0" extends="VkStructureType" name="VK_STRUCTURE_TYPE_IMAGE_VIEW_HANDLE_INFO_NVX"/>
+ <enum offset="1" extends="VkStructureType" name="VK_STRUCTURE_TYPE_IMAGE_VIEW_ADDRESS_PROPERTIES_NVX"/>
+ <type name="VkImageViewHandleInfoNVX"/>
+ <type name="VkImageViewAddressPropertiesNVX"/>
+ <command name="vkGetImageViewHandleNVX"/>
+ <command name="vkGetImageViewAddressNVX"/>
+ </require>
+ </extension>
+ <extension name="VK_AMD_extension_32" number="32" author="AMD" contact="Daniel Rakos @drakos-amd" supported="disabled">
+ <require>
+ <enum value="0" name="VK_AMD_EXTENSION_32_SPEC_VERSION"/>
+ <enum value="&quot;VK_AMD_extension_32&quot;" name="VK_AMD_EXTENSION_32_EXTENSION_NAME"/>
+ </require>
+ </extension>
+ <extension name="VK_AMD_extension_33" number="33" author="AMD" contact="Daniel Rakos @drakos-amd" supported="disabled">
+ <require>
+ <enum value="0" name="VK_AMD_EXTENSION_33_SPEC_VERSION"/>
+ <enum value="&quot;VK_AMD_extension_33&quot;" name="VK_AMD_EXTENSION_33_EXTENSION_NAME"/>
+ </require>
+ </extension>
+ <extension name="VK_AMD_draw_indirect_count" number="34" type="device" author="AMD" contact="Daniel Rakos @drakos-amd" supported="vulkan" promotedto="VK_KHR_draw_indirect_count">
+ <require>
+ <enum value="2" name="VK_AMD_DRAW_INDIRECT_COUNT_SPEC_VERSION"/>
+ <enum value="&quot;VK_AMD_draw_indirect_count&quot;" name="VK_AMD_DRAW_INDIRECT_COUNT_EXTENSION_NAME"/>
+ <command name="vkCmdDrawIndirectCountAMD"/>
+ <command name="vkCmdDrawIndexedIndirectCountAMD"/>
+ </require>
+ </extension>
+ <extension name="VK_AMD_extension_35" number="35" author="AMD" contact="Daniel Rakos @drakos-amd" supported="disabled">
+ <require>
+ <enum value="0" name="VK_AMD_EXTENSION_35_SPEC_VERSION"/>
+ <enum value="&quot;VK_AMD_extension_35&quot;" name="VK_AMD_EXTENSION_35_EXTENSION_NAME"/>
+ </require>
+ </extension>
+ <extension name="VK_AMD_negative_viewport_height" number="36" type="device" author="AMD" contact="Matthaeus G. Chajdas @anteru" supported="vulkan" obsoletedby="VK_KHR_maintenance1">
+ <require>
+ <enum value="1" name="VK_AMD_NEGATIVE_VIEWPORT_HEIGHT_SPEC_VERSION"/>
+ <enum value="&quot;VK_AMD_negative_viewport_height&quot;" name="VK_AMD_NEGATIVE_VIEWPORT_HEIGHT_EXTENSION_NAME"/>
+ </require>
+ </extension>
+ <extension name="VK_AMD_gpu_shader_half_float" number="37" type="device" author="AMD" contact="Dominik Witczak @dominikwitczakamd" supported="vulkan" deprecatedby="VK_KHR_shader_float16_int8">
+ <require>
+ <enum value="2" name="VK_AMD_GPU_SHADER_HALF_FLOAT_SPEC_VERSION"/>
+ <enum value="&quot;VK_AMD_gpu_shader_half_float&quot;" name="VK_AMD_GPU_SHADER_HALF_FLOAT_EXTENSION_NAME"/>
+ </require>
+ </extension>
+ <extension name="VK_AMD_shader_ballot" number="38" type="device" author="AMD" contact="Dominik Witczak @dominikwitczakamd" supported="vulkan">
+ <require>
+ <enum value="1" name="VK_AMD_SHADER_BALLOT_SPEC_VERSION"/>
+ <enum value="&quot;VK_AMD_shader_ballot&quot;" name="VK_AMD_SHADER_BALLOT_EXTENSION_NAME"/>
+ </require>
+ </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="&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 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="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="VkVideoEncodeH264DpbSlotInfoEXT"/>
+ <type name="VkVideoEncodeH264NaluSliceEXT"/>
+ <type name="VkVideoEncodeH264ProfileEXT"/>
+ </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">
+ <require>
+ <enum value="0" 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"/>
+
+ <type name="VkVideoDecodeH264MvcEXT"/>
+ <type name="VkVideoDecodeH264DpbSlotInfoEXT"/>
+ </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">
+ <require>
+ <enum value="1" name="VK_AMD_TEXTURE_GATHER_BIAS_LOD_SPEC_VERSION"/>
+ <enum value="&quot;VK_AMD_texture_gather_bias_lod&quot;" name="VK_AMD_TEXTURE_GATHER_BIAS_LOD_EXTENSION_NAME"/>
+ <enum offset="0" extends="VkStructureType" name="VK_STRUCTURE_TYPE_TEXTURE_LOD_GATHER_FORMAT_PROPERTIES_AMD"/>
+ <type name="VkTextureLODGatherFormatPropertiesAMD"/>
+ </require>
+ </extension>
+ <extension name="VK_AMD_shader_info" number="43" author="AMD" contact="Jaakko Konttinen @jaakkoamd" supported="vulkan" specialuse="devtools" type="device">
+ <require>
+ <enum value="1" name="VK_AMD_SHADER_INFO_SPEC_VERSION"/>
+ <enum value="&quot;VK_AMD_shader_info&quot;" name="VK_AMD_SHADER_INFO_EXTENSION_NAME"/>
+ <type name="VkShaderInfoTypeAMD"/>
+ <type name="VkShaderResourceUsageAMD"/>
+ <type name="VkShaderStatisticsInfoAMD"/>
+ <command name="vkGetShaderInfoAMD"/>
+ </require>
+ </extension>
+ <extension name="VK_AMD_extension_44" number="44" author="AMD" contact="Daniel Rakos @drakos-amd" supported="disabled">
+ <require>
+ <enum value="0" name="VK_AMD_EXTENSION_44_SPEC_VERSION"/>
+ <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"/>
+ </require>
+ </extension>
+ <extension name="VK_AMD_extension_46" number="46" author="AMD" contact="Daniel Rakos @drakos-amd" supported="disabled">
+ <require>
+ <enum value="0" name="VK_AMD_EXTENSION_46_SPEC_VERSION"/>
+ <enum value="&quot;VK_AMD_extension_46&quot;" name="VK_AMD_EXTENSION_46_EXTENSION_NAME"/>
+ </require>
+ </extension>
+ <extension name="VK_AMD_shader_image_load_store_lod" number="47" author="AMD" contact="Dominik Witczak @dominikwitczakamd" supported="vulkan" type="device">
+ <require>
+ <enum value="1" name="VK_AMD_SHADER_IMAGE_LOAD_STORE_LOD_SPEC_VERSION"/>
+ <enum value="&quot;VK_AMD_shader_image_load_store_lod&quot;" name="VK_AMD_SHADER_IMAGE_LOAD_STORE_LOD_EXTENSION_NAME"/>
+ </require>
+ </extension>
+ <extension name="VK_NVX_extension_48" number="48" author="NVX" contact="James Jones @cubanismo" supported="disabled">
+ <require>
+ <enum value="0" name="VK_NVX_EXTENSION_48_SPEC_VERSION"/>
+ <enum value="&quot;VK_NVX_extension_48&quot;" name="VK_NVX_EXTENSION_48_EXTENSION_NAME"/>
+ </require>
+ </extension>
+ <extension name="VK_GOOGLE_extension_49" number="49" author="GOOGLE" contact="Jean-Francois Roy @jfroy" supported="disabled">
+ <require>
+ <enum value="0" name="VK_GOOGLE_EXTENSION_49_SPEC_VERSION"/>
+ <enum value="&quot;VK_GOOGLE_extension_49&quot;" name="VK_GOOGLE_EXTENSION_49_EXTENSION_NAME"/>
+ </require>
+ </extension>
+ <extension name="VK_GGP_stream_descriptor_surface" number="50" type="instance" requires="VK_KHR_surface" platform="ggp" author="GGP" contact="Jean-Francois Roy @jfroy" supported="vulkan">
+ <require>
+ <enum value="1" name="VK_GGP_STREAM_DESCRIPTOR_SURFACE_SPEC_VERSION"/>
+ <enum value="&quot;VK_GGP_stream_descriptor_surface&quot;" name="VK_GGP_STREAM_DESCRIPTOR_SURFACE_EXTENSION_NAME"/>
+ <enum offset="0" extends="VkStructureType" name="VK_STRUCTURE_TYPE_STREAM_DESCRIPTOR_SURFACE_CREATE_INFO_GGP"/>
+ <type name="VkStreamDescriptorSurfaceCreateFlagsGGP"/>
+ <type name="VkStreamDescriptorSurfaceCreateInfoGGP"/>
+ <command name="vkCreateStreamDescriptorSurfaceGGP"/>
+ </require>
+ </extension>
+ <extension name="VK_NV_corner_sampled_image" number="51" author="NV" type="device" requires="VK_KHR_get_physical_device_properties2" contact="Daniel Koch @dgkoch" supported="vulkan">
+ <require>
+ <enum value="2" name="VK_NV_CORNER_SAMPLED_IMAGE_SPEC_VERSION"/>
+ <enum value="&quot;VK_NV_corner_sampled_image&quot;" name="VK_NV_CORNER_SAMPLED_IMAGE_EXTENSION_NAME"/>
+ <enum bitpos="13" extends="VkImageCreateFlagBits" name="VK_IMAGE_CREATE_CORNER_SAMPLED_BIT_NV"/>
+ <enum offset="0" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CORNER_SAMPLED_IMAGE_FEATURES_NV"/>
+ <type name="VkPhysicalDeviceCornerSampledImageFeaturesNV"/>
+ </require>
+ </extension>
+ <extension name="VK_NV_extension_52" number="52" author="NV" contact="Daniel Koch @dgkoch" supported="disabled">
+ <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">
+ <require>
+ <enum value="0" name="VK_NV_EXTENSION_53_SPEC_VERSION"/>
+ <enum value="&quot;VK_NV_extension_53&quot;" name="VK_NV_EXTENSION_53_EXTENSION_NAME"/>
+ </require>
+ </extension>
+ <extension name="VK_KHR_multiview" number="54" type="device" author="KHR" requires="VK_KHR_get_physical_device_properties2" contact="Jeff Bolz @jeffbolznv" supported="vulkan" promotedto="VK_VERSION_1_1">
+ <require>
+ <enum value="1" name="VK_KHR_MULTIVIEW_SPEC_VERSION"/>
+ <enum value="&quot;VK_KHR_multiview&quot;" name="VK_KHR_MULTIVIEW_EXTENSION_NAME"/>
+ <enum extends="VkStructureType" name="VK_STRUCTURE_TYPE_RENDER_PASS_MULTIVIEW_CREATE_INFO_KHR" alias="VK_STRUCTURE_TYPE_RENDER_PASS_MULTIVIEW_CREATE_INFO"/>
+ <enum extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_FEATURES_KHR" alias="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_FEATURES"/>
+ <enum extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_PROPERTIES_KHR" alias="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_PROPERTIES"/>
+ <enum extends="VkDependencyFlagBits" name="VK_DEPENDENCY_VIEW_LOCAL_BIT_KHR" alias="VK_DEPENDENCY_VIEW_LOCAL_BIT"/>
+ <type name="VkRenderPassMultiviewCreateInfoKHR"/>
+ <type name="VkPhysicalDeviceMultiviewFeaturesKHR"/>
+ <type name="VkPhysicalDeviceMultiviewPropertiesKHR"/>
+ </require>
+ </extension>
+ <extension name="VK_IMG_format_pvrtc" number="55" type="device" author="IMG" contact="Stuart Smith" supported="vulkan">
+ <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"/>
+ <enum offset="0" extends="VkFormat" name="VK_FORMAT_PVRTC1_2BPP_UNORM_BLOCK_IMG"/>
+ <enum offset="1" extends="VkFormat" name="VK_FORMAT_PVRTC1_4BPP_UNORM_BLOCK_IMG"/>
+ <enum offset="2" extends="VkFormat" name="VK_FORMAT_PVRTC2_2BPP_UNORM_BLOCK_IMG"/>
+ <enum offset="3" extends="VkFormat" name="VK_FORMAT_PVRTC2_4BPP_UNORM_BLOCK_IMG"/>
+ <enum offset="4" extends="VkFormat" name="VK_FORMAT_PVRTC1_2BPP_SRGB_BLOCK_IMG"/>
+ <enum offset="5" extends="VkFormat" name="VK_FORMAT_PVRTC1_4BPP_SRGB_BLOCK_IMG"/>
+ <enum offset="6" extends="VkFormat" name="VK_FORMAT_PVRTC2_2BPP_SRGB_BLOCK_IMG"/>
+ <enum offset="7" extends="VkFormat" name="VK_FORMAT_PVRTC2_4BPP_SRGB_BLOCK_IMG"/>
+ </require>
+ </extension>
+ <extension name="VK_NV_external_memory_capabilities" number="56" type="instance" author="NV" contact="James Jones @cubanismo" supported="vulkan" deprecatedby="VK_KHR_external_memory_capabilities">
+ <require>
+ <enum value="1" name="VK_NV_EXTERNAL_MEMORY_CAPABILITIES_SPEC_VERSION"/>
+ <enum value="&quot;VK_NV_external_memory_capabilities&quot;" name="VK_NV_EXTERNAL_MEMORY_CAPABILITIES_EXTENSION_NAME"/>
+ <type name="VkExternalMemoryHandleTypeFlagsNV"/>
+ <type name="VkExternalMemoryHandleTypeFlagBitsNV"/>
+ <type name="VkExternalMemoryFeatureFlagsNV"/>
+ <type name="VkExternalMemoryFeatureFlagBitsNV"/>
+ <type name="VkExternalImageFormatPropertiesNV"/>
+ <command name="vkGetPhysicalDeviceExternalImageFormatPropertiesNV"/>
+ </require>
+ </extension>
+ <extension name="VK_NV_external_memory" number="57" type="device" requires="VK_NV_external_memory_capabilities" author="NV" contact="James Jones @cubanismo" supported="vulkan" deprecatedby="VK_KHR_external_memory">
+ <require>
+ <enum value="1" name="VK_NV_EXTERNAL_MEMORY_SPEC_VERSION"/>
+ <enum value="&quot;VK_NV_external_memory&quot;" name="VK_NV_EXTERNAL_MEMORY_EXTENSION_NAME"/>
+ <enum offset="0" extends="VkStructureType" name="VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO_NV"/>
+ <enum offset="1" extends="VkStructureType" name="VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO_NV"/>
+ <type name="VkExternalMemoryImageCreateInfoNV"/>
+ <type name="VkExportMemoryAllocateInfoNV"/>
+ </require>
+ </extension>
+ <extension name="VK_NV_external_memory_win32" number="58" type="device" requires="VK_NV_external_memory" author="NV" contact="James Jones @cubanismo" platform="win32" supported="vulkan" deprecatedby="VK_KHR_external_memory_win32">
+ <require>
+ <enum value="1" name="VK_NV_EXTERNAL_MEMORY_WIN32_SPEC_VERSION"/>
+ <enum value="&quot;VK_NV_external_memory_win32&quot;" name="VK_NV_EXTERNAL_MEMORY_WIN32_EXTENSION_NAME"/>
+ <enum offset="0" extends="VkStructureType" name="VK_STRUCTURE_TYPE_IMPORT_MEMORY_WIN32_HANDLE_INFO_NV"/>
+ <enum offset="1" extends="VkStructureType" name="VK_STRUCTURE_TYPE_EXPORT_MEMORY_WIN32_HANDLE_INFO_NV"/>
+ <type name="VkImportMemoryWin32HandleInfoNV"/>
+ <type name="VkExportMemoryWin32HandleInfoNV"/>
+ <command name="vkGetMemoryWin32HandleNV"/>
+ </require>
+ </extension>
+ <extension name="VK_NV_win32_keyed_mutex" number="59" type="device" requires="VK_NV_external_memory_win32" author="NV" contact="Carsten Rohde @crohde" platform="win32" supported="vulkan" promotedto="VK_KHR_win32_keyed_mutex">
+ <require>
+ <enum value="2" name="VK_NV_WIN32_KEYED_MUTEX_SPEC_VERSION"/>
+ <enum value="&quot;VK_NV_win32_keyed_mutex&quot;" name="VK_NV_WIN32_KEYED_MUTEX_EXTENSION_NAME"/>
+ <enum offset="0" extends="VkStructureType" name="VK_STRUCTURE_TYPE_WIN32_KEYED_MUTEX_ACQUIRE_RELEASE_INFO_NV"/>
+ <type name="VkWin32KeyedMutexAcquireReleaseInfoNV"/>
+ </require>
+ </extension>
+ <extension name="VK_KHR_get_physical_device_properties2" number="60" type="instance" author="KHR" contact="Jeff Bolz @jeffbolznv" supported="vulkan" promotedto="VK_VERSION_1_1">
+ <require>
+ <enum value="2" name="VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_SPEC_VERSION"/>
+ <enum value="&quot;VK_KHR_get_physical_device_properties2&quot;" name="VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME"/>
+ <enum extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2_KHR" alias="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2"/>
+ <enum extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2_KHR" alias="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2"/>
+ <enum extends="VkStructureType" name="VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2_KHR" alias="VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2"/>
+ <enum extends="VkStructureType" name="VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2_KHR" alias="VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2"/>
+ <enum extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2_KHR" alias="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2"/>
+ <enum extends="VkStructureType" name="VK_STRUCTURE_TYPE_QUEUE_FAMILY_PROPERTIES_2_KHR" alias="VK_STRUCTURE_TYPE_QUEUE_FAMILY_PROPERTIES_2"/>
+ <enum extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_PROPERTIES_2_KHR" alias="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_PROPERTIES_2"/>
+ <enum extends="VkStructureType" name="VK_STRUCTURE_TYPE_SPARSE_IMAGE_FORMAT_PROPERTIES_2_KHR" alias="VK_STRUCTURE_TYPE_SPARSE_IMAGE_FORMAT_PROPERTIES_2"/>
+ <enum extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SPARSE_IMAGE_FORMAT_INFO_2_KHR" alias="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SPARSE_IMAGE_FORMAT_INFO_2"/>
+ <type name="VkPhysicalDeviceFeatures2KHR"/>
+ <type name="VkPhysicalDeviceProperties2KHR"/>
+ <type name="VkFormatProperties2KHR"/>
+ <type name="VkImageFormatProperties2KHR"/>
+ <type name="VkPhysicalDeviceImageFormatInfo2KHR"/>
+ <type name="VkQueueFamilyProperties2KHR"/>
+ <type name="VkPhysicalDeviceMemoryProperties2KHR"/>
+ <type name="VkSparseImageFormatProperties2KHR"/>
+ <type name="VkPhysicalDeviceSparseImageFormatInfo2KHR"/>
+ <command name="vkGetPhysicalDeviceFeatures2KHR"/>
+ <command name="vkGetPhysicalDeviceProperties2KHR"/>
+ <command name="vkGetPhysicalDeviceFormatProperties2KHR"/>
+ <command name="vkGetPhysicalDeviceImageFormatProperties2KHR"/>
+ <command name="vkGetPhysicalDeviceQueueFamilyProperties2KHR"/>
+ <command name="vkGetPhysicalDeviceMemoryProperties2KHR"/>
+ <command name="vkGetPhysicalDeviceSparseImageFormatProperties2KHR"/>
+ </require>
+ </extension>
+ <extension name="VK_KHR_device_group" number="61" type="device" author="KHR" requires="VK_KHR_device_group_creation" contact="Jeff Bolz @jeffbolznv" supported="vulkan" promotedto="VK_VERSION_1_1">
+ <require>
+ <enum value="4" name="VK_KHR_DEVICE_GROUP_SPEC_VERSION"/>
+ <enum value="&quot;VK_KHR_device_group&quot;" name="VK_KHR_DEVICE_GROUP_EXTENSION_NAME"/>
+ <enum extends="VkStructureType" name="VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_FLAGS_INFO_KHR" alias="VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_FLAGS_INFO"/>
+ <enum extends="VkStructureType" name="VK_STRUCTURE_TYPE_DEVICE_GROUP_RENDER_PASS_BEGIN_INFO_KHR" alias="VK_STRUCTURE_TYPE_DEVICE_GROUP_RENDER_PASS_BEGIN_INFO"/>
+ <enum extends="VkStructureType" name="VK_STRUCTURE_TYPE_DEVICE_GROUP_COMMAND_BUFFER_BEGIN_INFO_KHR" alias="VK_STRUCTURE_TYPE_DEVICE_GROUP_COMMAND_BUFFER_BEGIN_INFO"/>
+ <enum extends="VkStructureType" name="VK_STRUCTURE_TYPE_DEVICE_GROUP_SUBMIT_INFO_KHR" alias="VK_STRUCTURE_TYPE_DEVICE_GROUP_SUBMIT_INFO"/>
+ <enum extends="VkStructureType" name="VK_STRUCTURE_TYPE_DEVICE_GROUP_BIND_SPARSE_INFO_KHR" alias="VK_STRUCTURE_TYPE_DEVICE_GROUP_BIND_SPARSE_INFO"/>
+ <type name="VkPeerMemoryFeatureFlagsKHR"/>
+ <type name="VkPeerMemoryFeatureFlagBitsKHR"/>
+ <enum extends="VkPeerMemoryFeatureFlagBits" name="VK_PEER_MEMORY_FEATURE_COPY_SRC_BIT_KHR" alias="VK_PEER_MEMORY_FEATURE_COPY_SRC_BIT"/>
+ <enum extends="VkPeerMemoryFeatureFlagBits" name="VK_PEER_MEMORY_FEATURE_COPY_DST_BIT_KHR" alias="VK_PEER_MEMORY_FEATURE_COPY_DST_BIT"/>
+ <enum extends="VkPeerMemoryFeatureFlagBits" name="VK_PEER_MEMORY_FEATURE_GENERIC_SRC_BIT_KHR" alias="VK_PEER_MEMORY_FEATURE_GENERIC_SRC_BIT"/>
+ <enum extends="VkPeerMemoryFeatureFlagBits" name="VK_PEER_MEMORY_FEATURE_GENERIC_DST_BIT_KHR" alias="VK_PEER_MEMORY_FEATURE_GENERIC_DST_BIT"/>
+ <type name="VkMemoryAllocateFlagsKHR"/>
+ <type name="VkMemoryAllocateFlagBitsKHR"/>
+ <enum extends="VkMemoryAllocateFlagBits" name="VK_MEMORY_ALLOCATE_DEVICE_MASK_BIT_KHR" alias="VK_MEMORY_ALLOCATE_DEVICE_MASK_BIT"/>
+ <type name="VkMemoryAllocateFlagsInfoKHR"/>
+ <type name="VkDeviceGroupRenderPassBeginInfoKHR"/>
+ <type name="VkDeviceGroupCommandBufferBeginInfoKHR"/>
+ <type name="VkDeviceGroupSubmitInfoKHR"/>
+ <type name="VkDeviceGroupBindSparseInfoKHR"/>
+ <command name="vkGetDeviceGroupPeerMemoryFeaturesKHR"/>
+ <command name="vkCmdSetDeviceMaskKHR"/>
+ <command name="vkCmdDispatchBaseKHR"/>
+ <enum extends="VkPipelineCreateFlagBits" name="VK_PIPELINE_CREATE_VIEW_INDEX_FROM_DEVICE_INDEX_BIT_KHR" alias="VK_PIPELINE_CREATE_VIEW_INDEX_FROM_DEVICE_INDEX_BIT"/>
+ <enum extends="VkPipelineCreateFlagBits" name="VK_PIPELINE_CREATE_DISPATCH_BASE_KHR" alias="VK_PIPELINE_CREATE_DISPATCH_BASE"/>
+ <enum extends="VkDependencyFlagBits" name="VK_DEPENDENCY_DEVICE_GROUP_BIT_KHR" alias="VK_DEPENDENCY_DEVICE_GROUP_BIT"/>
+ </require>
+ <require extension="VK_KHR_bind_memory2">
+ <enum extends="VkStructureType" name="VK_STRUCTURE_TYPE_BIND_BUFFER_MEMORY_DEVICE_GROUP_INFO_KHR" alias="VK_STRUCTURE_TYPE_BIND_BUFFER_MEMORY_DEVICE_GROUP_INFO"/>
+ <enum extends="VkStructureType" name="VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_DEVICE_GROUP_INFO_KHR" alias="VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_DEVICE_GROUP_INFO"/>
+ <type name="VkBindBufferMemoryDeviceGroupInfoKHR"/>
+ <type name="VkBindImageMemoryDeviceGroupInfoKHR"/>
+ <enum extends="VkImageCreateFlagBits" name="VK_IMAGE_CREATE_SPLIT_INSTANCE_BIND_REGIONS_BIT_KHR" alias="VK_IMAGE_CREATE_SPLIT_INSTANCE_BIND_REGIONS_BIT"/>
+ </require>
+ <require extension="VK_KHR_surface">
+ <enum offset="7" extends="VkStructureType" name="VK_STRUCTURE_TYPE_DEVICE_GROUP_PRESENT_CAPABILITIES_KHR"/>
+ <type name="VkDeviceGroupPresentModeFlagBitsKHR"/>
+ <type name="VkDeviceGroupPresentModeFlagsKHR"/>
+ <type name="VkDeviceGroupPresentCapabilitiesKHR"/>
+ <command name="vkGetDeviceGroupPresentCapabilitiesKHR"/>
+ <command name="vkGetDeviceGroupSurfacePresentModesKHR"/>
+ <command name="vkGetPhysicalDevicePresentRectanglesKHR"/>
+ </require>
+ <require extension="VK_KHR_swapchain">
+ <enum offset="8" extends="VkStructureType" name="VK_STRUCTURE_TYPE_IMAGE_SWAPCHAIN_CREATE_INFO_KHR"/>
+ <enum offset="9" extends="VkStructureType" name="VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_SWAPCHAIN_INFO_KHR"/>
+ <enum offset="10" extends="VkStructureType" name="VK_STRUCTURE_TYPE_ACQUIRE_NEXT_IMAGE_INFO_KHR"/>
+ <enum offset="11" extends="VkStructureType" name="VK_STRUCTURE_TYPE_DEVICE_GROUP_PRESENT_INFO_KHR"/>
+ <enum offset="12" extends="VkStructureType" name="VK_STRUCTURE_TYPE_DEVICE_GROUP_SWAPCHAIN_CREATE_INFO_KHR"/>
+ <enum bitpos="0" extends="VkSwapchainCreateFlagBitsKHR" name="VK_SWAPCHAIN_CREATE_SPLIT_INSTANCE_BIND_REGIONS_BIT_KHR" comment="Allow images with VK_IMAGE_CREATE_SPLIT_INSTANCE_BIND_REGIONS_BIT"/>
+ <type name="VkImageSwapchainCreateInfoKHR"/>
+ <type name="VkBindImageMemorySwapchainInfoKHR"/>
+ <type name="VkAcquireNextImageInfoKHR"/>
+ <type name="VkDeviceGroupPresentInfoKHR"/>
+ <type name="VkDeviceGroupSwapchainCreateInfoKHR"/>
+ <command name="vkAcquireNextImage2KHR"/>
+ </require>
+ </extension>
+ <extension name="VK_EXT_validation_flags" number="62" type="instance" author="GOOGLE" contact="Tobin Ehlis @tobine" specialuse="debugging" supported="vulkan" deprecatedby="VK_EXT_validation_features">
+ <require>
+ <enum value="2" name="VK_EXT_VALIDATION_FLAGS_SPEC_VERSION"/>
+ <enum value="&quot;VK_EXT_validation_flags&quot;" name="VK_EXT_VALIDATION_FLAGS_EXTENSION_NAME"/>
+ <enum offset="0" extends="VkStructureType" name="VK_STRUCTURE_TYPE_VALIDATION_FLAGS_EXT"/>
+ <type name="VkValidationFlagsEXT"/>
+ <type name="VkValidationCheckEXT"/>
+ </require>
+ </extension>
+ <extension name="VK_NN_vi_surface" number="63" type="instance" author="NN" contact="Mathias Heyer gitlab:@mheyer" requires="VK_KHR_surface" platform="vi" supported="vulkan">
+ <require>
+ <enum value="1" name="VK_NN_VI_SURFACE_SPEC_VERSION"/>
+ <enum value="&quot;VK_NN_vi_surface&quot;" name="VK_NN_VI_SURFACE_EXTENSION_NAME"/>
+ <enum offset="0" extends="VkStructureType" name="VK_STRUCTURE_TYPE_VI_SURFACE_CREATE_INFO_NN"/>
+ <type name="VkViSurfaceCreateFlagsNN"/>
+ <type name="VkViSurfaceCreateInfoNN"/>
+ <command name="vkCreateViSurfaceNN"/>
+ </require>
+ </extension>
+ <extension name="VK_KHR_shader_draw_parameters" number="64" type="device" author="KHR" contact="Daniel Koch @dgkoch" supported="vulkan" promotedto="VK_VERSION_1_1">
+ <require>
+ <enum value="1" name="VK_KHR_SHADER_DRAW_PARAMETERS_SPEC_VERSION"/>
+ <enum value="&quot;VK_KHR_shader_draw_parameters&quot;" name="VK_KHR_SHADER_DRAW_PARAMETERS_EXTENSION_NAME"/>
+ </require>
+ </extension>
+ <extension name="VK_EXT_shader_subgroup_ballot" number="65" type="device" author="NV" contact="Daniel Koch @dgkoch" supported="vulkan" deprecatedby="VK_VERSION_1_2">
+ <require>
+ <enum value="1" name="VK_EXT_SHADER_SUBGROUP_BALLOT_SPEC_VERSION"/>
+ <enum value="&quot;VK_EXT_shader_subgroup_ballot&quot;" name="VK_EXT_SHADER_SUBGROUP_BALLOT_EXTENSION_NAME"/>
+ </require>
+ </extension>
+ <extension name="VK_EXT_shader_subgroup_vote" number="66" type="device" author="NV" contact="Daniel Koch @dgkoch" supported="vulkan" deprecatedby="VK_VERSION_1_1">
+ <require>
+ <enum value="1" name="VK_EXT_SHADER_SUBGROUP_VOTE_SPEC_VERSION"/>
+ <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">
+ <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"/>
+ <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"/>
+ </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"/>
+ <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">
+ <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"/>
+ </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 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"/>
+ <enum extends="VkImageCreateFlagBits" name="VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT_KHR" alias="VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT"/>
+ <type name="VkCommandPoolTrimFlagsKHR"/>
+ <command name="vkTrimCommandPoolKHR"/>
+ </require>
+ </extension>
+ <extension name="VK_KHR_device_group_creation" number="71" type="instance" author="KHR" contact="Jeff Bolz @jeffbolznv" supported="vulkan" promotedto="VK_VERSION_1_1">
+ <require>
+ <enum value="1" name="VK_KHR_DEVICE_GROUP_CREATION_SPEC_VERSION"/>
+ <enum value="&quot;VK_KHR_device_group_creation&quot;" name="VK_KHR_DEVICE_GROUP_CREATION_EXTENSION_NAME"/>
+ <enum extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_GROUP_PROPERTIES_KHR" alias="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_GROUP_PROPERTIES"/>
+ <enum extends="VkStructureType" name="VK_STRUCTURE_TYPE_DEVICE_GROUP_DEVICE_CREATE_INFO_KHR" alias="VK_STRUCTURE_TYPE_DEVICE_GROUP_DEVICE_CREATE_INFO"/>
+ <enum name="VK_MAX_DEVICE_GROUP_SIZE_KHR"/>
+ <type name="VkPhysicalDeviceGroupPropertiesKHR"/>
+ <type name="VkDeviceGroupDeviceCreateInfoKHR"/>
+ <command name="vkEnumeratePhysicalDeviceGroupsKHR"/>
+ <enum extends="VkMemoryHeapFlagBits" name="VK_MEMORY_HEAP_MULTI_INSTANCE_BIT_KHR" alias="VK_MEMORY_HEAP_MULTI_INSTANCE_BIT"/>
+ </require>
+ </extension>
+ <extension name="VK_KHR_external_memory_capabilities" number="72" type="instance" author="KHR" requires="VK_KHR_get_physical_device_properties2" contact="James Jones @cubanismo" supported="vulkan" promotedto="VK_VERSION_1_1">
+ <require>
+ <enum value="1" name="VK_KHR_EXTERNAL_MEMORY_CAPABILITIES_SPEC_VERSION"/>
+ <enum value="&quot;VK_KHR_external_memory_capabilities&quot;" name="VK_KHR_EXTERNAL_MEMORY_CAPABILITIES_EXTENSION_NAME"/>
+ <enum extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_IMAGE_FORMAT_INFO_KHR" alias="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_IMAGE_FORMAT_INFO"/>
+ <enum extends="VkStructureType" name="VK_STRUCTURE_TYPE_EXTERNAL_IMAGE_FORMAT_PROPERTIES_KHR" alias="VK_STRUCTURE_TYPE_EXTERNAL_IMAGE_FORMAT_PROPERTIES"/>
+ <enum extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_BUFFER_INFO_KHR" alias="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_BUFFER_INFO"/>
+ <enum extends="VkStructureType" name="VK_STRUCTURE_TYPE_EXTERNAL_BUFFER_PROPERTIES_KHR" alias="VK_STRUCTURE_TYPE_EXTERNAL_BUFFER_PROPERTIES"/>
+ <enum extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ID_PROPERTIES_KHR" alias="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ID_PROPERTIES"/>
+ <enum name="VK_LUID_SIZE_KHR"/>
+ <type name="VkExternalMemoryHandleTypeFlagsKHR"/>
+ <type name="VkExternalMemoryHandleTypeFlagBitsKHR"/>
+ <enum extends="VkExternalMemoryHandleTypeFlagBits" name="VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT_KHR" alias="VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT"/>
+ <enum extends="VkExternalMemoryHandleTypeFlagBits" name="VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT_KHR" alias="VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT"/>
+ <enum extends="VkExternalMemoryHandleTypeFlagBits" name="VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT_KHR" alias="VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT"/>
+ <enum extends="VkExternalMemoryHandleTypeFlagBits" name="VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_TEXTURE_BIT_KHR" alias="VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_TEXTURE_BIT"/>
+ <enum extends="VkExternalMemoryHandleTypeFlagBits" name="VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_TEXTURE_KMT_BIT_KHR" alias="VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_TEXTURE_KMT_BIT"/>
+ <enum extends="VkExternalMemoryHandleTypeFlagBits" name="VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D12_HEAP_BIT_KHR" alias="VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D12_HEAP_BIT"/>
+ <enum extends="VkExternalMemoryHandleTypeFlagBits" name="VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D12_RESOURCE_BIT_KHR" alias="VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D12_RESOURCE_BIT"/>
+ <type name="VkExternalMemoryFeatureFlagsKHR"/>
+ <type name="VkExternalMemoryFeatureFlagBitsKHR"/>
+ <enum extends="VkExternalMemoryFeatureFlagBits" name="VK_EXTERNAL_MEMORY_FEATURE_DEDICATED_ONLY_BIT_KHR" alias="VK_EXTERNAL_MEMORY_FEATURE_DEDICATED_ONLY_BIT"/>
+ <enum extends="VkExternalMemoryFeatureFlagBits" name="VK_EXTERNAL_MEMORY_FEATURE_EXPORTABLE_BIT_KHR" alias="VK_EXTERNAL_MEMORY_FEATURE_EXPORTABLE_BIT"/>
+ <enum extends="VkExternalMemoryFeatureFlagBits" name="VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT_KHR" alias="VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT"/>
+ <type name="VkExternalMemoryPropertiesKHR"/>
+ <type name="VkPhysicalDeviceExternalImageFormatInfoKHR"/>
+ <type name="VkExternalImageFormatPropertiesKHR"/>
+ <type name="VkPhysicalDeviceExternalBufferInfoKHR"/>
+ <type name="VkExternalBufferPropertiesKHR"/>
+ <type name="VkPhysicalDeviceIDPropertiesKHR"/>
+ <command name="vkGetPhysicalDeviceExternalBufferPropertiesKHR"/>
+ </require>
+ </extension>
+ <extension name="VK_KHR_external_memory" number="73" type="device" requires="VK_KHR_external_memory_capabilities" author="KHR" contact="James Jones @cubanismo" supported="vulkan" promotedto="VK_VERSION_1_1">
+ <require>
+ <enum value="1" name="VK_KHR_EXTERNAL_MEMORY_SPEC_VERSION"/>
+ <enum value="&quot;VK_KHR_external_memory&quot;" name="VK_KHR_EXTERNAL_MEMORY_EXTENSION_NAME"/>
+ <enum extends="VkStructureType" name="VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_BUFFER_CREATE_INFO_KHR" alias="VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_BUFFER_CREATE_INFO"/>
+ <enum extends="VkStructureType" name="VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO_KHR" alias="VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO"/>
+ <enum extends="VkStructureType" name="VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO_KHR" alias="VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO"/>
+ <enum extends="VkResult" name="VK_ERROR_INVALID_EXTERNAL_HANDLE_KHR" alias="VK_ERROR_INVALID_EXTERNAL_HANDLE"/>
+ <enum name="VK_QUEUE_FAMILY_EXTERNAL_KHR"/>
+ <type name="VkExternalMemoryImageCreateInfoKHR"/>
+ <type name="VkExternalMemoryBufferCreateInfoKHR"/>
+ <type name="VkExportMemoryAllocateInfoKHR"/>
+ </require>
+ </extension>
+ <extension name="VK_KHR_external_memory_win32" number="74" type="device" requires="VK_KHR_external_memory" author="KHR" contact="James Jones @cubanismo" platform="win32" supported="vulkan">
+ <require>
+ <enum value="1" name="VK_KHR_EXTERNAL_MEMORY_WIN32_SPEC_VERSION"/>
+ <enum value="&quot;VK_KHR_external_memory_win32&quot;" name="VK_KHR_EXTERNAL_MEMORY_WIN32_EXTENSION_NAME"/>
+ <enum offset="0" extends="VkStructureType" name="VK_STRUCTURE_TYPE_IMPORT_MEMORY_WIN32_HANDLE_INFO_KHR"/>
+ <enum offset="1" extends="VkStructureType" name="VK_STRUCTURE_TYPE_EXPORT_MEMORY_WIN32_HANDLE_INFO_KHR"/>
+ <enum offset="2" extends="VkStructureType" name="VK_STRUCTURE_TYPE_MEMORY_WIN32_HANDLE_PROPERTIES_KHR"/>
+ <enum offset="3" extends="VkStructureType" name="VK_STRUCTURE_TYPE_MEMORY_GET_WIN32_HANDLE_INFO_KHR"/>
+ <type name="VkImportMemoryWin32HandleInfoKHR"/>
+ <type name="VkExportMemoryWin32HandleInfoKHR"/>
+ <type name="VkMemoryWin32HandlePropertiesKHR"/>
+ <type name="VkMemoryGetWin32HandleInfoKHR"/>
+ <command name="vkGetMemoryWin32HandleKHR"/>
+ <command name="vkGetMemoryWin32HandlePropertiesKHR"/>
+ </require>
+ </extension>
+ <extension name="VK_KHR_external_memory_fd" number="75" type="device" requires="VK_KHR_external_memory" author="KHR" contact="James Jones @cubanismo" supported="vulkan">
+ <require>
+ <enum value="1" name="VK_KHR_EXTERNAL_MEMORY_FD_SPEC_VERSION"/>
+ <enum value="&quot;VK_KHR_external_memory_fd&quot;" name="VK_KHR_EXTERNAL_MEMORY_FD_EXTENSION_NAME"/>
+ <enum offset="0" extends="VkStructureType" name="VK_STRUCTURE_TYPE_IMPORT_MEMORY_FD_INFO_KHR"/>
+ <enum offset="1" extends="VkStructureType" name="VK_STRUCTURE_TYPE_MEMORY_FD_PROPERTIES_KHR"/>
+ <enum offset="2" extends="VkStructureType" name="VK_STRUCTURE_TYPE_MEMORY_GET_FD_INFO_KHR"/>
+ <type name="VkImportMemoryFdInfoKHR"/>
+ <type name="VkMemoryFdPropertiesKHR"/>
+ <type name="VkMemoryGetFdInfoKHR"/>
+ <command name="vkGetMemoryFdKHR"/>
+ <command name="vkGetMemoryFdPropertiesKHR"/>
+ </require>
+ </extension>
+ <extension name="VK_KHR_win32_keyed_mutex" number="76" type="device" requires="VK_KHR_external_memory_win32" author="KHR" contact="Carsten Rohde @crohde" platform="win32" supported="vulkan">
+ <require>
+ <enum value="1" name="VK_KHR_WIN32_KEYED_MUTEX_SPEC_VERSION"/>
+ <enum value="&quot;VK_KHR_win32_keyed_mutex&quot;" name="VK_KHR_WIN32_KEYED_MUTEX_EXTENSION_NAME"/>
+ <enum offset="0" extends="VkStructureType" name="VK_STRUCTURE_TYPE_WIN32_KEYED_MUTEX_ACQUIRE_RELEASE_INFO_KHR"/>
+ <type name="VkWin32KeyedMutexAcquireReleaseInfoKHR"/>
+ </require>
+ </extension>
+ <extension name="VK_KHR_external_semaphore_capabilities" number="77" type="instance" author="KHR" requires="VK_KHR_get_physical_device_properties2" contact="James Jones @cubanismo" supported="vulkan" promotedto="VK_VERSION_1_1">
+ <require>
+ <enum value="1" name="VK_KHR_EXTERNAL_SEMAPHORE_CAPABILITIES_SPEC_VERSION"/>
+ <enum value="&quot;VK_KHR_external_semaphore_capabilities&quot;" name="VK_KHR_EXTERNAL_SEMAPHORE_CAPABILITIES_EXTENSION_NAME"/>
+ <enum extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_SEMAPHORE_INFO_KHR" alias="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_SEMAPHORE_INFO"/>
+ <enum extends="VkStructureType" name="VK_STRUCTURE_TYPE_EXTERNAL_SEMAPHORE_PROPERTIES_KHR" alias="VK_STRUCTURE_TYPE_EXTERNAL_SEMAPHORE_PROPERTIES"/>
+ <enum extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ID_PROPERTIES_KHR" alias="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ID_PROPERTIES"/>
+ <enum name="VK_LUID_SIZE_KHR"/>
+ <type name="VkExternalSemaphoreHandleTypeFlagsKHR"/>
+ <type name="VkExternalSemaphoreHandleTypeFlagBitsKHR"/>
+ <enum extends="VkExternalSemaphoreHandleTypeFlagBits" name="VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT_KHR" alias="VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT"/>
+ <enum extends="VkExternalSemaphoreHandleTypeFlagBits" name="VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_BIT_KHR" alias="VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_BIT"/>
+ <enum extends="VkExternalSemaphoreHandleTypeFlagBits" name="VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT_KHR" alias="VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT"/>
+ <enum extends="VkExternalSemaphoreHandleTypeFlagBits" name="VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_D3D12_FENCE_BIT_KHR" alias="VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_D3D12_FENCE_BIT"/>
+ <enum extends="VkExternalSemaphoreHandleTypeFlagBits" name="VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT_KHR" alias="VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT"/>
+ <type name="VkExternalSemaphoreFeatureFlagsKHR"/>
+ <type name="VkExternalSemaphoreFeatureFlagBitsKHR"/>
+ <enum extends="VkExternalSemaphoreFeatureFlagBits" name="VK_EXTERNAL_SEMAPHORE_FEATURE_EXPORTABLE_BIT_KHR" alias="VK_EXTERNAL_SEMAPHORE_FEATURE_EXPORTABLE_BIT"/>
+ <enum extends="VkExternalSemaphoreFeatureFlagBits" name="VK_EXTERNAL_SEMAPHORE_FEATURE_IMPORTABLE_BIT_KHR" alias="VK_EXTERNAL_SEMAPHORE_FEATURE_IMPORTABLE_BIT"/>
+ <type name="VkPhysicalDeviceExternalSemaphoreInfoKHR"/>
+ <type name="VkExternalSemaphorePropertiesKHR"/>
+ <type name="VkPhysicalDeviceIDPropertiesKHR"/>
+ <command name="vkGetPhysicalDeviceExternalSemaphorePropertiesKHR"/>
+ </require>
+ </extension>
+ <extension name="VK_KHR_external_semaphore" number="78" type="device" requires="VK_KHR_external_semaphore_capabilities" author="KHR" contact="James Jones @cubanismo" supported="vulkan" promotedto="VK_VERSION_1_1">
+ <require>
+ <enum value="1" name="VK_KHR_EXTERNAL_SEMAPHORE_SPEC_VERSION"/>
+ <enum value="&quot;VK_KHR_external_semaphore&quot;" name="VK_KHR_EXTERNAL_SEMAPHORE_EXTENSION_NAME"/>
+ <enum extends="VkStructureType" name="VK_STRUCTURE_TYPE_EXPORT_SEMAPHORE_CREATE_INFO_KHR" alias="VK_STRUCTURE_TYPE_EXPORT_SEMAPHORE_CREATE_INFO"/>
+ <type name="VkSemaphoreImportFlagsKHR"/>
+ <type name="VkSemaphoreImportFlagBitsKHR"/>
+ <enum extends="VkSemaphoreImportFlagBits" name="VK_SEMAPHORE_IMPORT_TEMPORARY_BIT_KHR" alias="VK_SEMAPHORE_IMPORT_TEMPORARY_BIT"/>
+ <type name="VkExportSemaphoreCreateInfoKHR"/>
+ </require>
+ </extension>
+ <extension name="VK_KHR_external_semaphore_win32" number="79" type="device" requires="VK_KHR_external_semaphore" author="KHR" contact="James Jones @cubanismo" platform="win32" supported="vulkan">
+ <require>
+ <enum value="1" name="VK_KHR_EXTERNAL_SEMAPHORE_WIN32_SPEC_VERSION"/>
+ <enum value="&quot;VK_KHR_external_semaphore_win32&quot;" name="VK_KHR_EXTERNAL_SEMAPHORE_WIN32_EXTENSION_NAME"/>
+ <enum offset="0" extends="VkStructureType" name="VK_STRUCTURE_TYPE_IMPORT_SEMAPHORE_WIN32_HANDLE_INFO_KHR"/>
+ <enum offset="1" extends="VkStructureType" name="VK_STRUCTURE_TYPE_EXPORT_SEMAPHORE_WIN32_HANDLE_INFO_KHR"/>
+ <enum offset="2" extends="VkStructureType" name="VK_STRUCTURE_TYPE_D3D12_FENCE_SUBMIT_INFO_KHR"/>
+ <enum offset="3" extends="VkStructureType" name="VK_STRUCTURE_TYPE_SEMAPHORE_GET_WIN32_HANDLE_INFO_KHR"/>
+ <type name="VkImportSemaphoreWin32HandleInfoKHR"/>
+ <type name="VkExportSemaphoreWin32HandleInfoKHR"/>
+ <type name="VkD3D12FenceSubmitInfoKHR"/>
+ <type name="VkSemaphoreGetWin32HandleInfoKHR"/>
+ <command name="vkImportSemaphoreWin32HandleKHR"/>
+ <command name="vkGetSemaphoreWin32HandleKHR"/>
+ </require>
+ </extension>
+ <extension name="VK_KHR_external_semaphore_fd" number="80" type="device" requires="VK_KHR_external_semaphore" author="KHR" contact="James Jones @cubanismo" supported="vulkan">
+ <require>
+ <enum value="1" name="VK_KHR_EXTERNAL_SEMAPHORE_FD_SPEC_VERSION"/>
+ <enum value="&quot;VK_KHR_external_semaphore_fd&quot;" name="VK_KHR_EXTERNAL_SEMAPHORE_FD_EXTENSION_NAME"/>
+ <enum offset="0" extends="VkStructureType" name="VK_STRUCTURE_TYPE_IMPORT_SEMAPHORE_FD_INFO_KHR"/>
+ <enum offset="1" extends="VkStructureType" name="VK_STRUCTURE_TYPE_SEMAPHORE_GET_FD_INFO_KHR"/>
+ <type name="VkImportSemaphoreFdInfoKHR"/>
+ <type name="VkSemaphoreGetFdInfoKHR"/>
+ <command name="vkImportSemaphoreFdKHR"/>
+ <command name="vkGetSemaphoreFdKHR"/>
+ </require>
+ </extension>
+ <extension name="VK_KHR_push_descriptor" number="81" type="device" author="KHR" requires="VK_KHR_get_physical_device_properties2" contact="Jeff Bolz @jeffbolznv" supported="vulkan">
+ <require>
+ <enum value="2" name="VK_KHR_PUSH_DESCRIPTOR_SPEC_VERSION"/>
+ <enum value="&quot;VK_KHR_push_descriptor&quot;" name="VK_KHR_PUSH_DESCRIPTOR_EXTENSION_NAME"/>
+ <enum offset="0" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PUSH_DESCRIPTOR_PROPERTIES_KHR"/>
+ <enum bitpos="0" extends="VkDescriptorSetLayoutCreateFlagBits" name="VK_DESCRIPTOR_SET_LAYOUT_CREATE_PUSH_DESCRIPTOR_BIT_KHR" comment="Descriptors are pushed via flink:vkCmdPushDescriptorSetKHR"/>
+ <command name="vkCmdPushDescriptorSetKHR"/>
+ <type name="VkPhysicalDevicePushDescriptorPropertiesKHR"/>
+ </require>
+ <require feature="VK_VERSION_1_1">
+ <command name="vkCmdPushDescriptorSetWithTemplateKHR"/>
+ <enum value="1" extends="VkDescriptorUpdateTemplateType" name="VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_PUSH_DESCRIPTORS_KHR" comment="Create descriptor update template for pushed descriptor updates"/>
+ </require>
+ <require extension="VK_KHR_descriptor_update_template">
+ <command name="vkCmdPushDescriptorSetWithTemplateKHR"/>
+ <enum value="1" extends="VkDescriptorUpdateTemplateType" name="VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_PUSH_DESCRIPTORS_KHR" comment="Create descriptor update template for pushed descriptor updates"/>
+ </require>
+ </extension>
+ <extension name="VK_EXT_conditional_rendering" number="82" type="device" author="NV" contact="Vikram Kushwaha @vkushwaha" supported="vulkan">
+ <require>
+ <enum value="2" name="VK_EXT_CONDITIONAL_RENDERING_SPEC_VERSION"/>
+ <enum value="&quot;VK_EXT_conditional_rendering&quot;" name="VK_EXT_CONDITIONAL_RENDERING_EXTENSION_NAME"/>
+ <enum offset="0" extends="VkStructureType" name="VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_CONDITIONAL_RENDERING_INFO_EXT"/>
+ <enum offset="1" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CONDITIONAL_RENDERING_FEATURES_EXT"/>
+ <enum offset="2" extends="VkStructureType" name="VK_STRUCTURE_TYPE_CONDITIONAL_RENDERING_BEGIN_INFO_EXT"/>
+ <type name="VkConditionalRenderingFlagsEXT"/>
+ <type name="VkConditionalRenderingFlagBitsEXT"/>
+ <enum bitpos="20" extends="VkAccessFlagBits" name="VK_ACCESS_CONDITIONAL_RENDERING_READ_BIT_EXT" comment="read access flag for reading conditional rendering predicate"/>
+ <enum bitpos="9" extends="VkBufferUsageFlagBits" name="VK_BUFFER_USAGE_CONDITIONAL_RENDERING_BIT_EXT" comment="Specifies the buffer can be used as predicate in conditional rendering"/>
+ <enum bitpos="18" extends="VkPipelineStageFlagBits" name="VK_PIPELINE_STAGE_CONDITIONAL_RENDERING_BIT_EXT" comment="A pipeline stage for conditional rendering predicate fetch"/>
+ <command name="vkCmdBeginConditionalRenderingEXT"/>
+ <command name="vkCmdEndConditionalRenderingEXT"/>
+ <type name="VkConditionalRenderingBeginInfoEXT"/>
+ <type name="VkPhysicalDeviceConditionalRenderingFeaturesEXT"/>
+ <type name="VkCommandBufferInheritanceConditionalRenderingInfoEXT"/>
+ </require>
+ </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"/>
+ <type name="VkPhysicalDeviceShaderFloat16Int8FeaturesKHR"/>
+ <type name="VkPhysicalDeviceFloat16Int8FeaturesKHR"/>
+ </require>
+ </extension>
+ <extension name="VK_KHR_16bit_storage" number="84" type="device" requires="VK_KHR_get_physical_device_properties2,VK_KHR_storage_buffer_storage_class" author="KHR" contact="Jan-Harald Fredriksen @janharaldfredriksen-arm" supported="vulkan" promotedto="VK_VERSION_1_1">
+ <require>
+ <enum value="1" name="VK_KHR_16BIT_STORAGE_SPEC_VERSION"/>
+ <enum value="&quot;VK_KHR_16bit_storage&quot;" name="VK_KHR_16BIT_STORAGE_EXTENSION_NAME"/>
+ <enum extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_16BIT_STORAGE_FEATURES_KHR" alias="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_16BIT_STORAGE_FEATURES"/>
+ <type name="VkPhysicalDevice16BitStorageFeaturesKHR"/>
+ </require>
+ </extension>
+ <extension name="VK_KHR_incremental_present" number="85" type="device" author="KHR" requires="VK_KHR_swapchain" contact="Ian Elliott @ianelliottus" supported="vulkan">
+ <require>
+ <enum value="2" name="VK_KHR_INCREMENTAL_PRESENT_SPEC_VERSION"/>
+ <enum value="&quot;VK_KHR_incremental_present&quot;" name="VK_KHR_INCREMENTAL_PRESENT_EXTENSION_NAME"/>
+ <enum offset="0" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PRESENT_REGIONS_KHR"/>
+ <type name="VkPresentRegionsKHR"/>
+ <type name="VkPresentRegionKHR"/>
+ <type name="VkRectLayerKHR"/>
+ </require>
+ </extension>
+ <extension name="VK_KHR_descriptor_update_template" number="86" type="device" author="KHR" contact="Markus Tavenrath @mtavenrath" supported="vulkan" promotedto="VK_VERSION_1_1">
+ <require>
+ <enum value="1" name="VK_KHR_DESCRIPTOR_UPDATE_TEMPLATE_SPEC_VERSION"/>
+ <enum value="&quot;VK_KHR_descriptor_update_template&quot;" name="VK_KHR_DESCRIPTOR_UPDATE_TEMPLATE_EXTENSION_NAME"/>
+ <enum extends="VkStructureType" name="VK_STRUCTURE_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_CREATE_INFO_KHR" alias="VK_STRUCTURE_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_CREATE_INFO"/>
+ <enum extends="VkObjectType" name="VK_OBJECT_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_KHR" alias="VK_OBJECT_TYPE_DESCRIPTOR_UPDATE_TEMPLATE"/>
+ <command name="vkCreateDescriptorUpdateTemplateKHR"/>
+ <command name="vkDestroyDescriptorUpdateTemplateKHR"/>
+ <command name="vkUpdateDescriptorSetWithTemplateKHR"/>
+ <type name="VkDescriptorUpdateTemplateKHR"/>
+ <type name="VkDescriptorUpdateTemplateCreateFlagsKHR"/>
+ <type name="VkDescriptorUpdateTemplateTypeKHR"/>
+ <type name="VkDescriptorUpdateTemplateEntryKHR"/>
+ <type name="VkDescriptorUpdateTemplateCreateInfoKHR"/>
+ <enum extends="VkDescriptorUpdateTemplateType" name="VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_DESCRIPTOR_SET_KHR" alias="VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_DESCRIPTOR_SET"/>
+ </require>
+ <require extension="VK_KHR_push_descriptor">
+ <command name="vkCmdPushDescriptorSetWithTemplateKHR"/>
+ <enum value="1" extends="VkDescriptorUpdateTemplateType" name="VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_PUSH_DESCRIPTORS_KHR" comment="Create descriptor update template for pushed descriptor updates"/>
+ </require>
+ <require extension="VK_EXT_debug_report">
+ <enum extends="VkDebugReportObjectTypeEXT" name="VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_KHR_EXT" alias="VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_EXT"/>
+ </require>
+ </extension>
+ <extension name="VK_NVX_device_generated_commands" number="87" type="device" author="NVX" contact="Christoph Kubisch @pixeljetstream" supported="disabled">
+ <require>
+ <enum value="3" name="VK_NVX_DEVICE_GENERATED_COMMANDS_SPEC_VERSION"/>
+ <enum value="&quot;VK_NVX_device_generated_commands&quot;" name="VK_NVX_DEVICE_GENERATED_COMMANDS_EXTENSION_NAME"/>
+ </require>
+ </extension>
+ <extension name="VK_NV_clip_space_w_scaling" number="88" type="device" author="NV" contact="Eric Werness @ewerness-nv" supported="vulkan">
+ <require>
+ <enum value="1" name="VK_NV_CLIP_SPACE_W_SCALING_SPEC_VERSION"/>
+ <enum value="&quot;VK_NV_clip_space_w_scaling&quot;" name="VK_NV_CLIP_SPACE_W_SCALING_EXTENSION_NAME"/>
+ <enum offset="0" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_W_SCALING_STATE_CREATE_INFO_NV"/>
+ <enum offset="0" extends="VkDynamicState" name="VK_DYNAMIC_STATE_VIEWPORT_W_SCALING_NV"/>
+ <type name="VkViewportWScalingNV"/>
+ <type name="VkPipelineViewportWScalingStateCreateInfoNV"/>
+ <command name="vkCmdSetViewportWScalingNV"/>
+ </require>
+ </extension>
+ <extension name="VK_EXT_direct_mode_display" number="89" type="instance" requires="VK_KHR_display" author="NV" contact="James Jones @cubanismo" supported="vulkan">
+ <require>
+ <enum value="1" name="VK_EXT_DIRECT_MODE_DISPLAY_SPEC_VERSION"/>
+ <enum value="&quot;VK_EXT_direct_mode_display&quot;" name="VK_EXT_DIRECT_MODE_DISPLAY_EXTENSION_NAME"/>
+ <command name="vkReleaseDisplayEXT"/>
+ </require>
+ </extension>
+ <extension name="VK_EXT_acquire_xlib_display" number="90" type="instance" requires="VK_EXT_direct_mode_display" author="NV" contact="James Jones @cubanismo" platform="xlib_xrandr" supported="vulkan">
+ <require>
+ <enum value="1" name="VK_EXT_ACQUIRE_XLIB_DISPLAY_SPEC_VERSION"/>
+ <enum value="&quot;VK_EXT_acquire_xlib_display&quot;" name="VK_EXT_ACQUIRE_XLIB_DISPLAY_EXTENSION_NAME"/>
+ <command name="vkAcquireXlibDisplayEXT"/>
+ <command name="vkGetRandROutputDisplayEXT"/>
+ </require>
+ </extension>
+ <extension name="VK_EXT_display_surface_counter" number="91" type="instance" requires="VK_KHR_display" author="NV" contact="James Jones @cubanismo" supported="vulkan">
+ <require>
+ <enum value="1" name="VK_EXT_DISPLAY_SURFACE_COUNTER_SPEC_VERSION"/>
+ <enum value="&quot;VK_EXT_display_surface_counter&quot;" name="VK_EXT_DISPLAY_SURFACE_COUNTER_EXTENSION_NAME"/>
+ <enum offset="0" extends="VkStructureType" name="VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES_2_EXT"/>
+ <enum alias="VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES_2_EXT" extends="VkStructureType" name="VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES2_EXT" comment="Backwards-compatible alias containing a typo"/>
+ <type name="VkSurfaceCounterFlagsEXT"/>
+ <type name="VkSurfaceCounterFlagBitsEXT"/>
+ <type name="VkSurfaceCapabilities2EXT"/>
+ <command name="vkGetPhysicalDeviceSurfaceCapabilities2EXT"/>
+ </require>
+ </extension>
+ <extension name="VK_EXT_display_control" number="92" type="device" requires="VK_EXT_display_surface_counter,VK_KHR_swapchain" author="NV" contact="James Jones @cubanismo" supported="vulkan">
+ <require>
+ <enum value="1" name="VK_EXT_DISPLAY_CONTROL_SPEC_VERSION"/>
+ <enum value="&quot;VK_EXT_display_control&quot;" name="VK_EXT_DISPLAY_CONTROL_EXTENSION_NAME"/>
+ <enum offset="0" extends="VkStructureType" name="VK_STRUCTURE_TYPE_DISPLAY_POWER_INFO_EXT"/>
+ <enum offset="1" extends="VkStructureType" name="VK_STRUCTURE_TYPE_DEVICE_EVENT_INFO_EXT"/>
+ <enum offset="2" extends="VkStructureType" name="VK_STRUCTURE_TYPE_DISPLAY_EVENT_INFO_EXT"/>
+ <enum offset="3" extends="VkStructureType" name="VK_STRUCTURE_TYPE_SWAPCHAIN_COUNTER_CREATE_INFO_EXT"/>
+ <type name="VkDisplayPowerStateEXT"/>
+ <type name="VkDeviceEventTypeEXT"/>
+ <type name="VkDisplayEventTypeEXT"/>
+ <type name="VkDisplayPowerInfoEXT"/>
+ <type name="VkDeviceEventInfoEXT"/>
+ <type name="VkDisplayEventInfoEXT"/>
+ <type name="VkSwapchainCounterCreateInfoEXT"/>
+ <command name="vkDisplayPowerControlEXT"/>
+ <command name="vkRegisterDeviceEventEXT"/>
+ <command name="vkRegisterDisplayEventEXT"/>
+ <command name="vkGetSwapchainCounterEXT"/>
+ </require>
+ </extension>
+ <extension name="VK_GOOGLE_display_timing" number="93" type="device" author="GOOGLE" requires="VK_KHR_swapchain" contact="Ian Elliott @ianelliottus" supported="vulkan">
+ <require>
+ <enum value="1" name="VK_GOOGLE_DISPLAY_TIMING_SPEC_VERSION"/>
+ <enum value="&quot;VK_GOOGLE_display_timing&quot;" name="VK_GOOGLE_DISPLAY_TIMING_EXTENSION_NAME"/>
+ <enum offset="0" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PRESENT_TIMES_INFO_GOOGLE"/>
+ <type name="VkRefreshCycleDurationGOOGLE"/>
+ <type name="VkPastPresentationTimingGOOGLE"/>
+ <type name="VkPresentTimesInfoGOOGLE"/>
+ <type name="VkPresentTimeGOOGLE"/>
+ <command name="vkGetRefreshCycleDurationGOOGLE"/>
+ <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>
+ <extension name="VK_NV_sample_mask_override_coverage" number="95" type="device" author="NV" contact="Piers Daniell @pdaniell-nv" supported="vulkan">
+ <require>
+ <enum value="1" name="VK_NV_SAMPLE_MASK_OVERRIDE_COVERAGE_SPEC_VERSION"/>
+ <enum value="&quot;VK_NV_sample_mask_override_coverage&quot;" name="VK_NV_SAMPLE_MASK_OVERRIDE_COVERAGE_EXTENSION_NAME"/>
+ <comment>
+ enum offset=0 was mistakenly used for the 1.1 core enum
+ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_PROPERTIES
+ (value=1000094000). Fortunately, no conflict resulted.
+ </comment>
+ </require>
+ </extension>
+ <extension name="VK_NV_geometry_shader_passthrough" number="96" type="device" author="NV" contact="Daniel Koch @dgkoch" supported="vulkan">
+ <require>
+ <enum value="1" name="VK_NV_GEOMETRY_SHADER_PASSTHROUGH_SPEC_VERSION"/>
+ <enum value="&quot;VK_NV_geometry_shader_passthrough&quot;" name="VK_NV_GEOMETRY_SHADER_PASSTHROUGH_EXTENSION_NAME"/>
+ </require>
+ </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"/>
+ </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">
+ <require>
+ <enum value="1" name="VK_NVX_MULTIVIEW_PER_VIEW_ATTRIBUTES_SPEC_VERSION"/>
+ <enum value="&quot;VK_NVX_multiview_per_view_attributes&quot;" name="VK_NVX_MULTIVIEW_PER_VIEW_ATTRIBUTES_EXTENSION_NAME"/>
+ <enum offset="0" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_PER_VIEW_ATTRIBUTES_PROPERTIES_NVX"/>
+ <enum bitpos="0" extends="VkSubpassDescriptionFlagBits" name="VK_SUBPASS_DESCRIPTION_PER_VIEW_ATTRIBUTES_BIT_NVX"/>
+ <enum bitpos="1" extends="VkSubpassDescriptionFlagBits" name="VK_SUBPASS_DESCRIPTION_PER_VIEW_POSITION_X_ONLY_BIT_NVX"/>
+ <type name="VkPhysicalDeviceMultiviewPerViewAttributesPropertiesNVX"/>
+ </require>
+ </extension>
+ <extension name="VK_NV_viewport_swizzle" number="99" type="device" author="NV" contact="Piers Daniell @pdaniell-nv" supported="vulkan">
+ <require>
+ <enum value="1" name="VK_NV_VIEWPORT_SWIZZLE_SPEC_VERSION"/>
+ <enum value="&quot;VK_NV_viewport_swizzle&quot;" name="VK_NV_VIEWPORT_SWIZZLE_EXTENSION_NAME"/>
+ <enum offset="0" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_SWIZZLE_STATE_CREATE_INFO_NV"/>
+ <type name="VkViewportSwizzleNV"/>
+ <type name="VkViewportCoordinateSwizzleNV"/>
+ <type name="VkPipelineViewportSwizzleStateCreateInfoNV"/>
+ <type name="VkPipelineViewportSwizzleStateCreateFlagsNV"/>
+ </require>
+ </extension>
+ <extension name="VK_EXT_discard_rectangles" number="100" type="device" requires="VK_KHR_get_physical_device_properties2" author="NV" contact="Piers Daniell @pdaniell-nv" supported="vulkan">
+ <require>
+ <enum value="1" name="VK_EXT_DISCARD_RECTANGLES_SPEC_VERSION"/>
+ <enum value="&quot;VK_EXT_discard_rectangles&quot;" name="VK_EXT_DISCARD_RECTANGLES_EXTENSION_NAME"/>
+ <enum offset="0" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DISCARD_RECTANGLE_PROPERTIES_EXT"/>
+ <enum offset="1" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PIPELINE_DISCARD_RECTANGLE_STATE_CREATE_INFO_EXT"/>
+ <enum offset="0" extends="VkDynamicState" name="VK_DYNAMIC_STATE_DISCARD_RECTANGLE_EXT"/>
+ <type name="VkPhysicalDeviceDiscardRectanglePropertiesEXT"/>
+ <type name="VkPipelineDiscardRectangleStateCreateInfoEXT"/>
+ <type name="VkPipelineDiscardRectangleStateCreateFlagsEXT"/>
+ <type name="VkDiscardRectangleModeEXT"/>
+ <command name="vkCmdSetDiscardRectangleEXT"/>
+ </require>
+ </extension>
+ <extension name="VK_NV_extension_101" number="101" author="NV" contact="Daniel Koch @dgkoch" supported="disabled">
+ <require>
+ <enum value="0" name="VK_NV_EXTENSION_101_SPEC_VERSION"/>
+ <enum value="&quot;VK_NV_extension_101&quot;" name="VK_NV_EXTENSION_101_EXTENSION_NAME"/>
+ </require>
+ </extension>
+ <extension name="VK_EXT_conservative_rasterization" number="102" type="device" requires="VK_KHR_get_physical_device_properties2" author="NV" contact="Piers Daniell @pdaniell-nv" supported="vulkan">
+ <require>
+ <enum value="1" name="VK_EXT_CONSERVATIVE_RASTERIZATION_SPEC_VERSION"/>
+ <enum value="&quot;VK_EXT_conservative_rasterization&quot;" name="VK_EXT_CONSERVATIVE_RASTERIZATION_EXTENSION_NAME"/>
+ <enum offset="0" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CONSERVATIVE_RASTERIZATION_PROPERTIES_EXT"/>
+ <enum offset="1" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_CONSERVATIVE_STATE_CREATE_INFO_EXT"/>
+ <type name="VkPhysicalDeviceConservativeRasterizationPropertiesEXT"/>
+ <type name="VkPipelineRasterizationConservativeStateCreateInfoEXT"/>
+ <type name="VkPipelineRasterizationConservativeStateCreateFlagsEXT"/>
+ <type name="VkConservativeRasterizationModeEXT"/>
+ </require>
+ </extension>
+ <extension name="VK_EXT_depth_clip_enable" number="103" type="device" author="EXT" contact="Piers Daniell @pdaniell-nv" specialuse="d3demulation" supported="vulkan">
+ <require>
+ <enum value="1" name="VK_EXT_DEPTH_CLIP_ENABLE_SPEC_VERSION"/>
+ <enum value="&quot;VK_EXT_depth_clip_enable&quot;" name="VK_EXT_DEPTH_CLIP_ENABLE_EXTENSION_NAME"/>
+ <enum offset="0" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEPTH_CLIP_ENABLE_FEATURES_EXT"/>
+ <enum offset="1" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_DEPTH_CLIP_STATE_CREATE_INFO_EXT"/>
+ <type name="VkPhysicalDeviceDepthClipEnableFeaturesEXT"/>
+ <type name="VkPipelineRasterizationDepthClipStateCreateInfoEXT"/>
+ <type name="VkPipelineRasterizationDepthClipStateCreateFlagsEXT"/>
+ </require>
+ </extension>
+ <extension name="VK_NV_extension_104" number="104" author="NV" contact="Mathias Schott gitlab:@mschott" supported="disabled">
+ <require>
+ <enum value="0" name="VK_NV_EXTENSION_104_SPEC_VERSION"/>
+ <enum value="&quot;VK_NV_extension_104&quot;" name="VK_NV_EXTENSION_104_EXTENSION_NAME"/>
+ </require>
+ </extension>
+ <extension name="VK_EXT_swapchain_colorspace" number="105" type="instance" author="GOOGLE" contact="Courtney Goeltzenleuchter @courtney-g" requires="VK_KHR_surface" supported="vulkan">
+ <require>
+ <enum value="4" name="VK_EXT_SWAPCHAIN_COLOR_SPACE_SPEC_VERSION"/>
+ <enum value="&quot;VK_EXT_swapchain_colorspace&quot;" name="VK_EXT_SWAPCHAIN_COLOR_SPACE_EXTENSION_NAME"/>
+ <enum offset="1" extends="VkColorSpaceKHR" name="VK_COLOR_SPACE_DISPLAY_P3_NONLINEAR_EXT"/>
+ <enum offset="2" extends="VkColorSpaceKHR" name="VK_COLOR_SPACE_EXTENDED_SRGB_LINEAR_EXT"/>
+ <enum offset="3" extends="VkColorSpaceKHR" name="VK_COLOR_SPACE_DISPLAY_P3_LINEAR_EXT"/>
+ <enum offset="4" extends="VkColorSpaceKHR" name="VK_COLOR_SPACE_DCI_P3_NONLINEAR_EXT"/>
+ <enum offset="5" extends="VkColorSpaceKHR" name="VK_COLOR_SPACE_BT709_LINEAR_EXT"/>
+ <enum offset="6" extends="VkColorSpaceKHR" name="VK_COLOR_SPACE_BT709_NONLINEAR_EXT"/>
+ <enum offset="7" extends="VkColorSpaceKHR" name="VK_COLOR_SPACE_BT2020_LINEAR_EXT"/>
+ <enum offset="8" extends="VkColorSpaceKHR" name="VK_COLOR_SPACE_HDR10_ST2084_EXT"/>
+ <enum offset="9" extends="VkColorSpaceKHR" name="VK_COLOR_SPACE_DOLBYVISION_EXT"/>
+ <enum offset="10" extends="VkColorSpaceKHR" name="VK_COLOR_SPACE_HDR10_HLG_EXT"/>
+ <enum offset="11" extends="VkColorSpaceKHR" name="VK_COLOR_SPACE_ADOBERGB_LINEAR_EXT"/>
+ <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"/>
+ </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">
+ <require>
+ <enum value="2" name="VK_EXT_HDR_METADATA_SPEC_VERSION"/>
+ <enum value="&quot;VK_EXT_hdr_metadata&quot;" name="VK_EXT_HDR_METADATA_EXTENSION_NAME"/>
+ <enum offset="0" extends="VkStructureType" name="VK_STRUCTURE_TYPE_HDR_METADATA_EXT"/>
+ <type name="VkHdrMetadataEXT"/>
+ <type name="VkXYColorEXT"/>
+ <command name="vkSetHdrMetadataEXT"/>
+ </require>
+ </extension>
+ <extension name="VK_IMG_extension_107" number="107" author="IMG" contact="Michael Worcester @michaelworcester" supported="disabled">
+ <require>
+ <enum value="0" name="VK_IMG_EXTENSION_107_SPEC_VERSION"/>
+ <enum value="&quot;VK_IMG_extension_107&quot;" name="VK_IMG_EXTENSION_107_EXTENSION_NAME"/>
+ </require>
+ </extension>
+ <extension name="VK_IMG_extension_108" number="108" author="IMG" contact="Michael Worcester @michaelworcester" supported="disabled">
+ <require>
+ <enum value="0" name="VK_IMG_EXTENSION_108_SPEC_VERSION"/>
+ <enum value="&quot;VK_IMG_extension_108&quot;" name="VK_IMG_EXTENSION_108_EXTENSION_NAME"/>
+ </require>
+ </extension>
+ <extension name="VK_KHR_imageless_framebuffer" requires="VK_KHR_maintenance2,VK_KHR_image_format_list" number="109" author="KHR" contact="Tobias Hector @tobias" type="device" supported="vulkan" promotedto="VK_VERSION_1_2">
+ <require>
+ <enum value="1" name="VK_KHR_IMAGELESS_FRAMEBUFFER_SPEC_VERSION"/>
+ <enum value="&quot;VK_KHR_imageless_framebuffer&quot;" name="VK_KHR_IMAGELESS_FRAMEBUFFER_EXTENSION_NAME"/>
+ <type name="VkPhysicalDeviceImagelessFramebufferFeaturesKHR"/>
+ <type name="VkFramebufferAttachmentsCreateInfoKHR"/>
+ <type name="VkFramebufferAttachmentImageInfoKHR"/>
+ <type name="VkRenderPassAttachmentBeginInfoKHR"/>
+ <enum extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGELESS_FRAMEBUFFER_FEATURES_KHR" alias="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGELESS_FRAMEBUFFER_FEATURES"/>
+ <enum extends="VkStructureType" name="VK_STRUCTURE_TYPE_FRAMEBUFFER_ATTACHMENTS_CREATE_INFO_KHR" alias="VK_STRUCTURE_TYPE_FRAMEBUFFER_ATTACHMENTS_CREATE_INFO"/>
+ <enum extends="VkStructureType" name="VK_STRUCTURE_TYPE_FRAMEBUFFER_ATTACHMENT_IMAGE_INFO_KHR" alias="VK_STRUCTURE_TYPE_FRAMEBUFFER_ATTACHMENT_IMAGE_INFO"/>
+ <enum extends="VkStructureType" name="VK_STRUCTURE_TYPE_RENDER_PASS_ATTACHMENT_BEGIN_INFO_KHR" alias="VK_STRUCTURE_TYPE_RENDER_PASS_ATTACHMENT_BEGIN_INFO"/>
+ <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">
+ <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"/>
+ <enum extends="VkStructureType" name="VK_STRUCTURE_TYPE_ATTACHMENT_DESCRIPTION_2_KHR" alias="VK_STRUCTURE_TYPE_ATTACHMENT_DESCRIPTION_2"/>
+ <enum extends="VkStructureType" name="VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2_KHR" alias="VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2"/>
+ <enum extends="VkStructureType" name="VK_STRUCTURE_TYPE_SUBPASS_DESCRIPTION_2_KHR" alias="VK_STRUCTURE_TYPE_SUBPASS_DESCRIPTION_2"/>
+ <enum extends="VkStructureType" name="VK_STRUCTURE_TYPE_SUBPASS_DEPENDENCY_2_KHR" alias="VK_STRUCTURE_TYPE_SUBPASS_DEPENDENCY_2"/>
+ <enum extends="VkStructureType" name="VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO_2_KHR" alias="VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO_2"/>
+ <enum extends="VkStructureType" name="VK_STRUCTURE_TYPE_SUBPASS_BEGIN_INFO_KHR" alias="VK_STRUCTURE_TYPE_SUBPASS_BEGIN_INFO"/>
+ <enum extends="VkStructureType" name="VK_STRUCTURE_TYPE_SUBPASS_END_INFO_KHR" alias="VK_STRUCTURE_TYPE_SUBPASS_END_INFO"/>
+ <command name="vkCreateRenderPass2KHR"/>
+ <command name="vkCmdBeginRenderPass2KHR"/>
+ <command name="vkCmdNextSubpass2KHR"/>
+ <command name="vkCmdEndRenderPass2KHR"/>
+ <type name="VkRenderPassCreateInfo2KHR"/>
+ <type name="VkAttachmentDescription2KHR"/>
+ <type name="VkAttachmentReference2KHR"/>
+ <type name="VkSubpassDescription2KHR"/>
+ <type name="VkSubpassDependency2KHR"/>
+ <type name="VkSubpassBeginInfoKHR"/>
+ <type name="VkSubpassEndInfoKHR"/>
+ </require>
+ </extension>
+ <extension name="VK_IMG_extension_111" number="111" author="IMG" contact="Michael Worcester @michaelworcester" supported="disabled">
+ <require>
+ <enum value="0" name="VK_IMG_EXTENSION_111_SPEC_VERSION"/>
+ <enum value="&quot;VK_IMG_extension_111&quot;" name="VK_IMG_EXTENSION_111_EXTENSION_NAME"/>
+ </require>
+ </extension>
+ <extension name="VK_KHR_shared_presentable_image" number="112" type="device" requires="VK_KHR_swapchain,VK_KHR_get_physical_device_properties2,VK_KHR_get_surface_capabilities2" author="KHR" contact="Alon Or-bach @alonorbach" supported="vulkan">
+ <require>
+ <enum value="1" name="VK_KHR_SHARED_PRESENTABLE_IMAGE_SPEC_VERSION"/>
+ <enum value="&quot;VK_KHR_shared_presentable_image&quot;" name="VK_KHR_SHARED_PRESENTABLE_IMAGE_EXTENSION_NAME"/>
+ <enum offset="0" extends="VkStructureType" name="VK_STRUCTURE_TYPE_SHARED_PRESENT_SURFACE_CAPABILITIES_KHR"/>
+ <enum offset="0" extends="VkPresentModeKHR" name="VK_PRESENT_MODE_SHARED_DEMAND_REFRESH_KHR"/>
+ <enum offset="1" extends="VkPresentModeKHR" name="VK_PRESENT_MODE_SHARED_CONTINUOUS_REFRESH_KHR"/>
+ <enum offset="0" extends="VkImageLayout" name="VK_IMAGE_LAYOUT_SHARED_PRESENT_KHR"/>
+ <type name="VkSharedPresentSurfaceCapabilitiesKHR"/>
+ <command name="vkGetSwapchainStatusKHR"/>
+ </require>
+ </extension>
+ <extension name="VK_KHR_external_fence_capabilities" number="113" type="instance" author="KHR" requires="VK_KHR_get_physical_device_properties2" contact="Jesse Hall @critsec" supported="vulkan" promotedto="VK_VERSION_1_1">
+ <require>
+ <enum value="1" name="VK_KHR_EXTERNAL_FENCE_CAPABILITIES_SPEC_VERSION"/>
+ <enum value="&quot;VK_KHR_external_fence_capabilities&quot;" name="VK_KHR_EXTERNAL_FENCE_CAPABILITIES_EXTENSION_NAME"/>
+ <enum extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_FENCE_INFO_KHR" alias="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_FENCE_INFO"/>
+ <enum extends="VkStructureType" name="VK_STRUCTURE_TYPE_EXTERNAL_FENCE_PROPERTIES_KHR" alias="VK_STRUCTURE_TYPE_EXTERNAL_FENCE_PROPERTIES"/>
+ <enum extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ID_PROPERTIES_KHR" alias="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ID_PROPERTIES"/>
+ <enum name="VK_LUID_SIZE_KHR"/>
+ <type name="VkExternalFenceHandleTypeFlagsKHR"/>
+ <type name="VkExternalFenceHandleTypeFlagBitsKHR"/>
+ <enum extends="VkExternalFenceHandleTypeFlagBits" name="VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_FD_BIT_KHR" alias="VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_FD_BIT"/>
+ <enum extends="VkExternalFenceHandleTypeFlagBits" name="VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_WIN32_BIT_KHR" alias="VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_WIN32_BIT"/>
+ <enum extends="VkExternalFenceHandleTypeFlagBits" name="VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT_KHR" alias="VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT"/>
+ <enum extends="VkExternalFenceHandleTypeFlagBits" name="VK_EXTERNAL_FENCE_HANDLE_TYPE_SYNC_FD_BIT_KHR" alias="VK_EXTERNAL_FENCE_HANDLE_TYPE_SYNC_FD_BIT"/>
+ <type name="VkExternalFenceFeatureFlagsKHR"/>
+ <type name="VkExternalFenceFeatureFlagBitsKHR"/>
+ <enum extends="VkExternalFenceFeatureFlagBits" name="VK_EXTERNAL_FENCE_FEATURE_EXPORTABLE_BIT_KHR" alias="VK_EXTERNAL_FENCE_FEATURE_EXPORTABLE_BIT"/>
+ <enum extends="VkExternalFenceFeatureFlagBits" name="VK_EXTERNAL_FENCE_FEATURE_IMPORTABLE_BIT_KHR" alias="VK_EXTERNAL_FENCE_FEATURE_IMPORTABLE_BIT"/>
+ <type name="VkPhysicalDeviceExternalFenceInfoKHR"/>
+ <type name="VkExternalFencePropertiesKHR"/>
+ <type name="VkPhysicalDeviceIDPropertiesKHR"/>
+ <command name="vkGetPhysicalDeviceExternalFencePropertiesKHR"/>
+ </require>
+ </extension>
+ <extension name="VK_KHR_external_fence" number="114" type="device" requires="VK_KHR_external_fence_capabilities" author="KHR" contact="Jesse Hall @critsec" supported="vulkan" promotedto="VK_VERSION_1_1">
+ <require>
+ <enum value="1" name="VK_KHR_EXTERNAL_FENCE_SPEC_VERSION"/>
+ <enum value="&quot;VK_KHR_external_fence&quot;" name="VK_KHR_EXTERNAL_FENCE_EXTENSION_NAME"/>
+ <enum extends="VkStructureType" name="VK_STRUCTURE_TYPE_EXPORT_FENCE_CREATE_INFO_KHR" alias="VK_STRUCTURE_TYPE_EXPORT_FENCE_CREATE_INFO"/>
+ <type name="VkFenceImportFlagsKHR"/>
+ <type name="VkFenceImportFlagBitsKHR"/>
+ <enum extends="VkFenceImportFlagBits" name="VK_FENCE_IMPORT_TEMPORARY_BIT_KHR" alias="VK_FENCE_IMPORT_TEMPORARY_BIT"/>
+ <type name="VkExportFenceCreateInfoKHR"/>
+ </require>
+ </extension>
+ <extension name="VK_KHR_external_fence_win32" number="115" type="device" requires="VK_KHR_external_fence" author="KHR" contact="Jesse Hall @critsec" platform="win32" supported="vulkan">
+ <require>
+ <enum value="1" name="VK_KHR_EXTERNAL_FENCE_WIN32_SPEC_VERSION"/>
+ <enum value="&quot;VK_KHR_external_fence_win32&quot;" name="VK_KHR_EXTERNAL_FENCE_WIN32_EXTENSION_NAME"/>
+ <enum offset="0" extends="VkStructureType" name="VK_STRUCTURE_TYPE_IMPORT_FENCE_WIN32_HANDLE_INFO_KHR"/>
+ <enum offset="1" extends="VkStructureType" name="VK_STRUCTURE_TYPE_EXPORT_FENCE_WIN32_HANDLE_INFO_KHR"/>
+ <enum offset="2" extends="VkStructureType" name="VK_STRUCTURE_TYPE_FENCE_GET_WIN32_HANDLE_INFO_KHR"/>
+ <type name="VkImportFenceWin32HandleInfoKHR"/>
+ <type name="VkExportFenceWin32HandleInfoKHR"/>
+ <type name="VkFenceGetWin32HandleInfoKHR"/>
+ <command name="vkImportFenceWin32HandleKHR"/>
+ <command name="vkGetFenceWin32HandleKHR"/>
+ </require>
+ </extension>
+ <extension name="VK_KHR_external_fence_fd" number="116" type="device" requires="VK_KHR_external_fence" author="KHR" contact="Jesse Hall @critsec" supported="vulkan">
+ <require>
+ <enum value="1" name="VK_KHR_EXTERNAL_FENCE_FD_SPEC_VERSION"/>
+ <enum value="&quot;VK_KHR_external_fence_fd&quot;" name="VK_KHR_EXTERNAL_FENCE_FD_EXTENSION_NAME"/>
+ <enum offset="0" extends="VkStructureType" name="VK_STRUCTURE_TYPE_IMPORT_FENCE_FD_INFO_KHR"/>
+ <enum offset="1" extends="VkStructureType" name="VK_STRUCTURE_TYPE_FENCE_GET_FD_INFO_KHR"/>
+ <type name="VkImportFenceFdInfoKHR"/>
+ <type name="VkFenceGetFdInfoKHR"/>
+ <command name="vkImportFenceFdKHR"/>
+ <command name="vkGetFenceFdKHR"/>
+ </require>
+ </extension>
+ <extension name="VK_KHR_performance_query" number="117" type="device" requires="VK_KHR_get_physical_device_properties2" author="KHR" contact="Alon Or-bach @alonorbach" specialuse="devtools" supported="vulkan">
+ <require>
+ <enum value="1" name="VK_KHR_PERFORMANCE_QUERY_SPEC_VERSION"/>
+ <enum value="&quot;VK_KHR_performance_query&quot;" name="VK_KHR_PERFORMANCE_QUERY_EXTENSION_NAME"/>
+ <enum offset="0" extends="VkQueryType" name="VK_QUERY_TYPE_PERFORMANCE_QUERY_KHR"/>
+ <enum offset="0" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PERFORMANCE_QUERY_FEATURES_KHR"/>
+ <enum offset="1" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PERFORMANCE_QUERY_PROPERTIES_KHR"/>
+ <enum offset="2" extends="VkStructureType" name="VK_STRUCTURE_TYPE_QUERY_POOL_PERFORMANCE_CREATE_INFO_KHR"/>
+ <enum offset="3" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PERFORMANCE_QUERY_SUBMIT_INFO_KHR"/>
+ <enum offset="4" extends="VkStructureType" name="VK_STRUCTURE_TYPE_ACQUIRE_PROFILING_LOCK_INFO_KHR"/>
+ <enum offset="5" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PERFORMANCE_COUNTER_KHR"/>
+ <enum offset="6" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PERFORMANCE_COUNTER_DESCRIPTION_KHR"/>
+ <type name="VkPhysicalDevicePerformanceQueryFeaturesKHR"/>
+ <type name="VkPhysicalDevicePerformanceQueryPropertiesKHR"/>
+ <type name="VkPerformanceCounterKHR"/>
+ <type name="VkPerformanceCounterDescriptionKHR"/>
+ <type name="VkPerformanceCounterDescriptionFlagsKHR"/>
+ <type name="VkPerformanceCounterDescriptionFlagBitsKHR"/>
+ <type name="VkQueryPoolPerformanceCreateInfoKHR"/>
+ <type name="VkPerformanceCounterScopeKHR"/>
+ <type name="VkPerformanceCounterStorageKHR"/>
+ <type name="VkPerformanceCounterUnitKHR"/>
+ <type name="VkPerformanceCounterResultKHR"/>
+ <type name="VkAcquireProfilingLockInfoKHR"/>
+ <type name="VkAcquireProfilingLockFlagsKHR"/>
+ <type name="VkAcquireProfilingLockFlagBitsKHR"/>
+ <type name="VkPerformanceQuerySubmitInfoKHR"/>
+ <command name="vkEnumeratePhysicalDeviceQueueFamilyPerformanceQueryCountersKHR"/>
+ <command name="vkGetPhysicalDeviceQueueFamilyPerformanceQueryPassesKHR"/>
+ <command name="vkAcquireProfilingLockKHR"/>
+ <command name="vkReleaseProfilingLockKHR"/>
+ </require>
+ </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 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"/>
+ <enum extends="VkStructureType" name="VK_STRUCTURE_TYPE_RENDER_PASS_INPUT_ATTACHMENT_ASPECT_CREATE_INFO_KHR" alias="VK_STRUCTURE_TYPE_RENDER_PASS_INPUT_ATTACHMENT_ASPECT_CREATE_INFO"/>
+ <enum extends="VkStructureType" name="VK_STRUCTURE_TYPE_IMAGE_VIEW_USAGE_CREATE_INFO_KHR" alias="VK_STRUCTURE_TYPE_IMAGE_VIEW_USAGE_CREATE_INFO"/>
+ <enum extends="VkStructureType" name="VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_DOMAIN_ORIGIN_STATE_CREATE_INFO_KHR" alias="VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_DOMAIN_ORIGIN_STATE_CREATE_INFO"/>
+ <enum extends="VkImageLayout" name="VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL_KHR" alias="VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL"/>
+ <enum extends="VkImageLayout" name="VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL_KHR" alias="VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL"/>
+ <type name="VkPhysicalDevicePointClippingPropertiesKHR"/>
+ <type name="VkPointClippingBehaviorKHR"/>
+ <enum extends="VkPointClippingBehavior" name="VK_POINT_CLIPPING_BEHAVIOR_ALL_CLIP_PLANES_KHR" alias="VK_POINT_CLIPPING_BEHAVIOR_ALL_CLIP_PLANES"/>
+ <enum extends="VkPointClippingBehavior" name="VK_POINT_CLIPPING_BEHAVIOR_USER_CLIP_PLANES_ONLY_KHR" alias="VK_POINT_CLIPPING_BEHAVIOR_USER_CLIP_PLANES_ONLY"/>
+ <type name="VkRenderPassInputAttachmentAspectCreateInfoKHR"/>
+ <type name="VkInputAttachmentAspectReferenceKHR"/>
+ <type name="VkImageViewUsageCreateInfoKHR"/>
+ <type name="VkTessellationDomainOriginKHR"/>
+ <enum extends="VkTessellationDomainOrigin" name="VK_TESSELLATION_DOMAIN_ORIGIN_UPPER_LEFT_KHR" alias="VK_TESSELLATION_DOMAIN_ORIGIN_UPPER_LEFT"/>
+ <enum extends="VkTessellationDomainOrigin" name="VK_TESSELLATION_DOMAIN_ORIGIN_LOWER_LEFT_KHR" alias="VK_TESSELLATION_DOMAIN_ORIGIN_LOWER_LEFT"/>
+ <type name="VkPipelineTessellationDomainOriginStateCreateInfoKHR"/>
+ </require>
+ </extension>
+ <extension name="VK_KHR_extension_119" number="119" author="KHR" contact="Michael Worcester @michaelworcester" supported="disabled">
+ <require>
+ <enum value="0" name="VK_KHR_EXTENSION_119_SPEC_VERSION"/>
+ <enum value="&quot;VK_KHR_extension_119&quot;" name="VK_KHR_EXTENSION_119_EXTENSION_NAME"/>
+ </require>
+ </extension>
+ <extension name="VK_KHR_get_surface_capabilities2" number="120" type="instance" requires="VK_KHR_surface" author="KHR" contact="James Jones @cubanismo" supported="vulkan">
+ <require>
+ <enum value="1" name="VK_KHR_GET_SURFACE_CAPABILITIES_2_SPEC_VERSION"/>
+ <enum value="&quot;VK_KHR_get_surface_capabilities2&quot;" name="VK_KHR_GET_SURFACE_CAPABILITIES_2_EXTENSION_NAME"/>
+ <enum offset="0" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SURFACE_INFO_2_KHR"/>
+ <enum offset="1" extends="VkStructureType" name="VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES_2_KHR"/>
+ <enum offset="2" extends="VkStructureType" name="VK_STRUCTURE_TYPE_SURFACE_FORMAT_2_KHR"/>
+ <type name="VkPhysicalDeviceSurfaceInfo2KHR"/>
+ <type name="VkSurfaceCapabilities2KHR"/>
+ <type name="VkSurfaceFormat2KHR"/>
+ <command name="vkGetPhysicalDeviceSurfaceCapabilities2KHR"/>
+ <command name="vkGetPhysicalDeviceSurfaceFormats2KHR"/>
+ </require>
+ </extension>
+ <extension name="VK_KHR_variable_pointers" number="121" type="device" author="KHR" contact="Jesse Hall @critsec" requires="VK_KHR_get_physical_device_properties2,VK_KHR_storage_buffer_storage_class" supported="vulkan" promotedto="VK_VERSION_1_1">
+ <require>
+ <enum value="1" name="VK_KHR_VARIABLE_POINTERS_SPEC_VERSION"/>
+ <enum value="&quot;VK_KHR_variable_pointers&quot;" name="VK_KHR_VARIABLE_POINTERS_EXTENSION_NAME"/>
+ <enum extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VARIABLE_POINTERS_FEATURES_KHR" alias="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VARIABLE_POINTERS_FEATURES"/>
+ <enum extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VARIABLE_POINTER_FEATURES_KHR" alias="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VARIABLE_POINTERS_FEATURES_KHR"/>
+ <type name="VkPhysicalDeviceVariablePointerFeaturesKHR"/>
+ <type name="VkPhysicalDeviceVariablePointersFeaturesKHR"/>
+ </require>
+ </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"/>
+ <type name="VkDisplayProperties2KHR"/>
+ <type name="VkDisplayPlaneProperties2KHR"/>
+ <type name="VkDisplayModeProperties2KHR"/>
+ <type name="VkDisplayPlaneInfo2KHR"/>
+ <type name="VkDisplayPlaneCapabilities2KHR"/>
+ <command name="vkGetPhysicalDeviceDisplayProperties2KHR"/>
+ <command name="vkGetPhysicalDeviceDisplayPlaneProperties2KHR"/>
+ <command name="vkGetDisplayModeProperties2KHR"/>
+ <command name="vkGetDisplayPlaneCapabilities2KHR"/>
+ </require>
+ </extension>
+ <extension name="VK_MVK_ios_surface" number="123" type="instance" requires="VK_KHR_surface" platform="ios" supported="vulkan" author="MVK" contact="Bill Hollings @billhollings" deprecatedby="VK_EXT_metal_surface">
+ <require>
+ <enum value="3" name="VK_MVK_IOS_SURFACE_SPEC_VERSION"/>
+ <enum value="&quot;VK_MVK_ios_surface&quot;" name="VK_MVK_IOS_SURFACE_EXTENSION_NAME"/>
+ <enum offset="0" extends="VkStructureType" name="VK_STRUCTURE_TYPE_IOS_SURFACE_CREATE_INFO_MVK"/>
+ <type name="VkIOSSurfaceCreateFlagsMVK"/>
+ <type name="VkIOSSurfaceCreateInfoMVK"/>
+ <command name="vkCreateIOSSurfaceMVK"/>
+ </require>
+ </extension>
+ <extension name="VK_MVK_macos_surface" number="124" type="instance" requires="VK_KHR_surface" platform="macos" supported="vulkan" author="MVK" contact="Bill Hollings @billhollings" deprecatedby="VK_EXT_metal_surface">
+ <require>
+ <enum value="3" name="VK_MVK_MACOS_SURFACE_SPEC_VERSION"/>
+ <enum value="&quot;VK_MVK_macos_surface&quot;" name="VK_MVK_MACOS_SURFACE_EXTENSION_NAME"/>
+ <enum offset="0" extends="VkStructureType" name="VK_STRUCTURE_TYPE_MACOS_SURFACE_CREATE_INFO_MVK"/>
+ <type name="VkMacOSSurfaceCreateFlagsMVK"/>
+ <type name="VkMacOSSurfaceCreateInfoMVK"/>
+ <command name="vkCreateMacOSSurfaceMVK"/>
+ </require>
+ </extension>
+ <extension name="VK_MVK_moltenvk" number="125" type="instance" author="MVK" contact="Bill Hollings @billhollings" supported="disabled">
+ <require>
+ <enum value="0" name="VK_MVK_MOLTENVK_SPEC_VERSION"/>
+ <enum value="&quot;VK_MVK_moltenvk&quot;" name="VK_MVK_MOLTENVK_EXTENSION_NAME"/>
+ </require>
+ </extension>
+ <extension name="VK_EXT_external_memory_dma_buf" number="126" type="device" requires="VK_KHR_external_memory_fd" author="EXT" contact="Chad Versace @chadversary" supported="vulkan">
+ <require>
+ <enum value="1" name="VK_EXT_EXTERNAL_MEMORY_DMA_BUF_SPEC_VERSION"/>
+ <enum value="&quot;VK_EXT_external_memory_dma_buf&quot;" name="VK_EXT_EXTERNAL_MEMORY_DMA_BUF_EXTENSION_NAME"/>
+ <enum bitpos="9" extends="VkExternalMemoryHandleTypeFlagBits" name="VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT"/>
+ </require>
+ </extension>
+ <extension name="VK_EXT_queue_family_foreign" number="127" type="device" author="EXT" requires="VK_KHR_external_memory" contact="Chad Versace @chadversary" supported="vulkan">
+ <require>
+ <enum value="1" name="VK_EXT_QUEUE_FAMILY_FOREIGN_SPEC_VERSION"/>
+ <enum value="&quot;VK_EXT_queue_family_foreign&quot;" name="VK_EXT_QUEUE_FAMILY_FOREIGN_EXTENSION_NAME"/>
+ <enum name="VK_QUEUE_FAMILY_FOREIGN_EXT"/>
+ </require>
+ </extension>
+ <extension name="VK_KHR_dedicated_allocation" number="128" type="device" author="KHR" requires="VK_KHR_get_memory_requirements2" contact="James Jones @cubanismo" supported="vulkan" promotedto="VK_VERSION_1_1">
+ <require>
+ <enum value="3" name="VK_KHR_DEDICATED_ALLOCATION_SPEC_VERSION"/>
+ <enum value="&quot;VK_KHR_dedicated_allocation&quot;" name="VK_KHR_DEDICATED_ALLOCATION_EXTENSION_NAME"/>
+ <enum extends="VkStructureType" name="VK_STRUCTURE_TYPE_MEMORY_DEDICATED_REQUIREMENTS_KHR" alias="VK_STRUCTURE_TYPE_MEMORY_DEDICATED_REQUIREMENTS"/>
+ <enum extends="VkStructureType" name="VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO_KHR" alias="VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO"/>
+ <type name="VkMemoryDedicatedRequirementsKHR"/>
+ <type name="VkMemoryDedicatedAllocateInfoKHR"/>
+ </require>
+ </extension>
+ <extension name="VK_EXT_debug_utils" number="129" type="instance" author="EXT" contact="Mark Young @marky-lunarg" specialuse="debugging" supported="vulkan">
+ <require>
+ <enum value="2" name="VK_EXT_DEBUG_UTILS_SPEC_VERSION"/>
+ <enum value="&quot;VK_EXT_debug_utils&quot;" name="VK_EXT_DEBUG_UTILS_EXTENSION_NAME"/>
+ <enum offset="0" extends="VkStructureType" name="VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT"/>
+ <enum offset="1" extends="VkStructureType" name="VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_TAG_INFO_EXT"/>
+ <enum offset="2" extends="VkStructureType" name="VK_STRUCTURE_TYPE_DEBUG_UTILS_LABEL_EXT"/>
+ <enum offset="3" extends="VkStructureType" name="VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CALLBACK_DATA_EXT"/>
+ <enum offset="4" extends="VkStructureType" name="VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT"/>
+ <enum offset="0" extends="VkObjectType" name="VK_OBJECT_TYPE_DEBUG_UTILS_MESSENGER_EXT"/>
+ <type name="PFN_vkDebugUtilsMessengerCallbackEXT"/>
+ <type name="VkDebugUtilsLabelEXT"/>
+ <type name="VkDebugUtilsMessageSeverityFlagBitsEXT"/>
+ <type name="VkDebugUtilsMessageSeverityFlagsEXT"/>
+ <type name="VkDebugUtilsMessageTypeFlagBitsEXT"/>
+ <type name="VkDebugUtilsMessageTypeFlagsEXT"/>
+ <type name="VkDebugUtilsMessengerCallbackDataEXT"/>
+ <type name="VkDebugUtilsMessengerCallbackDataFlagsEXT"/>
+ <type name="VkDebugUtilsMessengerCreateFlagsEXT"/>
+ <type name="VkDebugUtilsMessengerCreateInfoEXT"/>
+ <type name="VkDebugUtilsMessengerEXT"/>
+ <type name="VkDebugUtilsObjectNameInfoEXT"/>
+ <type name="VkDebugUtilsObjectTagInfoEXT"/>
+ <command name="vkSetDebugUtilsObjectNameEXT"/>
+ <command name="vkSetDebugUtilsObjectTagEXT"/>
+ <command name="vkQueueBeginDebugUtilsLabelEXT"/>
+ <command name="vkQueueEndDebugUtilsLabelEXT"/>
+ <command name="vkQueueInsertDebugUtilsLabelEXT"/>
+ <command name="vkCmdBeginDebugUtilsLabelEXT"/>
+ <command name="vkCmdEndDebugUtilsLabelEXT"/>
+ <command name="vkCmdInsertDebugUtilsLabelEXT"/>
+ <command name="vkCreateDebugUtilsMessengerEXT"/>
+ <command name="vkDestroyDebugUtilsMessengerEXT"/>
+ <command name="vkSubmitDebugUtilsMessageEXT"/>
+ </require>
+ </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="&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"/>
+ <enum offset="1" extends="VkStructureType" name="VK_STRUCTURE_TYPE_ANDROID_HARDWARE_BUFFER_PROPERTIES_ANDROID"/>
+ <enum offset="2" extends="VkStructureType" name="VK_STRUCTURE_TYPE_ANDROID_HARDWARE_BUFFER_FORMAT_PROPERTIES_ANDROID"/>
+ <enum offset="3" extends="VkStructureType" name="VK_STRUCTURE_TYPE_IMPORT_ANDROID_HARDWARE_BUFFER_INFO_ANDROID"/>
+ <enum offset="4" extends="VkStructureType" name="VK_STRUCTURE_TYPE_MEMORY_GET_ANDROID_HARDWARE_BUFFER_INFO_ANDROID"/>
+ <enum offset="5" extends="VkStructureType" name="VK_STRUCTURE_TYPE_EXTERNAL_FORMAT_ANDROID"/>
+ <type name="VkAndroidHardwareBufferUsageANDROID"/>
+ <type name="VkAndroidHardwareBufferPropertiesANDROID"/>
+ <type name="VkAndroidHardwareBufferFormatPropertiesANDROID"/>
+ <type name="VkImportAndroidHardwareBufferInfoANDROID"/>
+ <type name="VkMemoryGetAndroidHardwareBufferInfoANDROID"/>
+ <type name="VkExternalFormatANDROID"/>
+ <command name="vkGetAndroidHardwareBufferPropertiesANDROID"/>
+ <command name="vkGetMemoryAndroidHardwareBufferANDROID"/>
+ <type name="AHardwareBuffer"/>
+ </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>
+ <enum value="2" name="VK_EXT_SAMPLER_FILTER_MINMAX_SPEC_VERSION"/>
+ <enum value="&quot;VK_EXT_sampler_filter_minmax&quot;" name="VK_EXT_SAMPLER_FILTER_MINMAX_EXTENSION_NAME"/>
+ <enum extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLER_FILTER_MINMAX_PROPERTIES_EXT" alias="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLER_FILTER_MINMAX_PROPERTIES"/>
+ <enum extends="VkStructureType" name="VK_STRUCTURE_TYPE_SAMPLER_REDUCTION_MODE_CREATE_INFO_EXT" alias="VK_STRUCTURE_TYPE_SAMPLER_REDUCTION_MODE_CREATE_INFO"/>
+ <enum extends="VkFormatFeatureFlagBits" name="VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_MINMAX_BIT_EXT" alias="VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_MINMAX_BIT"/>
+ <enum extends="VkSamplerReductionMode" name="VK_SAMPLER_REDUCTION_MODE_WEIGHTED_AVERAGE_EXT" alias="VK_SAMPLER_REDUCTION_MODE_WEIGHTED_AVERAGE"/>
+ <enum extends="VkSamplerReductionMode" name="VK_SAMPLER_REDUCTION_MODE_MIN_EXT" alias="VK_SAMPLER_REDUCTION_MODE_MIN"/>
+ <enum extends="VkSamplerReductionMode" name="VK_SAMPLER_REDUCTION_MODE_MAX_EXT" alias="VK_SAMPLER_REDUCTION_MODE_MAX"/>
+ <type name="VkSamplerReductionModeEXT"/>
+ <type name="VkSamplerReductionModeCreateInfoEXT"/>
+ <type name="VkPhysicalDeviceSamplerFilterMinmaxPropertiesEXT"/>
+ </require>
+ </extension>
+ <extension name="VK_KHR_storage_buffer_storage_class" number="132" type="device" author="KHR" contact="Alexander Galazin @alegal-arm" supported="vulkan" promotedto="VK_VERSION_1_1">
+ <require>
+ <enum value="1" name="VK_KHR_STORAGE_BUFFER_STORAGE_CLASS_SPEC_VERSION"/>
+ <enum value="&quot;VK_KHR_storage_buffer_storage_class&quot;" name="VK_KHR_STORAGE_BUFFER_STORAGE_CLASS_EXTENSION_NAME"/>
+ </require>
+ </extension>
+ <extension name="VK_AMD_gpu_shader_int16" number="133" type="device" author="AMD" contact="Qun Lin @linqun" supported="vulkan" deprecatedby="VK_KHR_shader_float16_int8">
+ <require>
+ <enum value="2" name="VK_AMD_GPU_SHADER_INT16_SPEC_VERSION"/>
+ <enum value="&quot;VK_AMD_gpu_shader_int16&quot;" name="VK_AMD_GPU_SHADER_INT16_EXTENSION_NAME"/>
+ </require>
+ </extension>
+ <extension name="VK_AMD_extension_134" number="134" author="AMD" contact="Mais Alnasser @malnasse" supported="disabled">
+ <require>
+ <enum value="0" name="VK_AMD_EXTENSION_134_SPEC_VERSION"/>
+ <enum value="&quot;VK_AMD_extension_134&quot;" name="VK_AMD_EXTENSION_134_EXTENSION_NAME"/>
+ </require>
+ </extension>
+ <extension name="VK_AMD_extension_135" number="135" author="AMD" contact="Mais Alnasser @malnasse" supported="disabled">
+ <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"/>
+ </require>
+ </extension>
+ <extension name="VK_AMD_extension_136" number="136" author="AMD" contact="Mais Alnasser @malnasse" supported="disabled">
+ <require>
+ <enum value="0" name="VK_AMD_EXTENSION_136_SPEC_VERSION"/>
+ <enum value="&quot;VK_AMD_extension_136&quot;" name="VK_AMD_EXTENSION_136_EXTENSION_NAME"/>
+ </require>
+ </extension>
+ <extension name="VK_AMD_mixed_attachment_samples" number="137" type="device" author="AMD" contact="Matthaeus G. Chajdas @anteru" supported="vulkan">
+ <require>
+ <enum value="1" name="VK_AMD_MIXED_ATTACHMENT_SAMPLES_SPEC_VERSION"/>
+ <enum value="&quot;VK_AMD_mixed_attachment_samples&quot;" name="VK_AMD_MIXED_ATTACHMENT_SAMPLES_EXTENSION_NAME"/>
+ </require>
+ </extension>
+ <extension name="VK_AMD_shader_fragment_mask" number="138" author="AMD" contact="Aaron Hagan @AaronHaganAMD" supported="vulkan" type="device">
+ <require>
+ <enum value="1" name="VK_AMD_SHADER_FRAGMENT_MASK_SPEC_VERSION"/>
+ <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">
+ <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"/>
+ <type name="VkPhysicalDeviceInlineUniformBlockFeaturesEXT"/>
+ <type name="VkPhysicalDeviceInlineUniformBlockPropertiesEXT"/>
+ <type name="VkWriteDescriptorSetInlineUniformBlockEXT"/>
+ <type name="VkDescriptorPoolInlineUniformBlockCreateInfoEXT"/>
+ </require>
+ </extension>
+ <extension name="VK_AMD_extension_140" number="140" author="AMD" contact="Mais Alnasser @malnasse" supported="disabled">
+ <require>
+ <enum value="0" name="VK_AMD_EXTENSION_140_SPEC_VERSION"/>
+ <enum value="&quot;VK_AMD_extension_140&quot;" name="VK_AMD_EXTENSION_140_EXTENSION_NAME"/>
+ </require>
+ </extension>
+ <extension name="VK_EXT_shader_stencil_export" number="141" type="device" author="EXT" contact="Dominik Witczak @dominikwitczakamd" supported="vulkan">
+ <require>
+ <enum value="1" name="VK_EXT_SHADER_STENCIL_EXPORT_SPEC_VERSION"/>
+ <enum value="&quot;VK_EXT_shader_stencil_export&quot;" name="VK_EXT_SHADER_STENCIL_EXPORT_EXTENSION_NAME"/>
+ </require>
+ </extension>
+ <extension name="VK_AMD_extension_142" number="142" author="AMD" contact="Mais Alnasser @malnasse" supported="disabled">
+ <require>
+ <enum value="0" name="VK_AMD_EXTENSION_142_SPEC_VERSION"/>
+ <enum value="&quot;VK_AMD_extension_142&quot;" name="VK_AMD_EXTENSION_142_EXTENSION_NAME"/>
+ </require>
+ </extension>
+ <extension name="VK_AMD_extension_143" number="143" author="AMD" contact="Mais Alnasser @malnasse" supported="disabled">
+ <require>
+ <enum value="0" name="VK_AMD_EXTENSION_143_SPEC_VERSION"/>
+ <enum value="&quot;VK_AMD_extension_143&quot;" name="VK_AMD_EXTENSION_143_EXTENSION_NAME"/>
+ </require>
+ </extension>
+ <extension name="VK_EXT_sample_locations" number="144" type="device" author="AMD" contact="Daniel Rakos @drakos-amd" supported="vulkan" requires="VK_KHR_get_physical_device_properties2">
+ <require>
+ <enum value="1" name="VK_EXT_SAMPLE_LOCATIONS_SPEC_VERSION"/>
+ <enum value="&quot;VK_EXT_sample_locations&quot;" name="VK_EXT_SAMPLE_LOCATIONS_EXTENSION_NAME"/>
+ <enum bitpos="12" extends="VkImageCreateFlagBits" name="VK_IMAGE_CREATE_SAMPLE_LOCATIONS_COMPATIBLE_DEPTH_BIT_EXT"/>
+ <enum offset="0" extends="VkStructureType" name="VK_STRUCTURE_TYPE_SAMPLE_LOCATIONS_INFO_EXT"/>
+ <enum offset="1" extends="VkStructureType" name="VK_STRUCTURE_TYPE_RENDER_PASS_SAMPLE_LOCATIONS_BEGIN_INFO_EXT"/>
+ <enum offset="2" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PIPELINE_SAMPLE_LOCATIONS_STATE_CREATE_INFO_EXT"/>
+ <enum offset="3" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLE_LOCATIONS_PROPERTIES_EXT"/>
+ <enum offset="4" extends="VkStructureType" name="VK_STRUCTURE_TYPE_MULTISAMPLE_PROPERTIES_EXT"/>
+ <enum offset="0" extends="VkDynamicState" name="VK_DYNAMIC_STATE_SAMPLE_LOCATIONS_EXT"/>
+ <type name="VkSampleLocationEXT"/>
+ <type name="VkSampleLocationsInfoEXT"/>
+ <type name="VkAttachmentSampleLocationsEXT"/>
+ <type name="VkSubpassSampleLocationsEXT"/>
+ <type name="VkRenderPassSampleLocationsBeginInfoEXT"/>
+ <type name="VkPipelineSampleLocationsStateCreateInfoEXT"/>
+ <type name="VkPhysicalDeviceSampleLocationsPropertiesEXT"/>
+ <type name="VkMultisamplePropertiesEXT"/>
+ <command name="vkCmdSetSampleLocationsEXT"/>
+ <command name="vkGetPhysicalDeviceMultisamplePropertiesEXT"/>
+ </require>
+ </extension>
+ <extension name="VK_KHR_relaxed_block_layout" number="145" type="device" author="KHR" contact="John Kessenich @johnkslang" supported="vulkan" promotedto="VK_VERSION_1_1">
+ <require>
+ <enum value="1" name="VK_KHR_RELAXED_BLOCK_LAYOUT_SPEC_VERSION"/>
+ <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>
+ <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>
+ <enum value="1" name="VK_KHR_GET_MEMORY_REQUIREMENTS_2_SPEC_VERSION"/>
+ <enum value="&quot;VK_KHR_get_memory_requirements2&quot;" name="VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME"/>
+ <enum extends="VkStructureType" name="VK_STRUCTURE_TYPE_BUFFER_MEMORY_REQUIREMENTS_INFO_2_KHR" alias="VK_STRUCTURE_TYPE_BUFFER_MEMORY_REQUIREMENTS_INFO_2"/>
+ <enum extends="VkStructureType" name="VK_STRUCTURE_TYPE_IMAGE_MEMORY_REQUIREMENTS_INFO_2_KHR" alias="VK_STRUCTURE_TYPE_IMAGE_MEMORY_REQUIREMENTS_INFO_2"/>
+ <enum extends="VkStructureType" name="VK_STRUCTURE_TYPE_IMAGE_SPARSE_MEMORY_REQUIREMENTS_INFO_2_KHR" alias="VK_STRUCTURE_TYPE_IMAGE_SPARSE_MEMORY_REQUIREMENTS_INFO_2"/>
+ <enum extends="VkStructureType" name="VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2_KHR" alias="VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2"/>
+ <enum extends="VkStructureType" name="VK_STRUCTURE_TYPE_SPARSE_IMAGE_MEMORY_REQUIREMENTS_2_KHR" alias="VK_STRUCTURE_TYPE_SPARSE_IMAGE_MEMORY_REQUIREMENTS_2"/>
+ <type name="VkBufferMemoryRequirementsInfo2KHR"/>
+ <type name="VkImageMemoryRequirementsInfo2KHR"/>
+ <type name="VkImageSparseMemoryRequirementsInfo2KHR"/>
+ <type name="VkMemoryRequirements2KHR"/>
+ <type name="VkSparseImageMemoryRequirements2KHR"/>
+ <command name="vkGetImageMemoryRequirements2KHR"/>
+ <command name="vkGetBufferMemoryRequirements2KHR"/>
+ <command name="vkGetImageSparseMemoryRequirements2KHR"/>
+ </require>
+ </extension>
+ <extension name="VK_KHR_image_format_list" number="148" type="device" author="KHR" contact="Jason Ekstrand @jekstrand" supported="vulkan" promotedto="VK_VERSION_1_2">
+ <require>
+ <enum value="1" name="VK_KHR_IMAGE_FORMAT_LIST_SPEC_VERSION"/>
+ <enum value="&quot;VK_KHR_image_format_list&quot;" name="VK_KHR_IMAGE_FORMAT_LIST_EXTENSION_NAME"/>
+ <enum extends="VkStructureType" name="VK_STRUCTURE_TYPE_IMAGE_FORMAT_LIST_CREATE_INFO_KHR" alias="VK_STRUCTURE_TYPE_IMAGE_FORMAT_LIST_CREATE_INFO"/>
+ <type name="VkImageFormatListCreateInfoKHR"/>
+ </require>
+ </extension>
+ <extension name="VK_EXT_blend_operation_advanced" number="149" type="device" author="NV" contact="Jeff Bolz @jeffbolznv" supported="vulkan">
+ <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"/>
+ <enum offset="0" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BLEND_OPERATION_ADVANCED_FEATURES_EXT"/>
+ <enum offset="1" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BLEND_OPERATION_ADVANCED_PROPERTIES_EXT"/>
+ <enum offset="2" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_ADVANCED_STATE_CREATE_INFO_EXT"/>
+ <type name="VkPhysicalDeviceBlendOperationAdvancedFeaturesEXT"/>
+ <type name="VkPhysicalDeviceBlendOperationAdvancedPropertiesEXT"/>
+ <type name="VkPipelineColorBlendAdvancedStateCreateInfoEXT"/>
+ <type name="VkBlendOverlapEXT"/>
+ <enum offset="0" extends="VkBlendOp" name="VK_BLEND_OP_ZERO_EXT"/>
+ <enum offset="1" extends="VkBlendOp" name="VK_BLEND_OP_SRC_EXT"/>
+ <enum offset="2" extends="VkBlendOp" name="VK_BLEND_OP_DST_EXT"/>
+ <enum offset="3" extends="VkBlendOp" name="VK_BLEND_OP_SRC_OVER_EXT"/>
+ <enum offset="4" extends="VkBlendOp" name="VK_BLEND_OP_DST_OVER_EXT"/>
+ <enum offset="5" extends="VkBlendOp" name="VK_BLEND_OP_SRC_IN_EXT"/>
+ <enum offset="6" extends="VkBlendOp" name="VK_BLEND_OP_DST_IN_EXT"/>
+ <enum offset="7" extends="VkBlendOp" name="VK_BLEND_OP_SRC_OUT_EXT"/>
+ <enum offset="8" extends="VkBlendOp" name="VK_BLEND_OP_DST_OUT_EXT"/>
+ <enum offset="9" extends="VkBlendOp" name="VK_BLEND_OP_SRC_ATOP_EXT"/>
+ <enum offset="10" extends="VkBlendOp" name="VK_BLEND_OP_DST_ATOP_EXT"/>
+ <enum offset="11" extends="VkBlendOp" name="VK_BLEND_OP_XOR_EXT"/>
+ <enum offset="12" extends="VkBlendOp" name="VK_BLEND_OP_MULTIPLY_EXT"/>
+ <enum offset="13" extends="VkBlendOp" name="VK_BLEND_OP_SCREEN_EXT"/>
+ <enum offset="14" extends="VkBlendOp" name="VK_BLEND_OP_OVERLAY_EXT"/>
+ <enum offset="15" extends="VkBlendOp" name="VK_BLEND_OP_DARKEN_EXT"/>
+ <enum offset="16" extends="VkBlendOp" name="VK_BLEND_OP_LIGHTEN_EXT"/>
+ <enum offset="17" extends="VkBlendOp" name="VK_BLEND_OP_COLORDODGE_EXT"/>
+ <enum offset="18" extends="VkBlendOp" name="VK_BLEND_OP_COLORBURN_EXT"/>
+ <enum offset="19" extends="VkBlendOp" name="VK_BLEND_OP_HARDLIGHT_EXT"/>
+ <enum offset="20" extends="VkBlendOp" name="VK_BLEND_OP_SOFTLIGHT_EXT"/>
+ <enum offset="21" extends="VkBlendOp" name="VK_BLEND_OP_DIFFERENCE_EXT"/>
+ <enum offset="22" extends="VkBlendOp" name="VK_BLEND_OP_EXCLUSION_EXT"/>
+ <enum offset="23" extends="VkBlendOp" name="VK_BLEND_OP_INVERT_EXT"/>
+ <enum offset="24" extends="VkBlendOp" name="VK_BLEND_OP_INVERT_RGB_EXT"/>
+ <enum offset="25" extends="VkBlendOp" name="VK_BLEND_OP_LINEARDODGE_EXT"/>
+ <enum offset="26" extends="VkBlendOp" name="VK_BLEND_OP_LINEARBURN_EXT"/>
+ <enum offset="27" extends="VkBlendOp" name="VK_BLEND_OP_VIVIDLIGHT_EXT"/>
+ <enum offset="28" extends="VkBlendOp" name="VK_BLEND_OP_LINEARLIGHT_EXT"/>
+ <enum offset="29" extends="VkBlendOp" name="VK_BLEND_OP_PINLIGHT_EXT"/>
+ <enum offset="30" extends="VkBlendOp" name="VK_BLEND_OP_HARDMIX_EXT"/>
+ <enum offset="31" extends="VkBlendOp" name="VK_BLEND_OP_HSL_HUE_EXT"/>
+ <enum offset="32" extends="VkBlendOp" name="VK_BLEND_OP_HSL_SATURATION_EXT"/>
+ <enum offset="33" extends="VkBlendOp" name="VK_BLEND_OP_HSL_COLOR_EXT"/>
+ <enum offset="34" extends="VkBlendOp" name="VK_BLEND_OP_HSL_LUMINOSITY_EXT"/>
+ <enum offset="35" extends="VkBlendOp" name="VK_BLEND_OP_PLUS_EXT"/>
+ <enum offset="36" extends="VkBlendOp" name="VK_BLEND_OP_PLUS_CLAMPED_EXT"/>
+ <enum offset="37" extends="VkBlendOp" name="VK_BLEND_OP_PLUS_CLAMPED_ALPHA_EXT"/>
+ <enum offset="38" extends="VkBlendOp" name="VK_BLEND_OP_PLUS_DARKER_EXT"/>
+ <enum offset="39" extends="VkBlendOp" name="VK_BLEND_OP_MINUS_EXT"/>
+ <enum offset="40" extends="VkBlendOp" name="VK_BLEND_OP_MINUS_CLAMPED_EXT"/>
+ <enum offset="41" extends="VkBlendOp" name="VK_BLEND_OP_CONTRAST_EXT"/>
+ <enum offset="42" extends="VkBlendOp" name="VK_BLEND_OP_INVERT_OVG_EXT"/>
+ <enum offset="43" extends="VkBlendOp" name="VK_BLEND_OP_RED_EXT"/>
+ <enum offset="44" extends="VkBlendOp" name="VK_BLEND_OP_GREEN_EXT"/>
+ <enum offset="45" extends="VkBlendOp" name="VK_BLEND_OP_BLUE_EXT"/>
+ <enum bitpos="19" extends="VkAccessFlagBits" name="VK_ACCESS_COLOR_ATTACHMENT_READ_NONCOHERENT_BIT_EXT"/>
+ </require>
+ </extension>
+ <extension name="VK_NV_fragment_coverage_to_color" number="150" type="device" author="NV" contact="Jeff Bolz @jeffbolznv" supported="vulkan">
+ <require>
+ <enum value="1" name="VK_NV_FRAGMENT_COVERAGE_TO_COLOR_SPEC_VERSION"/>
+ <enum value="&quot;VK_NV_fragment_coverage_to_color&quot;" name="VK_NV_FRAGMENT_COVERAGE_TO_COLOR_EXTENSION_NAME"/>
+ <enum offset="0" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PIPELINE_COVERAGE_TO_COLOR_STATE_CREATE_INFO_NV"/>
+ <type name="VkPipelineCoverageToColorStateCreateFlagsNV"/>
+ <type name="VkPipelineCoverageToColorStateCreateInfoNV"/>
+ </require>
+ </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="&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"/>
+ <enum offset="2" extends="VkStructureType" name="VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_DEVICE_ADDRESS_INFO_KHR"/>
+ <enum offset="3" extends="VkStructureType" name="VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_AABBS_DATA_KHR"/>
+ <enum offset="4" extends="VkStructureType" name="VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_INSTANCES_DATA_KHR"/>
+ <enum offset="5" extends="VkStructureType" name="VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_TRIANGLES_DATA_KHR"/>
+ <enum offset="6" extends="VkStructureType" name="VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_KHR"/>
+ <enum offset="9" extends="VkStructureType" name="VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_VERSION_INFO_KHR"/>
+ <enum offset="10" extends="VkStructureType" name="VK_STRUCTURE_TYPE_COPY_ACCELERATION_STRUCTURE_INFO_KHR"/>
+ <enum offset="11" extends="VkStructureType" name="VK_STRUCTURE_TYPE_COPY_ACCELERATION_STRUCTURE_TO_MEMORY_INFO_KHR"/>
+ <enum offset="12" extends="VkStructureType" name="VK_STRUCTURE_TYPE_COPY_MEMORY_TO_ACCELERATION_STRUCTURE_INFO_KHR"/>
+ <enum offset="13" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ACCELERATION_STRUCTURE_FEATURES_KHR"/>
+ <enum offset="14" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ACCELERATION_STRUCTURE_PROPERTIES_KHR"/>
+ <enum offset="17" extends="VkStructureType" name="VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_CREATE_INFO_KHR"/>
+ <enum offset="20" extends="VkStructureType" name="VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_BUILD_SIZES_INFO_KHR"/>
+ <enum bitpos="25" extends="VkPipelineStageFlagBits" name="VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_KHR"/>
+ <enum offset="0" extends="VkDescriptorType" name="VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR"/>
+ <enum bitpos="21" extends="VkAccessFlagBits" name="VK_ACCESS_ACCELERATION_STRUCTURE_READ_BIT_KHR"/>
+ <enum bitpos="22" extends="VkAccessFlagBits" name="VK_ACCESS_ACCELERATION_STRUCTURE_WRITE_BIT_KHR"/>
+ <enum offset="0" extends="VkQueryType" name="VK_QUERY_TYPE_ACCELERATION_STRUCTURE_COMPACTED_SIZE_KHR"/>
+ <enum offset="1" extends="VkQueryType" name="VK_QUERY_TYPE_ACCELERATION_STRUCTURE_SERIALIZATION_SIZE_KHR"/>
+ <enum offset="0" extends="VkObjectType" name="VK_OBJECT_TYPE_ACCELERATION_STRUCTURE_KHR"/>
+ <enum offset="0" extends="VkDebugReportObjectTypeEXT" name="VK_DEBUG_REPORT_OBJECT_TYPE_ACCELERATION_STRUCTURE_KHR_EXT"/>
+ <enum offset="0" extends="VkIndexType" extnumber="166" name="VK_INDEX_TYPE_NONE_KHR"/>
+ <enum bitpos="29" extends="VkFormatFeatureFlagBits" name="VK_FORMAT_FEATURE_ACCELERATION_STRUCTURE_VERTEX_BUFFER_BIT_KHR"/>
+ <enum bitpos="19" extends="VkBufferUsageFlagBits" name="VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR"/>
+ <enum bitpos="20" extends="VkBufferUsageFlagBits" name="VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_STORAGE_BIT_KHR"/>
+ <type name="VkAccelerationStructureTypeKHR"/>
+ <type name="VkDeviceOrHostAddressKHR"/>
+ <type name="VkDeviceOrHostAddressConstKHR"/>
+ <type name="VkAccelerationStructureBuildRangeInfoKHR"/>
+ <type name="VkAabbPositionsKHR"/>
+ <type name="VkAccelerationStructureGeometryTrianglesDataKHR"/>
+ <type name="VkTransformMatrixKHR"/>
+ <type name="VkAccelerationStructureBuildGeometryInfoKHR"/>
+ <type name="VkAccelerationStructureBuildTypeKHR"/>
+ <type name="VkAccelerationStructureGeometryAabbsDataKHR"/>
+ <type name="VkAccelerationStructureInstanceKHR"/>
+ <type name="VkAccelerationStructureGeometryInstancesDataKHR"/>
+ <type name="VkAccelerationStructureGeometryDataKHR"/>
+ <type name="VkAccelerationStructureGeometryKHR"/>
+ <type name="VkGeometryFlagsKHR"/>
+ <type name="VkGeometryInstanceFlagsKHR"/>
+ <type name="VkGeometryFlagBitsKHR"/>
+ <type name="VkGeometryInstanceFlagBitsKHR"/>
+ <type name="VkAccelerationStructureCreateInfoKHR"/>
+ <type name="VkAccelerationStructureKHR"/>
+ <type name="VkBuildAccelerationStructureFlagBitsKHR"/>
+ <type name="VkBuildAccelerationStructureFlagsKHR"/>
+ <type name="VkCopyAccelerationStructureModeKHR"/>
+ <type name="VkGeometryTypeKHR"/>
+ <type name="VkWriteDescriptorSetAccelerationStructureKHR"/>
+ <type name="VkPhysicalDeviceAccelerationStructureFeaturesKHR"/>
+ <type name="VkPhysicalDeviceAccelerationStructurePropertiesKHR"/>
+ <type name="VkAccelerationStructureDeviceAddressInfoKHR"/>
+ <type name="VkAccelerationStructureVersionInfoKHR"/>
+ <type name="VkCopyAccelerationStructureToMemoryInfoKHR"/>
+ <type name="VkCopyMemoryToAccelerationStructureInfoKHR"/>
+ <type name="VkCopyAccelerationStructureInfoKHR"/>
+ <type name="VkAccelerationStructureCompatibilityKHR"/>
+ <type name="VkAccelerationStructureCreateFlagBitsKHR"/>
+ <type name="VkAccelerationStructureCreateFlagsKHR"/>
+ <type name="VkBuildAccelerationStructureModeKHR"/>
+ <type name="VkAccelerationStructureBuildSizesInfoKHR"/>
+ <command name="vkCreateAccelerationStructureKHR"/>
+ <command name="vkDestroyAccelerationStructureKHR"/>
+ <command name="vkCmdBuildAccelerationStructuresKHR"/>
+ <command name="vkCmdBuildAccelerationStructuresIndirectKHR"/>
+ <command name="vkBuildAccelerationStructuresKHR"/>
+ <command name="vkCopyAccelerationStructureKHR"/>
+ <command name="vkCopyAccelerationStructureToMemoryKHR"/>
+ <command name="vkCopyMemoryToAccelerationStructureKHR"/>
+ <command name="vkWriteAccelerationStructuresPropertiesKHR"/>
+ <command name="vkCmdCopyAccelerationStructureKHR"/>
+ <command name="vkCmdCopyAccelerationStructureToMemoryKHR"/>
+ <command name="vkCmdCopyMemoryToAccelerationStructureKHR"/>
+ <command name="vkGetAccelerationStructureDeviceAddressKHR"/>
+ <command name="vkCmdWriteAccelerationStructuresPropertiesKHR"/>
+ <command name="vkGetDeviceAccelerationStructureCompatibilityKHR"/>
+ <command name="vkGetAccelerationStructureBuildSizesKHR"/>
+ </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>
+ <enum value="1" name="VK_KHR_RAY_TRACING_PIPELINE_SPEC_VERSION"/>
+ <enum value="&quot;VK_KHR_ray_tracing_pipeline&quot;" name="VK_KHR_RAY_TRACING_PIPELINE_EXTENSION_NAME"/>
+ <enum name="VK_SHADER_UNUSED_KHR"/>
+ <enum offset="0" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_FEATURES_KHR"/>
+ <enum offset="1" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_PROPERTIES_KHR"/>
+ <enum offset="15" extends="VkStructureType" extnumber="151" name="VK_STRUCTURE_TYPE_RAY_TRACING_PIPELINE_CREATE_INFO_KHR"/>
+ <enum offset="16" extends="VkStructureType" extnumber="151" name="VK_STRUCTURE_TYPE_RAY_TRACING_SHADER_GROUP_CREATE_INFO_KHR"/>
+ <enum offset="18" extends="VkStructureType" extnumber="151" name="VK_STRUCTURE_TYPE_RAY_TRACING_PIPELINE_INTERFACE_CREATE_INFO_KHR"/>
+ <enum bitpos="8" extends="VkShaderStageFlagBits" name="VK_SHADER_STAGE_RAYGEN_BIT_KHR"/>
+ <enum bitpos="9" extends="VkShaderStageFlagBits" name="VK_SHADER_STAGE_ANY_HIT_BIT_KHR"/>
+ <enum bitpos="10" extends="VkShaderStageFlagBits" name="VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR"/>
+ <enum bitpos="11" extends="VkShaderStageFlagBits" name="VK_SHADER_STAGE_MISS_BIT_KHR"/>
+ <enum bitpos="12" extends="VkShaderStageFlagBits" name="VK_SHADER_STAGE_INTERSECTION_BIT_KHR"/>
+ <enum bitpos="13" extends="VkShaderStageFlagBits" name="VK_SHADER_STAGE_CALLABLE_BIT_KHR"/>
+ <enum bitpos="21" extends="VkPipelineStageFlagBits" name="VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_KHR"/>
+ <enum bitpos="10" extends="VkBufferUsageFlagBits" name="VK_BUFFER_USAGE_SHADER_BINDING_TABLE_BIT_KHR"/>
+ <enum offset="0" extends="VkPipelineBindPoint" extnumber="166" name="VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR"/>
+ <enum bitpos="14" extends="VkPipelineCreateFlagBits" name="VK_PIPELINE_CREATE_RAY_TRACING_NO_NULL_ANY_HIT_SHADERS_BIT_KHR"/>
+ <enum bitpos="15" extends="VkPipelineCreateFlagBits" name="VK_PIPELINE_CREATE_RAY_TRACING_NO_NULL_CLOSEST_HIT_SHADERS_BIT_KHR"/>
+ <enum bitpos="16" extends="VkPipelineCreateFlagBits" name="VK_PIPELINE_CREATE_RAY_TRACING_NO_NULL_MISS_SHADERS_BIT_KHR"/>
+ <enum bitpos="17" extends="VkPipelineCreateFlagBits" name="VK_PIPELINE_CREATE_RAY_TRACING_NO_NULL_INTERSECTION_SHADERS_BIT_KHR"/>
+ <enum bitpos="12" extends="VkPipelineCreateFlagBits" name="VK_PIPELINE_CREATE_RAY_TRACING_SKIP_TRIANGLES_BIT_KHR"/>
+ <enum bitpos="13" extends="VkPipelineCreateFlagBits" name="VK_PIPELINE_CREATE_RAY_TRACING_SKIP_AABBS_BIT_KHR"/>
+ <enum bitpos="19" extends="VkPipelineCreateFlagBits" name="VK_PIPELINE_CREATE_RAY_TRACING_SHADER_GROUP_HANDLE_CAPTURE_REPLAY_BIT_KHR"/>
+ <enum offset="0" extends="VkDynamicState" name="VK_DYNAMIC_STATE_RAY_TRACING_PIPELINE_STACK_SIZE_KHR"/>
+ <type name="VkRayTracingShaderGroupCreateInfoKHR"/>
+ <type name="VkRayTracingShaderGroupTypeKHR"/>
+ <type name="VkRayTracingPipelineCreateInfoKHR"/>
+ <type name="VkPhysicalDeviceRayTracingPipelineFeaturesKHR"/>
+ <type name="VkPhysicalDeviceRayTracingPipelinePropertiesKHR"/>
+ <type name="VkStridedDeviceAddressRegionKHR"/>
+ <type name="VkTraceRaysIndirectCommandKHR"/>
+ <type name="VkRayTracingPipelineInterfaceCreateInfoKHR"/>
+ <type name="VkShaderGroupShaderKHR"/>
+ <command name="vkCmdTraceRaysKHR"/>
+ <command name="vkCreateRayTracingPipelinesKHR"/>
+ <command name="vkGetRayTracingShaderGroupHandlesKHR"/>
+ <command name="vkGetRayTracingCaptureReplayShaderGroupHandlesKHR"/>
+ <command name="vkCmdTraceRaysIndirectKHR"/>
+ <command name="vkGetRayTracingShaderGroupStackSizeKHR"/>
+ <command name="vkCmdSetRayTracingPipelineStackSizeKHR"/>
+ </require>
+ </extension>
+ <extension name="VK_KHR_ray_query" number="349" 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>
+ <enum value="1" name="VK_KHR_RAY_QUERY_SPEC_VERSION"/>
+ <enum value="&quot;VK_KHR_ray_query&quot;" name="VK_KHR_RAY_QUERY_EXTENSION_NAME"/>
+ <enum offset="13" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_QUERY_FEATURES_KHR"/>
+ <type name="VkPhysicalDeviceRayQueryFeaturesKHR"/>
+ </require>
+ </extension>
+ <extension name="VK_NV_extension_152" number="152" author="NV" contact="Jeff Bolz @jeffbolznv" supported="disabled">
+ <require>
+ <enum value="0" name="VK_NV_EXTENSION_152_SPEC_VERSION"/>
+ <enum value="&quot;VK_NV_extension_152&quot;" name="VK_NV_EXTENSION_152_EXTENSION_NAME"/>
+ </require>
+ </extension>
+ <extension name="VK_NV_framebuffer_mixed_samples" number="153" type="device" author="NV" contact="Jeff Bolz @jeffbolznv" supported="vulkan">
+ <require>
+ <enum value="1" name="VK_NV_FRAMEBUFFER_MIXED_SAMPLES_SPEC_VERSION"/>
+ <enum value="&quot;VK_NV_framebuffer_mixed_samples&quot;" name="VK_NV_FRAMEBUFFER_MIXED_SAMPLES_EXTENSION_NAME"/>
+ <enum offset="0" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PIPELINE_COVERAGE_MODULATION_STATE_CREATE_INFO_NV"/>
+ <type name="VkPipelineCoverageModulationStateCreateInfoNV"/>
+ <type name="VkPipelineCoverageModulationStateCreateFlagsNV"/>
+ <type name="VkCoverageModulationModeNV"/>
+ </require>
+ </extension>
+ <extension name="VK_NV_fill_rectangle" number="154" type="device" author="NV" contact="Jeff Bolz @jeffbolznv" supported="vulkan">
+ <require>
+ <enum value="1" name="VK_NV_FILL_RECTANGLE_SPEC_VERSION"/>
+ <enum value="&quot;VK_NV_fill_rectangle&quot;" name="VK_NV_FILL_RECTANGLE_EXTENSION_NAME"/>
+ <enum offset="0" extends="VkPolygonMode" name="VK_POLYGON_MODE_FILL_RECTANGLE_NV"/>
+ </require>
+ </extension>
+ <extension name="VK_NV_shader_sm_builtins" number="155" type="device" requiresCore="1.1" author="NV" contact="Daniel Koch @dgkoch" supported="vulkan">
+ <require>
+ <enum value="1" name="VK_NV_SHADER_SM_BUILTINS_SPEC_VERSION"/>
+ <enum value="&quot;VK_NV_shader_sm_builtins&quot;" name="VK_NV_SHADER_SM_BUILTINS_EXTENSION_NAME"/>
+ <enum offset="0" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_SM_BUILTINS_FEATURES_NV"/>
+ <enum offset="1" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_SM_BUILTINS_PROPERTIES_NV"/>
+ <type name="VkPhysicalDeviceShaderSMBuiltinsPropertiesNV"/>
+ <type name="VkPhysicalDeviceShaderSMBuiltinsFeaturesNV"/>
+ </require>
+ </extension>
+ <extension name="VK_EXT_post_depth_coverage" number="156" type="device" author="NV" contact="Daniel Koch @dgkoch" supported="vulkan">
+ <require>
+ <enum value="1" name="VK_EXT_POST_DEPTH_COVERAGE_SPEC_VERSION"/>
+ <enum value="&quot;VK_EXT_post_depth_coverage&quot;" name="VK_EXT_POST_DEPTH_COVERAGE_EXTENSION_NAME"/>
+ </require>
+ </extension>
+ <extension name="VK_KHR_sampler_ycbcr_conversion" number="157" type="device" requires="VK_KHR_maintenance1,VK_KHR_bind_memory2,VK_KHR_get_memory_requirements2,VK_KHR_get_physical_device_properties2" author="KHR" contact="Andrew Garrard @fluppeteer" supported="vulkan" promotedto="VK_VERSION_1_1">
+ <require>
+ <enum value="14" name="VK_KHR_SAMPLER_YCBCR_CONVERSION_SPEC_VERSION"/>
+ <enum value="&quot;VK_KHR_sampler_ycbcr_conversion&quot;" name="VK_KHR_SAMPLER_YCBCR_CONVERSION_EXTENSION_NAME"/>
+ <enum extends="VkStructureType" name="VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_CREATE_INFO_KHR" alias="VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_CREATE_INFO"/>
+ <enum extends="VkStructureType" name="VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_INFO_KHR" alias="VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_INFO"/>
+ <enum extends="VkStructureType" name="VK_STRUCTURE_TYPE_BIND_IMAGE_PLANE_MEMORY_INFO_KHR" alias="VK_STRUCTURE_TYPE_BIND_IMAGE_PLANE_MEMORY_INFO"/>
+ <enum extends="VkStructureType" name="VK_STRUCTURE_TYPE_IMAGE_PLANE_MEMORY_REQUIREMENTS_INFO_KHR" alias="VK_STRUCTURE_TYPE_IMAGE_PLANE_MEMORY_REQUIREMENTS_INFO"/>
+ <enum extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLER_YCBCR_CONVERSION_FEATURES_KHR" alias="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLER_YCBCR_CONVERSION_FEATURES"/>
+ <enum extends="VkStructureType" name="VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_IMAGE_FORMAT_PROPERTIES_KHR" alias="VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_IMAGE_FORMAT_PROPERTIES"/>
+ <enum extends="VkDebugReportObjectTypeEXT" name="VK_DEBUG_REPORT_OBJECT_TYPE_SAMPLER_YCBCR_CONVERSION_KHR_EXT" alias="VK_DEBUG_REPORT_OBJECT_TYPE_SAMPLER_YCBCR_CONVERSION_EXT"/>
+ <enum extends="VkObjectType" name="VK_OBJECT_TYPE_SAMPLER_YCBCR_CONVERSION_KHR" alias="VK_OBJECT_TYPE_SAMPLER_YCBCR_CONVERSION"/>
+ <enum extends="VkFormat" name="VK_FORMAT_G8B8G8R8_422_UNORM_KHR" alias="VK_FORMAT_G8B8G8R8_422_UNORM"/>
+ <enum extends="VkFormat" name="VK_FORMAT_B8G8R8G8_422_UNORM_KHR" alias="VK_FORMAT_B8G8R8G8_422_UNORM"/>
+ <enum extends="VkFormat" name="VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM_KHR" alias="VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM"/>
+ <enum extends="VkFormat" name="VK_FORMAT_G8_B8R8_2PLANE_420_UNORM_KHR" alias="VK_FORMAT_G8_B8R8_2PLANE_420_UNORM"/>
+ <enum extends="VkFormat" name="VK_FORMAT_G8_B8_R8_3PLANE_422_UNORM_KHR" alias="VK_FORMAT_G8_B8_R8_3PLANE_422_UNORM"/>
+ <enum extends="VkFormat" name="VK_FORMAT_G8_B8R8_2PLANE_422_UNORM_KHR" alias="VK_FORMAT_G8_B8R8_2PLANE_422_UNORM"/>
+ <enum extends="VkFormat" name="VK_FORMAT_G8_B8_R8_3PLANE_444_UNORM_KHR" alias="VK_FORMAT_G8_B8_R8_3PLANE_444_UNORM"/>
+ <enum extends="VkFormat" name="VK_FORMAT_R10X6_UNORM_PACK16_KHR" alias="VK_FORMAT_R10X6_UNORM_PACK16"/>
+ <enum extends="VkFormat" name="VK_FORMAT_R10X6G10X6_UNORM_2PACK16_KHR" alias="VK_FORMAT_R10X6G10X6_UNORM_2PACK16"/>
+ <enum extends="VkFormat" name="VK_FORMAT_R10X6G10X6B10X6A10X6_UNORM_4PACK16_KHR" alias="VK_FORMAT_R10X6G10X6B10X6A10X6_UNORM_4PACK16"/>
+ <enum extends="VkFormat" name="VK_FORMAT_G10X6B10X6G10X6R10X6_422_UNORM_4PACK16_KHR" alias="VK_FORMAT_G10X6B10X6G10X6R10X6_422_UNORM_4PACK16"/>
+ <enum extends="VkFormat" name="VK_FORMAT_B10X6G10X6R10X6G10X6_422_UNORM_4PACK16_KHR" alias="VK_FORMAT_B10X6G10X6R10X6G10X6_422_UNORM_4PACK16"/>
+ <enum extends="VkFormat" name="VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_420_UNORM_3PACK16_KHR" alias="VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_420_UNORM_3PACK16"/>
+ <enum extends="VkFormat" name="VK_FORMAT_G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16_KHR" alias="VK_FORMAT_G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16"/>
+ <enum extends="VkFormat" name="VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_422_UNORM_3PACK16_KHR" alias="VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_422_UNORM_3PACK16"/>
+ <enum extends="VkFormat" name="VK_FORMAT_G10X6_B10X6R10X6_2PLANE_422_UNORM_3PACK16_KHR" alias="VK_FORMAT_G10X6_B10X6R10X6_2PLANE_422_UNORM_3PACK16"/>
+ <enum extends="VkFormat" name="VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_444_UNORM_3PACK16_KHR" alias="VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_444_UNORM_3PACK16"/>
+ <enum extends="VkFormat" name="VK_FORMAT_R12X4_UNORM_PACK16_KHR" alias="VK_FORMAT_R12X4_UNORM_PACK16"/>
+ <enum extends="VkFormat" name="VK_FORMAT_R12X4G12X4_UNORM_2PACK16_KHR" alias="VK_FORMAT_R12X4G12X4_UNORM_2PACK16"/>
+ <enum extends="VkFormat" name="VK_FORMAT_R12X4G12X4B12X4A12X4_UNORM_4PACK16_KHR" alias="VK_FORMAT_R12X4G12X4B12X4A12X4_UNORM_4PACK16"/>
+ <enum extends="VkFormat" name="VK_FORMAT_G12X4B12X4G12X4R12X4_422_UNORM_4PACK16_KHR" alias="VK_FORMAT_G12X4B12X4G12X4R12X4_422_UNORM_4PACK16"/>
+ <enum extends="VkFormat" name="VK_FORMAT_B12X4G12X4R12X4G12X4_422_UNORM_4PACK16_KHR" alias="VK_FORMAT_B12X4G12X4R12X4G12X4_422_UNORM_4PACK16"/>
+ <enum extends="VkFormat" name="VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_420_UNORM_3PACK16_KHR" alias="VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_420_UNORM_3PACK16"/>
+ <enum extends="VkFormat" name="VK_FORMAT_G12X4_B12X4R12X4_2PLANE_420_UNORM_3PACK16_KHR" alias="VK_FORMAT_G12X4_B12X4R12X4_2PLANE_420_UNORM_3PACK16"/>
+ <enum extends="VkFormat" name="VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_422_UNORM_3PACK16_KHR" alias="VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_422_UNORM_3PACK16"/>
+ <enum extends="VkFormat" name="VK_FORMAT_G12X4_B12X4R12X4_2PLANE_422_UNORM_3PACK16_KHR" alias="VK_FORMAT_G12X4_B12X4R12X4_2PLANE_422_UNORM_3PACK16"/>
+ <enum extends="VkFormat" name="VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_444_UNORM_3PACK16_KHR" alias="VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_444_UNORM_3PACK16"/>
+ <enum extends="VkFormat" name="VK_FORMAT_G16B16G16R16_422_UNORM_KHR" alias="VK_FORMAT_G16B16G16R16_422_UNORM"/>
+ <enum extends="VkFormat" name="VK_FORMAT_B16G16R16G16_422_UNORM_KHR" alias="VK_FORMAT_B16G16R16G16_422_UNORM"/>
+ <enum extends="VkFormat" name="VK_FORMAT_G16_B16_R16_3PLANE_420_UNORM_KHR" alias="VK_FORMAT_G16_B16_R16_3PLANE_420_UNORM"/>
+ <enum extends="VkFormat" name="VK_FORMAT_G16_B16R16_2PLANE_420_UNORM_KHR" alias="VK_FORMAT_G16_B16R16_2PLANE_420_UNORM"/>
+ <enum extends="VkFormat" name="VK_FORMAT_G16_B16_R16_3PLANE_422_UNORM_KHR" alias="VK_FORMAT_G16_B16_R16_3PLANE_422_UNORM"/>
+ <enum extends="VkFormat" name="VK_FORMAT_G16_B16R16_2PLANE_422_UNORM_KHR" alias="VK_FORMAT_G16_B16R16_2PLANE_422_UNORM"/>
+ <enum extends="VkFormat" name="VK_FORMAT_G16_B16_R16_3PLANE_444_UNORM_KHR" alias="VK_FORMAT_G16_B16_R16_3PLANE_444_UNORM"/>
+ <enum extends="VkImageAspectFlagBits" name="VK_IMAGE_ASPECT_PLANE_0_BIT_KHR" alias="VK_IMAGE_ASPECT_PLANE_0_BIT"/>
+ <enum extends="VkImageAspectFlagBits" name="VK_IMAGE_ASPECT_PLANE_1_BIT_KHR" alias="VK_IMAGE_ASPECT_PLANE_1_BIT"/>
+ <enum extends="VkImageAspectFlagBits" name="VK_IMAGE_ASPECT_PLANE_2_BIT_KHR" alias="VK_IMAGE_ASPECT_PLANE_2_BIT"/>
+ <enum extends="VkImageCreateFlagBits" name="VK_IMAGE_CREATE_DISJOINT_BIT_KHR" alias="VK_IMAGE_CREATE_DISJOINT_BIT"/>
+ <enum extends="VkFormatFeatureFlagBits" name="VK_FORMAT_FEATURE_MIDPOINT_CHROMA_SAMPLES_BIT_KHR" alias="VK_FORMAT_FEATURE_MIDPOINT_CHROMA_SAMPLES_BIT"/>
+ <enum extends="VkFormatFeatureFlagBits" name="VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_LINEAR_FILTER_BIT_KHR" alias="VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_LINEAR_FILTER_BIT"/>
+ <enum extends="VkFormatFeatureFlagBits" name="VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_SEPARATE_RECONSTRUCTION_FILTER_BIT_KHR" alias="VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_SEPARATE_RECONSTRUCTION_FILTER_BIT"/>
+ <enum extends="VkFormatFeatureFlagBits" name="VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_CHROMA_RECONSTRUCTION_EXPLICIT_BIT_KHR" alias="VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_CHROMA_RECONSTRUCTION_EXPLICIT_BIT"/>
+ <enum extends="VkFormatFeatureFlagBits" name="VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_CHROMA_RECONSTRUCTION_EXPLICIT_FORCEABLE_BIT_KHR" alias="VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_CHROMA_RECONSTRUCTION_EXPLICIT_FORCEABLE_BIT"/>
+ <enum extends="VkFormatFeatureFlagBits" name="VK_FORMAT_FEATURE_DISJOINT_BIT_KHR" alias="VK_FORMAT_FEATURE_DISJOINT_BIT"/>
+ <enum extends="VkFormatFeatureFlagBits" name="VK_FORMAT_FEATURE_COSITED_CHROMA_SAMPLES_BIT_KHR" alias="VK_FORMAT_FEATURE_COSITED_CHROMA_SAMPLES_BIT"/>
+ <type name="VkSamplerYcbcrConversionCreateInfoKHR"/>
+ <type name="VkSamplerYcbcrConversionInfoKHR"/>
+ <type name="VkBindImagePlaneMemoryInfoKHR"/>
+ <type name="VkImagePlaneMemoryRequirementsInfoKHR"/>
+ <type name="VkPhysicalDeviceSamplerYcbcrConversionFeaturesKHR"/>
+ <type name="VkSamplerYcbcrConversionImageFormatPropertiesKHR"/>
+ <command name="vkCreateSamplerYcbcrConversionKHR"/>
+ <command name="vkDestroySamplerYcbcrConversionKHR"/>
+ <type name="VkSamplerYcbcrConversionKHR"/>
+ <type name="VkSamplerYcbcrModelConversionKHR"/>
+ <enum extends="VkSamplerYcbcrModelConversion" name="VK_SAMPLER_YCBCR_MODEL_CONVERSION_RGB_IDENTITY_KHR" alias="VK_SAMPLER_YCBCR_MODEL_CONVERSION_RGB_IDENTITY"/>
+ <enum extends="VkSamplerYcbcrModelConversion" name="VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_IDENTITY_KHR" alias="VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_IDENTITY"/>
+ <enum extends="VkSamplerYcbcrModelConversion" name="VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_709_KHR" alias="VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_709"/>
+ <enum extends="VkSamplerYcbcrModelConversion" name="VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_601_KHR" alias="VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_601"/>
+ <enum extends="VkSamplerYcbcrModelConversion" name="VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_2020_KHR" alias="VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_2020"/>
+ <type name="VkSamplerYcbcrRangeKHR"/>
+ <enum extends="VkSamplerYcbcrRange" name="VK_SAMPLER_YCBCR_RANGE_ITU_FULL_KHR" alias="VK_SAMPLER_YCBCR_RANGE_ITU_FULL"/>
+ <enum extends="VkSamplerYcbcrRange" name="VK_SAMPLER_YCBCR_RANGE_ITU_NARROW_KHR" alias="VK_SAMPLER_YCBCR_RANGE_ITU_NARROW"/>
+ <type name="VkChromaLocationKHR"/>
+ <enum extends="VkChromaLocation" name="VK_CHROMA_LOCATION_COSITED_EVEN_KHR" alias="VK_CHROMA_LOCATION_COSITED_EVEN"/>
+ <enum extends="VkChromaLocation" name="VK_CHROMA_LOCATION_MIDPOINT_KHR" alias="VK_CHROMA_LOCATION_MIDPOINT"/>
+ </require>
+ <require extension="VK_EXT_debug_report">
+ <enum extends="VkDebugReportObjectTypeEXT" offset="0" name="VK_DEBUG_REPORT_OBJECT_TYPE_SAMPLER_YCBCR_CONVERSION_EXT"/>
+ </require>
+ </extension>
+ <extension name="VK_KHR_bind_memory2" number="158" type="device" author="KHR" contact="Tobias Hector @tobski" supported="vulkan" promotedto="VK_VERSION_1_1">
+ <require>
+ <enum value="1" name="VK_KHR_BIND_MEMORY_2_SPEC_VERSION"/>
+ <enum value="&quot;VK_KHR_bind_memory2&quot;" name="VK_KHR_BIND_MEMORY_2_EXTENSION_NAME"/>
+ <command name="vkBindBufferMemory2KHR"/>
+ <command name="vkBindImageMemory2KHR"/>
+ <enum extends="VkStructureType" name="VK_STRUCTURE_TYPE_BIND_BUFFER_MEMORY_INFO_KHR" alias="VK_STRUCTURE_TYPE_BIND_BUFFER_MEMORY_INFO"/>
+ <enum extends="VkStructureType" name="VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_INFO_KHR" alias="VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_INFO"/>
+ <enum extends="VkImageCreateFlagBits" name="VK_IMAGE_CREATE_ALIAS_BIT_KHR" alias="VK_IMAGE_CREATE_ALIAS_BIT"/>
+ <type name="VkBindBufferMemoryInfoKHR"/>
+ <type name="VkBindImageMemoryInfoKHR"/>
+ </require>
+ </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="&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"/>
+
+ <type name="VkDrmFormatModifierPropertiesListEXT"/>
+ <type name="VkDrmFormatModifierPropertiesEXT"/>
+ <type name="VkPhysicalDeviceImageDrmFormatModifierInfoEXT"/>
+ <type name="VkImageDrmFormatModifierListCreateInfoEXT"/>
+ <type name="VkImageDrmFormatModifierExplicitCreateInfoEXT"/>
+ <type name="VkImageDrmFormatModifierPropertiesEXT"/>
+
+ <command name="vkGetImageDrmFormatModifierPropertiesEXT"/>
+ </require>
+ </extension>
+ <extension name="VK_EXT_extension_160" number="160" author="EXT" contact="Mark Young @marky-lunarg" supported="disabled">
+ <require>
+ <enum value="0" name="VK_EXT_EXTENSION_160_SPEC_VERSION"/>
+ <enum value="&quot;VK_EXT_extension_160&quot;" name="VK_EXT_EXTENSION_160_EXTENSION_NAME"/>
+ </require>
+ </extension>
+ <extension name="VK_EXT_validation_cache" number="161" type="device" author="GOOGLE" contact="Cort Stratton @cdwfs" supported="vulkan">
+ <require>
+ <enum value="1" name="VK_EXT_VALIDATION_CACHE_SPEC_VERSION"/>
+ <enum value="&quot;VK_EXT_validation_cache&quot;" name="VK_EXT_VALIDATION_CACHE_EXTENSION_NAME"/>
+ <enum offset="0" extends="VkStructureType" name="VK_STRUCTURE_TYPE_VALIDATION_CACHE_CREATE_INFO_EXT"/>
+ <enum offset="1" extends="VkStructureType" name="VK_STRUCTURE_TYPE_SHADER_MODULE_VALIDATION_CACHE_CREATE_INFO_EXT"/>
+ <enum offset="0" extends="VkObjectType" name="VK_OBJECT_TYPE_VALIDATION_CACHE_EXT"/>
+ <type name="VkValidationCacheEXT"/>
+ <type name="VkValidationCacheCreateInfoEXT"/>
+ <type name="VkShaderModuleValidationCacheCreateInfoEXT"/>
+ <type name="VkValidationCacheHeaderVersionEXT"/>
+ <type name="VkValidationCacheCreateFlagsEXT"/>
+ <command name="vkCreateValidationCacheEXT"/>
+ <command name="vkDestroyValidationCacheEXT"/>
+ <command name="vkMergeValidationCachesEXT"/>
+ <command name="vkGetValidationCacheDataEXT"/>
+ </require>
+ </extension>
+ <extension name="VK_EXT_descriptor_indexing" number="162" type="device" requires="VK_KHR_get_physical_device_properties2,VK_KHR_maintenance3" author="NV" contact="Jeff Bolz @jeffbolznv" supported="vulkan" promotedto="VK_VERSION_1_2">
+ <require>
+ <enum value="2" name="VK_EXT_DESCRIPTOR_INDEXING_SPEC_VERSION"/>
+ <enum value="&quot;VK_EXT_descriptor_indexing&quot;" name="VK_EXT_DESCRIPTOR_INDEXING_EXTENSION_NAME"/>
+ <enum extends="VkStructureType" name="VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_BINDING_FLAGS_CREATE_INFO_EXT" alias="VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_BINDING_FLAGS_CREATE_INFO"/>
+ <enum extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_INDEXING_FEATURES_EXT" alias="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_INDEXING_FEATURES"/>
+ <enum extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_INDEXING_PROPERTIES_EXT" alias="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_INDEXING_PROPERTIES"/>
+ <enum extends="VkStructureType" name="VK_STRUCTURE_TYPE_DESCRIPTOR_SET_VARIABLE_DESCRIPTOR_COUNT_ALLOCATE_INFO_EXT" alias="VK_STRUCTURE_TYPE_DESCRIPTOR_SET_VARIABLE_DESCRIPTOR_COUNT_ALLOCATE_INFO"/>
+ <enum extends="VkStructureType" name="VK_STRUCTURE_TYPE_DESCRIPTOR_SET_VARIABLE_DESCRIPTOR_COUNT_LAYOUT_SUPPORT_EXT" alias="VK_STRUCTURE_TYPE_DESCRIPTOR_SET_VARIABLE_DESCRIPTOR_COUNT_LAYOUT_SUPPORT"/>
+ <enum extends="VkDescriptorBindingFlagBits" name="VK_DESCRIPTOR_BINDING_UPDATE_AFTER_BIND_BIT_EXT" alias="VK_DESCRIPTOR_BINDING_UPDATE_AFTER_BIND_BIT"/>
+ <enum extends="VkDescriptorBindingFlagBits" name="VK_DESCRIPTOR_BINDING_UPDATE_UNUSED_WHILE_PENDING_BIT_EXT" alias="VK_DESCRIPTOR_BINDING_UPDATE_UNUSED_WHILE_PENDING_BIT"/>
+ <enum extends="VkDescriptorBindingFlagBits" name="VK_DESCRIPTOR_BINDING_PARTIALLY_BOUND_BIT_EXT" alias="VK_DESCRIPTOR_BINDING_PARTIALLY_BOUND_BIT"/>
+ <enum extends="VkDescriptorBindingFlagBits" name="VK_DESCRIPTOR_BINDING_VARIABLE_DESCRIPTOR_COUNT_BIT_EXT" alias="VK_DESCRIPTOR_BINDING_VARIABLE_DESCRIPTOR_COUNT_BIT"/>
+ <enum extends="VkDescriptorPoolCreateFlagBits" name="VK_DESCRIPTOR_POOL_CREATE_UPDATE_AFTER_BIND_BIT_EXT" alias="VK_DESCRIPTOR_POOL_CREATE_UPDATE_AFTER_BIND_BIT"/>
+ <enum extends="VkDescriptorSetLayoutCreateFlagBits" name="VK_DESCRIPTOR_SET_LAYOUT_CREATE_UPDATE_AFTER_BIND_POOL_BIT_EXT" alias="VK_DESCRIPTOR_SET_LAYOUT_CREATE_UPDATE_AFTER_BIND_POOL_BIT"/>
+ <enum extends="VkResult" name="VK_ERROR_FRAGMENTATION_EXT" alias="VK_ERROR_FRAGMENTATION"/>
+ <type name="VkDescriptorSetLayoutBindingFlagsCreateInfoEXT"/>
+ <type name="VkPhysicalDeviceDescriptorIndexingFeaturesEXT"/>
+ <type name="VkPhysicalDeviceDescriptorIndexingPropertiesEXT"/>
+ <type name="VkDescriptorSetVariableDescriptorCountAllocateInfoEXT"/>
+ <type name="VkDescriptorSetVariableDescriptorCountLayoutSupportEXT"/>
+ <type name="VkDescriptorBindingFlagBitsEXT"/>
+ <type name="VkDescriptorBindingFlagsEXT"/>
+ </require>
+ </extension>
+ <extension name="VK_EXT_shader_viewport_index_layer" number="163" type="device" author="NV" contact="Daniel Koch @dgkoch" supported="vulkan" promotedto="VK_VERSION_1_2">
+ <require>
+ <enum value="1" name="VK_EXT_SHADER_VIEWPORT_INDEX_LAYER_SPEC_VERSION"/>
+ <enum value="&quot;VK_EXT_shader_viewport_index_layer&quot;" name="VK_EXT_SHADER_VIEWPORT_INDEX_LAYER_EXTENSION_NAME"/>
+ </require>
+ </extension>
+ <extension name="VK_KHR_portability_subset" number="164" type="device" requires="VK_KHR_get_physical_device_properties2" author="KHR" contact="Bill Hollings @billhollings" platform="provisional" supported="vulkan" provisional="true">
+ <require>
+ <enum value="1" name="VK_KHR_PORTABILITY_SUBSET_SPEC_VERSION"/>
+ <enum value="&quot;VK_KHR_portability_subset&quot;" name="VK_KHR_PORTABILITY_SUBSET_EXTENSION_NAME"/>
+ <enum offset="0" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PORTABILITY_SUBSET_FEATURES_KHR" protect="VK_ENABLE_BETA_EXTENSIONS"/>
+ <enum offset="1" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PORTABILITY_SUBSET_PROPERTIES_KHR" protect="VK_ENABLE_BETA_EXTENSIONS"/>
+ <type name="VkPhysicalDevicePortabilitySubsetFeaturesKHR"/>
+ <type name="VkPhysicalDevicePortabilitySubsetPropertiesKHR"/>
+ </require>
+ </extension>
+ <extension name="VK_NV_shading_rate_image" number="165" type="device" requires="VK_KHR_get_physical_device_properties2" author="NV" contact="Pat Brown @nvpbrown" supported="vulkan">
+ <require>
+ <enum value="3" name="VK_NV_SHADING_RATE_IMAGE_SPEC_VERSION"/>
+ <enum value="&quot;VK_NV_shading_rate_image&quot;" name="VK_NV_SHADING_RATE_IMAGE_EXTENSION_NAME"/>
+ <enum offset="0" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_SHADING_RATE_IMAGE_STATE_CREATE_INFO_NV"/>
+ <enum offset="1" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADING_RATE_IMAGE_FEATURES_NV"/>
+ <enum offset="2" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADING_RATE_IMAGE_PROPERTIES_NV"/>
+ <enum extends="VkImageLayout" name="VK_IMAGE_LAYOUT_SHADING_RATE_OPTIMAL_NV" alias="VK_IMAGE_LAYOUT_FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL_KHR"/>
+ <enum offset="4" extends="VkDynamicState" name="VK_DYNAMIC_STATE_VIEWPORT_SHADING_RATE_PALETTE_NV"/>
+ <enum extends="VkAccessFlagBits" name="VK_ACCESS_SHADING_RATE_IMAGE_READ_BIT_NV" alias="VK_ACCESS_FRAGMENT_SHADING_RATE_ATTACHMENT_READ_BIT_KHR"/>
+ <enum extends="VkImageUsageFlagBits" name="VK_IMAGE_USAGE_SHADING_RATE_IMAGE_BIT_NV" alias="VK_IMAGE_USAGE_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR"/>
+ <enum extends="VkPipelineStageFlagBits" name="VK_PIPELINE_STAGE_SHADING_RATE_IMAGE_BIT_NV" alias="VK_PIPELINE_STAGE_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR"/>
+ <enum offset="5" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_COARSE_SAMPLE_ORDER_STATE_CREATE_INFO_NV"/>
+ <enum offset="6" extends="VkDynamicState" name="VK_DYNAMIC_STATE_VIEWPORT_COARSE_SAMPLE_ORDER_NV"/>
+ <type name="VkShadingRatePaletteEntryNV"/>
+ <type name="VkShadingRatePaletteNV"/>
+ <type name="VkPipelineViewportShadingRateImageStateCreateInfoNV"/>
+ <type name="VkPhysicalDeviceShadingRateImageFeaturesNV"/>
+ <type name="VkPhysicalDeviceShadingRateImagePropertiesNV"/>
+ <type name="VkCoarseSampleLocationNV"/>
+ <type name="VkCoarseSampleOrderCustomNV"/>
+ <type name="VkPipelineViewportCoarseSampleOrderStateCreateInfoNV"/>
+ <type name="VkCoarseSampleOrderTypeNV"/>
+ <command name="vkCmdBindShadingRateImageNV"/>
+ <command name="vkCmdSetViewportShadingRatePaletteNV"/>
+ <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">
+ <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"/>
+ <enum name="VK_SHADER_UNUSED_NV"/>
+ <enum offset="0" extends="VkStructureType" name="VK_STRUCTURE_TYPE_RAY_TRACING_PIPELINE_CREATE_INFO_NV"/>
+ <enum offset="1" extends="VkStructureType" name="VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_CREATE_INFO_NV"/>
+ <enum offset="3" extends="VkStructureType" name="VK_STRUCTURE_TYPE_GEOMETRY_NV"/>
+ <enum offset="4" extends="VkStructureType" name="VK_STRUCTURE_TYPE_GEOMETRY_TRIANGLES_NV"/>
+ <enum offset="5" extends="VkStructureType" name="VK_STRUCTURE_TYPE_GEOMETRY_AABB_NV"/>
+ <enum offset="6" extends="VkStructureType" name="VK_STRUCTURE_TYPE_BIND_ACCELERATION_STRUCTURE_MEMORY_INFO_NV"/>
+ <enum offset="7" extends="VkStructureType" name="VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_ACCELERATION_STRUCTURE_NV"/>
+ <enum offset="8" extends="VkStructureType" name="VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_INFO_NV"/>
+ <enum offset="9" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PROPERTIES_NV"/>
+ <enum offset="11" extends="VkStructureType" name="VK_STRUCTURE_TYPE_RAY_TRACING_SHADER_GROUP_CREATE_INFO_NV"/>
+ <enum offset="12" extends="VkStructureType" name="VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_INFO_NV"/>
+ <enum extends="VkShaderStageFlagBits" name="VK_SHADER_STAGE_RAYGEN_BIT_NV" alias="VK_SHADER_STAGE_RAYGEN_BIT_KHR"/>
+ <enum extends="VkShaderStageFlagBits" name="VK_SHADER_STAGE_ANY_HIT_BIT_NV" alias="VK_SHADER_STAGE_ANY_HIT_BIT_KHR"/>
+ <enum extends="VkShaderStageFlagBits" name="VK_SHADER_STAGE_CLOSEST_HIT_BIT_NV" alias="VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR"/>
+ <enum extends="VkShaderStageFlagBits" name="VK_SHADER_STAGE_MISS_BIT_NV" alias="VK_SHADER_STAGE_MISS_BIT_KHR"/>
+ <enum extends="VkShaderStageFlagBits" name="VK_SHADER_STAGE_INTERSECTION_BIT_NV" alias="VK_SHADER_STAGE_INTERSECTION_BIT_KHR"/>
+ <enum extends="VkShaderStageFlagBits" name="VK_SHADER_STAGE_CALLABLE_BIT_NV" alias="VK_SHADER_STAGE_CALLABLE_BIT_KHR"/>
+ <enum extends="VkPipelineStageFlagBits" name="VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_NV" alias="VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_KHR"/>
+ <enum extends="VkPipelineStageFlagBits" name="VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_NV" alias="VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_KHR"/>
+ <enum extends="VkBufferUsageFlagBits" name="VK_BUFFER_USAGE_RAY_TRACING_BIT_NV" alias="VK_BUFFER_USAGE_SHADER_BINDING_TABLE_BIT_KHR"/>
+ <enum extends="VkPipelineBindPoint" name="VK_PIPELINE_BIND_POINT_RAY_TRACING_NV" alias="VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR"/>
+ <enum offset="0" extends="VkDescriptorType" name="VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_NV"/>
+ <enum extends="VkAccessFlagBits" name="VK_ACCESS_ACCELERATION_STRUCTURE_READ_BIT_NV" alias="VK_ACCESS_ACCELERATION_STRUCTURE_READ_BIT_KHR"/>
+ <enum extends="VkAccessFlagBits" name="VK_ACCESS_ACCELERATION_STRUCTURE_WRITE_BIT_NV" alias="VK_ACCESS_ACCELERATION_STRUCTURE_WRITE_BIT_KHR"/>
+ <enum offset="0" extends="VkQueryType" name="VK_QUERY_TYPE_ACCELERATION_STRUCTURE_COMPACTED_SIZE_NV"/>
+ <enum bitpos="5" extends="VkPipelineCreateFlagBits" name="VK_PIPELINE_CREATE_DEFER_COMPILE_BIT_NV"/>
+ <enum offset="0" extends="VkObjectType" name="VK_OBJECT_TYPE_ACCELERATION_STRUCTURE_NV"/>
+ <enum offset="0" extends="VkDebugReportObjectTypeEXT" name="VK_DEBUG_REPORT_OBJECT_TYPE_ACCELERATION_STRUCTURE_NV_EXT"/>
+ <enum extends="VkIndexType" name="VK_INDEX_TYPE_NONE_NV" alias="VK_INDEX_TYPE_NONE_KHR"/>
+ <type name="VkRayTracingShaderGroupCreateInfoNV"/>
+ <type name="VkRayTracingShaderGroupTypeNV"/>
+ <enum extends="VkRayTracingShaderGroupTypeKHR" name="VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_NV" alias="VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_KHR"/>
+ <enum extends="VkRayTracingShaderGroupTypeKHR" name="VK_RAY_TRACING_SHADER_GROUP_TYPE_TRIANGLES_HIT_GROUP_NV" alias="VK_RAY_TRACING_SHADER_GROUP_TYPE_TRIANGLES_HIT_GROUP_KHR"/>
+ <enum extends="VkRayTracingShaderGroupTypeKHR" name="VK_RAY_TRACING_SHADER_GROUP_TYPE_PROCEDURAL_HIT_GROUP_NV" alias="VK_RAY_TRACING_SHADER_GROUP_TYPE_PROCEDURAL_HIT_GROUP_KHR"/>
+ <type name="VkRayTracingPipelineCreateInfoNV"/>
+ <type name="VkGeometryTypeNV"/>
+ <enum extends="VkGeometryTypeKHR" name="VK_GEOMETRY_TYPE_TRIANGLES_NV" alias="VK_GEOMETRY_TYPE_TRIANGLES_KHR"/>
+ <enum extends="VkGeometryTypeKHR" name="VK_GEOMETRY_TYPE_AABBS_NV" alias="VK_GEOMETRY_TYPE_AABBS_KHR"/>
+ <type name="VkAccelerationStructureTypeNV"/>
+ <enum extends="VkAccelerationStructureTypeKHR" name="VK_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL_NV" alias="VK_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL_KHR"/>
+ <enum extends="VkAccelerationStructureTypeKHR" name="VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_NV" alias="VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_KHR"/>
+ <type name="VkGeometryTrianglesNV"/>
+ <type name="VkGeometryAABBNV"/>
+ <type name="VkGeometryDataNV"/>
+ <type name="VkGeometryNV"/>
+ <type name="VkGeometryFlagsNV"/>
+ <type name="VkGeometryFlagBitsNV"/>
+ <enum extends="VkGeometryFlagBitsKHR" name="VK_GEOMETRY_OPAQUE_BIT_NV" alias="VK_GEOMETRY_OPAQUE_BIT_KHR"/>
+ <enum extends="VkGeometryFlagBitsKHR" name="VK_GEOMETRY_NO_DUPLICATE_ANY_HIT_INVOCATION_BIT_NV" alias="VK_GEOMETRY_NO_DUPLICATE_ANY_HIT_INVOCATION_BIT_KHR"/>
+ <type name="VkGeometryInstanceFlagsNV"/>
+ <type name="VkGeometryInstanceFlagBitsNV"/>
+ <enum extends="VkGeometryInstanceFlagBitsKHR" name="VK_GEOMETRY_INSTANCE_TRIANGLE_CULL_DISABLE_BIT_NV" alias="VK_GEOMETRY_INSTANCE_TRIANGLE_FACING_CULL_DISABLE_BIT_KHR"/>
+ <enum extends="VkGeometryInstanceFlagBitsKHR" name="VK_GEOMETRY_INSTANCE_TRIANGLE_FRONT_COUNTERCLOCKWISE_BIT_NV" alias="VK_GEOMETRY_INSTANCE_TRIANGLE_FRONT_COUNTERCLOCKWISE_BIT_KHR"/>
+ <enum extends="VkGeometryInstanceFlagBitsKHR" name="VK_GEOMETRY_INSTANCE_FORCE_OPAQUE_BIT_NV" alias="VK_GEOMETRY_INSTANCE_FORCE_OPAQUE_BIT_KHR"/>
+ <enum extends="VkGeometryInstanceFlagBitsKHR" name="VK_GEOMETRY_INSTANCE_FORCE_NO_OPAQUE_BIT_NV" alias="VK_GEOMETRY_INSTANCE_FORCE_NO_OPAQUE_BIT_KHR"/>
+ <type name="VkAccelerationStructureInfoNV"/>
+ <type name="VkAccelerationStructureCreateInfoNV"/>
+ <type name="VkAccelerationStructureNV"/>
+ <type name="VkBuildAccelerationStructureFlagBitsNV"/>
+ <enum extends="VkBuildAccelerationStructureFlagBitsKHR" name="VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_UPDATE_BIT_NV" alias="VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_UPDATE_BIT_KHR"/>
+ <enum extends="VkBuildAccelerationStructureFlagBitsKHR" name="VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_COMPACTION_BIT_NV" alias="VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_COMPACTION_BIT_KHR"/>
+ <enum extends="VkBuildAccelerationStructureFlagBitsKHR" name="VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_NV" alias="VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR"/>
+ <enum extends="VkBuildAccelerationStructureFlagBitsKHR" name="VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_BUILD_BIT_NV" alias="VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_BUILD_BIT_KHR"/>
+ <enum extends="VkBuildAccelerationStructureFlagBitsKHR" name="VK_BUILD_ACCELERATION_STRUCTURE_LOW_MEMORY_BIT_NV" alias="VK_BUILD_ACCELERATION_STRUCTURE_LOW_MEMORY_BIT_KHR"/>
+ <type name="VkBuildAccelerationStructureFlagsNV"/>
+ <type name="VkCopyAccelerationStructureModeNV"/>
+ <enum extends="VkCopyAccelerationStructureModeKHR" name="VK_COPY_ACCELERATION_STRUCTURE_MODE_CLONE_NV" alias="VK_COPY_ACCELERATION_STRUCTURE_MODE_CLONE_KHR"/>
+ <enum extends="VkCopyAccelerationStructureModeKHR" name="VK_COPY_ACCELERATION_STRUCTURE_MODE_COMPACT_NV" alias="VK_COPY_ACCELERATION_STRUCTURE_MODE_COMPACT_KHR"/>
+ <type name="VkBindAccelerationStructureMemoryInfoNV"/>
+ <type name="VkWriteDescriptorSetAccelerationStructureNV"/>
+ <type name="VkAccelerationStructureMemoryRequirementsInfoNV"/>
+ <type name="VkPhysicalDeviceRayTracingPropertiesNV"/>
+ <type name="VkMemoryRequirements2KHR"/>
+ <type name="VkAccelerationStructureMemoryRequirementsTypeNV"/>
+ <type name="VkTransformMatrixNV"/>
+ <type name="VkAabbPositionsNV"/>
+ <type name="VkAccelerationStructureInstanceNV"/>
+ <command name="vkCreateAccelerationStructureNV"/>
+ <command name="vkDestroyAccelerationStructureNV"/>
+ <command name="vkGetAccelerationStructureMemoryRequirementsNV"/>
+ <command name="vkBindAccelerationStructureMemoryNV"/>
+ <command name="vkCmdBuildAccelerationStructureNV"/>
+ <command name="vkCmdCopyAccelerationStructureNV"/>
+ <command name="vkCmdTraceRaysNV"/>
+ <command name="vkCreateRayTracingPipelinesNV"/>
+ <command name="vkGetRayTracingShaderGroupHandlesNV"/>
+ <command name="vkGetAccelerationStructureHandleNV"/>
+ <command name="vkCmdWriteAccelerationStructuresPropertiesNV"/>
+ <command name="vkCompileDeferredNV"/>
+ </require>
+ </extension>
+ <extension name="VK_NV_representative_fragment_test" number="167" type="device" author="NV" contact="Kedarnath Thangudu @kthangudu" supported="vulkan">
+ <require>
+ <enum value="2" name="VK_NV_REPRESENTATIVE_FRAGMENT_TEST_SPEC_VERSION"/>
+ <enum value="&quot;VK_NV_representative_fragment_test&quot;" name="VK_NV_REPRESENTATIVE_FRAGMENT_TEST_EXTENSION_NAME"/>
+ <enum offset="0" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_REPRESENTATIVE_FRAGMENT_TEST_FEATURES_NV"/>
+ <enum offset="1" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PIPELINE_REPRESENTATIVE_FRAGMENT_TEST_STATE_CREATE_INFO_NV"/>
+ <type name="VkPhysicalDeviceRepresentativeFragmentTestFeaturesNV"/>
+ <type name="VkPipelineRepresentativeFragmentTestStateCreateInfoNV"/>
+ </require>
+ </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"/>
+ </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 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"/>
+ <type name="VkDescriptorSetLayoutSupportKHR"/>
+ <command name="vkGetDescriptorSetLayoutSupportKHR"/>
+ </require>
+ </extension>
+ <extension name="VK_KHR_draw_indirect_count" number="170" type="device" author="KHR" contact="Piers Daniell @pdaniell-nv" supported="vulkan" promotedto="VK_VERSION_1_2">
+ <require>
+ <enum value="1" name="VK_KHR_DRAW_INDIRECT_COUNT_SPEC_VERSION"/>
+ <enum value="&quot;VK_KHR_draw_indirect_count&quot;" name="VK_KHR_DRAW_INDIRECT_COUNT_EXTENSION_NAME"/>
+ <command name="vkCmdDrawIndirectCountKHR"/>
+ <command name="vkCmdDrawIndexedIndirectCountKHR"/>
+ </require>
+ </extension>
+ <extension name="VK_EXT_filter_cubic" number="171" type="device" author="QCOM" contact="Bill Licea-Kane @wwlk" supported="vulkan">
+ <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="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"/>
+ <type name="VkFilterCubicImageViewImageFormatPropertiesEXT"/>
+ </require>
+ </extension>
+ <extension name="VK_QCOM_render_pass_shader_resolve" number="172" type="device" author="QCOM" contact="Bill Licea-Kane @wwlk" supported="vulkan">
+ <require>
+ <enum value="4" name="VK_QCOM_RENDER_PASS_SHADER_RESOLVE_SPEC_VERSION"/>
+ <enum value="&quot;VK_QCOM_render_pass_shader_resolve&quot;" name="VK_QCOM_RENDER_PASS_SHADER_RESOLVE_EXTENSION_NAME"/>
+ <enum bitpos="2" extends="VkSubpassDescriptionFlagBits" name="VK_SUBPASS_DESCRIPTION_FRAGMENT_REGION_BIT_QCOM"/>
+ <enum bitpos="3" extends="VkSubpassDescriptionFlagBits" name="VK_SUBPASS_DESCRIPTION_SHADER_RESOLVE_BIT_QCOM"/>
+ </require>
+ </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 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"/>
+ </require>
+ </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"/>
+ </require>
+ </extension>
+ <extension name="VK_EXT_global_priority" number="175" type="device" author="EXT" contact="Andres Rodriguez @lostgoat" supported="vulkan">
+ <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"/>
+ <type name="VkDeviceQueueGlobalPriorityCreateInfoEXT"/>
+ <type name="VkQueueGlobalPriorityEXT"/>
+ </require>
+ </extension>
+ <extension name="VK_KHR_shader_subgroup_extended_types" number="176" type="device" requiresCore="1.1" author="KHR" contact="Neil Henning @sheredom" supported="vulkan" promotedto="VK_VERSION_1_2">
+ <require>
+ <enum value="1" name="VK_KHR_SHADER_SUBGROUP_EXTENDED_TYPES_SPEC_VERSION"/>
+ <enum value="&quot;VK_KHR_shader_subgroup_extended_types&quot;" name="VK_KHR_SHADER_SUBGROUP_EXTENDED_TYPES_EXTENSION_NAME"/>
+ <enum extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_SUBGROUP_EXTENDED_TYPES_FEATURES_KHR" alias="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_SUBGROUP_EXTENDED_TYPES_FEATURES"/>
+ <type name="VkPhysicalDeviceShaderSubgroupExtendedTypesFeaturesKHR"/>
+ </require>
+ </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"/>
+ </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">
+ <require>
+ <enum value="1" name="VK_KHR_8BIT_STORAGE_SPEC_VERSION"/>
+ <enum value="&quot;VK_KHR_8bit_storage&quot;" name="VK_KHR_8BIT_STORAGE_EXTENSION_NAME"/>
+ <enum extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_8BIT_STORAGE_FEATURES_KHR" alias="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_8BIT_STORAGE_FEATURES"/>
+ <type name="VkPhysicalDevice8BitStorageFeaturesKHR"/>
+ </require>
+ </extension>
+ <extension name="VK_EXT_external_memory_host" number="179" type="device" author="EXT" requires="VK_KHR_external_memory" contact="Daniel Rakos @drakos-amd" supported="vulkan">
+ <require>
+ <enum value="1" name="VK_EXT_EXTERNAL_MEMORY_HOST_SPEC_VERSION"/>
+ <enum value="&quot;VK_EXT_external_memory_host&quot;" name="VK_EXT_EXTERNAL_MEMORY_HOST_EXTENSION_NAME"/>
+ <enum offset="0" extends="VkStructureType" name="VK_STRUCTURE_TYPE_IMPORT_MEMORY_HOST_POINTER_INFO_EXT"/>
+ <enum offset="1" extends="VkStructureType" name="VK_STRUCTURE_TYPE_MEMORY_HOST_POINTER_PROPERTIES_EXT"/>
+ <enum offset="2" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_MEMORY_HOST_PROPERTIES_EXT"/>
+ <enum bitpos="7" extends="VkExternalMemoryHandleTypeFlagBits" name="VK_EXTERNAL_MEMORY_HANDLE_TYPE_HOST_ALLOCATION_BIT_EXT"/>
+ <enum bitpos="8" extends="VkExternalMemoryHandleTypeFlagBits" name="VK_EXTERNAL_MEMORY_HANDLE_TYPE_HOST_MAPPED_FOREIGN_MEMORY_BIT_EXT"/>
+ <type name="VkImportMemoryHostPointerInfoEXT"/>
+ <type name="VkMemoryHostPointerPropertiesEXT"/>
+ <type name="VkPhysicalDeviceExternalMemoryHostPropertiesEXT"/>
+ <command name="vkGetMemoryHostPointerPropertiesEXT"/>
+ </require>
+ </extension>
+ <extension name="VK_AMD_buffer_marker" number="180" type="device" author="AMD" contact="Daniel Rakos @drakos-amd" specialuse="devtools" supported="vulkan">
+ <require>
+ <enum value="1" name="VK_AMD_BUFFER_MARKER_SPEC_VERSION"/>
+ <enum value="&quot;VK_AMD_buffer_marker&quot;" name="VK_AMD_BUFFER_MARKER_EXTENSION_NAME"/>
+ <command name="vkCmdWriteBufferMarkerAMD"/>
+ </require>
+ </extension>
+ <extension name="VK_KHR_shader_atomic_int64" number="181" type="device" author="KHR" requires="VK_KHR_get_physical_device_properties2" contact="Aaron Hagan @ahagan" supported="vulkan" promotedto="VK_VERSION_1_2">
+ <require>
+ <enum value="1" name="VK_KHR_SHADER_ATOMIC_INT64_SPEC_VERSION"/>
+ <enum value="&quot;VK_KHR_shader_atomic_int64&quot;" name="VK_KHR_SHADER_ATOMIC_INT64_EXTENSION_NAME"/>
+ <enum extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_ATOMIC_INT64_FEATURES_KHR" alias="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_ATOMIC_INT64_FEATURES"/>
+ <type name="VkPhysicalDeviceShaderAtomicInt64FeaturesKHR"/>
+ </require>
+ </extension>
+ <extension name="VK_KHR_shader_clock" number="182" type="device" author="KHR" requires="VK_KHR_get_physical_device_properties2" contact="Aaron Hagan @ahagan" supported="vulkan">
+ <require>
+ <enum value="1" name="VK_KHR_SHADER_CLOCK_SPEC_VERSION"/>
+ <enum value="&quot;VK_KHR_shader_clock&quot;" name="VK_KHR_SHADER_CLOCK_EXTENSION_NAME"/>
+ <enum offset="0" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_CLOCK_FEATURES_KHR"/>
+ <type name="VkPhysicalDeviceShaderClockFeaturesKHR"/>
+ </require>
+ </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"/>
+ </require>
+ </extension>
+ <extension name="VK_AMD_pipeline_compiler_control" number="184" type="device" author="AMD" contact="Matthaeus G. Chajdas @anteru" supported="vulkan">
+ <require>
+ <enum value="1" name="VK_AMD_PIPELINE_COMPILER_CONTROL_SPEC_VERSION"/>
+ <enum value="&quot;VK_AMD_pipeline_compiler_control&quot;" name="VK_AMD_PIPELINE_COMPILER_CONTROL_EXTENSION_NAME"/>
+ <enum offset="0" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PIPELINE_COMPILER_CONTROL_CREATE_INFO_AMD"/>
+ <type name="VkPipelineCompilerControlFlagBitsAMD"/>
+ <type name="VkPipelineCompilerControlFlagsAMD"/>
+ <type name="VkPipelineCompilerControlCreateInfoAMD"/>
+ </require>
+ </extension>
+ <extension name="VK_EXT_calibrated_timestamps" number="185" type="device" requires="VK_KHR_get_physical_device_properties2" author="EXT" contact="Daniel Rakos @drakos-amd" supported="vulkan">
+ <require>
+ <enum value="2" name="VK_EXT_CALIBRATED_TIMESTAMPS_SPEC_VERSION"/>
+ <enum value="&quot;VK_EXT_calibrated_timestamps&quot;" name="VK_EXT_CALIBRATED_TIMESTAMPS_EXTENSION_NAME"/>
+ <enum offset="0" extends="VkStructureType" name="VK_STRUCTURE_TYPE_CALIBRATED_TIMESTAMP_INFO_EXT"/>
+ <type name="VkTimeDomainEXT"/>
+ <type name="VkCalibratedTimestampInfoEXT"/>
+ <command name="vkGetPhysicalDeviceCalibrateableTimeDomainsEXT"/>
+ <command name="vkGetCalibratedTimestampsEXT"/>
+ </require>
+ </extension>
+ <extension name="VK_AMD_shader_core_properties" number="186" type="device" author="AMD" requires="VK_KHR_get_physical_device_properties2" contact="Martin Dinkov @mdinkov" supported="vulkan">
+ <require>
+ <enum value="2" name="VK_AMD_SHADER_CORE_PROPERTIES_SPEC_VERSION"/>
+ <enum value="&quot;VK_AMD_shader_core_properties&quot;" name="VK_AMD_SHADER_CORE_PROPERTIES_EXTENSION_NAME"/>
+ <enum offset="0" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_CORE_PROPERTIES_AMD"/>
+ <type name="VkPhysicalDeviceShaderCorePropertiesAMD"/>
+ </require>
+ </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"/>
+ </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">
+ <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"/>
+
+ <type name="VkVideoDecodeH265CreateFlagsEXT"/>
+ <type name="VkVideoDecodeH265ProfileEXT"/>
+ <type name="VkVideoDecodeH265CapabilitiesEXT"/>
+ <type name="VkVideoDecodeH265SessionCreateInfoEXT"/>
+
+ <type name="VkVideoDecodeH265SessionParametersCreateInfoEXT"/>
+ <type name="VkVideoDecodeH265SessionParametersAddInfoEXT"/>
+ <type name="VkVideoDecodeH265PictureInfoEXT"/>
+ <type name="VkVideoDecodeH265DpbSlotInfoEXT"/>
+ </require>
+ </extension>
+ <extension name="VK_AMD_extension_189" number="189" author="AMD" contact="Daniel Rakos @drakos-amd" supported="disabled">
+ <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"/>
+ </require>
+ </extension>
+ <extension name="VK_AMD_memory_overallocation_behavior" number="190" type="device" author="AMD" contact="Martin Dinkov @mdinkov" supported="vulkan">
+ <require>
+ <enum value="1" name="VK_AMD_MEMORY_OVERALLOCATION_BEHAVIOR_SPEC_VERSION"/>
+ <enum value="&quot;VK_AMD_memory_overallocation_behavior&quot;" name="VK_AMD_MEMORY_OVERALLOCATION_BEHAVIOR_EXTENSION_NAME"/>
+ <enum offset="0" extends="VkStructureType" name="VK_STRUCTURE_TYPE_DEVICE_MEMORY_OVERALLOCATION_CREATE_INFO_AMD"/>
+ <type name="VkMemoryOverallocationBehaviorAMD"/>
+ <type name="VkDeviceMemoryOverallocationCreateInfoAMD"/>
+ </require>
+ </extension>
+ <extension name="VK_EXT_vertex_attribute_divisor" number="191" type="device" requires="VK_KHR_get_physical_device_properties2" author="NV" contact="Vikram Kushwaha @vkushwaha" supported="vulkan">
+ <require>
+ <enum value="3" name="VK_EXT_VERTEX_ATTRIBUTE_DIVISOR_SPEC_VERSION"/>
+ <enum value="&quot;VK_EXT_vertex_attribute_divisor&quot;" name="VK_EXT_VERTEX_ATTRIBUTE_DIVISOR_EXTENSION_NAME"/>
+ <enum offset="0" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VERTEX_ATTRIBUTE_DIVISOR_PROPERTIES_EXT"/>
+ <enum offset="1" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_DIVISOR_STATE_CREATE_INFO_EXT"/>
+ <enum offset="2" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VERTEX_ATTRIBUTE_DIVISOR_FEATURES_EXT"/>
+ <type name="VkPhysicalDeviceVertexAttributeDivisorPropertiesEXT"/>
+ <type name="VkVertexInputBindingDivisorDescriptionEXT"/>
+ <type name="VkPipelineVertexInputDivisorStateCreateInfoEXT"/>
+ <type name="VkPhysicalDeviceVertexAttributeDivisorFeaturesEXT"/>
+ </require>
+ </extension>
+ <extension name="VK_GGP_frame_token" number="192" type="device" requires="VK_KHR_swapchain,VK_GGP_stream_descriptor_surface" platform="ggp" author="GGP" contact="Jean-Francois Roy @jfroy" supported="vulkan">
+ <require>
+ <enum value="1" name="VK_GGP_FRAME_TOKEN_SPEC_VERSION"/>
+ <enum value="&quot;VK_GGP_frame_token&quot;" name="VK_GGP_FRAME_TOKEN_EXTENSION_NAME"/>
+ <enum offset="0" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PRESENT_FRAME_TOKEN_GGP"/>
+ <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">
+ <require>
+ <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"/>
+ <type name="VkPipelineCreationFeedbackFlagBitsEXT"/>
+ <type name="VkPipelineCreationFeedbackFlagsEXT"/>
+ <type name="VkPipelineCreationFeedbackCreateInfoEXT"/>
+ <type name="VkPipelineCreationFeedbackEXT"/>
+ </require>
+ </extension>
+ <extension name="VK_GOOGLE_extension_194" number="194" author="GOOGLE" contact="Jean-Francois Roy @jfroy" supported="disabled">
+ <require>
+ <enum value="0" name="VK_GOOGLE_EXTENSION_194_SPEC_VERSION"/>
+ <enum value="&quot;VK_GOOGLE_extension_194&quot;" name="VK_GOOGLE_EXTENSION_194_EXTENSION_NAME"/>
+ </require>
+ </extension>
+ <extension name="VK_GOOGLE_extension_195" number="195" author="GOOGLE" contact="Jean-Francois Roy @jfroy" supported="disabled">
+ <require>
+ <enum value="0" name="VK_GOOGLE_EXTENSION_195_SPEC_VERSION"/>
+ <enum value="&quot;VK_GOOGLE_extension_195&quot;" name="VK_GOOGLE_EXTENSION_195_EXTENSION_NAME"/>
+ </require>
+ </extension>
+ <extension name="VK_GOOGLE_extension_196" number="196" author="GOOGLE" contact="Jean-Francois Roy @jfroy" supported="disabled">
+ <require>
+ <enum value="0" name="VK_GOOGLE_EXTENSION_196_SPEC_VERSION"/>
+ <enum value="&quot;VK_GOOGLE_extension_196&quot;" name="VK_GOOGLE_EXTENSION_196_EXTENSION_NAME"/>
+ <enum bitpos="1" extends="VkPipelineCacheCreateFlagBits"
+ name="VK_PIPELINE_CACHE_CREATE_RESERVED_1_BIT_EXT"/>
+ </require>
+ </extension>
+ <extension name="VK_KHR_driver_properties" number="197" type="device" requires="VK_KHR_get_physical_device_properties2" author="KHR" contact="Daniel Rakos @drakos-amd" supported="vulkan" promotedto="VK_VERSION_1_2">
+ <require>
+ <enum value="1" name="VK_KHR_DRIVER_PROPERTIES_SPEC_VERSION"/>
+ <enum value="&quot;VK_KHR_driver_properties&quot;" name="VK_KHR_DRIVER_PROPERTIES_EXTENSION_NAME"/>
+ <enum extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DRIVER_PROPERTIES_KHR" alias="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DRIVER_PROPERTIES"/>
+ <enum name="VK_MAX_DRIVER_NAME_SIZE_KHR"/>
+ <enum name="VK_MAX_DRIVER_INFO_SIZE_KHR"/>
+ <type name="VkDriverIdKHR"/>
+ <enum extends="VkDriverId" name="VK_DRIVER_ID_AMD_PROPRIETARY_KHR" alias="VK_DRIVER_ID_AMD_PROPRIETARY"/>
+ <enum extends="VkDriverId" name="VK_DRIVER_ID_AMD_OPEN_SOURCE_KHR" alias="VK_DRIVER_ID_AMD_OPEN_SOURCE"/>
+ <enum extends="VkDriverId" name="VK_DRIVER_ID_MESA_RADV_KHR" alias="VK_DRIVER_ID_MESA_RADV"/>
+ <enum extends="VkDriverId" name="VK_DRIVER_ID_NVIDIA_PROPRIETARY_KHR" alias="VK_DRIVER_ID_NVIDIA_PROPRIETARY"/>
+ <enum extends="VkDriverId" name="VK_DRIVER_ID_INTEL_PROPRIETARY_WINDOWS_KHR" alias="VK_DRIVER_ID_INTEL_PROPRIETARY_WINDOWS"/>
+ <enum extends="VkDriverId" name="VK_DRIVER_ID_INTEL_OPEN_SOURCE_MESA_KHR" alias="VK_DRIVER_ID_INTEL_OPEN_SOURCE_MESA"/>
+ <enum extends="VkDriverId" name="VK_DRIVER_ID_IMAGINATION_PROPRIETARY_KHR" alias="VK_DRIVER_ID_IMAGINATION_PROPRIETARY"/>
+ <enum extends="VkDriverId" name="VK_DRIVER_ID_QUALCOMM_PROPRIETARY_KHR" alias="VK_DRIVER_ID_QUALCOMM_PROPRIETARY"/>
+ <enum extends="VkDriverId" name="VK_DRIVER_ID_ARM_PROPRIETARY_KHR" alias="VK_DRIVER_ID_ARM_PROPRIETARY"/>
+ <enum extends="VkDriverId" name="VK_DRIVER_ID_GOOGLE_SWIFTSHADER_KHR" alias="VK_DRIVER_ID_GOOGLE_SWIFTSHADER"/>
+ <enum extends="VkDriverId" name="VK_DRIVER_ID_GGP_PROPRIETARY_KHR" alias="VK_DRIVER_ID_GGP_PROPRIETARY"/>
+ <enum extends="VkDriverId" name="VK_DRIVER_ID_BROADCOM_PROPRIETARY_KHR" alias="VK_DRIVER_ID_BROADCOM_PROPRIETARY"/>
+ <type name="VkConformanceVersionKHR"/>
+ <type name="VkPhysicalDeviceDriverPropertiesKHR"/>
+ </require>
+ </extension>
+ <extension name="VK_KHR_shader_float_controls" number="198" 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="4" name="VK_KHR_SHADER_FLOAT_CONTROLS_SPEC_VERSION"/>
+ <enum value="&quot;VK_KHR_shader_float_controls&quot;" name="VK_KHR_SHADER_FLOAT_CONTROLS_EXTENSION_NAME"/>
+ <enum extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FLOAT_CONTROLS_PROPERTIES_KHR" alias="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FLOAT_CONTROLS_PROPERTIES"/>
+ <type name="VkPhysicalDeviceFloatControlsPropertiesKHR"/>
+ <type name="VkShaderFloatControlsIndependenceKHR"/>
+ <enum extends="VkShaderFloatControlsIndependence" name="VK_SHADER_FLOAT_CONTROLS_INDEPENDENCE_32_BIT_ONLY_KHR" alias="VK_SHADER_FLOAT_CONTROLS_INDEPENDENCE_32_BIT_ONLY"/>
+ <enum extends="VkShaderFloatControlsIndependence" name="VK_SHADER_FLOAT_CONTROLS_INDEPENDENCE_ALL_KHR" alias="VK_SHADER_FLOAT_CONTROLS_INDEPENDENCE_ALL"/>
+ <enum extends="VkShaderFloatControlsIndependence" name="VK_SHADER_FLOAT_CONTROLS_INDEPENDENCE_NONE_KHR" alias="VK_SHADER_FLOAT_CONTROLS_INDEPENDENCE_NONE"/>
+ </require>
+ </extension>
+ <extension name="VK_NV_shader_subgroup_partitioned" number="199" type="device" requiresCore="1.1" author="NV" contact="Jeff Bolz @jeffbolznv" supported="vulkan">
+ <require>
+ <enum value="1" name="VK_NV_SHADER_SUBGROUP_PARTITIONED_SPEC_VERSION"/>
+ <enum value="&quot;VK_NV_shader_subgroup_partitioned&quot;" name="VK_NV_SHADER_SUBGROUP_PARTITIONED_EXTENSION_NAME"/>
+ <enum bitpos="8" extends="VkSubgroupFeatureFlagBits" name="VK_SUBGROUP_FEATURE_PARTITIONED_BIT_NV"/>
+ </require>
+ </extension>
+ <extension name="VK_KHR_depth_stencil_resolve" number="200" type="device" requires="VK_KHR_create_renderpass2" author="KHR" contact="Jan-Harald Fredriksen @janharald" supported="vulkan" promotedto="VK_VERSION_1_2">
+ <require>
+ <enum value="1" name="VK_KHR_DEPTH_STENCIL_RESOLVE_SPEC_VERSION"/>
+ <enum value="&quot;VK_KHR_depth_stencil_resolve&quot;" name="VK_KHR_DEPTH_STENCIL_RESOLVE_EXTENSION_NAME"/>
+ <enum extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEPTH_STENCIL_RESOLVE_PROPERTIES_KHR" alias="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEPTH_STENCIL_RESOLVE_PROPERTIES"/>
+ <enum extends="VkStructureType" name="VK_STRUCTURE_TYPE_SUBPASS_DESCRIPTION_DEPTH_STENCIL_RESOLVE_KHR" alias="VK_STRUCTURE_TYPE_SUBPASS_DESCRIPTION_DEPTH_STENCIL_RESOLVE"/>
+ <type name="VkSubpassDescriptionDepthStencilResolveKHR"/>
+ <type name="VkPhysicalDeviceDepthStencilResolvePropertiesKHR"/>
+ <type name="VkResolveModeFlagBitsKHR"/>
+ <type name="VkResolveModeFlagsKHR"/>
+ <enum extends="VkResolveModeFlagBits" name="VK_RESOLVE_MODE_NONE_KHR" alias="VK_RESOLVE_MODE_NONE"/>
+ <enum extends="VkResolveModeFlagBits" name="VK_RESOLVE_MODE_SAMPLE_ZERO_BIT_KHR" alias="VK_RESOLVE_MODE_SAMPLE_ZERO_BIT"/>
+ <enum extends="VkResolveModeFlagBits" name="VK_RESOLVE_MODE_AVERAGE_BIT_KHR" alias="VK_RESOLVE_MODE_AVERAGE_BIT"/>
+ <enum extends="VkResolveModeFlagBits" name="VK_RESOLVE_MODE_MIN_BIT_KHR" alias="VK_RESOLVE_MODE_MIN_BIT"/>
+ <enum extends="VkResolveModeFlagBits" name="VK_RESOLVE_MODE_MAX_BIT_KHR" alias="VK_RESOLVE_MODE_MAX_BIT"/>
+ </require>
+ </extension>
+ <extension name="VK_KHR_swapchain_mutable_format" number="201" type="device" author="KHR" requires="VK_KHR_swapchain,VK_KHR_maintenance2,VK_KHR_image_format_list" contact="Daniel Rakos @drakos-arm" supported="vulkan">
+ <require>
+ <enum value="1" name="VK_KHR_SWAPCHAIN_MUTABLE_FORMAT_SPEC_VERSION"/>
+ <enum value="&quot;VK_KHR_swapchain_mutable_format&quot;" name="VK_KHR_SWAPCHAIN_MUTABLE_FORMAT_EXTENSION_NAME"/>
+ <enum bitpos="2" extends="VkSwapchainCreateFlagBitsKHR" name="VK_SWAPCHAIN_CREATE_MUTABLE_FORMAT_BIT_KHR"/>
+ </require>
+ </extension>
+ <extension name="VK_NV_compute_shader_derivatives" number="202" type="device" requires="VK_KHR_get_physical_device_properties2" author="NV" contact="Pat Brown @nvpbrown" supported="vulkan">
+ <require>
+ <enum value="1" name="VK_NV_COMPUTE_SHADER_DERIVATIVES_SPEC_VERSION"/>
+ <enum value="&quot;VK_NV_compute_shader_derivatives&quot;" name="VK_NV_COMPUTE_SHADER_DERIVATIVES_EXTENSION_NAME"/>
+ <enum offset="0" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COMPUTE_SHADER_DERIVATIVES_FEATURES_NV"/>
+ <type name="VkPhysicalDeviceComputeShaderDerivativesFeaturesNV"/>
+ </require>
+ </extension>
+ <extension name="VK_NV_mesh_shader" number="203" type="device" requires="VK_KHR_get_physical_device_properties2" author="NV" contact="Christoph Kubisch @pixeljetstream" supported="vulkan">
+ <require>
+ <enum value="1" name="VK_NV_MESH_SHADER_SPEC_VERSION"/>
+ <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"/>
+ <command name="vkCmdDrawMeshTasksNV"/>
+ <command name="vkCmdDrawMeshTasksIndirectNV"/>
+ <command name="vkCmdDrawMeshTasksIndirectCountNV"/>
+ <type name="VkPhysicalDeviceMeshShaderFeaturesNV"/>
+ <type name="VkPhysicalDeviceMeshShaderPropertiesNV"/>
+ <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">
+ <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"/>
+ <type name="VkPhysicalDeviceFragmentShaderBarycentricFeaturesNV"/>
+ </require>
+ </extension>
+ <extension name="VK_NV_shader_image_footprint" number="205" type="device" requires="VK_KHR_get_physical_device_properties2" author="NV" contact="Pat Brown @nvpbrown" supported="vulkan">
+ <require>
+ <enum value="2" name="VK_NV_SHADER_IMAGE_FOOTPRINT_SPEC_VERSION"/>
+ <enum value="&quot;VK_NV_shader_image_footprint&quot;" name="VK_NV_SHADER_IMAGE_FOOTPRINT_EXTENSION_NAME"/>
+ <enum offset="0" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_IMAGE_FOOTPRINT_FEATURES_NV"/>
+ <type name="VkPhysicalDeviceShaderImageFootprintFeaturesNV"/>
+ </require>
+ </extension>
+ <extension name="VK_NV_scissor_exclusive" number="206" type="device" requires="VK_KHR_get_physical_device_properties2" author="NV" contact="Pat Brown @nvpbrown" supported="vulkan">
+ <require>
+ <enum value="1" name="VK_NV_SCISSOR_EXCLUSIVE_SPEC_VERSION"/>
+ <enum value="&quot;VK_NV_scissor_exclusive&quot;" name="VK_NV_SCISSOR_EXCLUSIVE_EXTENSION_NAME"/>
+ <enum offset="0" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_EXCLUSIVE_SCISSOR_STATE_CREATE_INFO_NV"/>
+ <enum offset="1" extends="VkDynamicState" name="VK_DYNAMIC_STATE_EXCLUSIVE_SCISSOR_NV"/>
+ <enum offset="2" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXCLUSIVE_SCISSOR_FEATURES_NV"/>
+ <type name="VkPipelineViewportExclusiveScissorStateCreateInfoNV"/>
+ <type name="VkPhysicalDeviceExclusiveScissorFeaturesNV"/>
+ <command name="vkCmdSetExclusiveScissorNV"/>
+ </require>
+ </extension>
+ <extension name="VK_NV_device_diagnostic_checkpoints" type="device" number="207" requires="VK_KHR_get_physical_device_properties2" author="NVIDIA" contact="Nuno Subtil @nsubtil" supported="vulkan">
+ <require>
+ <enum value="2" name="VK_NV_DEVICE_DIAGNOSTIC_CHECKPOINTS_SPEC_VERSION"/>
+ <enum value="&quot;VK_NV_device_diagnostic_checkpoints&quot;" name="VK_NV_DEVICE_DIAGNOSTIC_CHECKPOINTS_EXTENSION_NAME"/>
+ <enum offset="0" extends="VkStructureType" name="VK_STRUCTURE_TYPE_CHECKPOINT_DATA_NV"/>
+ <enum offset="1" extends="VkStructureType" name="VK_STRUCTURE_TYPE_QUEUE_FAMILY_CHECKPOINT_PROPERTIES_NV"/>
+ <type name="VkQueueFamilyCheckpointPropertiesNV"/>
+ <type name="VkCheckpointDataNV"/>
+ <command name="vkCmdSetCheckpointNV"/>
+ <command name="vkGetQueueCheckpointDataNV"/>
+ </require>
+ </extension>
+ <extension name="VK_KHR_timeline_semaphore" number="208" type="device" author="KHR" requires="VK_KHR_get_physical_device_properties2" contact="Jason Ekstrand @jekstrand" supported="vulkan" promotedto="VK_VERSION_1_2">
+ <require>
+ <enum value="2" name="VK_KHR_TIMELINE_SEMAPHORE_SPEC_VERSION"/>
+ <enum value="&quot;VK_KHR_timeline_semaphore&quot;" name="VK_KHR_TIMELINE_SEMAPHORE_EXTENSION_NAME"/>
+ <enum extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TIMELINE_SEMAPHORE_FEATURES_KHR" alias="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TIMELINE_SEMAPHORE_FEATURES"/>
+ <enum extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TIMELINE_SEMAPHORE_PROPERTIES_KHR" alias="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TIMELINE_SEMAPHORE_PROPERTIES"/>
+ <enum extends="VkStructureType" name="VK_STRUCTURE_TYPE_SEMAPHORE_TYPE_CREATE_INFO_KHR" alias="VK_STRUCTURE_TYPE_SEMAPHORE_TYPE_CREATE_INFO"/>
+ <enum extends="VkStructureType" name="VK_STRUCTURE_TYPE_TIMELINE_SEMAPHORE_SUBMIT_INFO_KHR" alias="VK_STRUCTURE_TYPE_TIMELINE_SEMAPHORE_SUBMIT_INFO"/>
+ <enum extends="VkStructureType" name="VK_STRUCTURE_TYPE_SEMAPHORE_WAIT_INFO_KHR" alias="VK_STRUCTURE_TYPE_SEMAPHORE_WAIT_INFO"/>
+ <enum extends="VkStructureType" name="VK_STRUCTURE_TYPE_SEMAPHORE_SIGNAL_INFO_KHR" alias="VK_STRUCTURE_TYPE_SEMAPHORE_SIGNAL_INFO"/>
+ <enum extends="VkSemaphoreType" name="VK_SEMAPHORE_TYPE_BINARY_KHR" alias="VK_SEMAPHORE_TYPE_BINARY"/>
+ <enum extends="VkSemaphoreType" name="VK_SEMAPHORE_TYPE_TIMELINE_KHR" alias="VK_SEMAPHORE_TYPE_TIMELINE"/>
+ <enum extends="VkSemaphoreWaitFlagBits" name="VK_SEMAPHORE_WAIT_ANY_BIT_KHR" alias="VK_SEMAPHORE_WAIT_ANY_BIT"/>
+ <type name="VkSemaphoreTypeKHR"/>
+ <type name="VkPhysicalDeviceTimelineSemaphoreFeaturesKHR"/>
+ <type name="VkPhysicalDeviceTimelineSemaphorePropertiesKHR"/>
+ <type name="VkSemaphoreTypeCreateInfoKHR"/>
+ <type name="VkTimelineSemaphoreSubmitInfoKHR"/>
+ <type name="VkSemaphoreWaitFlagBitsKHR"/>
+ <type name="VkSemaphoreWaitFlagsKHR"/>
+ <type name="VkSemaphoreWaitInfoKHR"/>
+ <type name="VkSemaphoreSignalInfoKHR"/>
+ <command name="vkGetSemaphoreCounterValueKHR"/>
+ <command name="vkWaitSemaphoresKHR"/>
+ <command name="vkSignalSemaphoreKHR"/>
+ </require>
+ </extension>
+ <extension name="VK_KHR_extension_209" number="209" type="device" author="KHR" contact="Ian Elliott @ianelliott" supported="disabled">
+ <require>
+ <enum value="0" name="VK_KHR_EXTENSION_209_SPEC_VERSION"/>
+ <enum value="&quot;VK_KHR_extension_209&quot;" name="VK_KHR_EXTENSION_209_EXTENSION_NAME"/>
+ </require>
+ </extension>
+ <extension name="VK_INTEL_shader_integer_functions2" number="210" type="device" requires="VK_KHR_get_physical_device_properties2" author="INTEL" contact="Ian Romanick @ianromanick" supported="vulkan">
+ <require>
+ <enum value="1" name="VK_INTEL_SHADER_INTEGER_FUNCTIONS_2_SPEC_VERSION"/>
+ <enum value="&quot;VK_INTEL_shader_integer_functions2&quot;" name="VK_INTEL_SHADER_INTEGER_FUNCTIONS_2_EXTENSION_NAME"/>
+ <enum offset="0" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_INTEGER_FUNCTIONS_2_FEATURES_INTEL"/>
+ <type name="VkPhysicalDeviceShaderIntegerFunctions2FeaturesINTEL"/>
+ </require>
+ </extension>
+ <extension name="VK_INTEL_performance_query" number="211" type="device" author="INTEL" contact="Lionel Landwerlin @llandwerlin" specialuse="devtools" supported="vulkan">
+ <require>
+ <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 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"/>
+ <enum offset="4" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PERFORMANCE_OVERRIDE_INFO_INTEL"/>
+ <enum offset="5" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PERFORMANCE_CONFIGURATION_ACQUIRE_INFO_INTEL"/>
+ <enum offset="0" extends="VkQueryType" name="VK_QUERY_TYPE_PERFORMANCE_QUERY_INTEL"/>
+ <enum offset="0" extends="VkObjectType" name="VK_OBJECT_TYPE_PERFORMANCE_CONFIGURATION_INTEL"/>
+ <type name="VkPerformanceConfigurationTypeINTEL"/>
+ <type name="VkQueryPoolSamplingModeINTEL"/>
+ <type name="VkPerformanceOverrideTypeINTEL"/>
+ <type name="VkPerformanceParameterTypeINTEL"/>
+ <type name="VkPerformanceValueTypeINTEL"/>
+ <type name="VkPerformanceValueDataINTEL"/>
+ <type name="VkPerformanceValueINTEL"/>
+ <type name="VkInitializePerformanceApiInfoINTEL"/>
+ <type name="VkQueryPoolCreateInfoINTEL"/>
+ <type name="VkQueryPoolPerformanceQueryCreateInfoINTEL"/>
+ <type name="VkPerformanceMarkerInfoINTEL"/>
+ <type name="VkPerformanceStreamMarkerInfoINTEL"/>
+ <type name="VkPerformanceOverrideInfoINTEL"/>
+ <type name="VkPerformanceConfigurationAcquireInfoINTEL"/>
+ <type name="VkPerformanceConfigurationINTEL"/>
+ <command name="vkInitializePerformanceApiINTEL"/>
+ <command name="vkUninitializePerformanceApiINTEL"/>
+ <command name="vkCmdSetPerformanceMarkerINTEL"/>
+ <command name="vkCmdSetPerformanceStreamMarkerINTEL"/>
+ <command name="vkCmdSetPerformanceOverrideINTEL"/>
+ <command name="vkAcquirePerformanceConfigurationINTEL"/>
+ <command name="vkReleasePerformanceConfigurationINTEL"/>
+ <command name="vkQueueSetPerformanceConfigurationINTEL"/>
+ <command name="vkGetPerformanceParameterINTEL"/>
+ </require>
+ </extension>
+ <extension name="VK_KHR_vulkan_memory_model" number="212" type="device" author="KHR" contact="Jeff Bolz @jeffbolznv" supported="vulkan" promotedto="VK_VERSION_1_2">
+ <require>
+ <enum value="3" name="VK_KHR_VULKAN_MEMORY_MODEL_SPEC_VERSION"/>
+ <enum value="&quot;VK_KHR_vulkan_memory_model&quot;" name="VK_KHR_VULKAN_MEMORY_MODEL_EXTENSION_NAME"/>
+ <enum extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_MEMORY_MODEL_FEATURES_KHR" alias="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_MEMORY_MODEL_FEATURES"/>
+ <type name="VkPhysicalDeviceVulkanMemoryModelFeaturesKHR"/>
+ </require>
+ </extension>
+ <extension name="VK_EXT_pci_bus_info" number="213" type="device" author="EXT" requires="VK_KHR_get_physical_device_properties2" contact="Matthaeus G. Chajdas @anteru" supported="vulkan">
+ <require>
+ <enum value="2" name="VK_EXT_PCI_BUS_INFO_SPEC_VERSION"/>
+ <enum value="&quot;VK_EXT_pci_bus_info&quot;" name="VK_EXT_PCI_BUS_INFO_EXTENSION_NAME"/>
+ <enum offset="0" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PCI_BUS_INFO_PROPERTIES_EXT"/>
+ <type name="VkPhysicalDevicePCIBusInfoPropertiesEXT"/>
+ </require>
+ </extension>
+ <extension name="VK_AMD_display_native_hdr" number="214" type="device" author="AMD" requires="VK_KHR_get_physical_device_properties2,VK_KHR_get_surface_capabilities2,VK_KHR_swapchain" contact="Matthaeus G. Chajdas @anteru" supported="vulkan">
+ <require>
+ <enum value="1" name="VK_AMD_DISPLAY_NATIVE_HDR_SPEC_VERSION"/>
+ <enum value="&quot;VK_AMD_display_native_hdr&quot;" name="VK_AMD_DISPLAY_NATIVE_HDR_EXTENSION_NAME"/>
+ <enum offset="0" extends="VkStructureType" name="VK_STRUCTURE_TYPE_DISPLAY_NATIVE_HDR_SURFACE_CAPABILITIES_AMD"/>
+ <enum offset="1" extends="VkStructureType" name="VK_STRUCTURE_TYPE_SWAPCHAIN_DISPLAY_NATIVE_HDR_CREATE_INFO_AMD"/>
+ <enum offset="0" extends="VkColorSpaceKHR" name="VK_COLOR_SPACE_DISPLAY_NATIVE_AMD"/>
+ <type name="VkDisplayNativeHdrSurfaceCapabilitiesAMD"/>
+ <type name="VkSwapchainDisplayNativeHdrCreateInfoAMD"/>
+ <command name="vkSetLocalDimmingAMD"/>
+ </require>
+ </extension>
+ <extension name="VK_FUCHSIA_imagepipe_surface" number="215" type="instance" author="FUCHSIA" requires="VK_KHR_surface" platform="fuchsia" contact="Craig Stout @cdotstout" supported="vulkan">
+ <require>
+ <enum value="1" name="VK_FUCHSIA_IMAGEPIPE_SURFACE_SPEC_VERSION"/>
+ <enum value="&quot;VK_FUCHSIA_imagepipe_surface&quot;" name="VK_FUCHSIA_IMAGEPIPE_SURFACE_EXTENSION_NAME"/>
+ <enum offset="0" extends="VkStructureType" name="VK_STRUCTURE_TYPE_IMAGEPIPE_SURFACE_CREATE_INFO_FUCHSIA"/>
+ <type name="VkImagePipeSurfaceCreateFlagsFUCHSIA"/>
+ <type name="VkImagePipeSurfaceCreateInfoFUCHSIA"/>
+ <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">
+ <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"/>
+ <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"/>
+ </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">
+ <require>
+ <enum value="1" name="VK_EXT_METAL_SURFACE_SPEC_VERSION"/>
+ <enum value="&quot;VK_EXT_metal_surface&quot;" name="VK_EXT_METAL_SURFACE_EXTENSION_NAME"/>
+ <enum offset="0" extends="VkStructureType" name="VK_STRUCTURE_TYPE_METAL_SURFACE_CREATE_INFO_EXT"/>
+ <type name="VkMetalSurfaceCreateFlagsEXT"/>
+ <type name="VkMetalSurfaceCreateInfoEXT"/>
+ <command name="vkCreateMetalSurfaceEXT"/>
+ <type name="CAMetalLayer"/>
+ </require>
+ </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="&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"/>
+ <enum offset="2" extends="VkStructureType" name="VK_STRUCTURE_TYPE_RENDER_PASS_FRAGMENT_DENSITY_MAP_CREATE_INFO_EXT"/>
+ <enum bitpos="14" extends="VkImageCreateFlagBits" name="VK_IMAGE_CREATE_SUBSAMPLED_BIT_EXT"/>
+ <enum offset="0" extends="VkImageLayout" name="VK_IMAGE_LAYOUT_FRAGMENT_DENSITY_MAP_OPTIMAL_EXT"/>
+ <enum bitpos="24" extends="VkAccessFlagBits" name="VK_ACCESS_FRAGMENT_DENSITY_MAP_READ_BIT_EXT"/>
+ <enum bitpos="24" extends="VkFormatFeatureFlagBits" name="VK_FORMAT_FEATURE_FRAGMENT_DENSITY_MAP_BIT_EXT"/>
+ <enum bitpos="9" extends="VkImageUsageFlagBits" name="VK_IMAGE_USAGE_FRAGMENT_DENSITY_MAP_BIT_EXT"/>
+ <enum bitpos="0" extends="VkImageViewCreateFlagBits" name="VK_IMAGE_VIEW_CREATE_FRAGMENT_DENSITY_MAP_DYNAMIC_BIT_EXT"/>
+ <enum bitpos="23" extends="VkPipelineStageFlagBits" name="VK_PIPELINE_STAGE_FRAGMENT_DENSITY_PROCESS_BIT_EXT"/>
+ <enum bitpos="0" extends="VkSamplerCreateFlagBits" name="VK_SAMPLER_CREATE_SUBSAMPLED_BIT_EXT"/>
+ <enum bitpos="1" extends="VkSamplerCreateFlagBits" name="VK_SAMPLER_CREATE_SUBSAMPLED_COARSE_RECONSTRUCTION_BIT_EXT"/>
+ <type name="VkPhysicalDeviceFragmentDensityMapFeaturesEXT"/>
+ <type name="VkPhysicalDeviceFragmentDensityMapPropertiesEXT"/>
+ <type name="VkRenderPassFragmentDensityMapCreateInfoEXT"/>
+ </require>
+ </extension>
+ <extension name="VK_EXT_extension_220" number="220" author="EXT" contact="Dzmitry Malyshau @kvark" supported="disabled">
+ <require>
+ <enum value="0" name="VK_EXT_EXTENSION_220_SPEC_VERSION"/>
+ <enum value="&quot;VK_EXT_extension_220&quot;" name="VK_EXT_EXTENSION_220_EXTENSION_NAME"/>
+ </require>
+ </extension>
+ <extension name="VK_KHR_extension_221" number="221" author="KHR" contact="Tobias Hector @tobski" supported="disabled">
+ <require>
+ <enum value="0" name="VK_KHR_EXTENSION_221_SPEC_VERSION"/>
+ <enum value="&quot;VK_KHR_extension_221&quot;" name="VK_KHR_EXTENSION_221_EXTENSION_NAME"/>
+ <enum bitpos="0" extends="VkRenderPassCreateFlagBits" name="VK_RENDER_PASS_CREATE_RESERVED_0_BIT_KHR"/>
+ </require>
+ </extension>
+ <extension name="VK_EXT_scalar_block_layout" number="222" requires="VK_KHR_get_physical_device_properties2" type="device" author="EXT" contact="Tobias Hector @tobski" supported="vulkan" promotedto="VK_VERSION_1_2">
+ <require>
+ <enum value="1" name="VK_EXT_SCALAR_BLOCK_LAYOUT_SPEC_VERSION"/>
+ <enum value="&quot;VK_EXT_scalar_block_layout&quot;" name="VK_EXT_SCALAR_BLOCK_LAYOUT_EXTENSION_NAME"/>
+ <type name="VkPhysicalDeviceScalarBlockLayoutFeaturesEXT"/>
+ <enum extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SCALAR_BLOCK_LAYOUT_FEATURES_EXT" alias="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SCALAR_BLOCK_LAYOUT_FEATURES"/>
+ </require>
+ </extension>
+ <extension name="VK_EXT_extension_223" number="223" author="EXT" contact="Tobias Hector @tobski" supported="disabled">
+ <require>
+ <enum value="0" name="VK_EXT_EXTENSION_223_SPEC_VERSION"/>
+ <enum value="&quot;VK_EXT_extension_223&quot;" name="VK_EXT_EXTENSION_223_EXTENSION_NAME"/>
+ </require>
+ </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"/>
+ </require>
+ </extension>
+ <extension name="VK_GOOGLE_decorate_string" number="225" type="device" author="GOOGLE" contact="Hai Nguyen @chaoticbob" supported="vulkan">
+ <require>
+ <enum value="1" name="VK_GOOGLE_DECORATE_STRING_SPEC_VERSION"/>
+ <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">
+ <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"/>
+ </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="&quot;VK_KHR_fragment_shading_rate&quot;" name="VK_KHR_FRAGMENT_SHADING_RATE_EXTENSION_NAME"/>
+ <type name="VkFragmentShadingRateCombinerOpKHR"/>
+ <type name="VkFragmentShadingRateAttachmentInfoKHR"/>
+ <type name="VkPipelineFragmentShadingRateStateCreateInfoKHR"/>
+ <type name="VkPhysicalDeviceFragmentShadingRateFeaturesKHR"/>
+ <type name="VkPhysicalDeviceFragmentShadingRatePropertiesKHR"/>
+ <type name="VkPhysicalDeviceFragmentShadingRateKHR"/>
+ <command name="vkGetPhysicalDeviceFragmentShadingRatesKHR"/>
+ <command name="vkCmdSetFragmentShadingRateKHR"/>
+ <enum offset="3" extends="VkImageLayout" extnumber="165" name="VK_IMAGE_LAYOUT_FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL_KHR"/>
+ <enum offset="0" extends="VkDynamicState" name="VK_DYNAMIC_STATE_FRAGMENT_SHADING_RATE_KHR"/>
+ <enum offset="0" extends="VkStructureType" name="VK_STRUCTURE_TYPE_FRAGMENT_SHADING_RATE_ATTACHMENT_INFO_KHR"/>
+ <enum offset="1" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PIPELINE_FRAGMENT_SHADING_RATE_STATE_CREATE_INFO_KHR"/>
+ <enum offset="2" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADING_RATE_PROPERTIES_KHR"/>
+ <enum offset="3" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADING_RATE_FEATURES_KHR"/>
+ <enum offset="4" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADING_RATE_KHR"/>
+ <enum bitpos="23" extends="VkAccessFlagBits" name="VK_ACCESS_FRAGMENT_SHADING_RATE_ATTACHMENT_READ_BIT_KHR"/>
+ <enum bitpos="8" extends="VkImageUsageFlagBits" name="VK_IMAGE_USAGE_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR"/>
+ <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>
+ </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>
+ <enum value="1" name="VK_AMD_SHADER_CORE_PROPERTIES_2_SPEC_VERSION"/>
+ <enum value="&quot;VK_AMD_shader_core_properties2&quot;" name="VK_AMD_SHADER_CORE_PROPERTIES_2_EXTENSION_NAME"/>
+ <enum offset="0" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_CORE_PROPERTIES_2_AMD"/>
+ <type name="VkPhysicalDeviceShaderCoreProperties2AMD"/>
+ <type name="VkShaderCorePropertiesFlagBitsAMD"/>
+ <type name="VkShaderCorePropertiesFlagsAMD"/>
+ </require>
+ </extension>
+ <extension name="VK_AMD_extension_229" number="229" author="AMD" contact="Martin Dinkov @mdinkov" supported="disabled">
+ <require>
+ <enum value="0" name="VK_AMD_EXTENSION_229_SPEC_VERSION"/>
+ <enum value="&quot;VK_AMD_extension_229&quot;" name="VK_AMD_EXTENSION_229_EXTENSION_NAME"/>
+ </require>
+ </extension>
+ <extension name="VK_AMD_device_coherent_memory" number="230" type="device" author="AMD" contact="Tobias Hector @tobski" supported="vulkan">
+ <require>
+ <enum value="1" name="VK_AMD_DEVICE_COHERENT_MEMORY_SPEC_VERSION"/>
+ <enum value="&quot;VK_AMD_device_coherent_memory&quot;" name="VK_AMD_DEVICE_COHERENT_MEMORY_EXTENSION_NAME"/>
+ <enum bitpos="6" extends="VkMemoryPropertyFlagBits" name="VK_MEMORY_PROPERTY_DEVICE_COHERENT_BIT_AMD"/>
+ <enum bitpos="7" extends="VkMemoryPropertyFlagBits" name="VK_MEMORY_PROPERTY_DEVICE_UNCACHED_BIT_AMD"/>
+ <enum offset="0" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COHERENT_MEMORY_FEATURES_AMD"/>
+ <type name="VkPhysicalDeviceCoherentMemoryFeaturesAMD"/>
+ </require>
+ </extension>
+ <extension name="VK_AMD_extension_231" number="231" author="AMD" contact="Martin Dinkov @mdinkov" supported="disabled">
+ <require>
+ <enum value="0" name="VK_AMD_EXTENSION_231_SPEC_VERSION"/>
+ <enum value="&quot;VK_AMD_extension_231&quot;" name="VK_AMD_EXTENSION_231_EXTENSION_NAME"/>
+ </require>
+ </extension>
+ <extension name="VK_AMD_extension_232" number="232" author="AMD" contact="Martin Dinkov @mdinkov" supported="disabled">
+ <require>
+ <enum value="0" name="VK_AMD_EXTENSION_232_SPEC_VERSION"/>
+ <enum value="&quot;VK_AMD_extension_232&quot;" name="VK_AMD_EXTENSION_232_EXTENSION_NAME"/>
+ </require>
+ </extension>
+ <extension name="VK_AMD_extension_233" number="233" author="AMD" contact="Martin Dinkov @mdinkov" supported="disabled">
+ <require>
+ <enum value="0" name="VK_AMD_EXTENSION_233_SPEC_VERSION"/>
+ <enum value="&quot;VK_AMD_extension_233&quot;" name="VK_AMD_EXTENSION_233_EXTENSION_NAME"/>
+ </require>
+ </extension>
+ <extension name="VK_AMD_extension_234" number="234" author="AMD" contact="Martin Dinkov @mdinkov" supported="disabled">
+ <require>
+ <enum value="0" name="VK_AMD_EXTENSION_234_SPEC_VERSION"/>
+ <enum value="&quot;VK_AMD_extension_234&quot;" name="VK_AMD_EXTENSION_234_EXTENSION_NAME"/>
+ </require>
+ </extension>
+ <extension name="VK_EXT_shader_image_atomic_int64" number="235" type="device" requires="VK_KHR_get_physical_device_properties2" author="EXT" contact="Tobias Hector @tobski" supported="vulkan">
+ <require>
+ <enum value="1" name="VK_EXT_SHADER_IMAGE_ATOMIC_INT64_SPEC_VERSION"/>
+ <enum value="&quot;VK_EXT_shader_image_atomic_int64&quot;" name="VK_EXT_SHADER_IMAGE_ATOMIC_INT64_EXTENSION_NAME"/>
+ <enum offset="0" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_IMAGE_ATOMIC_INT64_FEATURES_EXT"/>
+ <type name="VkPhysicalDeviceShaderImageAtomicInt64FeaturesEXT"/>
+ </require>
+ </extension>
+ <extension name="VK_AMD_extension_236" number="236" author="AMD" contact="Martin Dinkov @mdinkov" supported="disabled">
+ <require>
+ <enum value="0" name="VK_AMD_EXTENSION_236_SPEC_VERSION"/>
+ <enum value="&quot;VK_AMD_extension_236&quot;" name="VK_AMD_EXTENSION_236_EXTENSION_NAME"/>
+ </require>
+ </extension>
+ <extension name="VK_KHR_spirv_1_4" number="237" type="device" requiresCore="1.1" requires="VK_KHR_shader_float_controls" author="KHR" contact="Jesse Hall @critsec" supported="vulkan" promotedto="VK_VERSION_1_2">
+ <require>
+ <enum value="1" name="VK_KHR_SPIRV_1_4_SPEC_VERSION"/>
+ <enum value="&quot;VK_KHR_spirv_1_4&quot;" name="VK_KHR_SPIRV_1_4_EXTENSION_NAME"/>
+ </require>
+ </extension>
+ <extension name="VK_EXT_memory_budget" number="238" type="device" requires="VK_KHR_get_physical_device_properties2" author="EXT" contact="Jeff Bolz @jeffbolznv" supported="vulkan">
+ <require>
+ <enum value="1" name="VK_EXT_MEMORY_BUDGET_SPEC_VERSION"/>
+ <enum value="&quot;VK_EXT_memory_budget&quot;" name="VK_EXT_MEMORY_BUDGET_EXTENSION_NAME"/>
+ <enum offset="0" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_BUDGET_PROPERTIES_EXT"/>
+ <type name="VkPhysicalDeviceMemoryBudgetPropertiesEXT"/>
+ </require>
+ </extension>
+ <extension name="VK_EXT_memory_priority" number="239" type="device" requires="VK_KHR_get_physical_device_properties2" author="EXT" contact="Jeff Bolz @jeffbolznv" supported="vulkan">
+ <require>
+ <enum value="1" name="VK_EXT_MEMORY_PRIORITY_SPEC_VERSION"/>
+ <enum value="&quot;VK_EXT_memory_priority&quot;" name="VK_EXT_MEMORY_PRIORITY_EXTENSION_NAME"/>
+ <enum offset="0" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_PRIORITY_FEATURES_EXT"/>
+ <enum offset="1" extends="VkStructureType" name="VK_STRUCTURE_TYPE_MEMORY_PRIORITY_ALLOCATE_INFO_EXT"/>
+ <type name="VkPhysicalDeviceMemoryPriorityFeaturesEXT"/>
+ <type name="VkMemoryPriorityAllocateInfoEXT"/>
+ </require>
+ </extension>
+ <extension name="VK_KHR_surface_protected_capabilities" number="240" type="instance" requiresCore="1.1" requires="VK_KHR_get_surface_capabilities2" author="KHR" contact="Sandeep Shinde @sashinde" supported="vulkan">
+ <require>
+ <enum value="1" name="VK_KHR_SURFACE_PROTECTED_CAPABILITIES_SPEC_VERSION"/>
+ <enum value="&quot;VK_KHR_surface_protected_capabilities&quot;" name="VK_KHR_SURFACE_PROTECTED_CAPABILITIES_EXTENSION_NAME"/>
+ <enum offset="0" extends="VkStructureType" name="VK_STRUCTURE_TYPE_SURFACE_PROTECTED_CAPABILITIES_KHR"/>
+ <type name="VkSurfaceProtectedCapabilitiesKHR"/>
+ </require>
+ </extension>
+ <extension name="VK_NV_dedicated_allocation_image_aliasing" number="241" type="device" requires="VK_KHR_dedicated_allocation" author="NVIDIA" contact="Nuno Subtil @nsubtil" supported="vulkan">
+ <require>
+ <enum value="1" name="VK_NV_DEDICATED_ALLOCATION_IMAGE_ALIASING_SPEC_VERSION"/>
+ <enum value="&quot;VK_NV_dedicated_allocation_image_aliasing&quot;" name="VK_NV_DEDICATED_ALLOCATION_IMAGE_ALIASING_EXTENSION_NAME"/>
+ <enum offset="0" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEDICATED_ALLOCATION_IMAGE_ALIASING_FEATURES_NV"/>
+ <type name="VkPhysicalDeviceDedicatedAllocationImageAliasingFeaturesNV"/>
+ </require>
+ </extension>
+ <extension name="VK_KHR_separate_depth_stencil_layouts" number="242" type="device" requires="VK_KHR_get_physical_device_properties2,VK_KHR_create_renderpass2" author="KHR" contact="Piers Daniell @pdaniell-nv" supported="vulkan" promotedto="VK_VERSION_1_2">
+ <require>
+ <enum value="1" name="VK_KHR_SEPARATE_DEPTH_STENCIL_LAYOUTS_SPEC_VERSION"/>
+ <enum value="&quot;VK_KHR_separate_depth_stencil_layouts&quot;" name="VK_KHR_SEPARATE_DEPTH_STENCIL_LAYOUTS_EXTENSION_NAME"/>
+ <enum extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SEPARATE_DEPTH_STENCIL_LAYOUTS_FEATURES_KHR" alias="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SEPARATE_DEPTH_STENCIL_LAYOUTS_FEATURES"/>
+ <enum extends="VkStructureType" name="VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_STENCIL_LAYOUT_KHR" alias="VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_STENCIL_LAYOUT"/>
+ <enum extends="VkStructureType" name="VK_STRUCTURE_TYPE_ATTACHMENT_DESCRIPTION_STENCIL_LAYOUT_KHR" alias="VK_STRUCTURE_TYPE_ATTACHMENT_DESCRIPTION_STENCIL_LAYOUT"/>
+ <enum extends="VkImageLayout" name="VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL_KHR" alias="VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL"/>
+ <enum extends="VkImageLayout" name="VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_OPTIMAL_KHR" alias="VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_OPTIMAL"/>
+ <enum extends="VkImageLayout" name="VK_IMAGE_LAYOUT_STENCIL_ATTACHMENT_OPTIMAL_KHR" alias="VK_IMAGE_LAYOUT_STENCIL_ATTACHMENT_OPTIMAL"/>
+ <enum extends="VkImageLayout" name="VK_IMAGE_LAYOUT_STENCIL_READ_ONLY_OPTIMAL_KHR" alias="VK_IMAGE_LAYOUT_STENCIL_READ_ONLY_OPTIMAL"/>
+ <type name="VkPhysicalDeviceSeparateDepthStencilLayoutsFeaturesKHR"/>
+ <type name="VkAttachmentReferenceStencilLayoutKHR"/>
+ <type name="VkAttachmentDescriptionStencilLayoutKHR"/>
+ </require>
+ </extension>
+ <extension name="VK_INTEL_extension_243" number="243" author="INTEL" contact="Slawek Grajewski @sgrajewski" supported="disabled">
+ <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"/>
+ </require>
+ </extension>
+ <extension name="VK_MESA_extension_244" number="244" author="MESA" contact="Andres Rodriguez @lostgoat" supported="disabled">
+ <require>
+ <enum value="0" name="VK_MESA_EXTENSION_244_SPEC_VERSION"/>
+ <enum value="&quot;VK_MESA_extension_244&quot;" name="VK_MESA_EXTENSION_244_EXTENSION_NAME"/>
+ </require>
+ </extension>
+ <extension name="VK_EXT_buffer_device_address" number="245" type="device" requires="VK_KHR_get_physical_device_properties2" author="NV" contact="Jeff Bolz @jeffbolznv" deprecatedby="VK_KHR_buffer_device_address" supported="vulkan">
+ <require>
+ <enum value="2" name="VK_EXT_BUFFER_DEVICE_ADDRESS_SPEC_VERSION"/>
+ <enum value="&quot;VK_EXT_buffer_device_address&quot;" name="VK_EXT_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME"/>
+ <enum offset="0" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BUFFER_DEVICE_ADDRESS_FEATURES_EXT"/>
+ <enum extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BUFFER_ADDRESS_FEATURES_EXT" alias="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BUFFER_DEVICE_ADDRESS_FEATURES_EXT"/>
+ <enum extends="VkStructureType" name="VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO_EXT" alias="VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO"/>
+ <enum offset="2" extends="VkStructureType" name="VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_CREATE_INFO_EXT"/>
+ <enum extends="VkBufferUsageFlagBits" name="VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT_EXT" alias="VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT"/>
+ <enum extends="VkBufferCreateFlagBits" name="VK_BUFFER_CREATE_DEVICE_ADDRESS_CAPTURE_REPLAY_BIT_EXT" alias="VK_BUFFER_CREATE_DEVICE_ADDRESS_CAPTURE_REPLAY_BIT"/>
+ <enum extends="VkResult" name="VK_ERROR_INVALID_DEVICE_ADDRESS_EXT" alias="VK_ERROR_INVALID_OPAQUE_CAPTURE_ADDRESS"/>
+ <type name="VkPhysicalDeviceBufferAddressFeaturesEXT"/>
+ <type name="VkPhysicalDeviceBufferDeviceAddressFeaturesEXT"/>
+ <type name="VkBufferDeviceAddressInfoEXT"/>
+ <type name="VkBufferDeviceAddressCreateInfoEXT"/>
+ <command name="vkGetBufferDeviceAddressEXT"/>
+ </require>
+ </extension>
+ <extension name="VK_EXT_tooling_info" number="246" type="device" author="EXT" contact="Tobias Hector @tobski" supported="vulkan">
+ <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"/>
+ <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"/>
+ </require>
+ <require extension="VK_EXT_debug_marker">
+ <enum bitpos="6" extends="VkToolPurposeFlagBitsEXT" 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"/>
+ </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">
+ <require>
+ <enum value="1" name="VK_EXT_SEPARATE_STENCIL_USAGE_SPEC_VERSION"/>
+ <enum value="&quot;VK_EXT_separate_stencil_usage&quot;" name="VK_EXT_SEPARATE_STENCIL_USAGE_EXTENSION_NAME"/>
+ <enum extends="VkStructureType" name="VK_STRUCTURE_TYPE_IMAGE_STENCIL_USAGE_CREATE_INFO_EXT" alias="VK_STRUCTURE_TYPE_IMAGE_STENCIL_USAGE_CREATE_INFO"/>
+ <type name="VkImageStencilUsageCreateInfoEXT"/>
+ </require>
+ </extension>
+ <extension name="VK_EXT_validation_features" number="248" type="instance" author="LUNARG" contact="Karl Schultz @karl-lunarg" specialuse="debugging" supported="vulkan">
+ <require>
+ <enum value="5" name="VK_EXT_VALIDATION_FEATURES_SPEC_VERSION"/>
+ <enum value="&quot;VK_EXT_validation_features&quot;" name="VK_EXT_VALIDATION_FEATURES_EXTENSION_NAME"/>
+ <enum offset="0" extends="VkStructureType" name="VK_STRUCTURE_TYPE_VALIDATION_FEATURES_EXT"/>
+ <type name="VkValidationFeaturesEXT"/>
+ <type name="VkValidationFeatureEnableEXT"/>
+ <type name="VkValidationFeatureDisableEXT"/>
+ </require>
+ </extension>
+ <extension name="VK_KHR_present_wait" number="249" type="device" requires="VK_KHR_swapchain,VK_KHR_present_id" author="KHR" contact="Keith Packard @keithp" supported="vulkan">
+ <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"/>
+ </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">
+ <require>
+ <enum value="1" name="VK_NV_COOPERATIVE_MATRIX_SPEC_VERSION"/>
+ <enum value="&quot;VK_NV_cooperative_matrix&quot;" name="VK_NV_COOPERATIVE_MATRIX_EXTENSION_NAME"/>
+ <enum offset="0" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COOPERATIVE_MATRIX_FEATURES_NV"/>
+ <enum offset="1" extends="VkStructureType" name="VK_STRUCTURE_TYPE_COOPERATIVE_MATRIX_PROPERTIES_NV"/>
+ <enum offset="2" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COOPERATIVE_MATRIX_PROPERTIES_NV"/>
+ <type name="VkCooperativeMatrixPropertiesNV"/>
+ <type name="VkScopeNV"/>
+ <type name="VkComponentTypeNV"/>
+ <type name="VkPhysicalDeviceCooperativeMatrixFeaturesNV"/>
+ <type name="VkPhysicalDeviceCooperativeMatrixPropertiesNV"/>
+ <command name="vkGetPhysicalDeviceCooperativeMatrixPropertiesNV"/>
+ </require>
+ </extension>
+ <extension name="VK_NV_coverage_reduction_mode" number="251" requires="VK_NV_framebuffer_mixed_samples" type="device" author="NV" contact="Kedarnath Thangudu @kthangudu" supported="vulkan">
+ <require>
+ <enum value="1" name="VK_NV_COVERAGE_REDUCTION_MODE_SPEC_VERSION"/>
+ <enum value="&quot;VK_NV_coverage_reduction_mode&quot;" name="VK_NV_COVERAGE_REDUCTION_MODE_EXTENSION_NAME"/>
+ <enum offset="0" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COVERAGE_REDUCTION_MODE_FEATURES_NV"/>
+ <enum offset="1" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PIPELINE_COVERAGE_REDUCTION_STATE_CREATE_INFO_NV"/>
+ <enum offset="2" extends="VkStructureType" name="VK_STRUCTURE_TYPE_FRAMEBUFFER_MIXED_SAMPLES_COMBINATION_NV"/>
+ <type name="VkPhysicalDeviceCoverageReductionModeFeaturesNV"/>
+ <type name="VkPipelineCoverageReductionStateCreateInfoNV"/>
+ <type name="VkPipelineCoverageReductionStateCreateFlagsNV"/>
+ <type name="VkCoverageReductionModeNV"/>
+ <type name="VkFramebufferMixedSamplesCombinationNV"/>
+ <command name="vkGetPhysicalDeviceSupportedFramebufferMixedSamplesCombinationsNV"/>
+ </require>
+ </extension>
+ <extension name="VK_EXT_fragment_shader_interlock" number="252" author="EXT" type="device" requires="VK_KHR_get_physical_device_properties2" contact="Piers Daniell @pdaniell-nv" supported="vulkan">
+ <require>
+ <enum value="1" name="VK_EXT_FRAGMENT_SHADER_INTERLOCK_SPEC_VERSION"/>
+ <enum value="&quot;VK_EXT_fragment_shader_interlock&quot;" name="VK_EXT_FRAGMENT_SHADER_INTERLOCK_EXTENSION_NAME"/>
+ <enum offset="0" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADER_INTERLOCK_FEATURES_EXT"/>
+ <type name="VkPhysicalDeviceFragmentShaderInterlockFeaturesEXT"/>
+ </require>
+ </extension>
+ <extension name="VK_EXT_ycbcr_image_arrays" number="253" type="device" requires="VK_KHR_sampler_ycbcr_conversion" author="EXT" contact="Piers Daniell @pdaniell-nv" supported="vulkan">
+ <require>
+ <enum value="1" name="VK_EXT_YCBCR_IMAGE_ARRAYS_SPEC_VERSION"/>
+ <enum value="&quot;VK_EXT_ycbcr_image_arrays&quot;" name="VK_EXT_YCBCR_IMAGE_ARRAYS_EXTENSION_NAME"/>
+ <enum offset="0" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_YCBCR_IMAGE_ARRAYS_FEATURES_EXT"/>
+ <type name="VkPhysicalDeviceYcbcrImageArraysFeaturesEXT"/>
+ </require>
+ </extension>
+ <extension name="VK_KHR_uniform_buffer_standard_layout" number="254" requires="VK_KHR_get_physical_device_properties2" type="device" author="KHR" contact="Graeme Leese @gnl21" supported="vulkan" promotedto="VK_VERSION_1_2">
+ <require>
+ <enum value="1" name="VK_KHR_UNIFORM_BUFFER_STANDARD_LAYOUT_SPEC_VERSION"/>
+ <enum value="&quot;VK_KHR_uniform_buffer_standard_layout&quot;" name="VK_KHR_UNIFORM_BUFFER_STANDARD_LAYOUT_EXTENSION_NAME"/>
+ <type name="VkPhysicalDeviceUniformBufferStandardLayoutFeaturesKHR"/>
+ <enum extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_UNIFORM_BUFFER_STANDARD_LAYOUT_FEATURES_KHR" alias="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_UNIFORM_BUFFER_STANDARD_LAYOUT_FEATURES"/>
+ </require>
+ </extension>
+ <extension name="VK_EXT_provoking_vertex" number="255" type="device" author="EXT" requires="VK_KHR_get_physical_device_properties2" contact="Jesse Hall @jessehall" specialuse="glemulation" supported="vulkan">
+ <require>
+ <enum value="1" name="VK_EXT_PROVOKING_VERTEX_SPEC_VERSION"/>
+ <enum value="&quot;VK_EXT_provoking_vertex&quot;" name="VK_EXT_PROVOKING_VERTEX_EXTENSION_NAME"/>
+ <enum offset="0" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROVOKING_VERTEX_FEATURES_EXT"/>
+ <enum offset="1" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_PROVOKING_VERTEX_STATE_CREATE_INFO_EXT"/>
+ <enum offset="2" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROVOKING_VERTEX_PROPERTIES_EXT"/>
+ <type name="VkPhysicalDeviceProvokingVertexFeaturesEXT"/>
+ <type name="VkPhysicalDeviceProvokingVertexPropertiesEXT"/>
+ <type name="VkPipelineRasterizationProvokingVertexStateCreateInfoEXT"/>
+ <type name="VkProvokingVertexModeEXT"/>
+ </require>
+ </extension>
+ <extension name="VK_EXT_full_screen_exclusive" number="256" type="device" author="EXT" requires="VK_KHR_get_physical_device_properties2,VK_KHR_surface,VK_KHR_get_surface_capabilities2,VK_KHR_swapchain" platform="win32" contact="James Jones @cubanismo" supported="vulkan">
+ <require>
+ <enum value="4" name="VK_EXT_FULL_SCREEN_EXCLUSIVE_SPEC_VERSION"/>
+ <enum value="&quot;VK_EXT_full_screen_exclusive&quot;" name="VK_EXT_FULL_SCREEN_EXCLUSIVE_EXTENSION_NAME"/>
+ <enum offset="0" extends="VkStructureType" name="VK_STRUCTURE_TYPE_SURFACE_FULL_SCREEN_EXCLUSIVE_INFO_EXT"/>
+ <enum offset="2" extends="VkStructureType" name="VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES_FULL_SCREEN_EXCLUSIVE_EXT"/>
+ <enum offset="0" extends="VkResult" dir="-" name="VK_ERROR_FULL_SCREEN_EXCLUSIVE_MODE_LOST_EXT"/>
+ <type name="VkFullScreenExclusiveEXT"/>
+ <type name="VkSurfaceFullScreenExclusiveInfoEXT"/>
+ <type name="VkSurfaceCapabilitiesFullScreenExclusiveEXT"/>
+ <command name="vkGetPhysicalDeviceSurfacePresentModes2EXT"/>
+ <command name="vkAcquireFullScreenExclusiveModeEXT"/>
+ <command name="vkReleaseFullScreenExclusiveModeEXT"/>
+ </require>
+ <require extension="VK_KHR_win32_surface">
+ <enum offset="1" extends="VkStructureType" name="VK_STRUCTURE_TYPE_SURFACE_FULL_SCREEN_EXCLUSIVE_WIN32_INFO_EXT"/>
+ <type name="VkSurfaceFullScreenExclusiveWin32InfoEXT"/>
+ </require>
+ <require extension="VK_KHR_device_group">
+ <command name="vkGetDeviceGroupSurfacePresentModes2EXT"/>
+ </require>
+ <require feature="VK_VERSION_1_1">
+ <command name="vkGetDeviceGroupSurfacePresentModes2EXT"/>
+ </require>
+ </extension>
+ <extension name="VK_EXT_headless_surface" number="257" type="instance" requires="VK_KHR_surface" author="EXT" contact="Lisa Wu @chengtianww" supported="vulkan">
+ <require>
+ <enum value="1" name="VK_EXT_HEADLESS_SURFACE_SPEC_VERSION"/>
+ <enum value="&quot;VK_EXT_headless_surface&quot;" name="VK_EXT_HEADLESS_SURFACE_EXTENSION_NAME"/>
+ <enum offset="0" extends="VkStructureType" name="VK_STRUCTURE_TYPE_HEADLESS_SURFACE_CREATE_INFO_EXT"/>
+ <type name="VkHeadlessSurfaceCreateFlagsEXT"/>
+ <type name="VkHeadlessSurfaceCreateInfoEXT"/>
+ <command name="vkCreateHeadlessSurfaceEXT"/>
+ </require>
+ </extension>
+ <extension name="VK_KHR_buffer_device_address" number="258" type="device" requires="VK_KHR_get_physical_device_properties2" author="KHR" contact="Jeff Bolz @jeffbolznv" supported="vulkan" promotedto="VK_VERSION_1_2">
+ <require>
+ <enum value="1" name="VK_KHR_BUFFER_DEVICE_ADDRESS_SPEC_VERSION"/>
+ <enum value="&quot;VK_KHR_buffer_device_address&quot;" name="VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME"/>
+ <enum extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BUFFER_DEVICE_ADDRESS_FEATURES_KHR" alias="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BUFFER_DEVICE_ADDRESS_FEATURES"/>
+ <enum extends="VkStructureType" name="VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO_KHR" alias="VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO"/>
+ <enum extends="VkStructureType" name="VK_STRUCTURE_TYPE_BUFFER_OPAQUE_CAPTURE_ADDRESS_CREATE_INFO_KHR" alias="VK_STRUCTURE_TYPE_BUFFER_OPAQUE_CAPTURE_ADDRESS_CREATE_INFO"/>
+ <enum extends="VkStructureType" name="VK_STRUCTURE_TYPE_MEMORY_OPAQUE_CAPTURE_ADDRESS_ALLOCATE_INFO_KHR" alias="VK_STRUCTURE_TYPE_MEMORY_OPAQUE_CAPTURE_ADDRESS_ALLOCATE_INFO"/>
+ <enum extends="VkStructureType" name="VK_STRUCTURE_TYPE_DEVICE_MEMORY_OPAQUE_CAPTURE_ADDRESS_INFO_KHR" alias="VK_STRUCTURE_TYPE_DEVICE_MEMORY_OPAQUE_CAPTURE_ADDRESS_INFO"/>
+ <enum extends="VkBufferUsageFlagBits" name="VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT_KHR" alias="VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT"/>
+ <enum extends="VkBufferCreateFlagBits" name="VK_BUFFER_CREATE_DEVICE_ADDRESS_CAPTURE_REPLAY_BIT_KHR" alias="VK_BUFFER_CREATE_DEVICE_ADDRESS_CAPTURE_REPLAY_BIT"/>
+ <enum extends="VkMemoryAllocateFlagBits" name="VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT_KHR" alias="VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT"/>
+ <enum extends="VkMemoryAllocateFlagBits" name="VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_CAPTURE_REPLAY_BIT_KHR" alias="VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_CAPTURE_REPLAY_BIT"/>
+ <enum extends="VkResult" name="VK_ERROR_INVALID_OPAQUE_CAPTURE_ADDRESS_KHR" alias="VK_ERROR_INVALID_OPAQUE_CAPTURE_ADDRESS"/>
+ <type name="VkPhysicalDeviceBufferDeviceAddressFeaturesKHR"/>
+ <type name="VkBufferDeviceAddressInfoKHR"/>
+ <type name="VkBufferOpaqueCaptureAddressCreateInfoKHR"/>
+ <type name="VkMemoryOpaqueCaptureAddressAllocateInfoKHR"/>
+ <type name="VkDeviceMemoryOpaqueCaptureAddressInfoKHR"/>
+ <command name="vkGetBufferDeviceAddressKHR"/>
+ <command name="vkGetBufferOpaqueCaptureAddressKHR"/>
+ <command name="vkGetDeviceMemoryOpaqueCaptureAddressKHR"/>
+ </require>
+ </extension>
+ <extension name="VK_EXT_extension_259" number="259" author="EXT" contact="Jeff Leger @jackohound" supported="disabled">
+ <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"/>
+ </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">
+ <require>
+ <enum value="1" name="VK_EXT_LINE_RASTERIZATION_SPEC_VERSION"/>
+ <enum value="&quot;VK_EXT_line_rasterization&quot;" name="VK_EXT_LINE_RASTERIZATION_EXTENSION_NAME"/>
+ <enum offset="0" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LINE_RASTERIZATION_FEATURES_EXT"/>
+ <enum offset="1" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_LINE_STATE_CREATE_INFO_EXT"/>
+ <enum offset="2" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LINE_RASTERIZATION_PROPERTIES_EXT"/>
+ <enum offset="0" extends="VkDynamicState" name="VK_DYNAMIC_STATE_LINE_STIPPLE_EXT"/>
+ <type name="VkPhysicalDeviceLineRasterizationFeaturesEXT"/>
+ <type name="VkPhysicalDeviceLineRasterizationPropertiesEXT"/>
+ <type name="VkPipelineRasterizationLineStateCreateInfoEXT"/>
+ <type name="VkLineRasterizationModeEXT"/>
+ <command name="vkCmdSetLineStippleEXT"/>
+ </require>
+ </extension>
+ <extension name="VK_EXT_shader_atomic_float" number="261" type="device" author="NV" requires="VK_KHR_get_physical_device_properties2" contact="Vikram Kushwaha @vkushwaha-nv" supported="vulkan">
+ <require>
+ <enum value="1" name="VK_EXT_SHADER_ATOMIC_FLOAT_SPEC_VERSION"/>
+ <enum value="&quot;VK_EXT_shader_atomic_float&quot;" name="VK_EXT_SHADER_ATOMIC_FLOAT_EXTENSION_NAME"/>
+ <enum offset="0" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_ATOMIC_FLOAT_FEATURES_EXT"/>
+ <type name="VkPhysicalDeviceShaderAtomicFloatFeaturesEXT"/>
+ </require>
+ </extension>
+ <extension name="VK_EXT_host_query_reset" number="262" author="EXT" contact="Bas Nieuwenhuizen @BNieuwenhuizen" supported="vulkan" type="device" requires="VK_KHR_get_physical_device_properties2" promotedto="VK_VERSION_1_2">
+ <require>
+ <enum value="1" name="VK_EXT_HOST_QUERY_RESET_SPEC_VERSION"/>
+ <enum value="&quot;VK_EXT_host_query_reset&quot;" name="VK_EXT_HOST_QUERY_RESET_EXTENSION_NAME"/>
+ <enum extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_HOST_QUERY_RESET_FEATURES_EXT" alias="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_HOST_QUERY_RESET_FEATURES"/>
+ <type name="VkPhysicalDeviceHostQueryResetFeaturesEXT"/>
+ <command name="vkResetQueryPoolEXT"/>
+ </require>
+ </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"/>
+ </require>
+ </extension>
+ <extension name="VK_BRCM_extension_264" number="264" author="BRCM" contact="Graeme Leese @gnl21" supported="disabled">
+ <require>
+ <enum value="0" name="VK_BRCM_EXTENSION_264_SPEC_VERSION"/>
+ <enum value="&quot;VK_BRCM_extension_264&quot;" name="VK_BRCM_EXTENSION_264_EXTENSION_NAME"/>
+ </require>
+ </extension>
+ <extension name="VK_BRCM_extension_265" number="265" author="BRCM" contact="Graeme Leese @gnl21" supported="disabled">
+ <require>
+ <enum value="0" name="VK_BRCM_EXTENSION_265_SPEC_VERSION"/>
+ <enum value="&quot;VK_BRCM_extension_265&quot;" name="VK_BRCM_EXTENSION_265_EXTENSION_NAME"/>
+ </require>
+ </extension>
+ <extension name="VK_EXT_index_type_uint8" number="266" type="device" author="EXT" contact="Piers Daniell @pdaniell-nv" supported="vulkan">
+ <require>
+ <enum value="1" name="VK_EXT_INDEX_TYPE_UINT8_SPEC_VERSION"/>
+ <enum value="&quot;VK_EXT_index_type_uint8&quot;" name="VK_EXT_INDEX_TYPE_UINT8_EXTENSION_NAME"/>
+ <enum offset="0" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INDEX_TYPE_UINT8_FEATURES_EXT"/>
+ <enum offset="0" extends="VkIndexType" name="VK_INDEX_TYPE_UINT8_EXT"/>
+ <type name="VkPhysicalDeviceIndexTypeUint8FeaturesEXT"/>
+ </require>
+ </extension>
+ <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"/>
+ </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">
+ <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"/>
+ <command name="vkCmdSetCullModeEXT"/>
+ <command name="vkCmdSetFrontFaceEXT"/>
+ <command name="vkCmdSetPrimitiveTopologyEXT"/>
+ <command name="vkCmdSetViewportWithCountEXT"/>
+ <command name="vkCmdSetScissorWithCountEXT"/>
+ <command name="vkCmdBindVertexBuffers2EXT"/>
+ <command name="vkCmdSetDepthTestEnableEXT"/>
+ <command name="vkCmdSetDepthWriteEnableEXT"/>
+ <command name="vkCmdSetDepthCompareOpEXT"/>
+ <command name="vkCmdSetDepthBoundsTestEnableEXT"/>
+ <command name="vkCmdSetStencilTestEnableEXT"/>
+ <command name="vkCmdSetStencilOpEXT"/>
+ </require>
+ </extension>
+ <extension name="VK_KHR_deferred_host_operations" number="269" type="device" author="KHR" contact="Josh Barczak @jbarczak" supported="vulkan">
+ <require>
+ <enum value="4" name="VK_KHR_DEFERRED_HOST_OPERATIONS_SPEC_VERSION"/>
+ <enum value="&quot;VK_KHR_deferred_host_operations&quot;" name="VK_KHR_DEFERRED_HOST_OPERATIONS_EXTENSION_NAME"/>
+ <enum offset="0" extends="VkObjectType" name="VK_OBJECT_TYPE_DEFERRED_OPERATION_KHR"/>
+ <type name="VkDeferredOperationKHR"/>
+ <command name="vkCreateDeferredOperationKHR"/>
+ <command name="vkDestroyDeferredOperationKHR"/>
+ <command name="vkGetDeferredOperationMaxConcurrencyKHR"/>
+ <command name="vkGetDeferredOperationResultKHR"/>
+ <command name="vkDeferredOperationJoinKHR" />
+ <enum extends="VkResult" offset="0" name="VK_THREAD_IDLE_KHR" />
+ <enum extends="VkResult" offset="1" name="VK_THREAD_DONE_KHR" />
+ <enum extends="VkResult" offset="2" name="VK_OPERATION_DEFERRED_KHR" />
+ <enum extends="VkResult" offset="3" name="VK_OPERATION_NOT_DEFERRED_KHR" />
+ </require>
+ </extension>
+ <extension name="VK_KHR_pipeline_executable_properties" number="270" type="device" requires="VK_KHR_get_physical_device_properties2" author="KHR" contact="Jason Ekstrand @jekstrand" specialuse="devtools" supported="vulkan">
+ <require>
+ <enum value="1" name="VK_KHR_PIPELINE_EXECUTABLE_PROPERTIES_SPEC_VERSION"/>
+ <enum value="&quot;VK_KHR_pipeline_executable_properties&quot;" name="VK_KHR_PIPELINE_EXECUTABLE_PROPERTIES_EXTENSION_NAME"/>
+ <enum offset="0" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PIPELINE_EXECUTABLE_PROPERTIES_FEATURES_KHR"/>
+ <enum offset="1" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PIPELINE_INFO_KHR"/>
+ <enum offset="2" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PIPELINE_EXECUTABLE_PROPERTIES_KHR"/>
+ <enum offset="3" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PIPELINE_EXECUTABLE_INFO_KHR"/>
+ <enum offset="4" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PIPELINE_EXECUTABLE_STATISTIC_KHR"/>
+ <enum offset="5" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PIPELINE_EXECUTABLE_INTERNAL_REPRESENTATION_KHR"/>
+ <enum bitpos="6" extends="VkPipelineCreateFlagBits" name="VK_PIPELINE_CREATE_CAPTURE_STATISTICS_BIT_KHR"/>
+ <enum bitpos="7" extends="VkPipelineCreateFlagBits" name="VK_PIPELINE_CREATE_CAPTURE_INTERNAL_REPRESENTATIONS_BIT_KHR"/>
+ <type name="VkPhysicalDevicePipelineExecutablePropertiesFeaturesKHR"/>
+ <type name="VkPipelineInfoKHR"/>
+ <type name="VkPipelineExecutablePropertiesKHR"/>
+ <type name="VkPipelineExecutableInfoKHR"/>
+ <type name="VkPipelineExecutableStatisticFormatKHR"/>
+ <type name="VkPipelineExecutableStatisticValueKHR"/>
+ <type name="VkPipelineExecutableStatisticKHR"/>
+ <type name="VkPipelineExecutableInternalRepresentationKHR"/>
+ <command name="vkGetPipelineExecutablePropertiesKHR"/>
+ <command name="vkGetPipelineExecutableStatisticsKHR"/>
+ <command name="vkGetPipelineExecutableInternalRepresentationsKHR"/>
+ </require>
+ </extension>
+ <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"/>
+ </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"/>
+ </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"/>
+ </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">
+ <require>
+ <enum value="1" name="VK_EXT_SHADER_ATOMIC_FLOAT_2_SPEC_VERSION"/>
+ <enum value="&quot;VK_EXT_shader_atomic_float2&quot;" name="VK_EXT_SHADER_ATOMIC_FLOAT_2_EXTENSION_NAME"/>
+ <enum offset="0" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_ATOMIC_FLOAT_2_FEATURES_EXT"/>
+ <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">
+ <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"/>
+ <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">
+ <require>
+ <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"/>
+ <enum offset="1" extends="VkStructureType" name="VK_STRUCTURE_TYPE_GRAPHICS_SHADER_GROUP_CREATE_INFO_NV"/>
+ <enum offset="2" extends="VkStructureType" name="VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_SHADER_GROUPS_CREATE_INFO_NV"/>
+ <enum offset="3" extends="VkStructureType" name="VK_STRUCTURE_TYPE_INDIRECT_COMMANDS_LAYOUT_TOKEN_NV"/>
+ <enum offset="4" extends="VkStructureType" name="VK_STRUCTURE_TYPE_INDIRECT_COMMANDS_LAYOUT_CREATE_INFO_NV"/>
+ <enum offset="5" extends="VkStructureType" name="VK_STRUCTURE_TYPE_GENERATED_COMMANDS_INFO_NV"/>
+ <enum offset="6" extends="VkStructureType" name="VK_STRUCTURE_TYPE_GENERATED_COMMANDS_MEMORY_REQUIREMENTS_INFO_NV"/>
+ <enum offset="7" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEVICE_GENERATED_COMMANDS_FEATURES_NV"/>
+ <enum bitpos="18" extends="VkPipelineCreateFlagBits" name="VK_PIPELINE_CREATE_INDIRECT_BINDABLE_BIT_NV"/>
+ <enum bitpos="17" extends="VkPipelineStageFlagBits" name="VK_PIPELINE_STAGE_COMMAND_PREPROCESS_BIT_NV"/>
+ <enum bitpos="17" extends="VkAccessFlagBits" name="VK_ACCESS_COMMAND_PREPROCESS_READ_BIT_NV"/>
+ <enum bitpos="18" extends="VkAccessFlagBits" name="VK_ACCESS_COMMAND_PREPROCESS_WRITE_BIT_NV"/>
+ <enum offset="0" extends="VkObjectType" name="VK_OBJECT_TYPE_INDIRECT_COMMANDS_LAYOUT_NV"/>
+ <type name="VkPhysicalDeviceDeviceGeneratedCommandsPropertiesNV"/>
+ <type name="VkPhysicalDeviceDeviceGeneratedCommandsFeaturesNV"/>
+ <type name="VkGraphicsShaderGroupCreateInfoNV"/>
+ <type name="VkGraphicsPipelineShaderGroupsCreateInfoNV"/>
+ <type name="VkBindShaderGroupIndirectCommandNV"/>
+ <type name="VkBindIndexBufferIndirectCommandNV"/>
+ <type name="VkBindVertexBufferIndirectCommandNV"/>
+ <type name="VkSetStateFlagsIndirectCommandNV"/>
+ <type name="VkIndirectStateFlagBitsNV"/>
+ <type name="VkIndirectStateFlagsNV"/>
+ <type name="VkIndirectCommandsLayoutNV"/>
+ <type name="VkIndirectCommandsTokenTypeNV"/>
+ <type name="VkIndirectCommandsLayoutUsageFlagBitsNV"/>
+ <type name="VkIndirectCommandsLayoutUsageFlagsNV"/>
+ <type name="VkIndirectCommandsStreamNV"/>
+ <type name="VkIndirectCommandsLayoutTokenNV"/>
+ <type name="VkIndirectCommandsLayoutCreateInfoNV"/>
+ <type name="VkGeneratedCommandsInfoNV"/>
+ <type name="VkGeneratedCommandsMemoryRequirementsInfoNV"/>
+ <command name="vkGetGeneratedCommandsMemoryRequirementsNV"/>
+ <command name="vkCmdPreprocessGeneratedCommandsNV"/>
+ <command name="vkCmdExecuteGeneratedCommandsNV"/>
+ <command name="vkCmdBindPipelineShaderGroupNV"/>
+ <command name="vkCreateIndirectCommandsLayoutNV"/>
+ <command name="vkDestroyIndirectCommandsLayoutNV"/>
+ </require>
+ </extension>
+ <extension name="VK_NV_inherited_viewport_scissor" number="279" type="device" author="NV" contact="David Zhao Akeley @akeley98" supported="vulkan">
+ <require>
+ <enum value="1" name="VK_NV_INHERITED_VIEWPORT_SCISSOR_SPEC_VERSION"/>
+ <enum value="&quot;VK_NV_inherited_viewport_scissor&quot;" name="VK_NV_INHERITED_VIEWPORT_SCISSOR_EXTENSION_NAME"/>
+ <enum offset="0" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INHERITED_VIEWPORT_SCISSOR_FEATURES_NV"/>
+ <enum offset="1" extends="VkStructureType" name="VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_VIEWPORT_SCISSOR_INFO_NV"/>
+ <type name="VkPhysicalDeviceInheritedViewportScissorFeaturesNV"/>
+ <type name="VkCommandBufferInheritanceViewportScissorInfoNV"/>
+ </require>
+ </extension>
+ <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"/>
+ </require>
+ </extension>
+ <extension name="VK_ARM_extension_281" number="281" type="device" author="ARM" contact="Kevin Petit @kevinpetit" supported="disabled">
+ <require>
+ <enum value="0" name="VK_ARM_EXTENSION_281_SPEC_VERSION"/>
+ <enum value="&quot;VK_ARM_extension_281&quot;" name="VK_ARM_extension_281"/>
+ </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">
+ <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"/>
+ <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="&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"/>
+ <enum bitpos="1" extends="VkRenderPassCreateFlagBits" name="VK_RENDER_PASS_CREATE_TRANSFORM_BIT_QCOM"/>
+ <type name="VkRenderPassTransformBeginInfoQCOM"/>
+ <type name="VkCommandBufferInheritanceRenderPassTransformInfoQCOM"/>
+ </require>
+ </extension>
+ <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"/>
+ </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">
+ <require>
+ <enum value="2" name="VK_EXT_DEVICE_MEMORY_REPORT_SPEC_VERSION"/>
+ <enum value="&quot;VK_EXT_device_memory_report&quot;" name="VK_EXT_DEVICE_MEMORY_REPORT_EXTENSION_NAME"/>
+ <enum offset="0" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEVICE_MEMORY_REPORT_FEATURES_EXT"/>
+ <enum offset="1" extends="VkStructureType" name="VK_STRUCTURE_TYPE_DEVICE_DEVICE_MEMORY_REPORT_CREATE_INFO_EXT"/>
+ <enum offset="2" extends="VkStructureType" name="VK_STRUCTURE_TYPE_DEVICE_MEMORY_REPORT_CALLBACK_DATA_EXT"/>
+ <type name="VkPhysicalDeviceDeviceMemoryReportFeaturesEXT"/>
+ <type name="VkDeviceDeviceMemoryReportCreateInfoEXT"/>
+ <type name="VkDeviceMemoryReportCallbackDataEXT"/>
+ <type name="VkDeviceMemoryReportFlagsEXT"/>
+ <type name="VkDeviceMemoryReportEventTypeEXT"/>
+ <type name="PFN_vkDeviceMemoryReportCallbackEXT"/>
+ </require>
+ </extension>
+ <extension name="VK_EXT_acquire_drm_display" number="286" type="instance" requires="VK_EXT_direct_mode_display" author="EXT" contact="Drew DeVault sir@cmpwn.com" supported="vulkan">
+ <require>
+ <enum value="1" name="VK_EXT_ACQUIRE_DRM_DISPLAY_SPEC_VERSION"/>
+ <enum value="&quot;VK_EXT_acquire_drm_display&quot;" name="VK_EXT_ACQUIRE_DRM_DISPLAY_EXTENSION_NAME"/>
+ <command name="vkAcquireDrmDisplayEXT"/>
+ <command name="vkGetDrmDisplayEXT"/>
+ </require>
+ </extension>
+ <extension name="VK_EXT_robustness2" number="287" type="device" author="EXT" contact="Liam Middlebrook @liam-middlebrook" supported="vulkan">
+ <require>
+ <enum value="1" name="VK_EXT_ROBUSTNESS_2_SPEC_VERSION"/>
+ <enum value="&quot;VK_EXT_robustness2&quot;" name="VK_EXT_ROBUSTNESS_2_EXTENSION_NAME"/>
+ <enum offset="0" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ROBUSTNESS_2_FEATURES_EXT"/>
+ <enum offset="1" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ROBUSTNESS_2_PROPERTIES_EXT"/>
+ <type name="VkPhysicalDeviceRobustness2FeaturesEXT"/>
+ <type name="VkPhysicalDeviceRobustness2PropertiesEXT"/>
+ </require>
+ </extension>
+ <extension name="VK_EXT_custom_border_color" number="288" type="device" author="EXT" contact="Liam Middlebrook @liam-middlebrook" specialuse="glemulation,d3demulation" supported="vulkan">
+ <require>
+ <enum value="12" name="VK_EXT_CUSTOM_BORDER_COLOR_SPEC_VERSION"/>
+ <enum value="&quot;VK_EXT_custom_border_color&quot;" name="VK_EXT_CUSTOM_BORDER_COLOR_EXTENSION_NAME"/>
+ <enum offset="0" extends="VkStructureType" name="VK_STRUCTURE_TYPE_SAMPLER_CUSTOM_BORDER_COLOR_CREATE_INFO_EXT"/>
+ <enum offset="1" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CUSTOM_BORDER_COLOR_PROPERTIES_EXT"/>
+ <enum offset="2" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CUSTOM_BORDER_COLOR_FEATURES_EXT"/>
+ <enum offset="3" extends="VkBorderColor" name="VK_BORDER_COLOR_FLOAT_CUSTOM_EXT"/>
+ <enum offset="4" extends="VkBorderColor" name="VK_BORDER_COLOR_INT_CUSTOM_EXT"/>
+ <type name="VkSamplerCustomBorderColorCreateInfoEXT"/>
+ <type name="VkPhysicalDeviceCustomBorderColorPropertiesEXT"/>
+ <type name="VkPhysicalDeviceCustomBorderColorFeaturesEXT"/>
+ </require>
+ </extension>
+ <extension name="VK_EXT_extension_289" number="289" author="EXT" contact="Jan-Harald Fredriksen @janharaldfredriksen-arm" supported="disabled">
+ <require>
+ <comment>
+ These enums are present only to inform downstream
+ consumers like KTX2. There is no actual Vulkan extension
+ corresponding to the enums.
+ </comment>
+ <enum value="0" name="VK_EXT_EXTENSION_289_SPEC_VERSION"/>
+ <enum value="&quot;VK_EXT_extension_289&quot;" name="VK_EXT_EXTENSION_289_EXTENSION_NAME"/>
+ <enum extends="VkFormat" extnumber="289" offset="0" name="VK_FORMAT_ASTC_3x3x3_UNORM_BLOCK_EXT"/>
+ <enum extends="VkFormat" extnumber="289" offset="1" name="VK_FORMAT_ASTC_3x3x3_SRGB_BLOCK_EXT"/>
+ <enum extends="VkFormat" extnumber="289" offset="2" name="VK_FORMAT_ASTC_3x3x3_SFLOAT_BLOCK_EXT"/>
+ <enum extends="VkFormat" extnumber="289" offset="3" name="VK_FORMAT_ASTC_4x3x3_UNORM_BLOCK_EXT"/>
+ <enum extends="VkFormat" extnumber="289" offset="4" name="VK_FORMAT_ASTC_4x3x3_SRGB_BLOCK_EXT"/>
+ <enum extends="VkFormat" extnumber="289" offset="5" name="VK_FORMAT_ASTC_4x3x3_SFLOAT_BLOCK_EXT"/>
+ <enum extends="VkFormat" extnumber="289" offset="6" name="VK_FORMAT_ASTC_4x4x3_UNORM_BLOCK_EXT"/>
+ <enum extends="VkFormat" extnumber="289" offset="7" name="VK_FORMAT_ASTC_4x4x3_SRGB_BLOCK_EXT"/>
+ <enum extends="VkFormat" extnumber="289" offset="8" name="VK_FORMAT_ASTC_4x4x3_SFLOAT_BLOCK_EXT"/>
+ <enum extends="VkFormat" extnumber="289" offset="9" name="VK_FORMAT_ASTC_4x4x4_UNORM_BLOCK_EXT"/>
+ <enum extends="VkFormat" extnumber="289" offset="10" name="VK_FORMAT_ASTC_4x4x4_SRGB_BLOCK_EXT"/>
+ <enum extends="VkFormat" extnumber="289" offset="11" name="VK_FORMAT_ASTC_4x4x4_SFLOAT_BLOCK_EXT"/>
+ <enum extends="VkFormat" extnumber="289" offset="12" name="VK_FORMAT_ASTC_5x4x4_UNORM_BLOCK_EXT"/>
+ <enum extends="VkFormat" extnumber="289" offset="13" name="VK_FORMAT_ASTC_5x4x4_SRGB_BLOCK_EXT"/>
+ <enum extends="VkFormat" extnumber="289" offset="14" name="VK_FORMAT_ASTC_5x4x4_SFLOAT_BLOCK_EXT"/>
+ <enum extends="VkFormat" extnumber="289" offset="15" name="VK_FORMAT_ASTC_5x5x4_UNORM_BLOCK_EXT"/>
+ <enum extends="VkFormat" extnumber="289" offset="16" name="VK_FORMAT_ASTC_5x5x4_SRGB_BLOCK_EXT"/>
+ <enum extends="VkFormat" extnumber="289" offset="17" name="VK_FORMAT_ASTC_5x5x4_SFLOAT_BLOCK_EXT"/>
+ <enum extends="VkFormat" extnumber="289" offset="18" name="VK_FORMAT_ASTC_5x5x5_UNORM_BLOCK_EXT"/>
+ <enum extends="VkFormat" extnumber="289" offset="19" name="VK_FORMAT_ASTC_5x5x5_SRGB_BLOCK_EXT"/>
+ <enum extends="VkFormat" extnumber="289" offset="20" name="VK_FORMAT_ASTC_5x5x5_SFLOAT_BLOCK_EXT"/>
+ <enum extends="VkFormat" extnumber="289" offset="21" name="VK_FORMAT_ASTC_6x5x5_UNORM_BLOCK_EXT"/>
+ <enum extends="VkFormat" extnumber="289" offset="22" name="VK_FORMAT_ASTC_6x5x5_SRGB_BLOCK_EXT"/>
+ <enum extends="VkFormat" extnumber="289" offset="23" name="VK_FORMAT_ASTC_6x5x5_SFLOAT_BLOCK_EXT"/>
+ <enum extends="VkFormat" extnumber="289" offset="24" name="VK_FORMAT_ASTC_6x6x5_UNORM_BLOCK_EXT"/>
+ <enum extends="VkFormat" extnumber="289" offset="25" name="VK_FORMAT_ASTC_6x6x5_SRGB_BLOCK_EXT"/>
+ <enum extends="VkFormat" extnumber="289" offset="26" name="VK_FORMAT_ASTC_6x6x5_SFLOAT_BLOCK_EXT"/>
+ <enum extends="VkFormat" extnumber="289" offset="27" name="VK_FORMAT_ASTC_6x6x6_UNORM_BLOCK_EXT"/>
+ <enum extends="VkFormat" extnumber="289" offset="28" name="VK_FORMAT_ASTC_6x6x6_SRGB_BLOCK_EXT"/>
+ <enum extends="VkFormat" extnumber="289" offset="29" name="VK_FORMAT_ASTC_6x6x6_SFLOAT_BLOCK_EXT"/>
+ </require>
+ </extension>
+ <extension name="VK_GOOGLE_user_type" number="290" type="device" author="GOOGLE" contact="Kaye Mason @chaleur" supported="vulkan">
+ <require>
+ <enum value="1" name="VK_GOOGLE_USER_TYPE_SPEC_VERSION"/>
+ <enum value="&quot;VK_GOOGLE_user_type&quot;" name="VK_GOOGLE_USER_TYPE_EXTENSION_NAME"/>
+ </require>
+ </extension>
+ <extension name="VK_KHR_pipeline_library" number="291" type="device" author="KHR" contact="Christoph Kubisch @pixeljetstream" supported="vulkan">
+ <require>
+ <enum value="1" name="VK_KHR_PIPELINE_LIBRARY_SPEC_VERSION"/>
+ <enum value="&quot;VK_KHR_pipeline_library&quot;" name="VK_KHR_PIPELINE_LIBRARY_EXTENSION_NAME"/>
+ <enum bitpos="11" extends="VkPipelineCreateFlagBits" name="VK_PIPELINE_CREATE_LIBRARY_BIT_KHR"/>
+ <enum offset="0" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PIPELINE_LIBRARY_CREATE_INFO_KHR"/>
+ <type name="VkPipelineLibraryCreateInfoKHR"/>
+ </require>
+ </extension>
+ <extension name="VK_NV_extension_292" number="292" author="NV" contact="Daniel Koch @dgkoch" supported="disabled">
+ <require>
+ <enum value="0" name="VK_NV_EXTENSION_292_SPEC_VERSION"/>
+ <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">
+ <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"/>
+ </require>
+ </extension>
+ <extension name="VK_KHR_shader_non_semantic_info" number="294" type="device" author="KHR" contact="Baldur Karlsson @baldurk" supported="vulkan">
+ <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"/>
+ </require>
+ </extension>
+ <extension name="VK_KHR_present_id" number="295" type="device" requires="VK_KHR_swapchain" author="KHR" contact="Keith Packard @keithp" supported="vulkan">
+ <require>
+ <enum value="1" name="VK_KHR_PRESENT_ID_SPEC_VERSION"/>
+ <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"/>
+ </require>
+ </extension>
+ <extension name="VK_EXT_private_data" number="296" type="device" author="NV" contact="Matthew Rusch @mattruschnv" supported="vulkan">
+ <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"/>
+ <type name="VkPhysicalDevicePrivateDataFeaturesEXT"/>
+ <type name="VkDevicePrivateDataCreateInfoEXT"/>
+ <type name="VkPrivateDataSlotCreateInfoEXT"/>
+ <type name="VkPrivateDataSlotEXT"/>
+ <type name="VkPrivateDataSlotCreateFlagsEXT"/>
+ <type name="VkPrivateDataSlotCreateFlagBitsEXT"/>
+ <command name="vkCreatePrivateDataSlotEXT"/>
+ <command name="vkDestroyPrivateDataSlotEXT"/>
+ <command name="vkSetPrivateDataEXT"/>
+ <command name="vkGetPrivateDataEXT"/>
+ </require>
+ </extension>
+ <extension name="VK_KHR_extension_297" number="297" author="KHR" contact="Corentin Wallez @Kangz" supported="disabled">
+ <require>
+ <enum value="0" name="VK_KHR_EXTENSION_297_SPEC_VERSION"/>
+ <enum value="&quot;VK_KHR_extension_297&quot;" name="VK_KHR_EXTENSION_297_EXTENSION_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">
+ <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"/>
+ <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"/>
+ </require>
+ </extension>
+ <extension name="VK_KHR_extension_299" number="299" author="KHR" contact="Mark Bellamy @mark.bellamy_arm" supported="disabled">
+ <require>
+ <enum value="0" name="VK_KHR_EXTENSION_299_SPEC_VERSION"/>
+ <enum value="&quot;VK_KHR_extension_299&quot;" name="VK_KHR_EXTENSION_299_EXTENSION_NAME"/>
+ <enum bitpos="2" extends="VkMemoryHeapFlagBits" name="VK_MEMORY_HEAP_RESERVED_2_BIT_KHR"/>
+ <enum extends="VkPipelineCacheCreateFlagBits" name="VK_PIPELINE_CACHE_CREATE_RESERVED_1_BIT_KHR" alias="VK_PIPELINE_CACHE_CREATE_RESERVED_1_BIT_EXT"/>
+ <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">
+ <require>
+ <enum value="2" 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"/>
+ <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 bitpos="6" extends="VkQueueFlagBits" name="VK_QUEUE_VIDEO_ENCODE_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"/>
+ <enum bitpos="14" extends="VkImageUsageFlagBits" name="VK_IMAGE_USAGE_VIDEO_ENCODE_SRC_BIT_KHR" protect="VK_ENABLE_BETA_EXTENSIONS"/>
+ <enum bitpos="15" extends="VkImageUsageFlagBits" name="VK_IMAGE_USAGE_VIDEO_ENCODE_DPB_BIT_KHR" protect="VK_ENABLE_BETA_EXTENSIONS"/>
+ <enum bitpos="27" extends="VkFormatFeatureFlagBits" name="VK_FORMAT_FEATURE_VIDEO_ENCODE_INPUT_BIT_KHR" protect="VK_ENABLE_BETA_EXTENSIONS"/>
+ <enum bitpos="28" extends="VkFormatFeatureFlagBits" name="VK_FORMAT_FEATURE_VIDEO_ENCODE_DPB_BIT_KHR" protect="VK_ENABLE_BETA_EXTENSIONS"/>
+ <enum offset="0" extends="VkImageLayout" name="VK_IMAGE_LAYOUT_VIDEO_ENCODE_DST_KHR" protect="VK_ENABLE_BETA_EXTENSIONS"/>
+ <enum offset="1" extends="VkImageLayout" name="VK_IMAGE_LAYOUT_VIDEO_ENCODE_SRC_KHR" protect="VK_ENABLE_BETA_EXTENSIONS"/>
+ <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="VkVideoEncodeRateControlFlagsKHR"/>
+ <type name="VkVideoEncodeRateControlModeFlagBitsKHR"/>
+ <type name="VkVideoEncodeRateControlModeFlagsKHR"/>
+
+ <type name="VkVideoEncodeRateControlInfoKHR"/>
+ <command name="vkCmdEncodeVideoKHR"/>
+ </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="&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"/>
+ <type name="VkPhysicalDeviceDiagnosticsConfigFeaturesNV"/>
+ <type name="VkDeviceDiagnosticsConfigCreateInfoNV"/>
+ <type name="VkDeviceDiagnosticsConfigFlagsNV"/>
+ <type name="VkDeviceDiagnosticsConfigFlagBitsNV"/>
+ </require>
+ </extension>
+ <extension name="VK_QCOM_render_pass_store_ops" number="302" type="device" author="QCOM" contact="Bill Licea-Kane @wwlk" supported="vulkan">
+ <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"/>
+ </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"/>
+ </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"/>
+ </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"/>
+ </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"/>
+ </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"/>
+ </require>
+ </extension>
+ <extension name="VK_NV_extension_308" number="308" type="device" author="NV" contact="Tristan Lorach @tlorach" supported="disabled">
+ <require>
+ <enum value="0" name="VK_NV_EXTENSION_308_SPEC_VERSION"/>
+ <enum value="&quot;VK_NV_extension_308&quot;" name="VK_NV_EXTENSION_308_EXTENSION_NAME"/>
+ </require>
+ </extension>
+ <extension name="VK_KHR_extension_309" number="309" author="KHR" contact="Aidan Fabius @afabius" supported="disabled">
+ <require>
+ <enum value="0" name="VK_KHR_EXTENSION_309_SPEC_VERSION"/>
+ <enum value="&quot;VK_KHR_extension_309&quot;" name="VK_KHR_EXTENSION_309_EXTENSION_NAME"/>
+ </require>
+ </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 offset="0" extends="VkStructureType" name="VK_STRUCTURE_TYPE_RESERVED_QCOM"/>
+ </require>
+ </extension>
+ <extension name="VK_NV_extension_311" number="311" author="NV" contact="Charles Hansen @cshansen" supported="disabled">
+ <require>
+ <enum value="0" name="VK_NV_EXTENSION_311_SPEC_VERSION"/>
+ <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"/>
+ </require>
+ </extension>
+ <extension name="VK_EXT_extension_313" number="313" author="MVK" contact="Bill Hollings @billhollings" supported="disabled">
+ <require>
+ <enum value="0" name="VK_EXT_EXTENSION_313_SPEC_VERSION"/>
+ <enum value="&quot;VK_EXT_extension_313&quot;" name="VK_EXT_EXTENSION_313_EXTENSION_NAME"/>
+ </require>
+ </extension>
+ <extension name="VK_AMD_extension_314" number="314" author="AMD" contact="Martin Dinkov @mdinkov" supported="disabled">
+ <require>
+ <enum value="0" name="VK_AMD_EXTENSION_314_SPEC_VERSION"/>
+ <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">
+ <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"/>
+ <type name="VkPipelineStageFlags2KHR"/>
+ <type name="VkPipelineStageFlagBits2KHR"/>
+ <type name="VkAccessFlags2KHR"/>
+ <type name="VkAccessFlagBits2KHR"/>
+ <type name="VkMemoryBarrier2KHR"/>
+ <type name="VkBufferMemoryBarrier2KHR"/>
+ <type name="VkImageMemoryBarrier2KHR"/>
+ <type name="VkDependencyInfoKHR"/>
+ <type name="VkSubmitInfo2KHR"/>
+ <type name="VkSemaphoreSubmitInfoKHR"/>
+ <type name="VkCommandBufferSubmitInfoKHR"/>
+ <type name="VkSubmitFlagBitsKHR"/>
+ <type name="VkSubmitFlagsKHR"/>
+ <type name="VkPhysicalDeviceSynchronization2FeaturesKHR"/>
+ <command name="vkCmdSetEvent2KHR"/>
+ <command name="vkCmdResetEvent2KHR"/>
+ <command name="vkCmdWaitEvents2KHR"/>
+ <command name="vkCmdPipelineBarrier2KHR"/>
+ <command name="vkCmdWriteTimestamp2KHR"/>
+ <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"/>
+ </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"/>
+ </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"/>
+ </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"/>
+ </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"/>
+ </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"/>
+ </require>
+ <require extension="VK_KHR_ray_tracing_pipeline">
+ <enum bitpos="21" extends="VkPipelineStageFlagBits2KHR" 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"/>
+ </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"/>
+ </require>
+ <require extension="VK_EXT_blend_operation_advanced">
+ <enum bitpos="19" extends="VkAccessFlagBits2KHR" 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"/>
+ </require>
+ <require extension="VK_AMD_buffer_marker">
+ <command name="vkCmdWriteBufferMarker2AMD"/>
+ </require>
+ <require extension="VK_NV_device_diagnostic_checkpoints">
+ <type name="VkQueueFamilyCheckpointProperties2NV"/>
+ <type name="VkCheckpointData2NV"/>
+ <command name="vkGetQueueCheckpointData2NV"/>
+ <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>
+ </extension>
+ <extension name="VK_AMD_extension_316" number="316" author="AMD" contact="Martin Dinkov @mdinkov" supported="disabled">
+ <require>
+ <enum value="0" name="VK_AMD_EXTENSION_316_SPEC_VERSION"/>
+ <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"/>
+ </require>
+ </extension>
+ <extension name="VK_AMD_extension_318" number="318" author="AMD" contact="Martin Dinkov @mdinkov" supported="disabled">
+ <require>
+ <enum value="0" name="VK_AMD_EXTENSION_318_SPEC_VERSION"/>
+ <enum value="&quot;VK_AMD_extension_318&quot;" name="VK_AMD_EXTENSION_318_EXTENSION_NAME"/>
+ </require>
+ </extension>
+ <extension name="VK_AMD_extension_319" number="319" author="AMD" contact="Martin Dinkov @mdinkov" supported="disabled">
+ <require>
+ <enum value="0" name="VK_AMD_EXTENSION_319_SPEC_VERSION"/>
+ <enum value="&quot;VK_AMD_extension_319&quot;" name="VK_AMD_EXTENSION_319_EXTENSION_NAME"/>
+ <enum bitpos="3" extends="VkDescriptorSetLayoutCreateFlagBits" name="VK_DESCRIPTOR_SET_LAYOUT_CREATE_RESERVED_3_BIT_AMD"/>
+ <enum bitpos="0" extends="VkPipelineLayoutCreateFlagBits" name="VK_PIPELINE_LAYOUT_CREATE_RESERVED_0_BIT_AMD"/>
+ </require>
+ </extension>
+ <extension name="VK_AMD_extension_320" number="320" author="AMD" contact="Martin Dinkov @mdinkov" supported="disabled">
+ <require>
+ <enum value="0" name="VK_AMD_EXTENSION_320_SPEC_VERSION"/>
+ <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">
+ <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"/>
+ </require>
+ </extension>
+ <extension name="VK_AMD_extension_322" number="322" author="AMD" contact="Martin Dinkov @mdinkov" supported="disabled">
+ <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"/>
+ </require>
+ </extension>
+ <extension name="VK_AMD_extension_323" number="323" author="AMD" contact="Martin Dinkov @mdinkov" supported="disabled">
+ <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"/>
+ </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">
+ <require>
+ <enum value="1" name="VK_KHR_SHADER_SUBGROUP_UNIFORM_CONTROL_FLOW_SPEC_VERSION"/>
+ <enum value="&quot;VK_KHR_shader_subgroup_uniform_control_flow&quot;" name="VK_KHR_SHADER_SUBGROUP_UNIFORM_CONTROL_FLOW_EXTENSION_NAME"/>
+ <enum offset="0" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_SUBGROUP_UNIFORM_CONTROL_FLOW_FEATURES_KHR"/>
+ <type name="VkPhysicalDeviceShaderSubgroupUniformControlFlowFeaturesKHR"/>
+ </require>
+ </extension>
+ <extension name="VK_KHR_extension_325" number="325" author="KHR" contact="Ralph Potter gitlab:@r_potter" supported="disabled">
+ <require>
+ <enum value="0" name="VK_KHR_EXTENSION_325_SPEC_VERSION"/>
+ <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">
+ <require>
+ <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"/>
+ <type name="VkPhysicalDeviceZeroInitializeWorkgroupMemoryFeaturesKHR"/>
+ </require>
+ </extension>
+ <extension name="VK_NV_fragment_shading_rate_enums" number="327" type="device" requires="VK_KHR_fragment_shading_rate" author="NV" contact="Pat Brown @nvpbrown" supported="vulkan">
+ <require>
+ <enum value="1" name="VK_NV_FRAGMENT_SHADING_RATE_ENUMS_SPEC_VERSION"/>
+ <enum value="&quot;VK_NV_fragment_shading_rate_enums&quot;" name="VK_NV_FRAGMENT_SHADING_RATE_ENUMS_EXTENSION_NAME"/>
+ <enum offset="0" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADING_RATE_ENUMS_PROPERTIES_NV"/>
+ <enum offset="1" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADING_RATE_ENUMS_FEATURES_NV"/>
+ <enum offset="2" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PIPELINE_FRAGMENT_SHADING_RATE_ENUM_STATE_CREATE_INFO_NV"/>
+ <type name="VkPhysicalDeviceFragmentShadingRateEnumsFeaturesNV"/>
+ <type name="VkPhysicalDeviceFragmentShadingRateEnumsPropertiesNV"/>
+ <type name="VkPipelineFragmentShadingRateEnumStateCreateInfoNV"/>
+ <type name="VkFragmentShadingRateNV"/>
+ <type name="VkFragmentShadingRateTypeNV"/>
+ <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">
+ <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"/>
+ <enum offset="0" extends="VkStructureType" name="VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_MOTION_TRIANGLES_DATA_NV"/>
+ <enum offset="1" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_MOTION_BLUR_FEATURES_NV"/>
+ <enum offset="2" extends="VkStructureType" name="VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_MOTION_INFO_NV"/>
+ <enum bitpos="5" extends="VkBuildAccelerationStructureFlagBitsKHR" name="VK_BUILD_ACCELERATION_STRUCTURE_MOTION_BIT_NV"/>
+ <enum bitpos="2" extends="VkAccelerationStructureCreateFlagBitsKHR" name="VK_ACCELERATION_STRUCTURE_CREATE_MOTION_BIT_NV"/>
+ <enum bitpos="20" extends="VkPipelineCreateFlagBits" name="VK_PIPELINE_CREATE_RAY_TRACING_ALLOW_MOTION_BIT_NV"/>
+ <type name="VkAccelerationStructureGeometryMotionTrianglesDataNV"/>
+ <type name="VkAccelerationStructureMotionInfoNV"/>
+ <type name="VkAccelerationStructureMotionInstanceNV"/>
+ <type name="VkAccelerationStructureMotionInstanceDataNV"/>
+ <type name="VkAccelerationStructureMatrixMotionInstanceNV"/>
+ <type name="VkAccelerationStructureSRTMotionInstanceNV"/>
+ <type name="VkSRTDataNV"/>
+ <type name="VkAccelerationStructureMotionInstanceTypeNV"/>
+ <type name="VkPhysicalDeviceRayTracingMotionBlurFeaturesNV"/>
+ <type name="VkAccelerationStructureMotionInfoFlagsNV"/>
+ <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"/>
+ </require>
+ </extension>
+ <extension name="VK_NV_extension_330" number="330" author="NV" contact="Liam Middlebrook @liam-middlebrook" supported="disabled">
+ <require>
+ <enum value="0" name="VK_NV_EXTENSION_330_SPEC_VERSION"/>
+ <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">
+ <require>
+ <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"/>
+ <type name="VkPhysicalDeviceYcbcr2Plane444FormatsFeaturesEXT"/>
+ </require>
+ </extension>
+ <extension name="VK_NV_extension_332" number="332" author="NV" contact="Tony Zlatinski @tzlatinski" supported="disabled">
+ <require>
+ <enum value="0" name="VK_NV_EXTENSION_332_SPEC_VERSION"/>
+ <enum value="&quot;VK_NV_extension_332&quot;" name="VK_NV_EXTENSION_332_EXTENSION_NAME"/>
+ </require>
+ </extension>
+ <extension name="VK_EXT_fragment_density_map2" number="333" type="device" requires="VK_EXT_fragment_density_map" author="EXT" contact="Matthew Netsch @mnetsch" supported="vulkan">
+ <require>
+ <enum value="1" name="VK_EXT_FRAGMENT_DENSITY_MAP_2_SPEC_VERSION"/>
+ <enum value="&quot;VK_EXT_fragment_density_map2&quot;" name="VK_EXT_FRAGMENT_DENSITY_MAP_2_EXTENSION_NAME"/>
+ <enum offset="0" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_DENSITY_MAP_2_FEATURES_EXT"/>
+ <enum offset="1" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_DENSITY_MAP_2_PROPERTIES_EXT"/>
+ <enum bitpos="1" extends="VkImageViewCreateFlagBits" name="VK_IMAGE_VIEW_CREATE_FRAGMENT_DENSITY_MAP_DEFERRED_BIT_EXT"/>
+ <type name="VkPhysicalDeviceFragmentDensityMap2FeaturesEXT"/>
+ <type name="VkPhysicalDeviceFragmentDensityMap2PropertiesEXT"/>
+ </require>
+ </extension>
+ <extension name="VK_QCOM_rotated_copy_commands" number="334" type="device" requires="VK_KHR_swapchain,VK_KHR_copy_commands2" author="QCOM" contact="Jeff Leger @jackohound" supported="vulkan">
+ <require>
+ <enum value="1" name="VK_QCOM_ROTATED_COPY_COMMANDS_SPEC_VERSION"/>
+ <enum value="&quot;VK_QCOM_rotated_copy_commands&quot;" name="VK_QCOM_ROTATED_COPY_COMMANDS_EXTENSION_NAME"/>
+ <enum offset="0" extends="VkStructureType" name="VK_STRUCTURE_TYPE_COPY_COMMAND_TRANSFORM_INFO_QCOM"/>
+ <type name="VkCopyCommandTransformInfoQCOM"/>
+ </require>
+ </extension>
+ <extension name="VK_KHR_extension_335" number="335" author="KHR" contact="Mark Bellamy @mark.bellamy_arm" supported="disabled">
+ <require>
+ <enum value="0" name="VK_KHR_EXTENSION_335_SPEC_VERSION"/>
+ <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">
+ <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"/>
+ <type name="VkPhysicalDeviceImageRobustnessFeaturesEXT"/>
+ </require>
+ </extension>
+ <extension name="VK_KHR_workgroup_memory_explicit_layout" number="337" type="device" requires="VK_KHR_get_physical_device_properties2" author="KHR" contact="Caio Marcelo de Oliveira Filho @cmarcelo" supported="vulkan">
+ <require>
+ <enum value="1" name="VK_KHR_WORKGROUP_MEMORY_EXPLICIT_LAYOUT_SPEC_VERSION"/>
+ <enum value="&quot;VK_KHR_workgroup_memory_explicit_layout&quot;" name="VK_KHR_WORKGROUP_MEMORY_EXPLICIT_LAYOUT_EXTENSION_NAME"/>
+ <enum offset="0" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_WORKGROUP_MEMORY_EXPLICIT_LAYOUT_FEATURES_KHR"/>
+ <type name="VkPhysicalDeviceWorkgroupMemoryExplicitLayoutFeaturesKHR"/>
+ </require>
+ </extension>
+ <extension name="VK_KHR_copy_commands2" number="338" author="KHR" type="device" contact="Jeff Leger @jackohound" supported="vulkan">
+ <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"/>
+ <type name="VkCopyBufferInfo2KHR"/>
+ <type name="VkCopyImageInfo2KHR"/>
+ <type name="VkCopyBufferToImageInfo2KHR"/>
+ <type name="VkCopyImageToBufferInfo2KHR"/>
+ <type name="VkBlitImageInfo2KHR"/>
+ <type name="VkResolveImageInfo2KHR"/>
+ <type name="VkBufferCopy2KHR"/>
+ <type name="VkImageCopy2KHR"/>
+ <type name="VkImageBlit2KHR"/>
+ <type name="VkBufferImageCopy2KHR"/>
+ <type name="VkImageResolve2KHR"/>
+ <command name="vkCmdCopyBuffer2KHR"/>
+ <command name="vkCmdCopyImage2KHR"/>
+ <command name="vkCmdCopyBufferToImage2KHR"/>
+ <command name="vkCmdCopyImageToBuffer2KHR"/>
+ <command name="vkCmdBlitImage2KHR"/>
+ <command name="vkCmdResolveImage2KHR"/>
+ </require>
+ </extension>
+ <extension name="VK_ARM_extension_339" number="339" author="ARM" contact="Jan-Harald Fredriksen @janharaldfredriksen-arm" supported="disabled">
+ <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"/>
+ </require>
+ </extension>
+ <extension name="VK_EXT_extension_340" number="340" author="EXT" contact="Joshua Ashton @Joshua-Ashton" supported="disabled">
+ <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"/>
+ </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">
+ <require>
+ <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"/>
+ <type name="VkPhysicalDevice4444FormatsFeaturesEXT"/>
+ </require>
+ </extension>
+ <extension name="VK_EXT_extension_342" number="342" author="EXT" contact="Ralph Potter gitlab:@r_potter" supported="disabled">
+ <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"/>
+ </require>
+ </extension>
+ <extension name="VK_ARM_extension_343" number="343" author="ARM" contact="Jan-Harald Fredriksen @janharaldfredriksen-arm" supported="disabled">
+ <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"/>
+ </require>
+ </extension>
+ <extension name="VK_ARM_extension_344" number="344" author="ARM" contact="Jan-Harald Fredriksen @janharaldfredriksen-arm" supported="disabled">
+ <require>
+ <enum value="0" name="VK_ARM_EXTENSION_344_SPEC_VERSION"/>
+ <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"/>
+ </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">
+ <require>
+ <enum value="1" name="VK_NV_ACQUIRE_WINRT_DISPLAY_SPEC_VERSION"/>
+ <enum value="&quot;VK_NV_acquire_winrt_display&quot;" name="VK_NV_ACQUIRE_WINRT_DISPLAY_EXTENSION_NAME"/>
+ <command name="vkAcquireWinrtDisplayNV"/>
+ <command name="vkGetWinrtDisplayNV"/>
+ </require>
+ </extension>
+ <extension name="VK_EXT_directfb_surface" number="347" type="instance" requires="VK_KHR_surface" platform="directfb" supported="vulkan" author="EXT" contact="Nicolas Caramelli @caramelli">
+ <require>
+ <enum value="1" name="VK_EXT_DIRECTFB_SURFACE_SPEC_VERSION"/>
+ <enum value="&quot;VK_EXT_directfb_surface&quot;" name="VK_EXT_DIRECTFB_SURFACE_EXTENSION_NAME"/>
+ <enum offset="0" extends="VkStructureType" name="VK_STRUCTURE_TYPE_DIRECTFB_SURFACE_CREATE_INFO_EXT"/>
+ <type name="VkDirectFBSurfaceCreateFlagsEXT"/>
+ <type name="VkDirectFBSurfaceCreateInfoEXT"/>
+ <command name="vkCreateDirectFBSurfaceEXT"/>
+ <command name="vkGetPhysicalDeviceDirectFBPresentationSupportEXT"/>
+ </require>
+ </extension>
+ <extension name="VK_KHR_extension_350" number="350" author="KHR" contact="Mark Bellamy @mark.bellamy_arm" supported="disabled">
+ <require>
+ <enum value="0" name="VK_KHR_EXTENSION_350_SPEC_VERSION"/>
+ <enum value="&quot;VK_KHR_extension_350&quot;" name="VK_KHR_EXTENSION_350_EXTENSION_NAME"/>
+ </require>
+ </extension>
+ <extension name="VK_NV_extension_351" number="351" author="NV" contact="Liam Middlebrook @liam-middlebrook" supported="disabled">
+ <require>
+ <enum value="0" name="VK_NV_EXTENSION_351_SPEC_VERSION"/>
+ <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">
+ <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"/>
+ <type name="VkPhysicalDeviceMutableDescriptorTypeFeaturesVALVE"/>
+ <type name="VkMutableDescriptorTypeListVALVE"/>
+ <type name="VkMutableDescriptorTypeCreateInfoVALVE"/>
+ </require>
+ </extension>
+ <extension name="VK_EXT_vertex_input_dynamic_state" number="353" type="device" requires="VK_KHR_get_physical_device_properties2" author="EXT" contact="Piers Daniell @pdaniell-nv" supported="vulkan">
+ <require>
+ <enum value="2" name="VK_EXT_VERTEX_INPUT_DYNAMIC_STATE_SPEC_VERSION"/>
+ <enum value="&quot;VK_EXT_vertex_input_dynamic_state&quot;" name="VK_EXT_VERTEX_INPUT_DYNAMIC_STATE_EXTENSION_NAME"/>
+ <enum offset="0" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VERTEX_INPUT_DYNAMIC_STATE_FEATURES_EXT"/>
+ <enum offset="1" extends="VkStructureType" name="VK_STRUCTURE_TYPE_VERTEX_INPUT_BINDING_DESCRIPTION_2_EXT"/>
+ <enum offset="2" extends="VkStructureType" name="VK_STRUCTURE_TYPE_VERTEX_INPUT_ATTRIBUTE_DESCRIPTION_2_EXT"/>
+ <enum offset="0" extends="VkDynamicState" name="VK_DYNAMIC_STATE_VERTEX_INPUT_EXT"/>
+ <type name="VkPhysicalDeviceVertexInputDynamicStateFeaturesEXT"/>
+ <type name="VkVertexInputBindingDescription2EXT"/>
+ <type name="VkVertexInputAttributeDescription2EXT"/>
+ <command name="vkCmdSetVertexInputEXT"/>
+ </require>
+ </extension>
+ <extension name="VK_EXT_physical_device_drm" number="354" author="EXT" type="device" contact="Simon Ser @emersion" supported="vulkan" requires="VK_KHR_get_physical_device_properties2">
+ <require>
+ <enum value="1" name="VK_EXT_PHYSICAL_DEVICE_DRM_SPEC_VERSION"/>
+ <enum value="&quot;VK_EXT_physical_device_drm&quot;" name="VK_EXT_PHYSICAL_DEVICE_DRM_EXTENSION_NAME"/>
+
+ <enum offset="0" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DRM_PROPERTIES_EXT"/>
+
+ <type name="VkPhysicalDeviceDrmPropertiesEXT"/>
+ </require>
+ </extension>
+ <extension name="VK_EXT_extension_355" number="355" author="EXT" contact="Ralph Potter gitlab:@r_potter" supported="disabled">
+ <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"/>
+ </require>
+ </extension>
+ <extension name="VK_EXT_vertex_attribute_aliasing" number="356" type="device" author="EXT" contact="Shahbaz Youssefi @syoussefi" supported="disabled" 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"/>
+ </require>
+ </extension>
+ <extension name="VK_EXT_extension_357" number="357" author="EXT" contact="Courtney Goeltzenleuchter @courtney-g" supported="disabled" specialuse="glemulation">
+ <require>
+ <enum value="0" name="VK_EXT_EXTENSION_357"/>
+ <enum value="&quot;VK_EXT_extension_357&quot;" name="VK_EXT_EXTENSION_357"/>
+ </require>
+ </extension>
+ <extension name="VK_KHR_extension_358" number="358" author="KHR" contact="Jeff Bolz @jeffbolznv" supported="disabled">
+ <require>
+ <enum value="0" name="VK_KHR_EXTENSION_358_SPEC_VERSION"/>
+ <enum value="&quot;VK_KHR_extension_358&quot;" name="VK_KHR_EXTENSION_358_EXTENSION_NAME"/>
+ </require>
+ </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"/>
+ </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"/>
+ </require>
+ </extension>
+ <extension name="VK_KHR_extension_361" number="361" author="KHR" contact="Lionel Landwerlin @llandwerlin" supported="disabled">
+ <require>
+ <enum value="0" name="VK_EXT_EXTENSION_361"/>
+ <enum value="&quot;VK_EXT_extension_361&quot;" name="VK_EXT_EXTENSION_361"/>
+ </require>
+ </extension>
+ <extension name="VK_EXT_extension_362" number="362" author="EXT" contact="Lionel Duc @nvlduc" supported="disabled">
+ <require>
+ <enum value="0" name="VK_EXT_EXTENSION_362_SPEC_VERSION"/>
+ <enum value="&quot;VK_EXT_extension_362&quot;" name="VK_EXT_EXTENSION_362_EXTENSION_NAME"/>
+ </require>
+ </extension>
+ <extension name="VK_EXT_extension_363" number="363" author="EXT" contact="Kaye Mason @chaleur" supported="disabled">
+ <require>
+ <enum value="0" name="VK_EXT_EXTENSION_363_SPEC_VERSION"/>
+ <enum value="&quot;VK_EXT_extension_363&quot;" name="VK_EXT_EXTENSION_363_EXTENSION_NAME"/>
+ </require>
+ </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"/>
+ </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">
+ <require>
+ <enum value="1" name="VK_FUCHSIA_EXTERNAL_MEMORY_SPEC_VERSION"/>
+ <enum value="&quot;VK_FUCHSIA_external_memory&quot;" name="VK_FUCHSIA_EXTERNAL_MEMORY_EXTENSION_NAME"/>
+ <enum offset="0" extends="VkStructureType" name="VK_STRUCTURE_TYPE_IMPORT_MEMORY_ZIRCON_HANDLE_INFO_FUCHSIA"/>
+ <enum offset="1" extends="VkStructureType" name="VK_STRUCTURE_TYPE_MEMORY_ZIRCON_HANDLE_PROPERTIES_FUCHSIA"/>
+ <enum offset="2" extends="VkStructureType" name="VK_STRUCTURE_TYPE_MEMORY_GET_ZIRCON_HANDLE_INFO_FUCHSIA"/>
+ <enum bitpos="11" extends="VkExternalMemoryHandleTypeFlagBits" name="VK_EXTERNAL_MEMORY_HANDLE_TYPE_ZIRCON_VMO_BIT_FUCHSIA"/>
+ <type name="VkImportMemoryZirconHandleInfoFUCHSIA"/>
+ <type name="VkMemoryZirconHandlePropertiesFUCHSIA"/>
+ <type name="VkMemoryGetZirconHandleInfoFUCHSIA"/>
+ <command name="vkGetMemoryZirconHandleFUCHSIA"/>
+ <command name="vkGetMemoryZirconHandlePropertiesFUCHSIA"/>
+ </require>
+ </extension>
+ <extension name="VK_FUCHSIA_external_semaphore" number="366" type="device" requires="VK_KHR_external_semaphore_capabilities,VK_KHR_external_semaphore" author="FUCHSIA" contact="John Rosasco @rosasco" platform="fuchsia" supported="vulkan">
+ <require>
+ <enum value="1" name="VK_FUCHSIA_EXTERNAL_SEMAPHORE_SPEC_VERSION"/>
+ <enum value="&quot;VK_FUCHSIA_external_semaphore&quot;" name="VK_FUCHSIA_EXTERNAL_SEMAPHORE_EXTENSION_NAME"/>
+ <enum offset="0" extends="VkStructureType" name="VK_STRUCTURE_TYPE_IMPORT_SEMAPHORE_ZIRCON_HANDLE_INFO_FUCHSIA"/>
+ <enum offset="1" extends="VkStructureType" name="VK_STRUCTURE_TYPE_SEMAPHORE_GET_ZIRCON_HANDLE_INFO_FUCHSIA"/>
+ <enum bitpos="7" extends="VkExternalSemaphoreHandleTypeFlagBits" name="VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_ZIRCON_EVENT_BIT_FUCHSIA"/>
+ <type name="VkImportSemaphoreZirconHandleInfoFUCHSIA"/>
+ <type name="VkSemaphoreGetZirconHandleInfoFUCHSIA"/>
+ <command name="vkImportSemaphoreZirconHandleFUCHSIA"/>
+ <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"/>
+ </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"/>
+ </require>
+ </extension>
+ <extension name="VK_QCOM_extension_369" number="369" author="QCOM" contact="Matthew Netsch @mnetsch" supported="disabled">
+ <require>
+ <enum value="0" name="VK_QCOM_EXTENSION_369_SPEC_VERSION"/>
+ <enum value="&quot;VK_QCOM_extension_369&quot;" name="VK_QCOM_EXTENSION_369_EXTENSION_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">
+ <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"/>
+ <enum offset="0" extends="VkStructureType" name="VK_STRUCTURE_TYPE_SUBPASS_SHADING_PIPELINE_CREATE_INFO_HUAWEI"/>
+ <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="14" extends="VkShaderStageFlagBits" name="VK_SHADER_STAGE_SUBPASS_SHADING_BIT_HUAWEI"/>
+ <type name="VkSubpassShadingPipelineCreateInfoHUAWEI"/>
+ <type name="VkPhysicalDeviceSubpassShadingFeaturesHUAWEI"/>
+ <type name="VkPhysicalDeviceSubpassShadingPropertiesHUAWEI"/>
+ <command name="vkGetDeviceSubpassShadingMaxWorkgroupSizeHUAWEI"/>
+ <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">
+ <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="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"/>
+ <type name="VkPhysicalDeviceInvocationMaskFeaturesHUAWEI"/>
+ <command name="vkCmdBindInvocationMaskHUAWEI"/>
+ </require>
+ </extension>
+ <extension name="VK_NV_external_memory_rdma" number="372" type="device" requires="VK_KHR_external_memory" author="NV" contact="Carsten Rohde @crohde" supported="vulkan">
+ <require>
+ <enum value="1" name="VK_NV_EXTERNAL_MEMORY_RDMA_SPEC_VERSION"/>
+ <enum value="&quot;VK_NV_external_memory_rdma&quot;" name="VK_NV_EXTERNAL_MEMORY_RDMA_EXTENSION_NAME"/>
+ <enum offset="0" extends="VkStructureType" name="VK_STRUCTURE_TYPE_MEMORY_GET_REMOTE_ADDRESS_INFO_NV"/>
+ <enum offset="1" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_MEMORY_RDMA_FEATURES_NV"/>
+ <enum bitpos="8" extends="VkMemoryPropertyFlagBits" name="VK_MEMORY_PROPERTY_RDMA_CAPABLE_BIT_NV"/>
+ <enum bitpos="12" extends="VkExternalMemoryHandleTypeFlagBits" name="VK_EXTERNAL_MEMORY_HANDLE_TYPE_RDMA_ADDRESS_BIT_NV"/>
+ <type name="VkRemoteAddressNV"/>
+ <type name="VkMemoryGetRemoteAddressInfoNV"/>
+ <type name="VkPhysicalDeviceExternalMemoryRDMAFeaturesNV"/>
+ <command name="vkGetMemoryRemoteAddressNV"/>
+ </require>
+ </extension>
+ <extension name="VK_NV_extension_373" number="373" author="NV" contact="Daniel Koch @dgkoch" supported="disabled">
+ <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"/>
+ </require>
+ </extension>
+ <extension name="VK_NV_extension_374" number="374" author="NV" contact="Daniel Koch @dgkoch" supported="disabled">
+ <require>
+ <enum value="0" name="VK_NV_EXTENSION_374_SPEC_VERSION"/>
+ <enum value="&quot;VK_NV_extension_374&quot;" name="VK_NV_EXTENSION_374_EXTENSION_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">
+ <require>
+ <enum value="0" name="VK_NV_EXTENSION_375_SPEC_VERSION"/>
+ <enum value="&quot;VK_NV_extension_375&quot;" name="VK_NV_EXTENSION_375_EXTENSION_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">
+ <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">
+ <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"/>
+ </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">
+ <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"/>
+ <command name="vkCmdSetRasterizerDiscardEnableEXT"/>
+ <command name="vkCmdSetDepthBiasEnableEXT"/>
+ <command name="vkCmdSetLogicOpEXT"/>
+ <command name="vkCmdSetPrimitiveRestartEnableEXT"/>
+ </require>
+ </extension>
+ <extension name="VK_QNX_screen_surface" number="379" type="instance" requires="VK_KHR_surface" platform="screen" author="QNX" contact="Mike Gorchak @mgorchak-blackberry" supported="vulkan">
+ <require>
+ <enum value="1" name="VK_QNX_SCREEN_SURFACE_SPEC_VERSION"/>
+ <enum value="&quot;VK_QNX_screen_surface&quot;" name="VK_QNX_SCREEN_SURFACE_EXTENSION_NAME"/>
+ <enum offset="0" extends="VkStructureType" name="VK_STRUCTURE_TYPE_SCREEN_SURFACE_CREATE_INFO_QNX"/>
+ <type name="VkScreenSurfaceCreateFlagsQNX"/>
+ <type name="VkScreenSurfaceCreateInfoQNX"/>
+ <command name="vkCreateScreenSurfaceQNX"/>
+ <command name="vkGetPhysicalDeviceScreenPresentationSupportQNX"/>
+ </require>
+ </extension>
+ <extension name="VK_KHR_extension_380" number="380" author="KHR" contact="James Jones @cubanismo" supported="disabled">
+ <require>
+ <enum value="0" name="VK_KHR_EXTENSION_380_SPEC_VERSION"/>
+ <enum value="&quot;VK_KHR_extension_380&quot;" name="VK_KHR_EXTENSION_380_EXTENSION_NAME"/>
+ </require>
+ </extension>
+ <extension name="VK_KHR_extension_381" number="381" author="KHR" contact="James Jones @cubanismo" supported="disabled">
+ <require>
+ <enum value="0" name="VK_KHR_EXTENSION_381_SPEC_VERSION"/>
+ <enum value="&quot;VK_KHR_extension_381&quot;" name="VK_KHR_EXTENSION_381_EXTENSION_NAME"/>
+ </require>
+ </extension>
+ <extension name="VK_EXT_color_write_enable" number="382" type="device" requires="VK_KHR_get_physical_device_properties2" author="EXT" contact="Sharif Elcott @selcott" supported="vulkan">
+ <require>
+ <enum value="1" name="VK_EXT_COLOR_WRITE_ENABLE_SPEC_VERSION"/>
+ <enum value="&quot;VK_EXT_color_write_enable&quot;" name="VK_EXT_COLOR_WRITE_ENABLE_EXTENSION_NAME"/>
+ <enum offset="0" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COLOR_WRITE_ENABLE_FEATURES_EXT"/>
+ <enum offset="1" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PIPELINE_COLOR_WRITE_CREATE_INFO_EXT"/>
+ <enum offset="0" extends="VkDynamicState" name="VK_DYNAMIC_STATE_COLOR_WRITE_ENABLE_EXT"/>
+ <type name="VkPhysicalDeviceColorWriteEnableFeaturesEXT"/>
+ <type name="VkPipelineColorWriteCreateInfoEXT"/>
+ <command name="vkCmdSetColorWriteEnableEXT"/>
+ </require>
+ </extension>
+ <extension name="VK_EXT_extension_383" number="383" author="EXT" contact="Shahbaz Youssefi @syoussefi" supported="disabled">
+ <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"/>
+ </require>
+ </extension>
+ <extension name="VK_EXT_extension_384" number="384" type="instance" author="EXT" contact="Chia-I Wu @olvaffe1" supported="disabled">
+ <require>
+ <enum value="0" name="VK_EXT_EXTENSION_384_SPEC_VERSION"/>
+ <enum value="&quot;VK_EXT_extension_384&quot;" name="VK_EXT_EXTENSION_384_EXTENSION_NAME"/>
+ </require>
+ </extension>
+ <extension name="VK_MESA_extension_385" number="385" type="instance" author="MESA" contact="Chia-I Wu @olvaffe1" supported="disabled">
+ <require>
+ <enum value="0" name="VK_MESA_EXTENSION_385_SPEC_VERSION"/>
+ <enum value="&quot;VK_MESA_extension_385&quot;" name="VK_MESA_EXTENSION_385_EXTENSION_NAME"/>
+ </require>
+ </extension>
+ <extension name="VK_GOOGLE_extension_386" number="386" author="GOOGLE" contact="Chia-I Wu @olvaffe1" supported="disabled">
+ <require>
+ <enum value="0" name="VK_GOOGLE_EXTENSION_386_SPEC_VERSION"/>
+ <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">
+ <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"/>
+ </require>
+ </extension>
+ <extension name="VK_EXT_extension_388" number="388" author="EXT" contact="Alan Baker @alan-baker" supported="disabled">
+ <require>
+ <enum value="0" name="VK_EXT_EXTENSION_388_SPEC_VERSION"/>
+ <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">
+ <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 name="VK_MAX_GLOBAL_PRIORITY_SIZE_EXT"/>
+ <type name="VkPhysicalDeviceGlobalPriorityQueryFeaturesEXT"/>
+ <type name="VkQueueFamilyGlobalPriorityPropertiesEXT"/>
+ </require>
+ </extension>
+ <extension name="VK_EXT_extension_390" number="390" author="EXT" contact="Joshua Ashton @Joshua-Ashton" supported="disabled">
+ <require>
+ <enum value="0" name="VK_EXT_EXTENSION_390_SPEC_VERSION"/>
+ <enum value="&quot;VK_EXT_extension_390&quot;" name="VK_EXT_EXTENSION_390_EXTENSION_NAME"/>
+ </require>
+ </extension>
+ <extension name="VK_EXT_extension_391" number="391" author="EXT" contact="Joshua Ashton @Joshua-Ashton" supported="disabled">
+ <require>
+ <enum value="0" name="VK_EXT_EXTENSION_391_SPEC_VERSION"/>
+ <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">
+ <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"/>
+ </require>
+ </extension>
+ <extension name="VK_EXT_multi_draw" number="393" author="EXT" contact="Mike Blumenkrantz @zmike" type="device" supported="vulkan">
+ <require>
+ <enum value="1" name="VK_EXT_MULTI_DRAW_SPEC_VERSION"/>
+ <enum value="&quot;VK_EXT_multi_draw&quot;" name="VK_EXT_MULTI_DRAW_EXTENSION_NAME"/>
+ <enum offset="0" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTI_DRAW_FEATURES_EXT"/>
+ <enum offset="1" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTI_DRAW_PROPERTIES_EXT"/>
+ <type name="VkPhysicalDeviceMultiDrawFeaturesEXT"/>
+ <type name="VkPhysicalDeviceMultiDrawPropertiesEXT"/>
+ <command name="vkCmdDrawMultiEXT"/>
+ <command name="vkCmdDrawMultiIndexedEXT"/>
+ <type name="VkMultiDrawInfoEXT"/>
+ <type name="VkMultiDrawIndexedInfoEXT"/>
+ </require>
+ </extension>
+ <extension name="VK_EXT_extension_394" number="394" author="EXT" contact="Mike Blumenkrantz @zmike" type="device" supported="disabled">
+ <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"/>
+ </require>
+ </extension>
+ <extension name="VK_KHR_extension_395" number="395" author="KHR" contact="Lenny Komow @lkomow" supported="disabled">
+ <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"/>
+ </require>
+ </extension>
+ <extension name="VK_KHR_extension_396" number="396" author="EXT" contact="Jan-Harald Fredriksen @janharaldfredriksen-arm" supported="disabled">
+ <require>
+ <enum value="0" name="VK_KHR_EXTENSION_396_SPEC_VERSION"/>
+ <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">
+ <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"/>
+ </require>
+ </extension>
+ <extension name="VK_JUICE_extension_399" number="399" author="JUICE" contact="Dean Beeler @canadacow" supported="disabled">
+ <require>
+ <enum value="0" name="VK_JUICE_EXTENSION_399_SPEC_VERSION"/>
+ <enum value="&quot;VK_JUICE_extension_399&quot;" name="VK_JUICE_EXTENSION_399_EXTENSION_NAME"/>
+ </require>
+ </extension>
+ <extension name="VK_JUICE_extension_400" number="400" author="JUICE" contact="David McCloskey @damcclos" supported="disabled">
+ <require>
+ <enum value="0" name="VK_JUICE_EXTENSION_400_SPEC_VERSION"/>
+ <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">
+ <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"/>
+ </require>
+ </extension>
+ <extension name="VK_FB_extension_402" number="402" author="FB" contact="Artem Bolgar @artyom17" supported="disabled">
+ <require>
+ <enum value="0" name="VK_FB_EXTENSION_402_SPEC_VERSION"/>
+ <enum value="&quot;VK_FB_extension_402&quot;" name="VK_FB_EXTENSION_402_EXTENSION_NAME"/>
+ </require>
+ </extension>
+ <extension name="VK_FB_extension_403" number="403" author="FB" contact="Artem Bolgar @artyom17" supported="disabled">
+ <require>
+ <enum value="0" name="VK_FB_EXTENSION_403_SPEC_VERSION"/>
+ <enum value="&quot;VK_FB_extension_403&quot;" name="VK_FB_EXTENSION_403_EXTENSION_NAME"/>
+ </require>
+ </extension>
+ <extension name="VK_FB_extension_404" number="404" author="FB" contact="Artem Bolgar @artyom17" supported="disabled">
+ <require>
+ <enum value="0" name="VK_FB_EXTENSION_404_SPEC_VERSION"/>
+ <enum value="&quot;VK_FB_extension_404&quot;" name="VK_FB_EXTENSION_404_EXTENSION_NAME"/>
+ </require>
+ </extension>
+ <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"/>
+ </require>
+ </extension>
+ <extension name="VK_HUAWEI_extension_406" number="406" author="HUAWEI" contact="Hueilong Wang @wyvernathuawei" supported="disabled">
+ <require>
+ <enum value="0" name="VK_HUAWEI_EXTENSION_406_SPEC_VERSION"/>
+ <enum value="&quot;VK_HUAWEI_extension_406&quot;" name="VK_HUAWEI_EXTENSION_406_EXTENSION_NAME"/>
+ </require>
+ </extension>
+ <extension name="VK_GGP_extension_407" number="407" author="GGP" contact="J.D. Rouan @jdrouan" supported="disabled">
+ <require>
+ <enum value="0" name="VK_GGP_EXTENSION_407_SPEC_VERSION"/>
+ <enum value="&quot;VK_GGP_extension_407&quot;" name="VK_GGP_EXTENSION_407_EXTENSION_NAME"/>
+ </require>
+ </extension>
+ <extension name="VK_GGP_extension_408" number="408" author="GGP" contact="J.D. Rouan @jdrouan" supported="disabled">
+ <require>
+ <enum value="0" name="VK_GGP_EXTENSION_408_SPEC_VERSION"/>
+ <enum value="&quot;VK_GGP_extension_408&quot;" name="VK_GGP_EXTENSION_408_EXTENSION_NAME"/>
+ </require>
+ </extension>
+ <extension name="VK_GGP_extension_409" number="409" author="GGP" contact="J.D. Rouan @jdrouan" supported="disabled">
+ <require>
+ <enum value="0" name="VK_GGP_EXTENSION_409_SPEC_VERSION"/>
+ <enum value="&quot;VK_GGP_extension_409&quot;" name="VK_GGP_EXTENSION_409_EXTENSION_NAME"/>
+ </require>
+ </extension>
+ <extension name="VK_GGP_extension_410" number="410" author="GGP" contact="J.D. Rouan @jdrouan" supported="disabled">
+ <require>
+ <enum value="0" name="VK_GGP_EXTENSION_410_SPEC_VERSION"/>
+ <enum value="&quot;VK_GGP_extension_410&quot;" name="VK_GGP_EXTENSION_410_EXTENSION_NAME"/>
+ </require>
+ </extension>
+ <extension name="VK_GGP_extension_411" number="411" author="GGP" contact="J.D. Rouan @jdrouan" supported="disabled">
+ <require>
+ <enum value="0" name="VK_GGP_EXTENSION_411_SPEC_VERSION"/>
+ <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">
+ <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"/>
+ </require>
+ </extension>
+ <extension name="VK_NV_extension_413" number="413" author="NV" contact="Piers Daniell @pdaniell-nv" supported="disabled">
+ <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"/>
+ </require>
+ </extension>
+ <extension name="VK_NV_extension_414" number="414" author="NV" contact="Piers Daniell @pdaniell-nv" supported="disabled">
+ <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"/>
+ </require>
+ </extension>
+ <extension name="VK_HUAWEI_extension_415" number="415" author="HUAWEI" contact="Hueilong Wang @wyvernathuawei" supported="disabled">
+ <require>
+ <enum value="0" name="VK_HUAWEI_EXTENSION_415_SPEC_VERSION"/>
+ <enum value="&quot;VK_HUAWEI_extension_415&quot;" name="VK_HUAWEI_EXTENSION_415_EXTENSION_NAME"/>
+ </require>
+ </extension>
+ <extension name="VK_ARM_extension_416" number="416" author="ARM" contact="Jan-Harald Fredriksen @janharaldfredriksen-arm" supported="disabled">
+ <require>
+ <enum value="0" name="VK_ARM_EXTENSION_416_SPEC_VERSION"/>
+ <enum value="&quot;VK_ARM_extension_416&quot;" name="VK_ARM_EXTENSION_416_EXTENSION_NAME"/>
+ </require>
+ </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"/>
+ </require>
+ </extension>
+ <extension name="VK_ARM_extension_418" number="418" author="ARM" contact="Kevin Petit @kevinpetit" supported="disabled">
+ <require>
+ <enum value="0" name="VK_ARM_EXTENSION_418_SPEC_VERSION"/>
+ <enum value="&quot;VK_ARM_extension_418&quot;" name="VK_ARM_EXTENSION_418_EXTENSION_NAME"/>
+ </require>
+ </extension>
+ <extension name="VK_EXT_extension_419" number="419" author="EXT" contact="Mike Blumenkrantz @zmike" type="device" supported="disabled">
+ <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"/>
+ </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"/>
+ </require>
+ </extension>
+ <extension name="VK_KHR_extension_421" number="421" author="KHR" contact="Hans-Kristian Arntzen @HansKristian-Work" supported="disabled">
+ <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"/>
+ </require>
+ </extension>
+
+ </extensions>
+ <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 extension="VK_KHR_variable_pointers"/>
+ </spirvextension>
+ <spirvextension name="SPV_AMD_shader_explicit_vertex_parameter">
+ <enable extension="VK_AMD_shader_explicit_vertex_parameter"/>
+ </spirvextension>
+ <spirvextension name="SPV_AMD_gcn_shader">
+ <enable extension="VK_AMD_gcn_shader"/>
+ </spirvextension>
+ <spirvextension name="SPV_AMD_gpu_shader_half_float">
+ <enable extension="VK_AMD_gpu_shader_half_float"/>
+ </spirvextension>
+ <spirvextension name="SPV_AMD_gpu_shader_int16">
+ <enable extension="VK_AMD_gpu_shader_int16"/>
+ </spirvextension>
+ <spirvextension name="SPV_AMD_shader_ballot">
+ <enable extension="VK_AMD_shader_ballot"/>
+ </spirvextension>
+ <spirvextension name="SPV_AMD_shader_fragment_mask">
+ <enable extension="VK_AMD_shader_fragment_mask"/>
+ </spirvextension>
+ <spirvextension name="SPV_AMD_shader_image_load_store_lod">
+ <enable extension="VK_AMD_shader_image_load_store_lod"/>
+ </spirvextension>
+ <spirvextension name="SPV_AMD_shader_trinary_minmax">
+ <enable extension="VK_AMD_shader_trinary_minmax"/>
+ </spirvextension>
+ <spirvextension name="SPV_AMD_texture_gather_bias_lod">
+ <enable extension="VK_AMD_texture_gather_bias_lod"/>
+ </spirvextension>
+ <spirvextension name="SPV_KHR_shader_draw_parameters">
+ <enable version="VK_API_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 extension="VK_KHR_8bit_storage"/>
+ </spirvextension>
+ <spirvextension name="SPV_KHR_16bit_storage">
+ <enable version="VK_API_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 extension="VK_KHR_shader_float_controls"/>
+ </spirvextension>
+ <spirvextension name="SPV_KHR_storage_buffer_storage_class">
+ <enable version="VK_API_VERSION_1_1"/>
+ <enable extension="VK_KHR_storage_buffer_storage_class"/>
+ </spirvextension>
+ <spirvextension name="SPV_KHR_post_depth_coverage">
+ <enable extension="VK_EXT_post_depth_coverage"/>
+ </spirvextension>
+ <spirvextension name="SPV_EXT_shader_stencil_export">
+ <enable extension="VK_EXT_shader_stencil_export"/>
+ </spirvextension>
+ <spirvextension name="SPV_KHR_shader_ballot">
+ <enable extension="VK_EXT_shader_subgroup_ballot"/>
+ </spirvextension>
+ <spirvextension name="SPV_KHR_subgroup_vote">
+ <enable extension="VK_EXT_shader_subgroup_vote"/>
+ </spirvextension>
+ <spirvextension name="SPV_NV_sample_mask_override_coverage">
+ <enable extension="VK_NV_sample_mask_override_coverage"/>
+ </spirvextension>
+ <spirvextension name="SPV_NV_geometry_shader_passthrough">
+ <enable extension="VK_NV_geometry_shader_passthrough"/>
+ </spirvextension>
+ <spirvextension name="SPV_NV_mesh_shader">
+ <enable extension="VK_NV_mesh_shader"/>
+ </spirvextension>
+ <spirvextension name="SPV_NV_viewport_array2">
+ <enable extension="VK_NV_viewport_array2"/>
+ </spirvextension>
+ <spirvextension name="SPV_NV_shader_subgroup_partitioned">
+ <enable extension="VK_NV_shader_subgroup_partitioned"/>
+ </spirvextension>
+ <spirvextension name="SPV_EXT_shader_viewport_index_layer">
+ <enable version="VK_API_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 extension="VK_EXT_descriptor_indexing"/>
+ </spirvextension>
+ <spirvextension name="SPV_KHR_vulkan_memory_model">
+ <enable version="VK_API_VERSION_1_2"/>
+ <enable extension="VK_KHR_vulkan_memory_model"/>
+ </spirvextension>
+ <spirvextension name="SPV_NV_compute_shader_derivatives">
+ <enable extension="VK_NV_compute_shader_derivatives"/>
+ </spirvextension>
+ <spirvextension name="SPV_NV_fragment_shader_barycentric">
+ <enable extension="VK_NV_fragment_shader_barycentric"/>
+ </spirvextension>
+ <spirvextension name="SPV_NV_shader_image_footprint">
+ <enable extension="VK_NV_shader_image_footprint"/>
+ </spirvextension>
+ <spirvextension name="SPV_NV_shading_rate">
+ <enable extension="VK_NV_shading_rate_image"/>
+ </spirvextension>
+ <spirvextension name="SPV_NV_ray_tracing">
+ <enable extension="VK_NV_ray_tracing"/>
+ </spirvextension>
+ <spirvextension name="SPV_KHR_ray_tracing">
+ <enable extension="VK_KHR_ray_tracing_pipeline"/>
+ </spirvextension>
+ <spirvextension name="SPV_KHR_ray_query">
+ <enable extension="VK_KHR_ray_query"/>
+ </spirvextension>
+ <spirvextension name="SPV_GOOGLE_hlsl_functionality1">
+ <enable extension="VK_GOOGLE_hlsl_functionality1"/>
+ </spirvextension>
+ <spirvextension name="SPV_GOOGLE_user_type">
+ <enable extension="VK_GOOGLE_user_type"/>
+ </spirvextension>
+ <spirvextension name="SPV_GOOGLE_decorate_string">
+ <enable extension="VK_GOOGLE_decorate_string"/>
+ </spirvextension>
+ <spirvextension name="SPV_EXT_fragment_invocation_density">
+ <enable extension="VK_EXT_fragment_density_map"/>
+ </spirvextension>
+ <spirvextension name="SPV_KHR_physical_storage_buffer">
+ <enable version="VK_API_VERSION_1_2"/>
+ <enable extension="VK_KHR_buffer_device_address"/>
+ </spirvextension>
+ <spirvextension name="SPV_EXT_physical_storage_buffer">
+ <enable extension="VK_EXT_buffer_device_address"/>
+ </spirvextension>
+ <spirvextension name="SPV_NV_cooperative_matrix">
+ <enable extension="VK_NV_cooperative_matrix"/>
+ </spirvextension>
+ <spirvextension name="SPV_NV_shader_sm_builtins">
+ <enable extension="VK_NV_shader_sm_builtins"/>
+ </spirvextension>
+ <spirvextension name="SPV_EXT_fragment_shader_interlock">
+ <enable extension="VK_EXT_fragment_shader_interlock"/>
+ </spirvextension>
+ <spirvextension name="SPV_EXT_demote_to_helper_invocation">
+ <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 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 extension="VK_KHR_shader_terminate_invocation"/>
+ </spirvextension>
+ <spirvextension name="SPV_KHR_multiview">
+ <enable version="VK_API_VERSION_1_1"/>
+ <enable extension="VK_KHR_multiview"/>
+ </spirvextension>
+ <spirvextension name="SPV_KHR_workgroup_memory_explicit_layout">
+ <enable extension="VK_KHR_workgroup_memory_explicit_layout"/>
+ </spirvextension>
+ <spirvextension name="SPV_EXT_shader_atomic_float_add">
+ <enable extension="VK_EXT_shader_atomic_float"/>
+ </spirvextension>
+ <spirvextension name="SPV_KHR_subgroup_uniform_control_flow">
+ <enable extension="VK_KHR_shader_subgroup_uniform_control_flow"/>
+ </spirvextension>
+ <spirvextension name="SPV_EXT_shader_atomic_float_min_max">
+ <enable extension="VK_EXT_shader_atomic_float2"/>
+ </spirvextension>
+ <spirvextension name="SPV_EXT_shader_atomic_float16_add">
+ <enable extension="VK_EXT_shader_atomic_float2"/>
+ </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"/>
+ </spirvcapability>
+ <spirvcapability name="Shader">
+ <enable version="VK_API_VERSION_1_0"/>
+ </spirvcapability>
+ <spirvcapability name="InputAttachment">
+ <enable version="VK_API_VERSION_1_0"/>
+ </spirvcapability>
+ <spirvcapability name="Sampled1D">
+ <enable version="VK_API_VERSION_1_0"/>
+ </spirvcapability>
+ <spirvcapability name="Image1D">
+ <enable version="VK_API_VERSION_1_0"/>
+ </spirvcapability>
+ <spirvcapability name="SampledBuffer">
+ <enable version="VK_API_VERSION_1_0"/>
+ </spirvcapability>
+ <spirvcapability name="ImageBuffer">
+ <enable version="VK_API_VERSION_1_0"/>
+ </spirvcapability>
+ <spirvcapability name="ImageQuery">
+ <enable version="VK_API_VERSION_1_0"/>
+ </spirvcapability>
+ <spirvcapability name="DerivativeControl">
+ <enable version="VK_API_VERSION_1_0"/>
+ </spirvcapability>
+ <spirvcapability name="Geometry">
+ <enable struct="VkPhysicalDeviceFeatures" feature="geometryShader" requires="VK_VERSION_1_0"/>
+ </spirvcapability>
+ <spirvcapability name="Tessellation">
+ <enable struct="VkPhysicalDeviceFeatures" feature="tessellationShader" requires="VK_VERSION_1_0"/>
+ </spirvcapability>
+ <spirvcapability name="Float64">
+ <enable struct="VkPhysicalDeviceFeatures" feature="shaderFloat64" requires="VK_VERSION_1_0"/>
+ </spirvcapability>
+ <spirvcapability name="Int64">
+ <enable struct="VkPhysicalDeviceFeatures" feature="shaderInt64" requires="VK_VERSION_1_0"/>
+ </spirvcapability>
+ <spirvcapability name="Int64Atomics">
+ <enable struct="VkPhysicalDeviceVulkan12Features" feature="shaderBufferInt64Atomics" requires="VK_VERSION_1_2,VK_KHR_shader_atomic_int64"/>
+ <enable struct="VkPhysicalDeviceVulkan12Features" feature="shaderSharedInt64Atomics" requires="VK_VERSION_1_2,VK_KHR_shader_atomic_int64"/>
+ <enable struct="VkPhysicalDeviceShaderImageAtomicInt64FeaturesEXT" feature="shaderImageInt64Atomics" requires="VK_EXT_shader_image_atomic_int64"/>
+ </spirvcapability>
+ <spirvcapability name="AtomicFloat16AddEXT">
+ <enable struct="VkPhysicalDeviceShaderAtomicFloat2FeaturesEXT" feature="shaderBufferFloat16AtomicAdd" requires="VK_EXT_shader_atomic_float2"/>
+ <enable struct="VkPhysicalDeviceShaderAtomicFloat2FeaturesEXT" feature="shaderSharedFloat16AtomicAdd" requires="VK_EXT_shader_atomic_float2"/>
+ </spirvcapability>
+ <spirvcapability name="AtomicFloat32AddEXT">
+ <enable struct="VkPhysicalDeviceShaderAtomicFloatFeaturesEXT" feature="shaderBufferFloat32AtomicAdd" requires="VK_EXT_shader_atomic_float"/>
+ <enable struct="VkPhysicalDeviceShaderAtomicFloatFeaturesEXT" feature="shaderSharedFloat32AtomicAdd" requires="VK_EXT_shader_atomic_float"/>
+ <enable struct="VkPhysicalDeviceShaderAtomicFloatFeaturesEXT" feature="shaderImageFloat32AtomicAdd" requires="VK_EXT_shader_atomic_float"/>
+ </spirvcapability>
+ <spirvcapability name="AtomicFloat64AddEXT">
+ <enable struct="VkPhysicalDeviceShaderAtomicFloatFeaturesEXT" feature="shaderBufferFloat64AtomicAdd" requires="VK_EXT_shader_atomic_float"/>
+ <enable struct="VkPhysicalDeviceShaderAtomicFloatFeaturesEXT" feature="shaderSharedFloat64AtomicAdd" requires="VK_EXT_shader_atomic_float"/>
+ </spirvcapability>
+ <spirvcapability name="AtomicFloat16MinMaxEXT">
+ <enable struct="VkPhysicalDeviceShaderAtomicFloat2FeaturesEXT" feature="shaderBufferFloat16AtomicMinMax" requires="VK_EXT_shader_atomic_float2"/>
+ <enable struct="VkPhysicalDeviceShaderAtomicFloat2FeaturesEXT" feature="shaderSharedFloat16AtomicMinMax" requires="VK_EXT_shader_atomic_float2"/>
+ </spirvcapability>
+ <spirvcapability name="AtomicFloat32MinMaxEXT">
+ <enable struct="VkPhysicalDeviceShaderAtomicFloat2FeaturesEXT" feature="shaderBufferFloat32AtomicMinMax" requires="VK_EXT_shader_atomic_float2"/>
+ <enable struct="VkPhysicalDeviceShaderAtomicFloat2FeaturesEXT" feature="shaderSharedFloat32AtomicMinMax" requires="VK_EXT_shader_atomic_float2"/>
+ <enable struct="VkPhysicalDeviceShaderAtomicFloat2FeaturesEXT" feature="shaderImageFloat32AtomicMinMax" requires="VK_EXT_shader_atomic_float2"/>
+ </spirvcapability>
+ <spirvcapability name="AtomicFloat64MinMaxEXT">
+ <enable struct="VkPhysicalDeviceShaderAtomicFloat2FeaturesEXT" feature="shaderBufferFloat64AtomicMinMax" requires="VK_EXT_shader_atomic_float2"/>
+ <enable struct="VkPhysicalDeviceShaderAtomicFloat2FeaturesEXT" feature="shaderSharedFloat64AtomicMinMax" requires="VK_EXT_shader_atomic_float2"/>
+ </spirvcapability>
+ <spirvcapability name="Int64ImageEXT">
+ <enable struct="VkPhysicalDeviceShaderImageAtomicInt64FeaturesEXT" feature="shaderImageInt64Atomics" requires="VK_EXT_shader_image_atomic_int64"/>
+ </spirvcapability>
+ <spirvcapability name="Int16">
+ <enable struct="VkPhysicalDeviceFeatures" feature="shaderInt16" requires="VK_VERSION_1_0"/>
+ </spirvcapability>
+ <spirvcapability name="TessellationPointSize">
+ <enable struct="VkPhysicalDeviceFeatures" feature="shaderTessellationAndGeometryPointSize" requires="VK_VERSION_1_0"/>
+ </spirvcapability>
+ <spirvcapability name="GeometryPointSize">
+ <enable struct="VkPhysicalDeviceFeatures" feature="shaderTessellationAndGeometryPointSize" requires="VK_VERSION_1_0"/>
+ </spirvcapability>
+ <spirvcapability name="ImageGatherExtended">
+ <enable struct="VkPhysicalDeviceFeatures" feature="shaderImageGatherExtended" requires="VK_VERSION_1_0"/>
+ </spirvcapability>
+ <spirvcapability name="StorageImageMultisample">
+ <enable struct="VkPhysicalDeviceFeatures" feature="shaderStorageImageMultisample" requires="VK_VERSION_1_0"/>
+ </spirvcapability>
+ <spirvcapability name="UniformBufferArrayDynamicIndexing">
+ <enable struct="VkPhysicalDeviceFeatures" feature="shaderUniformBufferArrayDynamicIndexing" requires="VK_VERSION_1_0"/>
+ </spirvcapability>
+ <spirvcapability name="SampledImageArrayDynamicIndexing">
+ <enable struct="VkPhysicalDeviceFeatures" feature="shaderSampledImageArrayDynamicIndexing" requires="VK_VERSION_1_0"/>
+ </spirvcapability>
+ <spirvcapability name="StorageBufferArrayDynamicIndexing">
+ <enable struct="VkPhysicalDeviceFeatures" feature="shaderStorageBufferArrayDynamicIndexing" requires="VK_VERSION_1_0"/>
+ </spirvcapability>
+ <spirvcapability name="StorageImageArrayDynamicIndexing">
+ <enable struct="VkPhysicalDeviceFeatures" feature="shaderStorageImageArrayDynamicIndexing" requires="VK_VERSION_1_0"/>
+ </spirvcapability>
+ <spirvcapability name="ClipDistance">
+ <enable struct="VkPhysicalDeviceFeatures" feature="shaderClipDistance" requires="VK_VERSION_1_0"/>
+ </spirvcapability>
+ <spirvcapability name="CullDistance">
+ <enable struct="VkPhysicalDeviceFeatures" feature="shaderCullDistance" requires="VK_VERSION_1_0"/>
+ </spirvcapability>
+ <spirvcapability name="ImageCubeArray">
+ <enable struct="VkPhysicalDeviceFeatures" feature="imageCubeArray" requires="VK_VERSION_1_0"/>
+ </spirvcapability>
+ <spirvcapability name="SampleRateShading">
+ <enable struct="VkPhysicalDeviceFeatures" feature="sampleRateShading" requires="VK_VERSION_1_0"/>
+ </spirvcapability>
+ <spirvcapability name="SparseResidency">
+ <enable struct="VkPhysicalDeviceFeatures" feature="shaderResourceResidency" requires="VK_VERSION_1_0"/>
+ </spirvcapability>
+ <spirvcapability name="MinLod">
+ <enable struct="VkPhysicalDeviceFeatures" feature="shaderResourceMinLod" requires="VK_VERSION_1_0"/>
+ </spirvcapability>
+ <spirvcapability name="SampledCubeArray">
+ <enable struct="VkPhysicalDeviceFeatures" feature="imageCubeArray" requires="VK_VERSION_1_0"/>
+ </spirvcapability>
+ <spirvcapability name="ImageMSArray">
+ <enable struct="VkPhysicalDeviceFeatures" feature="shaderStorageImageMultisample" requires="VK_VERSION_1_0"/>
+ </spirvcapability>
+ <spirvcapability name="StorageImageExtendedFormats">
+ <enable version="VK_API_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"/>
+ </spirvcapability>
+ <spirvcapability name="StorageImageWriteWithoutFormat">
+ <enable struct="VkPhysicalDeviceFeatures" feature="shaderStorageImageWriteWithoutFormat" requires="VK_VERSION_1_0"/>
+ </spirvcapability>
+ <spirvcapability name="MultiViewport">
+ <enable struct="VkPhysicalDeviceFeatures" feature="multiViewport" requires="VK_VERSION_1_0"/>
+ </spirvcapability>
+ <spirvcapability name="DrawParameters">
+ <enable struct="VkPhysicalDeviceVulkan11Features" feature="shaderDrawParameters" requires="VK_VERSION_1_2"/>
+ <enable struct="VkPhysicalDeviceShaderDrawParametersFeatures" feature="shaderDrawParameters" requires="VK_VERSION_1_1"/>
+ <enable extension="VK_KHR_shader_draw_parameters"/>
+ </spirvcapability>
+ <spirvcapability name="MultiView">
+ <enable struct="VkPhysicalDeviceVulkan11Features" feature="multiview" requires="VK_VERSION_1_2"/>
+ <enable struct="VkPhysicalDeviceMultiviewFeatures" feature="multiview" requires="VK_KHR_multiview"/>
+ </spirvcapability>
+ <spirvcapability name="DeviceGroup">
+ <enable version="VK_API_VERSION_1_1"/>
+ <enable extension="VK_KHR_device_group"/>
+ </spirvcapability>
+ <spirvcapability name="VariablePointersStorageBuffer">
+ <enable struct="VkPhysicalDeviceVulkan11Features" feature="variablePointersStorageBuffer" requires="VK_VERSION_1_2"/>
+ <enable struct="VkPhysicalDeviceVariablePointersFeatures" feature="variablePointersStorageBuffer" requires="VK_KHR_variable_pointers"/>
+ </spirvcapability>
+ <spirvcapability name="VariablePointers">
+ <enable struct="VkPhysicalDeviceVulkan11Features" feature="variablePointers" requires="VK_VERSION_1_2"/>
+ <enable struct="VkPhysicalDeviceVariablePointersFeatures" feature="variablePointers" requires="VK_KHR_variable_pointers"/>
+ </spirvcapability>
+ <spirvcapability name="ShaderClockKHR">
+ <enable extension="VK_KHR_shader_clock"/>
+ </spirvcapability>
+ <spirvcapability name="StencilExportEXT">
+ <enable extension="VK_EXT_shader_stencil_export"/>
+ </spirvcapability>
+ <spirvcapability name="SubgroupBallotKHR">
+ <enable extension="VK_EXT_shader_subgroup_ballot"/>
+ </spirvcapability>
+ <spirvcapability name="SubgroupVoteKHR">
+ <enable extension="VK_EXT_shader_subgroup_vote"/>
+ </spirvcapability>
+ <spirvcapability name="ImageReadWriteLodAMD">
+ <enable extension="VK_AMD_shader_image_load_store_lod"/>
+ </spirvcapability>
+ <spirvcapability name="ImageGatherBiasLodAMD">
+ <enable extension="VK_AMD_texture_gather_bias_lod"/>
+ </spirvcapability>
+ <spirvcapability name="FragmentMaskAMD">
+ <enable extension="VK_AMD_shader_fragment_mask"/>
+ </spirvcapability>
+ <spirvcapability name="SampleMaskOverrideCoverageNV">
+ <enable extension="VK_NV_sample_mask_override_coverage"/>
+ </spirvcapability>
+ <spirvcapability name="GeometryShaderPassthroughNV">
+ <enable extension="VK_NV_geometry_shader_passthrough"/>
+ </spirvcapability>
+ <spirvcapability name="ShaderViewportIndex">
+ <enable struct="VkPhysicalDeviceVulkan12Features" feature="shaderOutputViewportIndex" requires="VK_VERSION_1_2"/>
+ </spirvcapability>
+ <spirvcapability name="ShaderLayer">
+ <enable struct="VkPhysicalDeviceVulkan12Features" feature="shaderOutputLayer" requires="VK_VERSION_1_2"/>
+ </spirvcapability>
+ <spirvcapability name="ShaderViewportIndexLayerEXT">
+ <enable extension="VK_EXT_shader_viewport_index_layer"/>
+ </spirvcapability>
+ <spirvcapability name="ShaderViewportIndexLayerNV">
+ <enable extension="VK_NV_viewport_array2"/>
+ </spirvcapability>
+ <spirvcapability name="ShaderViewportMaskNV">
+ <enable extension="VK_NV_viewport_array2"/>
+ </spirvcapability>
+ <spirvcapability name="PerViewAttributesNV">
+ <enable extension="VK_NVX_multiview_per_view_attributes"/>
+ </spirvcapability>
+ <spirvcapability name="StorageBuffer16BitAccess">
+ <enable struct="VkPhysicalDeviceVulkan11Features" feature="storageBuffer16BitAccess" requires="VK_VERSION_1_2"/>
+ <enable struct="VkPhysicalDevice16BitStorageFeatures" feature="storageBuffer16BitAccess" requires="VK_KHR_16bit_storage"/>
+ </spirvcapability>
+ <spirvcapability name="UniformAndStorageBuffer16BitAccess">
+ <enable struct="VkPhysicalDeviceVulkan11Features" feature="uniformAndStorageBuffer16BitAccess" requires="VK_VERSION_1_2"/>
+ <enable struct="VkPhysicalDevice16BitStorageFeatures" feature="uniformAndStorageBuffer16BitAccess" requires="VK_KHR_16bit_storage"/>
+ </spirvcapability>
+ <spirvcapability name="StoragePushConstant16">
+ <enable struct="VkPhysicalDeviceVulkan11Features" feature="storagePushConstant16" requires="VK_VERSION_1_2"/>
+ <enable struct="VkPhysicalDevice16BitStorageFeatures" feature="storagePushConstant16" requires="VK_KHR_16bit_storage"/>
+ </spirvcapability>
+ <spirvcapability name="StorageInputOutput16">
+ <enable struct="VkPhysicalDeviceVulkan11Features" feature="storageInputOutput16" requires="VK_VERSION_1_2"/>
+ <enable struct="VkPhysicalDevice16BitStorageFeatures" feature="storageInputOutput16" requires="VK_KHR_16bit_storage"/>
+ </spirvcapability>
+ <spirvcapability name="GroupNonUniform">
+ <enable property="VkPhysicalDeviceVulkan11Properties" member="subgroupSupportedOperations" value="VK_SUBGROUP_FEATURE_BASIC_BIT" requires="VK_VERSION_1_1"/>
+ </spirvcapability>
+ <spirvcapability name="GroupNonUniformVote">
+ <enable property="VkPhysicalDeviceVulkan11Properties" member="subgroupSupportedOperations" value="VK_SUBGROUP_FEATURE_VOTE_BIT" requires="VK_VERSION_1_1"/>
+ </spirvcapability>
+ <spirvcapability name="GroupNonUniformArithmetic">
+ <enable property="VkPhysicalDeviceVulkan11Properties" member="subgroupSupportedOperations" value="VK_SUBGROUP_FEATURE_ARITHMETIC_BIT" requires="VK_VERSION_1_1"/>
+ </spirvcapability>
+ <spirvcapability name="GroupNonUniformBallot">
+ <enable property="VkPhysicalDeviceVulkan11Properties" member="subgroupSupportedOperations" value="VK_SUBGROUP_FEATURE_BALLOT_BIT" requires="VK_VERSION_1_1"/>
+ </spirvcapability>
+ <spirvcapability name="GroupNonUniformShuffle">
+ <enable property="VkPhysicalDeviceVulkan11Properties" member="subgroupSupportedOperations" value="VK_SUBGROUP_FEATURE_SHUFFLE_BIT" requires="VK_VERSION_1_1"/>
+ </spirvcapability>
+ <spirvcapability name="GroupNonUniformShuffleRelative">
+ <enable property="VkPhysicalDeviceVulkan11Properties" member="subgroupSupportedOperations" value="VK_SUBGROUP_FEATURE_SHUFFLE_RELATIVE_BIT" requires="VK_VERSION_1_1"/>
+ </spirvcapability>
+ <spirvcapability name="GroupNonUniformClustered">
+ <enable property="VkPhysicalDeviceVulkan11Properties" member="subgroupSupportedOperations" value="VK_SUBGROUP_FEATURE_CLUSTERED_BIT" requires="VK_VERSION_1_1"/>
+ </spirvcapability>
+ <spirvcapability name="GroupNonUniformQuad">
+ <enable property="VkPhysicalDeviceVulkan11Properties" member="subgroupSupportedOperations" value="VK_SUBGROUP_FEATURE_QUAD_BIT" requires="VK_VERSION_1_1"/>
+ </spirvcapability>
+ <spirvcapability name="GroupNonUniformPartitionedNV">
+ <enable property="VkPhysicalDeviceVulkan11Properties" member="subgroupSupportedOperations" value="VK_SUBGROUP_FEATURE_PARTITIONED_BIT_NV" requires="VK_NV_shader_subgroup_partitioned"/>
+ </spirvcapability>
+ <spirvcapability name="SampleMaskPostDepthCoverage">
+ <enable extension="VK_EXT_post_depth_coverage"/>
+ </spirvcapability>
+ <spirvcapability name="ShaderNonUniform">
+ <enable version="VK_API_VERSION_1_2"/>
+ <enable extension="VK_EXT_descriptor_indexing"/>
+ </spirvcapability>
+ <spirvcapability name="RuntimeDescriptorArray">
+ <enable struct="VkPhysicalDeviceVulkan12Features" feature="runtimeDescriptorArray" requires="VK_VERSION_1_2,VK_EXT_descriptor_indexing"/>
+ </spirvcapability>
+ <spirvcapability name="InputAttachmentArrayDynamicIndexing">
+ <enable struct="VkPhysicalDeviceVulkan12Features" feature="shaderInputAttachmentArrayDynamicIndexing" requires="VK_VERSION_1_2,VK_EXT_descriptor_indexing"/>
+ </spirvcapability>
+ <spirvcapability name="UniformTexelBufferArrayDynamicIndexing">
+ <enable struct="VkPhysicalDeviceVulkan12Features" feature="shaderUniformTexelBufferArrayDynamicIndexing" requires="VK_VERSION_1_2,VK_EXT_descriptor_indexing"/>
+ </spirvcapability>
+ <spirvcapability name="StorageTexelBufferArrayDynamicIndexing">
+ <enable struct="VkPhysicalDeviceVulkan12Features" feature="shaderStorageTexelBufferArrayDynamicIndexing" requires="VK_VERSION_1_2,VK_EXT_descriptor_indexing"/>
+ </spirvcapability>
+ <spirvcapability name="UniformBufferArrayNonUniformIndexing">
+ <enable struct="VkPhysicalDeviceVulkan12Features" feature="shaderUniformBufferArrayNonUniformIndexing" requires="VK_VERSION_1_2,VK_EXT_descriptor_indexing"/>
+ </spirvcapability>
+ <spirvcapability name="SampledImageArrayNonUniformIndexing">
+ <enable struct="VkPhysicalDeviceVulkan12Features" feature="shaderSampledImageArrayNonUniformIndexing" requires="VK_VERSION_1_2,VK_EXT_descriptor_indexing"/>
+ </spirvcapability>
+ <spirvcapability name="StorageBufferArrayNonUniformIndexing">
+ <enable struct="VkPhysicalDeviceVulkan12Features" feature="shaderStorageBufferArrayNonUniformIndexing" requires="VK_VERSION_1_2,VK_EXT_descriptor_indexing"/>
+ </spirvcapability>
+ <spirvcapability name="StorageImageArrayNonUniformIndexing">
+ <enable struct="VkPhysicalDeviceVulkan12Features" feature="shaderStorageImageArrayNonUniformIndexing" requires="VK_VERSION_1_2,VK_EXT_descriptor_indexing"/>
+ </spirvcapability>
+ <spirvcapability name="InputAttachmentArrayNonUniformIndexing">
+ <enable struct="VkPhysicalDeviceVulkan12Features" feature="shaderInputAttachmentArrayNonUniformIndexing" requires="VK_VERSION_1_2,VK_EXT_descriptor_indexing"/>
+ </spirvcapability>
+ <spirvcapability name="UniformTexelBufferArrayNonUniformIndexing">
+ <enable struct="VkPhysicalDeviceVulkan12Features" feature="shaderUniformTexelBufferArrayNonUniformIndexing" requires="VK_VERSION_1_2,VK_EXT_descriptor_indexing"/>
+ </spirvcapability>
+ <spirvcapability name="StorageTexelBufferArrayNonUniformIndexing">
+ <enable struct="VkPhysicalDeviceVulkan12Features" feature="shaderStorageTexelBufferArrayNonUniformIndexing" requires="VK_VERSION_1_2,VK_EXT_descriptor_indexing"/>
+ </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"/>
+ </spirvcapability>
+ <spirvcapability name="Int8">
+ <enable struct="VkPhysicalDeviceVulkan12Features" feature="shaderInt8" requires="VK_VERSION_1_2,VK_KHR_shader_float16_int8"/>
+ </spirvcapability>
+ <spirvcapability name="StorageBuffer8BitAccess">
+ <enable struct="VkPhysicalDeviceVulkan12Features" feature="storageBuffer8BitAccess" requires="VK_VERSION_1_2,VK_KHR_8bit_storage"/>
+ </spirvcapability>
+ <spirvcapability name="UniformAndStorageBuffer8BitAccess">
+ <enable struct="VkPhysicalDeviceVulkan12Features" feature="uniformAndStorageBuffer8BitAccess" requires="VK_VERSION_1_2,VK_KHR_8bit_storage"/>
+ </spirvcapability>
+ <spirvcapability name="StoragePushConstant8">
+ <enable struct="VkPhysicalDeviceVulkan12Features" feature="storagePushConstant8" requires="VK_VERSION_1_2,VK_KHR_8bit_storage"/>
+ </spirvcapability>
+ <spirvcapability name="VulkanMemoryModel">
+ <enable struct="VkPhysicalDeviceVulkan12Features" feature="vulkanMemoryModel" requires="VK_VERSION_1_2,VK_KHR_vulkan_memory_model"/>
+ </spirvcapability>
+ <spirvcapability name="VulkanMemoryModelDeviceScope">
+ <enable struct="VkPhysicalDeviceVulkan12Features" feature="vulkanMemoryModelDeviceScope" requires="VK_VERSION_1_2,VK_KHR_vulkan_memory_model"/>
+ </spirvcapability>
+ <spirvcapability name="DenormPreserve">
+ <enable property="VkPhysicalDeviceVulkan12Properties" member="shaderDenormPreserveFloat16" value="VK_TRUE" requires="VK_VERSION_1_2,VK_KHR_shader_float_controls"/>
+ <enable property="VkPhysicalDeviceVulkan12Properties" member="shaderDenormPreserveFloat32" value="VK_TRUE" requires="VK_VERSION_1_2,VK_KHR_shader_float_controls"/>
+ <enable property="VkPhysicalDeviceVulkan12Properties" member="shaderDenormPreserveFloat64" value="VK_TRUE" requires="VK_VERSION_1_2,VK_KHR_shader_float_controls"/>
+ </spirvcapability>
+ <spirvcapability name="DenormFlushToZero">
+ <enable property="VkPhysicalDeviceVulkan12Properties" member="shaderDenormFlushToZeroFloat16" value="VK_TRUE" requires="VK_VERSION_1_2,VK_KHR_shader_float_controls"/>
+ <enable property="VkPhysicalDeviceVulkan12Properties" member="shaderDenormFlushToZeroFloat32" value="VK_TRUE" requires="VK_VERSION_1_2,VK_KHR_shader_float_controls"/>
+ <enable property="VkPhysicalDeviceVulkan12Properties" member="shaderDenormFlushToZeroFloat64" value="VK_TRUE" requires="VK_VERSION_1_2,VK_KHR_shader_float_controls"/>
+ </spirvcapability>
+ <spirvcapability name="SignedZeroInfNanPreserve">
+ <enable property="VkPhysicalDeviceVulkan12Properties" member="shaderSignedZeroInfNanPreserveFloat16" value="VK_TRUE" requires="VK_VERSION_1_2,VK_KHR_shader_float_controls"/>
+ <enable property="VkPhysicalDeviceVulkan12Properties" member="shaderSignedZeroInfNanPreserveFloat32" value="VK_TRUE" requires="VK_VERSION_1_2,VK_KHR_shader_float_controls"/>
+ <enable property="VkPhysicalDeviceVulkan12Properties" member="shaderSignedZeroInfNanPreserveFloat64" value="VK_TRUE" requires="VK_VERSION_1_2,VK_KHR_shader_float_controls"/>
+ </spirvcapability>
+ <spirvcapability name="RoundingModeRTE">
+ <enable property="VkPhysicalDeviceVulkan12Properties" member="shaderRoundingModeRTEFloat16" value="VK_TRUE" requires="VK_VERSION_1_2,VK_KHR_shader_float_controls"/>
+ <enable property="VkPhysicalDeviceVulkan12Properties" member="shaderRoundingModeRTEFloat32" value="VK_TRUE" requires="VK_VERSION_1_2,VK_KHR_shader_float_controls"/>
+ <enable property="VkPhysicalDeviceVulkan12Properties" member="shaderRoundingModeRTEFloat64" value="VK_TRUE" requires="VK_VERSION_1_2,VK_KHR_shader_float_controls"/>
+ </spirvcapability>
+ <spirvcapability name="RoundingModeRTZ">
+ <enable property="VkPhysicalDeviceVulkan12Properties" member="shaderRoundingModeRTZFloat16" value="VK_TRUE" requires="VK_VERSION_1_2,VK_KHR_shader_float_controls"/>
+ <enable property="VkPhysicalDeviceVulkan12Properties" member="shaderRoundingModeRTZFloat32" value="VK_TRUE" requires="VK_VERSION_1_2,VK_KHR_shader_float_controls"/>
+ <enable property="VkPhysicalDeviceVulkan12Properties" member="shaderRoundingModeRTZFloat64" value="VK_TRUE" requires="VK_VERSION_1_2,VK_KHR_shader_float_controls"/>
+ </spirvcapability>
+ <spirvcapability name="ComputeDerivativeGroupQuadsNV">
+ <enable struct="VkPhysicalDeviceComputeShaderDerivativesFeaturesNV" feature="computeDerivativeGroupQuads" requires="VK_NV_compute_shader_derivatives"/>
+ </spirvcapability>
+ <spirvcapability name="ComputeDerivativeGroupLinearNV">
+ <enable struct="VkPhysicalDeviceComputeShaderDerivativesFeaturesNV" feature="computeDerivativeGroupLinear" requires="VK_NV_compute_shader_derivatives"/>
+ </spirvcapability>
+ <spirvcapability name="FragmentBarycentricNV">
+ <enable struct="VkPhysicalDeviceFragmentShaderBarycentricFeaturesNV" feature="fragmentShaderBarycentric" requires="VK_NV_fragment_shader_barycentric"/>
+ </spirvcapability>
+ <spirvcapability name="ImageFootprintNV">
+ <enable struct="VkPhysicalDeviceShaderImageFootprintFeaturesNV" feature="imageFootprint" requires="VK_NV_shader_image_footprint"/>
+ </spirvcapability>
+ <spirvcapability name="ShadingRateNV">
+ <enable struct="VkPhysicalDeviceShadingRateImageFeaturesNV" feature="shadingRateImage" requires="VK_NV_shading_rate_image"/>
+ </spirvcapability>
+ <spirvcapability name="MeshShadingNV">
+ <enable extension="VK_NV_mesh_shader"/>
+ </spirvcapability>
+ <spirvcapability name="RayTracingKHR">
+ <enable struct="VkPhysicalDeviceRayTracingPipelineFeaturesKHR" feature="rayTracingPipeline" requires="VK_KHR_ray_tracing_pipeline"/>
+ </spirvcapability>
+ <spirvcapability name="RayQueryKHR">
+ <enable struct="VkPhysicalDeviceRayQueryFeaturesKHR" feature="rayQuery" requires="VK_KHR_ray_query"/>
+ </spirvcapability>
+ <spirvcapability name="RayTraversalPrimitiveCullingKHR">
+ <enable struct="VkPhysicalDeviceRayTracingPipelineFeaturesKHR" feature="rayTraversalPrimitiveCulling" requires="VK_KHR_ray_tracing_pipeline"/>
+ </spirvcapability>
+ <spirvcapability name="RayTracingNV">
+ <enable extension="VK_NV_ray_tracing"/>
+ </spirvcapability>
+ <spirvcapability name="RayTracingMotionBlurNV">
+ <enable struct="VkPhysicalDeviceRayTracingMotionBlurFeaturesNV" feature="rayTracingMotionBlur" requires="VK_NV_ray_tracing_motion_blur"/>
+ </spirvcapability>
+ <spirvcapability name="TransformFeedback">
+ <enable struct="VkPhysicalDeviceTransformFeedbackFeaturesEXT" feature="transformFeedback" requires="VK_EXT_transform_feedback"/>
+ </spirvcapability>
+ <spirvcapability name="GeometryStreams">
+ <enable struct="VkPhysicalDeviceTransformFeedbackFeaturesEXT" feature="geometryStreams" requires="VK_EXT_transform_feedback"/>
+ </spirvcapability>
+ <spirvcapability name="FragmentDensityEXT">
+ <enable struct="VkPhysicalDeviceFragmentDensityMapFeaturesEXT" feature="fragmentDensityMap" requires="VK_EXT_fragment_density_map"/>
+ </spirvcapability>
+ <spirvcapability name="PhysicalStorageBufferAddresses">
+ <enable struct="VkPhysicalDeviceVulkan12Features" feature="bufferDeviceAddress" requires="VK_VERSION_1_2,VK_KHR_buffer_device_address"/>
+ <enable struct="VkPhysicalDeviceBufferDeviceAddressFeaturesEXT" feature="bufferDeviceAddress" requires="VK_EXT_buffer_device_address" alias="bufferDeviceAddressEXT"/>
+ </spirvcapability>
+ <spirvcapability name="CooperativeMatrixNV">
+ <enable struct="VkPhysicalDeviceCooperativeMatrixFeaturesNV" feature="cooperativeMatrix" requires="VK_NV_cooperative_matrix"/>
+ </spirvcapability>
+ <spirvcapability name="IntegerFunctions2INTEL">
+ <enable struct="VkPhysicalDeviceShaderIntegerFunctions2FeaturesINTEL" feature="shaderIntegerFunctions2" requires="VK_INTEL_shader_integer_functions2"/>
+ </spirvcapability>
+ <spirvcapability name="ShaderSMBuiltinsNV">
+ <enable struct="VkPhysicalDeviceShaderSMBuiltinsFeaturesNV" feature="shaderSMBuiltins" requires="VK_NV_shader_sm_builtins"/>
+ </spirvcapability>
+ <spirvcapability name="FragmentShaderSampleInterlockEXT">
+ <enable struct="VkPhysicalDeviceFragmentShaderInterlockFeaturesEXT" feature="fragmentShaderSampleInterlock" requires="VK_EXT_fragment_shader_interlock"/>
+ </spirvcapability>
+ <spirvcapability name="FragmentShaderPixelInterlockEXT">
+ <enable struct="VkPhysicalDeviceFragmentShaderInterlockFeaturesEXT" feature="fragmentShaderPixelInterlock" requires="VK_EXT_fragment_shader_interlock"/>
+ </spirvcapability>
+ <spirvcapability name="FragmentShaderShadingRateInterlockEXT">
+ <enable struct="VkPhysicalDeviceFragmentShaderInterlockFeaturesEXT" feature="fragmentShaderShadingRateInterlock" requires="VK_EXT_fragment_shader_interlock"/>
+ <enable struct="VkPhysicalDeviceShadingRateImageFeaturesNV" feature="shadingRateImage" requires="VK_NV_shading_rate_image"/>
+ </spirvcapability>
+ <spirvcapability name="DemoteToHelperInvocationEXT">
+ <enable struct="VkPhysicalDeviceShaderDemoteToHelperInvocationFeaturesEXT" feature="shaderDemoteToHelperInvocation" requires="VK_EXT_shader_demote_to_helper_invocation"/>
+ </spirvcapability>
+ <spirvcapability name="FragmentShadingRateKHR">
+ <enable struct="VkPhysicalDeviceFragmentShadingRateFeaturesKHR" feature="pipelineFragmentShadingRate" requires="VK_KHR_fragment_shading_rate"/>
+ <enable struct="VkPhysicalDeviceFragmentShadingRateFeaturesKHR" feature="primitiveFragmentShadingRate" requires="VK_KHR_fragment_shading_rate"/>
+ <enable struct="VkPhysicalDeviceFragmentShadingRateFeaturesKHR" feature="attachmentFragmentShadingRate" requires="VK_KHR_fragment_shading_rate"/>
+ </spirvcapability>
+ <spirvcapability name="WorkgroupMemoryExplicitLayoutKHR">
+ <enable struct="VkPhysicalDeviceWorkgroupMemoryExplicitLayoutFeaturesKHR" feature="workgroupMemoryExplicitLayout" requires="VK_KHR_workgroup_memory_explicit_layout"/>
+ </spirvcapability>
+ <spirvcapability name="WorkgroupMemoryExplicitLayout8BitAccessKHR">
+ <enable struct="VkPhysicalDeviceWorkgroupMemoryExplicitLayoutFeaturesKHR" feature="workgroupMemoryExplicitLayout8BitAccess" requires="VK_KHR_workgroup_memory_explicit_layout"/>
+ </spirvcapability>
+ <spirvcapability name="WorkgroupMemoryExplicitLayout16BitAccessKHR">
+ <enable struct="VkPhysicalDeviceWorkgroupMemoryExplicitLayoutFeaturesKHR" feature="workgroupMemoryExplicitLayout16BitAccess" requires="VK_KHR_workgroup_memory_explicit_layout"/>
+ </spirvcapability>
+ </spirvcapabilities>
+</registry>