Shared Handles (#1619)
authorIlya Doroshenko <agrael@live.ru>
Tue, 19 Sep 2023 11:04:36 +0000 (13:04 +0200)
committerGitHub <noreply@github.com>
Tue, 19 Sep 2023 11:04:36 +0000 (13:04 +0200)
* stage 1: added shared handles and all traits

* moved deleter to the shared part, now Shared handle weights 2 pointers

* Fixed Destroy Function

* generated headers

* At least no errors.

TODO: get image overload of shared handle back
make an example

* fixed all SFINAE issues, moved image specialization

* Added a sample

* made better example, added specialization for swapchain, added shared handles to readme

* Major update:
Fixed all wishes
Made std::shared_ptr do heavy lifting
Reduced code complexity
Added ParentType to basic handles
Added put and put_native for cross-abi usage

* more readme

* safer release()
removed put() for now

* better synchronization
inspired by STL shared_ptr implementation

* removed test shared pointer

* added forward type for better interop with VMA
added parent checking

* fixed getParent()

* added non-deleting overloads for Queue, DisplayKHR and PhysicalDevice

* Shared non-destoyed type now have handles

* using constructors are made to comply standard

* fixed leak

* shared handles migrated to own header,
made module entries

* header is independent now

* rebased repo, updated the example

* fixed most of the stuff

* renamed parent of, added guide to make shared handles

* vulkansc

* moved destructor to shared handle traits

* resolved issues with CI

* more relaxed memory ordering for release operation

* trying to remove submodule

* renamed to destructorType

* suppressed function cast warning

* only GCC should be affected

15 files changed:
README.md
VulkanHppGenerator.cpp
VulkanHppGenerator.hpp
samples/CMakeLists.txt
samples/SharedHandles/CMakeLists.txt [new file with mode: 0644]
samples/SharedHandles/SharedHandles.cpp [new file with mode: 0644]
snippets/SharedDestroy.hpp [new file with mode: 0644]
snippets/SharedHandle.hpp [new file with mode: 0644]
snippets/SharedHandleSpecializations.hpp [new file with mode: 0644]
vulkan/vulkan.cppm
vulkan/vulkan.hpp
vulkan/vulkan_shared.hpp [new file with mode: 0644]
vulkan/vulkansc.cppm
vulkan/vulkansc.hpp
vulkan/vulkansc_shared.hpp [new file with mode: 0644]

index 4f1fc88..56ece40 100644 (file)
--- a/README.md
+++ b/README.md
@@ -436,6 +436,70 @@ For each function which constructs a Vulkan handle of type `vk::Type` Vulkan-Hpp
 \r
 Note that using `vk::UniqueHandle` comes at a cost since most deleters have to store the `vk::AllocationCallbacks` and parent handle used for construction because they are required for automatic destruction.\r
 \r
+### SharedHandle \r
+\r
+Vulkan-Hpp provides a `vk::SharedHandle<Type>` interface. For each Vulkan handle type `vk::Type` there is a shared handle `vk::SharedType` which will delete the underlying Vulkan resource upon destruction, e.g. `vk::SharedBuffer` is the shared handle for `vk::Buffer`.\r
+\r
+Unlike UniqueHandle, SharedHandle takes shared ownership of the resource as well as its parent. This means that parent handle will not be destroyed until all child resources are deleted. This is useful for resources that are shared between multiple threads or objects.\r
+\r
+This mechanism ensures correct destruction order even if the parent SharedHandle is destroyed before its child handle. Otherwise, the handle behaves like `std::shared_ptr`. `vk::SharedInstance` or any of its child object should be last to delete (first created, first in class declaration)\r
+\r
+There are no functions which return a `vk::SharedHandle` directly yet. Instead, you can construct a `vk::SharedHandle` from a `vk::Handle`:\r
+\r
+```c++\r
+\r
+vk::Buffer buffer = device.createBuffer(...);\r
+vk::SharedBuffer sharedBuffer(buffer, device); // sharedBuffer now owns the buffer\r
+```\r
+\r
+There are several specializations of `vk::SharedHandle` for different handle types. For example, `vk::SharedImage` may take an additional argument to specify if the image is owned by swapchain:\r
+\r
+```c++\r
+vk::Image image = swapchain.getImages(...)[0]; // get the first image from the swapchain\r
+vk::SharedImage sharedImage(image, device, SwapChainOwns::yes); // sharedImage now owns the image, but won't destroy it\r
+```\r
+\r
+There is also a specialization for `vk::SwapchainKHR` which takes an additional argument to specify a surface:\r
+\r
+```c++\r
+vk::SwapchainKHR swapchain = device.createSwapchainKHR(...);\r
+vk::SharedSwapchainKHR sharedSwapchain(swapchain, device, surface); // sharedSwapchain now owns the swapchain and surface\r
+```\r
+\r
+You can create a `vk::SharedHandle` overload for your own handle type or own shared handles by providing several template arguments to SharedHandleBase:\r
+ - A handle type\r
+ - A parent handle type or a header structure, that contains parent\r
+ - A class itself for CRTP\r
+\r
+With this, provide a custom static destruction function `internalDestroy`, that takes in a parent handle and a handle to destroy. Don't forget to add a friend declaration for the base class.\r
+\r
+```c++\r
+// Example of a custom shared device, that takes in an instance as a parent\r
+class shared_handle<VkDevice> : public vk::SharedHandleBase<VkDevice, vk::SharedInstance, shared_handle<VkDevice>>\r
+{\r
+    using base = vk::SharedHandleBase<VkDevice, vk::SharedInstance, shared_handle<VkDevice>>;\r
+    friend base;\r
+\r
+public:\r
+    shared_handle() = default;\r
+    explicit shared_handle(VkDevice handle, vk::SharedInstance parent) noexcept\r
+        : base(handle, std::move(parent)) {}\r
+\r
+    const auto& getParent() const noexcept {\r
+        return getHeader();\r
+    }\r
+\r
+protected:\r
+    static void internalDestroy(const vk::SharedInstance& /*control*/, VkDevice handle) noexcept {\r
+        vkDestroyDevice(handle);\r
+    }\r
+};\r
+```\r
+\r
+The API will be extended to provide creation functions in the future.\r
+\r
+\r
+\r
 ### Custom allocators\r
 \r
 Sometimes it is required to use `std::vector` with custom allocators. Vulkan-Hpp supports vectors with custom allocators as input for `vk::ArrayProxy` and for functions which do return a vector. For the latter case, add your favorite custom allocator as template argument to the function call like this:\r
index a1ba5ce..5ee4719 100644 (file)
@@ -390,11 +390,13 @@ typename std::enable_if<VULKAN_HPP_NAMESPACE::isVulkanHandleType<T>::value, bool
 )";
 
   std::string str = replaceWithMap( vulkanHandlesHppTemplate,
-                                    { { "handles", generateHandles() },
+                                    {
+                                      { "handles", generateHandles() },
                                       { "handleForwardDeclarations", generateHandleForwardDeclarations() },
                                       { "licenseHeader", m_vulkanLicenseHeader },
                                       { "structForwardDeclarations", generateStructForwardDeclarations() },
-                                      { "uniqueHandles", generateUniqueHandles() } } );
+                                      { "uniqueHandles", generateUniqueHandles() },
+                                    } );
 
   writeToFile( str, vulkan_handles_hpp );
 }
@@ -510,6 +512,7 @@ ${constexprDefines}
 #include <vulkan/${api}_funcs.hpp>
 // clang-format on
 
+
 namespace VULKAN_HPP_NAMESPACE
 {
 #if !defined( VULKAN_HPP_DISABLE_ENHANCED_MODE )
@@ -630,6 +633,46 @@ ${RAIICommandDefinitions}
   writeToFile( str, vulkan_raii_hpp );
 }
 
+void VulkanHppGenerator::generateSharedHppFile() const
+{
+  std::string const vulkan_shared_hpp = std::string( BASE_PATH ) + "/vulkan/" + m_api + "_shared.hpp";
+  std::cout << "VulkanHppGenerator: Generating " << vulkan_shared_hpp << " ..." << std::endl;
+
+  std::string const vulkanHandlesHppTemplate = R"(${licenseHeader}
+#ifndef VULKAN_SHARED_HPP
+#define VULKAN_SHARED_HPP
+
+#include <vulkan/${api}.hpp>
+#include <atomic>  // std::atomic_size_t
+
+
+namespace VULKAN_HPP_NAMESPACE
+{
+#if !defined( VULKAN_HPP_NO_SMART_HANDLE )
+${sharedHandle}
+${sharedDestroy}
+${sharedHandles}
+${sharedHandleSpecializations}
+${sharedHandlesNoDestroy}
+#endif // !VULKAN_HPP_NO_SMART_HANDLE
+} // namespace VULKAN_HPP_NAMESPACE
+#endif // VULKAN_SHARED_HPP
+)";
+
+  std::string str = replaceWithMap( vulkanHandlesHppTemplate,
+                                    {
+                                      { "api", m_api },
+                                      { "licenseHeader", m_vulkanLicenseHeader },
+                                      { "sharedDestroy", readSnippet( "SharedDestroy.hpp" ) },
+                                      { "sharedHandle", readSnippet( "SharedHandle.hpp" ) },
+                                      { "sharedHandles", generateSharedHandles() },
+                                      { "sharedHandlesNoDestroy", generateSharedHandlesNoDestroy() },
+                                      { "sharedHandleSpecializations", readSnippet( "SharedHandleSpecializations.hpp" ) },
+                                    } );
+
+  writeToFile( str, vulkan_shared_hpp );
+}
+
 void VulkanHppGenerator::generateStaticAssertionsHppFile() const
 {
   std::string const static_assertions_hpp = std::string( BASE_PATH ) + "/vulkan/" + m_api + "_static_assertions.hpp";
@@ -5064,6 +5107,53 @@ std::string VulkanHppGenerator::generateCppModuleStructUsings() const
   return structUsings;
 }
 
+std::string VulkanHppGenerator::generateCppModuleSharedHandleUsings() const
+{
+  auto const usingTemplate                        = std::string{ R"(  using VULKAN_HPP_NAMESPACE::Shared${handleName};
+)" };
+  auto       sharedHandleUsings                   = std::string{ R"(
+  //======================
+  //=== SHARED HANDLEs ===
+  //======================
+)" };
+  auto const [smartHandleEnter, smartHandleLeave] = generateProtection( "VULKAN_HPP_NO_SMART_HANDLE", false );
+
+  sharedHandleUsings += "\n" + smartHandleEnter;
+
+  auto const generateUsingsAndProtection = [&usingTemplate, this]( std::vector<RequireData> const & requireData, std::string const & title )
+  {
+    auto usings = std::string{};
+    for ( auto const & require : requireData )
+    {
+      for ( auto const & type : require.types )
+      {
+        if ( auto const & handleIt = m_handles.find( type ); handleIt != m_handles.end() )
+        {
+          usings += replaceWithMap( usingTemplate, { { "handleName", stripPrefix( handleIt->first, "Vk" ) } } );
+        }
+      }
+    }
+    return addTitleAndProtection( title, usings );
+  };
+
+  for ( auto const & feature : m_features )
+  {
+    sharedHandleUsings += generateUsingsAndProtection( feature.requireData, feature.name );
+  }
+
+  for ( auto const & extension : m_extensions )
+  {
+    sharedHandleUsings += generateUsingsAndProtection( extension.requireData, extension.name );
+  }
+
+  sharedHandleUsings += R"(  using VULKAN_HPP_NAMESPACE::SharedHandleTraits;
+)";
+
+  sharedHandleUsings += smartHandleLeave + "\n";
+
+  return sharedHandleUsings;
+}
+
 std::string VulkanHppGenerator::generateCppModuleUniqueHandleUsings() const
 {
   auto const usingTemplate                        = std::string{ R"(  using VULKAN_HPP_NAMESPACE::Unique${handleName};
@@ -5268,8 +5358,9 @@ std::string VulkanHppGenerator::generateCppModuleUsings() const
 
   auto const hardCodedTypes = std::array{ "ArrayWrapper1D", "ArrayWrapper2D", "FlagTraits", "Flags", "DispatchLoaderBase", "DispatchLoaderDynamic" };
   auto const hardCodedEnhancedModeTypes =
-    std::array{ "ArrayProxy", "ArrayProxyNoTemporaries", "StridedArrayProxy", "Optional", "StructureChain", "UniqueHandle" };
-  auto const hardCodedSmartHandleTypes = std::array{ "ObjectDestroy", "ObjectFree", "ObjectRelease", "PoolFree" };
+    std::array{ "ArrayProxy", "ArrayProxyNoTemporaries", "StridedArrayProxy", "Optional", "StructureChain", "UniqueHandle", "SharedHandle" };
+  auto const hardCodedSmartHandleTypes = std::array{ "ObjectDestroy",       "ObjectFree",       "ObjectRelease",       "PoolFree",
+                                                     "ObjectDestroyShared", "ObjectFreeShared", "ObjectReleaseShared", "PoolFreeShared" };
 
   auto usings = std::string{ R"(  //=====================================
   //=== HARDCODED TYPEs AND FUNCTIONs ===
@@ -5401,6 +5492,7 @@ std::string VulkanHppGenerator::generateCppModuleUsings() const
   usings += generateCppModuleStructUsings();
   usings += generateCppModuleHandleUsings();
   usings += generateCppModuleUniqueHandleUsings();
+  usings += generateCppModuleSharedHandleUsings();
   usings += generateCppModuleFuncsUsings();
 
   auto const [enterDisableEnhanced, leaveDisableEnhanced] = generateProtection( "VULKAN_HPP_DISABLE_ENHANCED_MODE", false );
@@ -11624,7 +11716,7 @@ ${aliasHandle})";
     return replaceWithMap( uniqueHandleTemplate,
                            { { "aliasHandle", aliasHandle },
                              { "deleterAction", ( handleData.second.deleteCommand.substr( 2, 4 ) == "Free" ) ? "Free" : "Destroy" },
-                             { "deleterParent", handleData.second.deleteParent.empty() ? "NoParent" : stripPrefix( handleData.second.deleteParent, "Vk" ) },
+                             { "deleterParent", handleData.second.destructorType.empty() ? "NoParent" : stripPrefix( handleData.second.destructorType, "Vk" ) },
                              { "deleterPool", handleData.second.deletePool.empty() ? "" : ", " + stripPrefix( handleData.second.deletePool, "Vk" ) },
                              { "deleterType", handleData.second.deletePool.empty() ? "Object" : "Pool" },
                              { "type", type } } );
@@ -11675,6 +11767,150 @@ ${uniqueHandles}
   return replaceWithMap( uniqueHandlesTemplate, { { "uniqueHandles", uniqueHandles } } );
 }
 
+std::string VulkanHppGenerator::generateSharedHandle( std::pair<std::string, HandleData> const & handleData ) const
+{
+  if ( !handleData.second.deleteCommand.empty() )
+  {
+    std::string type = stripPrefix( handleData.first, "Vk" );
+    std::string aliasHandle;
+    auto        aliasIt = findAlias( handleData.first, m_handleAliases );
+    if ( aliasIt != m_handleAliases.end() )
+    {
+      static const std::string aliasHandleTemplate = R"(  using Shared${aliasType} = SharedHandle<${type}>;)";
+
+      aliasHandle += replaceWithMap( aliasHandleTemplate, { { "aliasType", stripPrefix( aliasIt->first, "Vk" ) }, { "type", type } } );
+    }
+
+    static const std::string sharedHandleTemplate = R"(  template <>
+  class SharedHandleTraits<${type}>
+  {
+  public:
+    using DestructorType = ${destructor};
+    using deleter = ${deleterType}${deleterAction}Shared<${type}${deleterPool}>;
+  };
+  using Shared${type} = SharedHandle<${type}>;
+${aliasHandle})";
+
+    return replaceWithMap( sharedHandleTemplate,
+                           { { "aliasHandle", aliasHandle },
+                             { "deleterAction", ( handleData.second.deleteCommand.substr( 2, 4 ) == "Free" ) ? "Free" : "Destroy" },
+                             { "deleterPool", handleData.second.deletePool.empty() ? "" : ", " + stripPrefix( handleData.second.deletePool, "Vk" ) },
+                             { "deleterType", handleData.second.deletePool.empty() ? "Object" : "Pool" },
+                             { "destructor", handleData.second.destructorType.empty() ? "NoDestructor" : stripPrefix( handleData.second.destructorType, "Vk" ) },
+                             { "type", type } } );
+  }
+  return "";
+}
+
+std::string VulkanHppGenerator::generateSharedHandleNoDestroy( std::pair<std::string, HandleData> const & handleData ) const
+{
+  if ( handleData.second.deleteCommand.empty() )
+  {
+    std::string type = stripPrefix( handleData.first, "Vk" );
+    std::string aliasHandle;
+    auto        aliasIt = findAlias( handleData.first, m_handleAliases );
+    if ( aliasIt != m_handleAliases.end() )
+    {
+      static const std::string aliasHandleTemplate = R"(  using Shared${aliasType} = SharedHandle<${type}>;)";
+
+      aliasHandle += replaceWithMap( aliasHandleTemplate, { { "aliasType", stripPrefix( aliasIt->first, "Vk" ) }, { "type", type } } );
+    }
+
+    static const std::string sharedHandleTemplate = R"(  
+template <>
+class SharedHandle<${type}> : public SharedHandleBaseNoDestroy<${type}, ${parent}>
+{
+  friend SharedHandleBase<${type}, ${parent}>;
+
+public:
+  SharedHandle() = default;
+  explicit SharedHandle(${type} handle, ${parent} parent) noexcept
+    : SharedHandleBaseNoDestroy<${type}, ${parent}>(handle, std::move(parent))
+  {}
+};
+using Shared${type} = SharedHandle<${type}>;
+${aliasHandle})";
+
+    return replaceWithMap( sharedHandleTemplate,
+                           { { "aliasHandle", aliasHandle }, { "parent", "Shared" + stripPrefix( handleData.second.parent, "Vk" ) }, { "type", type } } );
+  }
+  return "";
+}
+
+std::string VulkanHppGenerator::generateSharedHandle( std::vector<RequireData> const & requireData, std::string const & title ) const
+{
+  std::string str;
+  for ( auto const & require : requireData )
+  {
+    for ( auto const & type : require.types )
+    {
+      auto handleIt = m_handles.find( type );
+      if ( handleIt != m_handles.end() )
+      {
+        str += generateSharedHandle( *handleIt );
+      }
+    }
+  }
+  return addTitleAndProtection( title, str );
+}
+
+std::string VulkanHppGenerator::generateSharedHandleNoDestroy( std::vector<RequireData> const & requireData, std::string const & title ) const
+{
+  std::string str;
+  for ( auto const & require : requireData )
+  {
+    for ( auto const & type : require.types )
+    {
+      auto handleIt = m_handles.find( type );
+      if ( handleIt != m_handles.end() )
+      {
+        str += generateSharedHandleNoDestroy( *handleIt );
+      }
+    }
+  }
+  return addTitleAndProtection( title, str );
+}
+
+std::string VulkanHppGenerator::generateSharedHandlesNoDestroy() const
+{
+  std::string sharedHandles;
+  for ( auto const & feature : m_features )
+  {
+    sharedHandles += generateSharedHandleNoDestroy( feature.requireData, feature.name );
+  }
+  for ( auto const & extension : m_extensions )
+  {
+    sharedHandles += generateSharedHandleNoDestroy( extension.requireData, extension.name );
+  }
+  assert( sharedHandles.back() == '\n' );
+  sharedHandles.pop_back();
+  return sharedHandles;
+}
+
+std::string VulkanHppGenerator::generateSharedHandles() const
+{
+  std::string sharedHandlesTemplate = R"(
+  //======================
+  //=== SHARED HANDLEs ===
+  //======================
+
+${sharedHandles}
+)";
+
+  std::string sharedHandles;
+  for ( auto const & feature : m_features )
+  {
+    sharedHandles += generateSharedHandle( feature.requireData, feature.name );
+  }
+  for ( auto const & extension : m_extensions )
+  {
+    sharedHandles += generateSharedHandle( extension.requireData, extension.name );
+  }
+  assert( sharedHandles.back() == '\n' );
+  sharedHandles.pop_back();
+  return replaceWithMap( sharedHandlesTemplate, { { "sharedHandles", sharedHandles } } );
+}
+
 std::string VulkanHppGenerator::generateVectorSizeCheck( std::string const &                           name,
                                                          CommandData const &                           commandData,
                                                          size_t                                        initialSkipCount,
@@ -14898,7 +15134,7 @@ void VulkanHppGenerator::registerDeleter( std::string const & commandName, Comma
     auto handleIt = m_handles.find( commandData.params[valueIndex].type.type );
     assert( handleIt != m_handles.end() );
     handleIt->second.deleteCommand = commandName;
-    handleIt->second.deleteParent  = key;
+    handleIt->second.destructorType = key;
   }
 }
 
@@ -15270,6 +15506,7 @@ int main( int argc, char ** argv )
     generator.prepareRAIIHandles();
     generator.generateMacrosFile();
     generator.generateRAIIHppFile();
+    generator.generateSharedHppFile();
     generator.generateStaticAssertionsHppFile();
     generator.generateStructsHppFile();
     generator.generateToStringHppFile();
index 5348211..8752fd1 100644 (file)
@@ -89,6 +89,7 @@ public:
   void generateHppFile() const;
   void generateMacrosFile() const;
   void generateRAIIHppFile() const;
+  void generateSharedHppFile() const;
   void generateStaticAssertionsHppFile() const;
   void generateStructsHppFile() const;
   void generateToStringHppFile() const;
@@ -291,8 +292,8 @@ private:
     std::set<std::string> childrenHandles     = {};
     std::set<std::string> commands            = {};
     std::string           deleteCommand       = {};
-    std::string           deleteParent        = {};
     std::string           deletePool          = {};
+    std::string           destructorType      = {};
     std::string           objTypeEnum         = {};
     std::string           parent              = {};
     std::set<std::string> secondLevelCommands = {};
@@ -611,6 +612,7 @@ private:
   std::string generateCppModuleExtensionInspectionUsings() const;
   std::string generateCppModuleUsings() const;
   std::string generateCppModuleRaiiUsings() const;
+  std::string generateCppModuleSharedHandleUsings() const;
   std::string generateDataDeclarations( CommandData const &                       commandData,
                                         std::vector<size_t> const &               returnParams,
                                         std::map<size_t, VectorParamData> const & vectorParams,
@@ -875,6 +877,12 @@ private:
   std::string                         generateUniqueHandle( std::pair<std::string, HandleData> const & handleData ) const;
   std::string                         generateUniqueHandle( std::vector<RequireData> const & requireData, std::string const & title ) const;
   std::string                         generateUniqueHandles() const;
+  std::string                         generateSharedHandle( std::pair<std::string, HandleData> const & handleData ) const;
+  std::string                         generateSharedHandle( std::vector<RequireData> const & requireData, std::string const & title ) const;
+  std::string                         generateSharedHandleNoDestroy( std::pair<std::string, HandleData> const & handleData ) const;
+  std::string                         generateSharedHandleNoDestroy( std::vector<RequireData> const & requireData, std::string const & title ) const;
+  std::string                         generateSharedHandles() const;
+  std::string                         generateSharedHandlesNoDestroy() const;
   std::string                         generateVectorSizeCheck( std::string const &                           name,
                                                                CommandData const &                           commandData,
                                                                size_t                                        initialSkipCount,
index 52354ec..5760141 100644 (file)
@@ -57,6 +57,7 @@ add_subdirectory( PipelineDerivative )
 add_subdirectory( PushConstants )
 add_subdirectory( PushDescriptors )
 add_subdirectory( RayTracing )
+add_subdirectory( SharedHandles )
 add_subdirectory( SecondaryCommandBuffer )
 add_subdirectory( SeparateImageSampler )
 add_subdirectory( SurfaceCapabilities )
diff --git a/samples/SharedHandles/CMakeLists.txt b/samples/SharedHandles/CMakeLists.txt
new file mode 100644 (file)
index 0000000..ba6d7d0
--- /dev/null
@@ -0,0 +1,15 @@
+# Copyright(c) 2019, NVIDIA CORPORATION. All rights reserved.
+#
+# 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.
+
+vulkan_hpp__setup_sample_dynamic( NAME SharedHandles )
diff --git a/samples/SharedHandles/SharedHandles.cpp b/samples/SharedHandles/SharedHandles.cpp
new file mode 100644 (file)
index 0000000..62fefee
--- /dev/null
@@ -0,0 +1,377 @@
+// Copyright(c) 2023, Ilya Doroshenko. All rights reserved.
+//
+// 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.
+//
+// VulkanHpp Samples : SharedHandles
+//                     Draw a textured cube using shared handles for resource management and correct order of destruction
+
+#include "../utils/geometries.hpp"
+#include "../utils/math.hpp"
+#include "../utils/shaders.hpp"
+#include "../utils/utils.hpp"
+#include "SPIRV/GlslangToSpv.h"
+
+#include <iostream>
+#include <thread>
+#include <vulkan/vulkan_shared.hpp>
+
+static char const * AppName    = "SharedHandles";
+static char const * EngineName = "Vulkan.hpp";
+
+std::vector<vk::SharedFramebuffer> makeSharedFramebuffers( const vk::SharedDevice &           device,
+                                                           const vk::SharedRenderPass &       renderPass,
+                                                           const std::vector<vk::ImageView> & imageViews,
+                                                           const vk::SharedImageView &        depthImageView,
+                                                           const vk::Extent2D &               extent )
+{
+  auto                               renderPassHandle = renderPass.get();  // lvalue reference is required for the capture below
+  std::vector<vk::SharedFramebuffer> sharedFramebuffers;
+  std::vector<vk::Framebuffer>       framebuffers = vk::su::createFramebuffers( device.get(), renderPassHandle, imageViews, depthImageView.get(), extent );
+  sharedFramebuffers.reserve( framebuffers.size() );
+  for ( auto & framebuffer : framebuffers )
+  {
+    sharedFramebuffers.emplace_back( framebuffer, device );
+  }
+
+  return sharedFramebuffers;
+}
+
+class Window
+{
+public:
+  Window( const char * windowName, vk::Extent2D extent ) : window( vk::su::createWindow( windowName, extent ) ) {}
+
+public:
+  vk::su::WindowData window;
+};
+
+class Engine
+{
+public:
+  Engine( const vk::su::WindowData & window )
+  {
+    instance = vk::SharedInstance{ vk::su::createInstance( AppName, EngineName, {}, vk::su::getInstanceExtensions() ) };
+#if !defined( NDEBUG )
+    debugUtilsMessenger =
+      vk::SharedDebugUtilsMessengerEXT{ instance->createDebugUtilsMessengerEXT( vk::su::makeDebugUtilsMessengerCreateInfoEXT() ), instance };
+#endif
+    physicalDevice = instance->enumeratePhysicalDevices().front();
+
+    createDeviceAndSwapChain( window );
+    initialize();
+  }
+
+  void createDeviceAndSwapChain( const vk::su::WindowData & window )
+  {
+    VkSurfaceKHR surface;
+    VkResult err = glfwCreateWindowSurface( static_cast<VkInstance>( instance.get() ), window.handle, nullptr, &surface );
+    if ( err != VK_SUCCESS )
+      throw std::runtime_error( "Failed to create window!" );
+    vk::SharedSurfaceKHR sharedSurface{ surface, instance };
+
+    auto graphicsAndPresentQueueFamilyIndex = vk::su::findGraphicsAndPresentQueueFamilyIndex( physicalDevice, sharedSurface.get() );
+    device = vk::SharedDevice{ vk::su::createDevice( physicalDevice, graphicsAndPresentQueueFamilyIndex.first, vk::su::getDeviceExtensions() ) };
+
+    vk::su::SwapChainData swapChainData( physicalDevice,
+                                         device.get(),
+                                         sharedSurface.get(),
+                                         window.extent,
+                                         vk::ImageUsageFlagBits::eColorAttachment | vk::ImageUsageFlagBits::eTransferSrc,
+                                         {},
+                                         graphicsAndPresentQueueFamilyIndex.first,
+                                         graphicsAndPresentQueueFamilyIndex.second );
+    swapChain = vk::SharedSwapchainKHR{ swapChainData.swapChain, device, sharedSurface };
+
+    imageViews.reserve( swapChainData.images.size() );
+    images.reserve( swapChainData.images.size() );
+
+    // we don't want to destroy the images, since they are owned by the swapchain,
+    // but for the consistent representation we might want shared textures
+    std::transform( swapChainData.images.begin(),
+                    swapChainData.images.end(),
+                    std::back_inserter( images ),
+                    [this]( vk::Image image ) {
+                      return vk::SharedImage{ image, device, vk::SwapchainOwns::yes };
+                    } );
+
+    std::transform( swapChainData.imageViews.begin(),
+                    swapChainData.imageViews.end(),
+                    std::back_inserter( imageViews ),
+                    [this]( vk::ImageView imageView ) {
+                      return vk::SharedImageView{ imageView, device };
+                    } );
+    commandPool =
+      vk::SharedCommandPool{ device->createCommandPool( { vk::CommandPoolCreateFlagBits::eResetCommandBuffer, graphicsAndPresentQueueFamilyIndex.first } ),
+                             device };
+    graphicsQueue = vk::SharedQueue{ device->getQueue( graphicsAndPresentQueueFamilyIndex.first, 0 ), device };
+
+
+    presentQueue = vk::SharedQueue{ device->getQueue( graphicsAndPresentQueueFamilyIndex.second, 0 ), device };
+
+    depthFormat = vk::Format::eD16Unorm;
+    vk::su::DepthBufferData depthBufferData( physicalDevice, device.get(), depthFormat, window.extent );
+    depthImage     = vk::SharedImage{ depthBufferData.image, device };
+    depthImageView = vk::SharedImageView{ depthBufferData.imageView, device };
+    depthMemory    = vk::SharedDeviceMemory{ depthBufferData.deviceMemory, device };
+
+    renderPass =
+      vk::SharedRenderPass{ vk::su::createRenderPass( device.get(),
+                                                      vk::su::pickSurfaceFormat( physicalDevice.getSurfaceFormatsKHR( swapChain.getSurface().get() ) ).format,
+                                                      depthFormat ),
+                            device };
+
+    framebuffers           = makeSharedFramebuffers( device, renderPass, swapChainData.imageViews, depthImageView, window.extent );
+    imageAcquiredSemaphore = vk::SharedSemaphore{ device->createSemaphore( vk::SemaphoreCreateInfo() ), device };
+    drawFence              = vk::SharedFence{ device->createFence( vk::FenceCreateInfo() ), device };
+    // We don't need to explicitly keep sharedSurface anymore, it is owned by swapChain now.
+  }
+
+  void initialize()
+  {
+    commandBuffer = vk::SharedCommandBuffer{
+      device->allocateCommandBuffers( vk::CommandBufferAllocateInfo( commandPool.get(), vk::CommandBufferLevel::ePrimary, 1 ) ).front(), device, commandPool
+    };
+
+    auto device_handle  = device.get();
+    descriptorSetLayout = vk::SharedDescriptorSetLayout{ vk::su::createDescriptorSetLayout(
+                                                           device_handle,
+                                                           { { vk::DescriptorType::eUniformBuffer, 1, vk::ShaderStageFlagBits::eVertex },
+                                                             { vk::DescriptorType::eCombinedImageSampler, 1, vk::ShaderStageFlagBits::eFragment } } ),
+                                                         device };
+
+    auto dsl = descriptorSetLayout.get();
+
+    pipelineLayout = vk::SharedPipelineLayout{ device->createPipelineLayout( vk::PipelineLayoutCreateInfo( vk::PipelineLayoutCreateFlags(), dsl ) ), device };
+
+    glslang::InitializeProcess();
+    vertexShaderModule = vk::SharedShaderModule{ vk::su::createShaderModule( device_handle, vk::ShaderStageFlagBits::eVertex, vertexShaderText_PT_T ), device };
+    fragmentShaderModule =
+      vk::SharedShaderModule{ vk::su::createShaderModule( device_handle, vk::ShaderStageFlagBits::eFragment, fragmentShaderText_T_C ), device };
+    glslang::FinalizeProcess();
+
+    descriptorPool = vk::SharedDescriptorPool{
+      vk::su::createDescriptorPool( device_handle, { { vk::DescriptorType::eUniformBuffer, 1 }, { vk::DescriptorType::eCombinedImageSampler, 1 } } ), device
+    };
+
+    descriptorSetAllocateInfo = vk::DescriptorSetAllocateInfo( descriptorPool.get(), dsl );
+    descriptorSet             = vk::SharedDescriptorSet{ device->allocateDescriptorSets( descriptorSetAllocateInfo ).front(), device, descriptorPool };
+
+    pipelineCache    = vk::SharedPipelineCache{ device->createPipelineCache( vk::PipelineCacheCreateInfo() ), device };
+    graphicsPipeline = vk::SharedPipeline{ vk::su::createGraphicsPipeline( device_handle,
+                                                                           pipelineCache.get(),
+                                                                           std::make_pair( vertexShaderModule.get(), nullptr ),
+                                                                           std::make_pair( fragmentShaderModule.get(), nullptr ),
+                                                                           sizeof( texturedCubeData[0] ),
+                                                                           { { vk::Format::eR32G32B32A32Sfloat, 0 }, { vk::Format::eR32G32Sfloat, 16 } },
+                                                                           vk::FrontFace::eClockwise,
+                                                                           true,
+                                                                           pipelineLayout.get(),
+                                                                           renderPass.get() ),
+                                           device };
+
+    // Get the index of the next available swapchain image:
+    vk::ResultValue<uint32_t> currentBufferR = device->acquireNextImageKHR( swapChain.get(), vk::su::FenceTimeout, imageAcquiredSemaphore.get(), nullptr );
+    assert( currentBufferR.result == vk::Result::eSuccess );
+    assert( currentBufferR.value < framebuffers.size() );
+    currentBuffer = currentBufferR.value;
+  }
+
+  void beginFrame( vk::Extent2D extent )
+  {
+    std::array<vk::ClearValue, 2> clearValues;
+    clearValues[0].color        = vk::ClearColorValue( 0.2f, 0.2f, 0.2f, 0.2f );
+    clearValues[1].depthStencil = vk::ClearDepthStencilValue( 1.0f, 0 );
+    vk::RenderPassBeginInfo renderPassBeginInfo( renderPass.get(), framebuffers[currentBuffer].get(), vk::Rect2D( vk::Offset2D( 0, 0 ), extent ), clearValues );
+
+    commandBuffer->begin( vk::CommandBufferBeginInfo() );
+    commandBuffer->beginRenderPass( renderPassBeginInfo, vk::SubpassContents::eInline );
+    commandBuffer->bindPipeline( vk::PipelineBindPoint::eGraphics, graphicsPipeline.get() );
+    commandBuffer->bindDescriptorSets( vk::PipelineBindPoint::eGraphics, pipelineLayout.get(), 0, descriptorSet.get(), nullptr );
+
+    commandBuffer->setViewport( 0, vk::Viewport( 0.0f, 0.0f, static_cast<float>( extent.width ), static_cast<float>( extent.height ), 0.0f, 1.0f ) );
+    commandBuffer->setScissor( 0, vk::Rect2D( vk::Offset2D( 0, 0 ), extent ) );
+  }
+
+  void endFrame()
+  {
+    commandBuffer->endRenderPass();
+    commandBuffer->end();
+
+    vk::PipelineStageFlags waitDestinationStageMask( vk::PipelineStageFlagBits::eColorAttachmentOutput );
+
+    auto ias    = imageAcquiredSemaphore.get();
+    auto comBuf = commandBuffer.get();
+
+    vk::SubmitInfo submitInfo( ias, waitDestinationStageMask, comBuf );
+    graphicsQueue->submit( submitInfo, drawFence.get() );
+
+    while ( vk::Result::eTimeout == device->waitForFences( drawFence.get(), VK_TRUE, vk::su::FenceTimeout ) )
+      ;
+
+    auto       swap   = swapChain.get();
+    vk::Result result = presentQueue->presentKHR( vk::PresentInfoKHR( {}, swap, currentBuffer ) );
+    switch ( result )
+    {
+      case vk::Result::eSuccess: break;
+      case vk::Result::eSuboptimalKHR: std::cout << "vk::Queue::presentKHR returned vk::Result::eSuboptimalKHR !\n"; break;
+      default: assert( false );  // an unexpected result is returned !
+    }
+    std::this_thread::sleep_for( std::chrono::milliseconds( 1000 ) );
+
+    /* VULKAN_KEY_END */
+    device->waitIdle();
+  }
+
+public:
+  vk::SharedSwapchainKHR           swapChain;       // swapchain owns surface, that owns Instance, which should be destroyed last
+  vk::PhysicalDevice               physicalDevice;  // physical device does not have a shared handle since it is not destroyed
+  vk::SharedDevice                 device;
+  vk::SharedInstance               instance;  // we don't need to keep the instance, this is just for convenience
+  vk::SharedDebugUtilsMessengerEXT debugUtilsMessenger;
+
+  std::vector<vk::SharedImageView> imageViews;
+  std::vector<vk::SharedImage>     images;
+
+  uint32_t            currentBuffer = 0;
+  vk::SharedSemaphore imageAcquiredSemaphore;
+
+  // memory still needs to be before the resources that use it in order to get a proper destruction sequence.
+  vk::SharedDeviceMemory depthMemory;
+  vk::SharedImage        depthImage;
+  vk::SharedImageView    depthImageView;
+  vk::Format             depthFormat;
+
+  vk::SharedCommandPool   commandPool;
+  vk::SharedCommandBuffer commandBuffer;
+
+  vk::SharedQueue graphicsQueue;  // queue is not destroyed, shared handle is purely for consistency
+  vk::SharedQueue presentQueue;
+
+  vk::SharedPipelineCache       pipelineCache;
+  vk::SharedPipelineLayout      pipelineLayout;
+  vk::SharedRenderPass          renderPass;
+  vk::SharedPipeline            graphicsPipeline;
+  vk::SharedDescriptorPool      descriptorPool;
+  vk::DescriptorSetAllocateInfo descriptorSetAllocateInfo;
+  vk::SharedDescriptorSet       descriptorSet;
+  vk::SharedDescriptorSetLayout descriptorSetLayout;
+
+  vk::SharedShaderModule vertexShaderModule;
+  vk::SharedShaderModule fragmentShaderModule;
+
+  std::vector<vk::SharedFramebuffer> framebuffers;
+
+  vk::SharedFence drawFence;
+};
+
+class Asset
+{
+public:
+  Asset( const Engine & engine, vk::Extent2D extent )
+  {
+    auto               device_handle = engine.device.get();
+    vk::su::BufferData vertexBufferData( engine.physicalDevice, device_handle, sizeof( texturedCubeData ), vk::BufferUsageFlagBits::eVertexBuffer );
+    vk::su::copyToDevice( device_handle, vertexBufferData.deviceMemory, texturedCubeData, sizeof( texturedCubeData ) / sizeof( texturedCubeData[0] ) );
+
+    vertexBuffer       = vk::SharedBuffer{ vertexBufferData.buffer, engine.device };
+    vertexBufferMemory = vk::SharedDeviceMemory{ vertexBufferData.deviceMemory, engine.device };
+
+    engine.commandBuffer->begin( vk::CommandBufferBeginInfo() );
+
+    vk::su::BufferData uniformBufferData( engine.physicalDevice, device_handle, sizeof( glm::mat4x4 ), vk::BufferUsageFlagBits::eUniformBuffer );
+    glm::mat4x4        mvpcMatrix = vk::su::createModelViewProjectionClipMatrix( extent );
+    vk::su::copyToDevice( device_handle, uniformBufferData.deviceMemory, mvpcMatrix );
+
+    uniformBufferMemory = vk::SharedDeviceMemory{ uniformBufferData.deviceMemory, engine.device };
+    uniformBuffer       = vk::SharedBuffer{ uniformBufferData.buffer, engine.device };
+
+    vk::su::TextureData textureData( engine.physicalDevice, device_handle );
+    textureData.setImage( device_handle, engine.commandBuffer.get(), vk::su::CheckerboardImageGenerator() );
+
+    textureImage       = vk::SharedImage{ textureData.imageData->image, engine.device };
+    textureImageMemory = vk::SharedDeviceMemory{ textureData.imageData->deviceMemory, engine.device };
+    textureImageView   = vk::SharedImageView{ textureData.imageData->imageView, engine.device };
+    textureSampler     = vk::SharedSampler{ textureData.sampler, engine.device };
+
+    vk::su::updateDescriptorSets(
+      device_handle, engine.descriptorSet.get(), { { vk::DescriptorType::eUniformBuffer, uniformBufferData.buffer, VK_WHOLE_SIZE, {} } }, textureData );
+    engine.commandBuffer->end();
+
+    vk::su::submitAndWait( device_handle, engine.graphicsQueue.get(), engine.commandBuffer.get() );
+  }
+
+  void draw( vk::CommandBuffer commandBuffer )
+  {
+    commandBuffer.bindVertexBuffers( 0, vertexBuffer.get(), { 0 } );
+    commandBuffer.draw( 12 * 3, 1, 0, 0 );
+  }
+
+  vk::SharedDeviceMemory vertexBufferMemory;
+  vk::SharedBuffer       vertexBuffer;
+
+  vk::SharedDeviceMemory uniformBufferMemory;
+  vk::SharedBuffer       uniformBuffer;
+
+  vk::SharedDeviceMemory textureImageMemory;
+  vk::SharedImage        textureImage;
+  vk::SharedImageView    textureImageView;
+  vk::SharedSampler      textureSampler;
+};
+
+class Application
+{
+public:
+  Application() : window( AppName, vk::Extent2D( 500, 500 ) ), engine( window.window ), asset( engine, vk::Extent2D( 500, 500 ) ) {}
+
+  void renderFrame()
+  {
+    engine.beginFrame( vk::Extent2D( 500, 500 ) );
+    asset.draw( engine.commandBuffer.get() );
+    engine.endFrame();
+  }
+
+  int start()
+  {
+    renderFrame();
+    return 0;
+  }
+
+private:
+  // order of window, engine and asset variables is important !
+  Window window;
+  Engine engine;
+  Asset  asset;
+};
+
+int main( int /*argc*/, char ** /*argv*/ )
+{
+  try
+  {
+    return Application{}.start();
+  }
+  catch ( vk::SystemError & err )
+  {
+    std::cout << "vk::SystemError: " << err.what() << std::endl;
+    exit( -1 );
+  }
+  catch ( std::exception & err )
+  {
+    std::cout << "std::exception: " << err.what() << std::endl;
+    exit( -1 );
+  }
+  catch ( ... )
+  {
+    std::cout << "unknown error\n";
+    exit( -1 );
+  }
+}
diff --git a/snippets/SharedDestroy.hpp b/snippets/SharedDestroy.hpp
new file mode 100644 (file)
index 0000000..912015f
--- /dev/null
@@ -0,0 +1,150 @@
+
+template <typename HandleType>
+class SharedHandleTraits;
+
+// Silence the function cast warnings.
+#if defined( __GNUC__ ) && !defined( __clang__ ) && !defined( __INTEL_COMPILER )
+#  pragma GCC diagnostic push
+#  pragma GCC diagnostic ignored "-Wcast-function-type"
+#endif
+
+template <typename HandleType>
+class ObjectDestroyShared
+{
+public:
+  using DestructorType = typename SharedHandleTraits<HandleType>::DestructorType;
+
+  template <class Dispatcher>
+  using DestroyFunctionPointerType = typename std::conditional<HasDestructor<HandleType>::value,
+                                                               void ( DestructorType::* )( HandleType, const AllocationCallbacks *, const Dispatcher & ) const,
+                                                               void ( HandleType::* )( const AllocationCallbacks *, const Dispatcher & ) const>::type;
+
+  using SelectorType = typename std::conditional<HasDestructor<HandleType>::value, DestructorType, HandleType>::type;
+
+  template <typename Dispatcher = VULKAN_HPP_DEFAULT_DISPATCHER_TYPE>
+  ObjectDestroyShared( Optional<const AllocationCallbacks> allocationCallbacks VULKAN_HPP_DEFAULT_ARGUMENT_NULLPTR_ASSIGNMENT,
+                       const Dispatcher & dispatch                             VULKAN_HPP_DEFAULT_DISPATCHER_ASSIGNMENT )
+    : m_destroy( reinterpret_cast<decltype( m_destroy )>( static_cast<DestroyFunctionPointerType<Dispatcher>>( &SelectorType::destroy ) ) )
+    , m_dispatch( &dispatch )
+    , m_allocationCallbacks( allocationCallbacks )
+  {
+  }
+
+public:
+  template <typename T = HandleType>
+  typename std::enable_if<HasDestructor<T>::value, void>::type destroy( DestructorType parent, HandleType handle ) const VULKAN_HPP_NOEXCEPT
+  {
+    VULKAN_HPP_ASSERT( m_destroy && m_dispatch );
+    ( parent.*m_destroy )( handle, m_allocationCallbacks, *m_dispatch );
+  }
+
+  template <typename T = HandleType>
+  typename std::enable_if<!HasDestructor<T>::value, void>::type destroy( HandleType handle ) const VULKAN_HPP_NOEXCEPT
+  {
+    VULKAN_HPP_ASSERT( m_destroy && m_dispatch );
+    ( handle.*m_destroy )( m_allocationCallbacks, *m_dispatch );
+  }
+
+private:
+  DestroyFunctionPointerType<DispatchLoaderBase> m_destroy             = nullptr;
+  const DispatchLoaderBase *                     m_dispatch            = nullptr;
+  Optional<const AllocationCallbacks>            m_allocationCallbacks = nullptr;
+};
+
+template <typename HandleType>
+class ObjectFreeShared
+{
+public:
+  using DestructorType = typename SharedHandleTraits<HandleType>::DestructorType;
+
+  template <class Dispatcher>
+  using DestroyFunctionPointerType = void ( DestructorType::* )( HandleType, const AllocationCallbacks *, const Dispatcher & ) const;
+
+  template <class Dispatcher = VULKAN_HPP_DEFAULT_DISPATCHER_TYPE>
+  ObjectFreeShared( Optional<const AllocationCallbacks> allocationCallbacks VULKAN_HPP_DEFAULT_ARGUMENT_NULLPTR_ASSIGNMENT,
+                    const Dispatcher & dispatch                             VULKAN_HPP_DEFAULT_DISPATCHER_ASSIGNMENT )
+    : m_destroy( reinterpret_cast<decltype( m_destroy )>( static_cast<DestroyFunctionPointerType<Dispatcher>>( &DestructorType::free ) ) )
+    , m_dispatch( &dispatch )
+    , m_allocationCallbacks( allocationCallbacks )
+  {
+  }
+
+public:
+  void destroy( DestructorType parent, HandleType handle ) const VULKAN_HPP_NOEXCEPT
+  {
+    VULKAN_HPP_ASSERT( m_destroy && m_dispatch );
+    ( parent.*m_destroy )( handle, m_allocationCallbacks, *m_dispatch );
+  }
+
+private:
+  DestroyFunctionPointerType<DispatchLoaderBase> m_destroy             = nullptr;
+  const DispatchLoaderBase *                     m_dispatch            = nullptr;
+  Optional<const AllocationCallbacks>            m_allocationCallbacks = nullptr;
+};
+
+template <typename HandleType>
+class ObjectReleaseShared
+{
+public:
+  using DestructorType = typename SharedHandleTraits<HandleType>::DestructorType;
+
+  template <class Dispatcher>
+  using DestroyFunctionPointerType = void ( DestructorType::* )( HandleType, const Dispatcher & ) const;
+
+  template <class Dispatcher = VULKAN_HPP_DEFAULT_DISPATCHER_TYPE>
+  ObjectReleaseShared( const Dispatcher & dispatch VULKAN_HPP_DEFAULT_DISPATCHER_ASSIGNMENT )
+    : m_destroy( reinterpret_cast<decltype( m_destroy )>( static_cast<DestroyFunctionPointerType<Dispatcher>>( &DestructorType::release ) ) )
+    , m_dispatch( &dispatch )
+  {
+  }
+
+public:
+  void destroy( DestructorType parent, HandleType handle ) const VULKAN_HPP_NOEXCEPT
+  {
+    VULKAN_HPP_ASSERT( m_destroy && m_dispatch );
+    ( parent.*m_destroy )( handle, *m_dispatch );
+  }
+
+private:
+  DestroyFunctionPointerType<DispatchLoaderBase> m_destroy  = nullptr;
+  const DispatchLoaderBase *                     m_dispatch = nullptr;
+};
+
+template <typename HandleType, typename PoolType>
+class PoolFreeShared
+{
+public:
+  using DestructorType = typename SharedHandleTraits<HandleType>::DestructorType;
+
+  template <class Dispatcher>
+  using ReturnType = decltype( std::declval<DestructorType>().free( PoolType(), 0u, nullptr, Dispatcher() ) );
+
+  template <class Dispatcher>
+  using DestroyFunctionPointerType = ReturnType<Dispatcher> ( DestructorType::* )( PoolType, uint32_t, const HandleType *, const Dispatcher & ) const;
+
+  PoolFreeShared() = default;
+
+  template <class Dispatcher = VULKAN_HPP_DEFAULT_DISPATCHER_TYPE>
+  PoolFreeShared( SharedHandle<PoolType> pool, const Dispatcher & dispatch VULKAN_HPP_DEFAULT_DISPATCHER_ASSIGNMENT )
+    : m_destroy( reinterpret_cast<decltype( m_destroy )>( static_cast<DestroyFunctionPointerType<Dispatcher>>( &DestructorType::free ) ) )
+    , m_dispatch( &dispatch )
+    , m_pool( std::move( pool ) )
+  {
+  }
+
+public:
+  void destroy( DestructorType parent, HandleType handle ) const VULKAN_HPP_NOEXCEPT
+  {
+    VULKAN_HPP_ASSERT( m_destroy && m_dispatch );
+    ( parent.*m_destroy )( m_pool.get(), 1u, &handle, *m_dispatch );
+  }
+
+private:
+  DestroyFunctionPointerType<DispatchLoaderBase> m_destroy  = nullptr;
+  const DispatchLoaderBase *                     m_dispatch = nullptr;
+  SharedHandle<PoolType>                         m_pool{};
+};
+
+#if defined( __GNUC__ ) && !defined( __clang__ ) && !defined( __INTEL_COMPILER )
+#  pragma GCC diagnostic pop
+#endif
diff --git a/snippets/SharedHandle.hpp b/snippets/SharedHandle.hpp
new file mode 100644 (file)
index 0000000..871831c
--- /dev/null
@@ -0,0 +1,247 @@
+
+template <typename HandleType>
+class SharedHandleTraits;
+
+class NoDestructor
+{
+};
+
+template <typename HandleType, typename = void>
+struct HasDestructorType : std::false_type
+{
+};
+
+template <typename HandleType>
+struct HasDestructorType<HandleType, decltype( (void)typename SharedHandleTraits<HandleType>::DestructorType() )> : std::true_type
+{
+};
+
+template <typename HandleType, typename Enable = void>
+struct GetDestructorType
+{
+  using type = NoDestructor;
+};
+
+template <typename HandleType>
+struct GetDestructorType<HandleType, typename std::enable_if<HasDestructorType<HandleType>::value>::type>
+{
+  using type = typename SharedHandleTraits<HandleType>::DestructorType;
+};
+
+template <class HandleType>
+using DestructorTypeOf = typename GetDestructorType<HandleType>::type;
+
+template <class HandleType>
+struct HasDestructor : std::integral_constant<bool, !std::is_same<DestructorTypeOf<HandleType>, NoDestructor>::value>
+{
+};
+
+//=====================================================================================================================
+
+template <typename HandleType>
+class SharedHandle;
+
+template <typename DestructorType, typename Deleter>
+struct SharedHeader
+{
+  SharedHeader( SharedHandle<DestructorType> parent, Deleter deleter = Deleter() ) VULKAN_HPP_NOEXCEPT
+    : parent( std::move( parent ) )
+    , deleter( std::move( deleter ) )
+  {
+  }
+
+  SharedHandle<DestructorType> parent;
+  Deleter                      deleter;
+};
+
+template <typename Deleter>
+struct SharedHeader<NoDestructor, Deleter>
+{
+  SharedHeader( Deleter deleter = Deleter() ) VULKAN_HPP_NOEXCEPT : deleter( std::move( deleter ) ) {}
+
+  Deleter deleter;
+};
+
+//=====================================================================================================================
+
+template <typename HeaderType>
+class ReferenceCounter
+{
+public:
+  template <typename... Args>
+  ReferenceCounter( Args &&... control_args ) : m_header( std::forward<Args>( control_args )... ){}
+  ReferenceCounter( const ReferenceCounter & )             = delete;
+  ReferenceCounter & operator=( const ReferenceCounter & ) = delete;
+
+public:
+  size_t addRef() VULKAN_HPP_NOEXCEPT
+  {
+    // Relaxed memory order is sufficient since this does not impose any ordering on other operations
+    return m_ref_cnt.fetch_add( 1, std::memory_order_relaxed );
+  }
+
+  size_t release() VULKAN_HPP_NOEXCEPT
+  {
+    // A release memory order to ensure that all releases are ordered
+    return m_ref_cnt.fetch_sub( 1, std::memory_order_release );
+  }
+
+public:
+  std::atomic_size_t m_ref_cnt{ 1 };
+  HeaderType         m_header{};
+};
+
+//=====================================================================================================================
+
+template <typename HandleType, typename HeaderType, typename ForwardType = SharedHandle<HandleType>>
+class SharedHandleBase
+{
+public:
+  SharedHandleBase() = default;
+
+  template <typename... Args>
+  SharedHandleBase( HandleType handle, Args &&... control_args )
+    : m_control( new ReferenceCounter<HeaderType>( std::forward<Args>( control_args )... ) ), m_handle( handle )
+  {
+  }
+
+  SharedHandleBase( const SharedHandleBase & o ) VULKAN_HPP_NOEXCEPT
+  {
+    o.addRef();
+    m_handle  = o.m_handle;
+    m_control = o.m_control;
+  }
+
+  SharedHandleBase( SharedHandleBase && o ) VULKAN_HPP_NOEXCEPT
+    : m_control( o.m_control )
+    , m_handle( o.m_handle )
+  {
+    o.m_handle  = nullptr;
+    o.m_control = nullptr;
+  }
+
+  SharedHandleBase & operator=( const SharedHandleBase & o ) VULKAN_HPP_NOEXCEPT
+  {
+    SharedHandleBase( o ).swap( *this );
+    return *this;
+  }
+
+  SharedHandleBase & operator=( SharedHandleBase && o ) VULKAN_HPP_NOEXCEPT
+  {
+    SharedHandleBase( std::move( o ) ).swap( *this );
+    return *this;
+  }
+
+  ~SharedHandleBase()
+  {
+    // only this function owns the last reference to the control block
+    // the same principle is used in the default deleter of std::shared_ptr
+    if ( m_control && ( m_control->release() == 1 ) )
+    {
+      // noop in x86, but does thread synchronization in ARM
+      // it is required to ensure that last thread is getting to destroy the control block
+      // by ordering all atomic operations before this fence
+      std::atomic_thread_fence( std::memory_order_acquire );
+      ForwardType::internalDestroy( getHeader(), m_handle );
+      delete m_control;
+    }
+  }
+
+public:
+  HandleType get() const VULKAN_HPP_NOEXCEPT
+  {
+    return m_handle;
+  }
+
+  HandleType operator*() const VULKAN_HPP_NOEXCEPT
+  {
+    return m_handle;
+  }
+
+  explicit operator bool() const VULKAN_HPP_NOEXCEPT
+  {
+    return bool( m_handle );
+  }
+
+  const HandleType * operator->() const VULKAN_HPP_NOEXCEPT
+  {
+    return &m_handle;
+  }
+
+  HandleType * operator->() VULKAN_HPP_NOEXCEPT
+  {
+    return &m_handle;
+  }
+
+  void reset() VULKAN_HPP_NOEXCEPT
+  {
+    SharedHandleBase().swap( *this );
+  }
+
+  void swap( SharedHandleBase & o ) VULKAN_HPP_NOEXCEPT
+  {
+    std::swap( m_handle, o.m_handle );
+    std::swap( m_control, o.m_control );
+  }
+
+  template <typename T = HandleType>
+  typename std::enable_if<HasDestructor<T>::value, const SharedHandle<DestructorTypeOf<HandleType>> &>::type getDestructorType() const VULKAN_HPP_NOEXCEPT
+  {
+    return getHeader().parent;
+  }
+
+protected:
+  template <typename T = HandleType>
+  static typename std::enable_if<!HasDestructor<T>::value, void>::type internalDestroy( const HeaderType & control, HandleType handle ) VULKAN_HPP_NOEXCEPT
+  {
+    control.deleter.destroy( handle );
+  }
+
+  template <typename T = HandleType>
+  static typename std::enable_if<HasDestructor<T>::value, void>::type internalDestroy( const HeaderType & control, HandleType handle ) VULKAN_HPP_NOEXCEPT
+  {
+    control.deleter.destroy( control.parent.get(), handle );
+  }
+
+  const HeaderType & getHeader() const VULKAN_HPP_NOEXCEPT
+  {
+    return m_control->m_header;
+  }
+
+private:
+  void addRef() const VULKAN_HPP_NOEXCEPT
+  {
+    if ( m_control )
+      m_control->addRef();
+  }
+
+protected:
+  ReferenceCounter<HeaderType> * m_control = nullptr;
+  HandleType                     m_handle{};
+};
+
+template <typename HandleType>
+class SharedHandle : public SharedHandleBase<HandleType, SharedHeader<DestructorTypeOf<HandleType>, typename SharedHandleTraits<HandleType>::deleter>>
+{
+private:
+  using BaseType    = SharedHandleBase<HandleType, SharedHeader<DestructorTypeOf<HandleType>, typename SharedHandleTraits<HandleType>::deleter>>;
+  using DeleterType = typename SharedHandleTraits<HandleType>::deleter;
+  friend BaseType;
+
+public:
+  SharedHandle() = default;
+
+  template <typename T = HandleType, typename = typename std::enable_if<HasDestructor<T>::value>::type>
+  explicit SharedHandle( HandleType handle, SharedHandle<DestructorTypeOf<HandleType>> parent, DeleterType deleter = DeleterType() ) VULKAN_HPP_NOEXCEPT
+    : BaseType( handle, std::move( parent ), std::move( deleter ) )
+  {
+  }
+
+  template <typename T = HandleType, typename = typename std::enable_if<!HasDestructor<T>::value>::type>
+  explicit SharedHandle( HandleType handle, DeleterType deleter = DeleterType() ) VULKAN_HPP_NOEXCEPT : BaseType( handle, std::move( deleter ) )
+  {
+  }
+
+protected:
+  using BaseType::internalDestroy;
+};
diff --git a/snippets/SharedHandleSpecializations.hpp b/snippets/SharedHandleSpecializations.hpp
new file mode 100644 (file)
index 0000000..81f3f10
--- /dev/null
@@ -0,0 +1,108 @@
+
+enum class SwapchainOwns
+{
+  no,
+  yes,
+};
+
+struct ImageHeader : SharedHeader<DestructorTypeOf<VULKAN_HPP_NAMESPACE::Image>, typename SharedHandleTraits<VULKAN_HPP_NAMESPACE::Image>::deleter>
+{
+  ImageHeader( SharedHandle<DestructorTypeOf<VULKAN_HPP_NAMESPACE::Image>>       parent,
+               typename SharedHandleTraits<VULKAN_HPP_NAMESPACE::Image>::deleter deleter = typename SharedHandleTraits<VULKAN_HPP_NAMESPACE::Image>::deleter(),
+               SwapchainOwns                                                     swapchainOwned = SwapchainOwns::no ) VULKAN_HPP_NOEXCEPT
+    : SharedHeader<DestructorTypeOf<VULKAN_HPP_NAMESPACE::Image>, typename SharedHandleTraits<VULKAN_HPP_NAMESPACE::Image>::deleter>( std::move( parent ),
+                                                                                                                                      std::move( deleter ) )
+    , swapchainOwned( swapchainOwned )
+  {
+  }
+
+  SwapchainOwns swapchainOwned = SwapchainOwns::no;
+};
+
+template <>
+class SharedHandle<VULKAN_HPP_NAMESPACE::Image> : public SharedHandleBase<VULKAN_HPP_NAMESPACE::Image, ImageHeader>
+{
+  using BaseType    = SharedHandleBase<VULKAN_HPP_NAMESPACE::Image, ImageHeader>;
+  using DeleterType = typename SharedHandleTraits<VULKAN_HPP_NAMESPACE::Image>::deleter;
+  friend BaseType;
+
+public:
+  SharedHandle() = default;
+
+  explicit SharedHandle( VULKAN_HPP_NAMESPACE::Image                                 handle,
+                         SharedHandle<DestructorTypeOf<VULKAN_HPP_NAMESPACE::Image>> parent,
+                         SwapchainOwns                                               swapchain_owned = SwapchainOwns::no,
+                         DeleterType                                                 deleter         = DeleterType() ) VULKAN_HPP_NOEXCEPT
+    : BaseType( handle, std::move( parent ), std::move( deleter ), swapchain_owned )
+  {
+  }
+
+protected:
+  static void internalDestroy( const ImageHeader & control, VULKAN_HPP_NAMESPACE::Image handle ) VULKAN_HPP_NOEXCEPT
+  {
+    if ( control.swapchainOwned == SwapchainOwns::no )
+    {
+      control.deleter.destroy( control.parent.get(), handle );
+    }
+  }
+};
+
+struct SwapchainHeader
+{
+  SwapchainHeader( SharedHandle<VULKAN_HPP_NAMESPACE::SurfaceKHR>                           surface,
+                   SharedHandle<DestructorTypeOf<VULKAN_HPP_NAMESPACE::SwapchainKHR>>       parent,
+                   typename SharedHandleTraits<VULKAN_HPP_NAMESPACE::SwapchainKHR>::deleter deleter =
+                     typename SharedHandleTraits<VULKAN_HPP_NAMESPACE::SwapchainKHR>::deleter() ) VULKAN_HPP_NOEXCEPT
+    : surface( std::move( surface ) )
+    , parent( std::move( parent ) )
+    , deleter( std::move( deleter ) )
+  {
+  }
+
+  SharedHandle<VULKAN_HPP_NAMESPACE::SurfaceKHR>                           surface{};
+  SharedHandle<DestructorTypeOf<VULKAN_HPP_NAMESPACE::SwapchainKHR>>       parent{};
+  typename SharedHandleTraits<VULKAN_HPP_NAMESPACE::SwapchainKHR>::deleter deleter{};
+};
+
+template <>
+class SharedHandle<VULKAN_HPP_NAMESPACE::SwapchainKHR> : public SharedHandleBase<VULKAN_HPP_NAMESPACE::SwapchainKHR, SwapchainHeader>
+{
+  using BaseType    = SharedHandleBase<VULKAN_HPP_NAMESPACE::SwapchainKHR, SwapchainHeader>;
+  using DeleterType = typename SharedHandleTraits<VULKAN_HPP_NAMESPACE::SwapchainKHR>::deleter;
+  friend BaseType;
+
+public:
+  SharedHandle() = default;
+
+  explicit SharedHandle( VULKAN_HPP_NAMESPACE::SwapchainKHR                                 handle,
+                         SharedHandle<DestructorTypeOf<VULKAN_HPP_NAMESPACE::SwapchainKHR>> parent,
+                         SharedHandle<VULKAN_HPP_NAMESPACE::SurfaceKHR>                     surface,
+                         DeleterType                                                        deleter = DeleterType() ) VULKAN_HPP_NOEXCEPT
+    : BaseType( handle, std::move( surface ), std::move( parent ), std::move( deleter ) )
+  {
+  }
+
+public:
+  const SharedHandle<VULKAN_HPP_NAMESPACE::SurfaceKHR> & getSurface() const VULKAN_HPP_NOEXCEPT
+  {
+    return getHeader().surface;
+  }
+
+protected:
+  using BaseType::internalDestroy;
+};
+
+template <typename HandleType, typename DestructorType>
+class SharedHandleBaseNoDestroy : public SharedHandleBase<HandleType, DestructorType>
+{
+public:
+  using SharedHandleBase<HandleType, DestructorType>::SharedHandleBase;
+
+  const DestructorType & getDestructorType() const VULKAN_HPP_NOEXCEPT
+  {
+    return SharedHandleBase<HandleType, DestructorType>::getHeader();
+  }
+
+protected:
+  static void internalDestroy( const DestructorType &, HandleType ) VULKAN_HPP_NOEXCEPT {}
+};
\ No newline at end of file
index 7ff79b5..1bed8f3 100644 (file)
@@ -44,6 +44,7 @@ export namespace VULKAN_HPP_NAMESPACE
   using VULKAN_HPP_NAMESPACE::ArrayProxy;
   using VULKAN_HPP_NAMESPACE::ArrayProxyNoTemporaries;
   using VULKAN_HPP_NAMESPACE::Optional;
+  using VULKAN_HPP_NAMESPACE::SharedHandle;
   using VULKAN_HPP_NAMESPACE::StridedArrayProxy;
   using VULKAN_HPP_NAMESPACE::StructureChain;
   using VULKAN_HPP_NAMESPACE::UniqueHandle;
@@ -51,9 +52,13 @@ export namespace VULKAN_HPP_NAMESPACE
 
 #if !defined( VULKAN_HPP_NO_SMART_HANDLE )
   using VULKAN_HPP_NAMESPACE::ObjectDestroy;
+  using VULKAN_HPP_NAMESPACE::ObjectDestroyShared;
   using VULKAN_HPP_NAMESPACE::ObjectFree;
+  using VULKAN_HPP_NAMESPACE::ObjectFreeShared;
   using VULKAN_HPP_NAMESPACE::ObjectRelease;
+  using VULKAN_HPP_NAMESPACE::ObjectReleaseShared;
   using VULKAN_HPP_NAMESPACE::PoolFree;
+  using VULKAN_HPP_NAMESPACE::PoolFreeShared;
 #endif /*VULKAN_HPP_NO_SMART_HANDLE*/
 
   //==================
@@ -2870,6 +2875,104 @@ export namespace VULKAN_HPP_NAMESPACE
   using VULKAN_HPP_NAMESPACE::UniqueShaderEXT;
 #endif /*VULKAN_HPP_NO_SMART_HANDLE*/
 
+  //======================
+  //=== SHARED HANDLEs ===
+  //======================
+
+#if !defined( VULKAN_HPP_NO_SMART_HANDLE )
+
+  //=== VK_VERSION_1_0 ===
+  using VULKAN_HPP_NAMESPACE::SharedBuffer;
+  using VULKAN_HPP_NAMESPACE::SharedBufferView;
+  using VULKAN_HPP_NAMESPACE::SharedCommandBuffer;
+  using VULKAN_HPP_NAMESPACE::SharedCommandPool;
+  using VULKAN_HPP_NAMESPACE::SharedDescriptorPool;
+  using VULKAN_HPP_NAMESPACE::SharedDescriptorSet;
+  using VULKAN_HPP_NAMESPACE::SharedDescriptorSetLayout;
+  using VULKAN_HPP_NAMESPACE::SharedDevice;
+  using VULKAN_HPP_NAMESPACE::SharedDeviceMemory;
+  using VULKAN_HPP_NAMESPACE::SharedEvent;
+  using VULKAN_HPP_NAMESPACE::SharedFence;
+  using VULKAN_HPP_NAMESPACE::SharedFramebuffer;
+  using VULKAN_HPP_NAMESPACE::SharedImage;
+  using VULKAN_HPP_NAMESPACE::SharedImageView;
+  using VULKAN_HPP_NAMESPACE::SharedInstance;
+  using VULKAN_HPP_NAMESPACE::SharedPhysicalDevice;
+  using VULKAN_HPP_NAMESPACE::SharedPipeline;
+  using VULKAN_HPP_NAMESPACE::SharedPipelineCache;
+  using VULKAN_HPP_NAMESPACE::SharedPipelineLayout;
+  using VULKAN_HPP_NAMESPACE::SharedQueryPool;
+  using VULKAN_HPP_NAMESPACE::SharedQueue;
+  using VULKAN_HPP_NAMESPACE::SharedRenderPass;
+  using VULKAN_HPP_NAMESPACE::SharedSampler;
+  using VULKAN_HPP_NAMESPACE::SharedSemaphore;
+  using VULKAN_HPP_NAMESPACE::SharedShaderModule;
+
+  //=== VK_VERSION_1_1 ===
+  using VULKAN_HPP_NAMESPACE::SharedDescriptorUpdateTemplate;
+  using VULKAN_HPP_NAMESPACE::SharedSamplerYcbcrConversion;
+
+  //=== VK_VERSION_1_3 ===
+  using VULKAN_HPP_NAMESPACE::SharedPrivateDataSlot;
+
+  //=== VK_KHR_surface ===
+  using VULKAN_HPP_NAMESPACE::SharedSurfaceKHR;
+
+  //=== VK_KHR_swapchain ===
+  using VULKAN_HPP_NAMESPACE::SharedSwapchainKHR;
+
+  //=== VK_KHR_display ===
+  using VULKAN_HPP_NAMESPACE::SharedDisplayKHR;
+  using VULKAN_HPP_NAMESPACE::SharedDisplayModeKHR;
+
+  //=== VK_EXT_debug_report ===
+  using VULKAN_HPP_NAMESPACE::SharedDebugReportCallbackEXT;
+
+  //=== VK_KHR_video_queue ===
+  using VULKAN_HPP_NAMESPACE::SharedVideoSessionKHR;
+  using VULKAN_HPP_NAMESPACE::SharedVideoSessionParametersKHR;
+
+  //=== VK_NVX_binary_import ===
+  using VULKAN_HPP_NAMESPACE::SharedCuFunctionNVX;
+  using VULKAN_HPP_NAMESPACE::SharedCuModuleNVX;
+
+  //=== VK_EXT_debug_utils ===
+  using VULKAN_HPP_NAMESPACE::SharedDebugUtilsMessengerEXT;
+
+  //=== VK_KHR_acceleration_structure ===
+  using VULKAN_HPP_NAMESPACE::SharedAccelerationStructureKHR;
+
+  //=== VK_EXT_validation_cache ===
+  using VULKAN_HPP_NAMESPACE::SharedValidationCacheEXT;
+
+  //=== VK_NV_ray_tracing ===
+  using VULKAN_HPP_NAMESPACE::SharedAccelerationStructureNV;
+
+  //=== VK_INTEL_performance_query ===
+  using VULKAN_HPP_NAMESPACE::SharedPerformanceConfigurationINTEL;
+
+  //=== VK_KHR_deferred_host_operations ===
+  using VULKAN_HPP_NAMESPACE::SharedDeferredOperationKHR;
+
+  //=== VK_NV_device_generated_commands ===
+  using VULKAN_HPP_NAMESPACE::SharedIndirectCommandsLayoutNV;
+
+#  if defined( VK_USE_PLATFORM_FUCHSIA )
+  //=== VK_FUCHSIA_buffer_collection ===
+  using VULKAN_HPP_NAMESPACE::SharedBufferCollectionFUCHSIA;
+#  endif /*VK_USE_PLATFORM_FUCHSIA*/
+
+  //=== VK_EXT_opacity_micromap ===
+  using VULKAN_HPP_NAMESPACE::SharedMicromapEXT;
+
+  //=== VK_NV_optical_flow ===
+  using VULKAN_HPP_NAMESPACE::SharedOpticalFlowSessionNV;
+
+  //=== VK_EXT_shader_object ===
+  using VULKAN_HPP_NAMESPACE::SharedHandleTraits;
+  using VULKAN_HPP_NAMESPACE::SharedShaderEXT;
+#endif /*VULKAN_HPP_NO_SMART_HANDLE*/
+
   //===========================
   //=== COMMAND Definitions ===
   //===========================
index a3c2682..8327f29 100644 (file)
@@ -13895,7 +13895,7 @@ namespace VULKAN_HPP_NAMESPACE
 #  elif defined( __APPLE__ )
         m_library = dlopen( "libvulkan.dylib", RTLD_NOW | RTLD_LOCAL );
 #  elif defined( _WIN32 )
-          m_library = ::LoadLibraryA( "vulkan-1.dll" );
+        m_library = ::LoadLibraryA( "vulkan-1.dll" );
 #  else
 #    error unsupported platform
 #  endif
diff --git a/vulkan/vulkan_shared.hpp b/vulkan/vulkan_shared.hpp
new file mode 100644 (file)
index 0000000..b3fb82a
--- /dev/null
@@ -0,0 +1,1069 @@
+// Copyright 2015-2023 The Khronos Group Inc.
+//
+// SPDX-License-Identifier: Apache-2.0 OR MIT
+//
+
+// This header is generated from the Khronos Vulkan XML API Registry.
+
+#ifndef VULKAN_SHARED_HPP
+#define VULKAN_SHARED_HPP
+
+#include <atomic>  // std::atomic_size_t
+#include <vulkan/vulkan.hpp>
+
+namespace VULKAN_HPP_NAMESPACE
+{
+#if !defined( VULKAN_HPP_NO_SMART_HANDLE )
+
+  template <typename HandleType>
+  class SharedHandleTraits;
+
+  class NoDestructor
+  {
+  };
+
+  template <typename HandleType, typename = void>
+  struct HasDestructorType : std::false_type
+  {
+  };
+
+  template <typename HandleType>
+  struct HasDestructorType<HandleType, decltype( (void)typename SharedHandleTraits<HandleType>::DestructorType() )> : std::true_type
+  {
+  };
+
+  template <typename HandleType, typename Enable = void>
+  struct GetDestructorType
+  {
+    using type = NoDestructor;
+  };
+
+  template <typename HandleType>
+  struct GetDestructorType<HandleType, typename std::enable_if<HasDestructorType<HandleType>::value>::type>
+  {
+    using type = typename SharedHandleTraits<HandleType>::DestructorType;
+  };
+
+  template <class HandleType>
+  using DestructorTypeOf = typename GetDestructorType<HandleType>::type;
+
+  template <class HandleType>
+  struct HasDestructor : std::integral_constant<bool, !std::is_same<DestructorTypeOf<HandleType>, NoDestructor>::value>
+  {
+  };
+
+  //=====================================================================================================================
+
+  template <typename HandleType>
+  class SharedHandle;
+
+  template <typename DestructorType, typename Deleter>
+  struct SharedHeader
+  {
+    SharedHeader( SharedHandle<DestructorType> parent, Deleter deleter = Deleter() ) VULKAN_HPP_NOEXCEPT
+      : parent( std::move( parent ) )
+      , deleter( std::move( deleter ) )
+    {
+    }
+
+    SharedHandle<DestructorType> parent;
+    Deleter                      deleter;
+  };
+
+  template <typename Deleter>
+  struct SharedHeader<NoDestructor, Deleter>
+  {
+    SharedHeader( Deleter deleter = Deleter() ) VULKAN_HPP_NOEXCEPT : deleter( std::move( deleter ) ) {}
+
+    Deleter deleter;
+  };
+
+  //=====================================================================================================================
+
+  template <typename HeaderType>
+  class ReferenceCounter
+  {
+  public:
+    template <typename... Args>
+    ReferenceCounter( Args &&... control_args ) : m_header( std::forward<Args>( control_args )... )
+    {
+    }
+
+    ReferenceCounter( const ReferenceCounter & )             = delete;
+    ReferenceCounter & operator=( const ReferenceCounter & ) = delete;
+
+  public:
+    size_t addRef() VULKAN_HPP_NOEXCEPT
+    {
+      // Relaxed memory order is sufficient since this does not impose any ordering on other operations
+      return m_ref_cnt.fetch_add( 1, std::memory_order_relaxed );
+    }
+
+    size_t release() VULKAN_HPP_NOEXCEPT
+    {
+      // A release memory order to ensure that all releases are ordered
+      return m_ref_cnt.fetch_sub( 1, std::memory_order_release );
+    }
+
+  public:
+    std::atomic_size_t m_ref_cnt{ 1 };
+    HeaderType         m_header{};
+  };
+
+  //=====================================================================================================================
+
+  template <typename HandleType, typename HeaderType, typename ForwardType = SharedHandle<HandleType>>
+  class SharedHandleBase
+  {
+  public:
+    SharedHandleBase() = default;
+
+    template <typename... Args>
+    SharedHandleBase( HandleType handle, Args &&... control_args )
+      : m_control( new ReferenceCounter<HeaderType>( std::forward<Args>( control_args )... ) ), m_handle( handle )
+    {
+    }
+
+    SharedHandleBase( const SharedHandleBase & o ) VULKAN_HPP_NOEXCEPT
+    {
+      o.addRef();
+      m_handle  = o.m_handle;
+      m_control = o.m_control;
+    }
+
+    SharedHandleBase( SharedHandleBase && o ) VULKAN_HPP_NOEXCEPT
+      : m_control( o.m_control )
+      , m_handle( o.m_handle )
+    {
+      o.m_handle  = nullptr;
+      o.m_control = nullptr;
+    }
+
+    SharedHandleBase & operator=( const SharedHandleBase & o ) VULKAN_HPP_NOEXCEPT
+    {
+      SharedHandleBase( o ).swap( *this );
+      return *this;
+    }
+
+    SharedHandleBase & operator=( SharedHandleBase && o ) VULKAN_HPP_NOEXCEPT
+    {
+      SharedHandleBase( std::move( o ) ).swap( *this );
+      return *this;
+    }
+
+    ~SharedHandleBase()
+    {
+      // only this function owns the last reference to the control block
+      // the same principle is used in the default deleter of std::shared_ptr
+      if ( m_control && ( m_control->release() == 1 ) )
+      {
+        // noop in x86, but does thread synchronization in ARM
+        // it is required to ensure that last thread is getting to destroy the control block
+        // by ordering all atomic operations before this fence
+        std::atomic_thread_fence( std::memory_order_acquire );
+        ForwardType::internalDestroy( getHeader(), m_handle );
+        delete m_control;
+      }
+    }
+
+  public:
+    HandleType get() const VULKAN_HPP_NOEXCEPT
+    {
+      return m_handle;
+    }
+
+    HandleType operator*() const VULKAN_HPP_NOEXCEPT
+    {
+      return m_handle;
+    }
+
+    explicit operator bool() const VULKAN_HPP_NOEXCEPT
+    {
+      return bool( m_handle );
+    }
+
+    const HandleType * operator->() const VULKAN_HPP_NOEXCEPT
+    {
+      return &m_handle;
+    }
+
+    HandleType * operator->() VULKAN_HPP_NOEXCEPT
+    {
+      return &m_handle;
+    }
+
+    void reset() VULKAN_HPP_NOEXCEPT
+    {
+      SharedHandleBase().swap( *this );
+    }
+
+    void swap( SharedHandleBase & o ) VULKAN_HPP_NOEXCEPT
+    {
+      std::swap( m_handle, o.m_handle );
+      std::swap( m_control, o.m_control );
+    }
+
+    template <typename T = HandleType>
+    typename std::enable_if<HasDestructor<T>::value, const SharedHandle<DestructorTypeOf<HandleType>> &>::type getDestructorType() const VULKAN_HPP_NOEXCEPT
+    {
+      return getHeader().parent;
+    }
+
+  protected:
+    template <typename T = HandleType>
+    static typename std::enable_if<!HasDestructor<T>::value, void>::type internalDestroy( const HeaderType & control, HandleType handle ) VULKAN_HPP_NOEXCEPT
+    {
+      control.deleter.destroy( handle );
+    }
+
+    template <typename T = HandleType>
+    static typename std::enable_if<HasDestructor<T>::value, void>::type internalDestroy( const HeaderType & control, HandleType handle ) VULKAN_HPP_NOEXCEPT
+    {
+      control.deleter.destroy( control.parent.get(), handle );
+    }
+
+    const HeaderType & getHeader() const VULKAN_HPP_NOEXCEPT
+    {
+      return m_control->m_header;
+    }
+
+  private:
+    void addRef() const VULKAN_HPP_NOEXCEPT
+    {
+      if ( m_control )
+        m_control->addRef();
+    }
+
+  protected:
+    ReferenceCounter<HeaderType> * m_control = nullptr;
+    HandleType                     m_handle{};
+  };
+
+  template <typename HandleType>
+  class SharedHandle : public SharedHandleBase<HandleType, SharedHeader<DestructorTypeOf<HandleType>, typename SharedHandleTraits<HandleType>::deleter>>
+  {
+  private:
+    using BaseType    = SharedHandleBase<HandleType, SharedHeader<DestructorTypeOf<HandleType>, typename SharedHandleTraits<HandleType>::deleter>>;
+    using DeleterType = typename SharedHandleTraits<HandleType>::deleter;
+    friend BaseType;
+
+  public:
+    SharedHandle() = default;
+
+    template <typename T = HandleType, typename = typename std::enable_if<HasDestructor<T>::value>::type>
+    explicit SharedHandle( HandleType handle, SharedHandle<DestructorTypeOf<HandleType>> parent, DeleterType deleter = DeleterType() ) VULKAN_HPP_NOEXCEPT
+      : BaseType( handle, std::move( parent ), std::move( deleter ) )
+    {
+    }
+
+    template <typename T = HandleType, typename = typename std::enable_if<!HasDestructor<T>::value>::type>
+    explicit SharedHandle( HandleType handle, DeleterType deleter = DeleterType() ) VULKAN_HPP_NOEXCEPT : BaseType( handle, std::move( deleter ) )
+    {
+    }
+
+  protected:
+    using BaseType::internalDestroy;
+  };
+
+  template <typename HandleType>
+  class SharedHandleTraits;
+
+// Silence the function cast warnings.
+#  if defined( __GNUC__ ) && !defined( __clang__ ) && !defined( __INTEL_COMPILER )
+#    pragma GCC diagnostic push
+#    pragma GCC diagnostic ignored "-Wcast-function-type"
+#  endif
+
+  template <typename HandleType>
+  class ObjectDestroyShared
+  {
+  public:
+    using DestructorType = typename SharedHandleTraits<HandleType>::DestructorType;
+
+    template <class Dispatcher>
+    using DestroyFunctionPointerType =
+      typename std::conditional<HasDestructor<HandleType>::value,
+                                void ( DestructorType::* )( HandleType, const AllocationCallbacks *, const Dispatcher & ) const,
+                                void ( HandleType::* )( const AllocationCallbacks *, const Dispatcher & ) const>::type;
+
+    using SelectorType = typename std::conditional<HasDestructor<HandleType>::value, DestructorType, HandleType>::type;
+
+    template <typename Dispatcher = VULKAN_HPP_DEFAULT_DISPATCHER_TYPE>
+    ObjectDestroyShared( Optional<const AllocationCallbacks> allocationCallbacks VULKAN_HPP_DEFAULT_ARGUMENT_NULLPTR_ASSIGNMENT,
+                         const Dispatcher & dispatch                             VULKAN_HPP_DEFAULT_DISPATCHER_ASSIGNMENT )
+      : m_destroy( reinterpret_cast<decltype( m_destroy )>( static_cast<DestroyFunctionPointerType<Dispatcher>>( &SelectorType::destroy ) ) )
+      , m_dispatch( &dispatch )
+      , m_allocationCallbacks( allocationCallbacks )
+    {
+    }
+
+  public:
+    template <typename T = HandleType>
+    typename std::enable_if<HasDestructor<T>::value, void>::type destroy( DestructorType parent, HandleType handle ) const VULKAN_HPP_NOEXCEPT
+    {
+      VULKAN_HPP_ASSERT( m_destroy && m_dispatch );
+      ( parent.*m_destroy )( handle, m_allocationCallbacks, *m_dispatch );
+    }
+
+    template <typename T = HandleType>
+    typename std::enable_if<!HasDestructor<T>::value, void>::type destroy( HandleType handle ) const VULKAN_HPP_NOEXCEPT
+    {
+      VULKAN_HPP_ASSERT( m_destroy && m_dispatch );
+      ( handle.*m_destroy )( m_allocationCallbacks, *m_dispatch );
+    }
+
+  private:
+    DestroyFunctionPointerType<DispatchLoaderBase> m_destroy             = nullptr;
+    const DispatchLoaderBase *                     m_dispatch            = nullptr;
+    Optional<const AllocationCallbacks>            m_allocationCallbacks = nullptr;
+  };
+
+  template <typename HandleType>
+  class ObjectFreeShared
+  {
+  public:
+    using DestructorType = typename SharedHandleTraits<HandleType>::DestructorType;
+
+    template <class Dispatcher>
+    using DestroyFunctionPointerType = void ( DestructorType::* )( HandleType, const AllocationCallbacks *, const Dispatcher & ) const;
+
+    template <class Dispatcher = VULKAN_HPP_DEFAULT_DISPATCHER_TYPE>
+    ObjectFreeShared( Optional<const AllocationCallbacks> allocationCallbacks VULKAN_HPP_DEFAULT_ARGUMENT_NULLPTR_ASSIGNMENT,
+                      const Dispatcher & dispatch                             VULKAN_HPP_DEFAULT_DISPATCHER_ASSIGNMENT )
+      : m_destroy( reinterpret_cast<decltype( m_destroy )>( static_cast<DestroyFunctionPointerType<Dispatcher>>( &DestructorType::free ) ) )
+      , m_dispatch( &dispatch )
+      , m_allocationCallbacks( allocationCallbacks )
+    {
+    }
+
+  public:
+    void destroy( DestructorType parent, HandleType handle ) const VULKAN_HPP_NOEXCEPT
+    {
+      VULKAN_HPP_ASSERT( m_destroy && m_dispatch );
+      ( parent.*m_destroy )( handle, m_allocationCallbacks, *m_dispatch );
+    }
+
+  private:
+    DestroyFunctionPointerType<DispatchLoaderBase> m_destroy             = nullptr;
+    const DispatchLoaderBase *                     m_dispatch            = nullptr;
+    Optional<const AllocationCallbacks>            m_allocationCallbacks = nullptr;
+  };
+
+  template <typename HandleType>
+  class ObjectReleaseShared
+  {
+  public:
+    using DestructorType = typename SharedHandleTraits<HandleType>::DestructorType;
+
+    template <class Dispatcher>
+    using DestroyFunctionPointerType = void ( DestructorType::* )( HandleType, const Dispatcher & ) const;
+
+    template <class Dispatcher = VULKAN_HPP_DEFAULT_DISPATCHER_TYPE>
+    ObjectReleaseShared( const Dispatcher & dispatch VULKAN_HPP_DEFAULT_DISPATCHER_ASSIGNMENT )
+      : m_destroy( reinterpret_cast<decltype( m_destroy )>( static_cast<DestroyFunctionPointerType<Dispatcher>>( &DestructorType::release ) ) )
+      , m_dispatch( &dispatch )
+    {
+    }
+
+  public:
+    void destroy( DestructorType parent, HandleType handle ) const VULKAN_HPP_NOEXCEPT
+    {
+      VULKAN_HPP_ASSERT( m_destroy && m_dispatch );
+      ( parent.*m_destroy )( handle, *m_dispatch );
+    }
+
+  private:
+    DestroyFunctionPointerType<DispatchLoaderBase> m_destroy  = nullptr;
+    const DispatchLoaderBase *                     m_dispatch = nullptr;
+  };
+
+  template <typename HandleType, typename PoolType>
+  class PoolFreeShared
+  {
+  public:
+    using DestructorType = typename SharedHandleTraits<HandleType>::DestructorType;
+
+    template <class Dispatcher>
+    using ReturnType = decltype( std::declval<DestructorType>().free( PoolType(), 0u, nullptr, Dispatcher() ) );
+
+    template <class Dispatcher>
+    using DestroyFunctionPointerType = ReturnType<Dispatcher> ( DestructorType::* )( PoolType, uint32_t, const HandleType *, const Dispatcher & ) const;
+
+    PoolFreeShared() = default;
+
+    template <class Dispatcher = VULKAN_HPP_DEFAULT_DISPATCHER_TYPE>
+    PoolFreeShared( SharedHandle<PoolType> pool, const Dispatcher & dispatch VULKAN_HPP_DEFAULT_DISPATCHER_ASSIGNMENT )
+      : m_destroy( reinterpret_cast<decltype( m_destroy )>( static_cast<DestroyFunctionPointerType<Dispatcher>>( &DestructorType::free ) ) )
+      , m_dispatch( &dispatch )
+      , m_pool( std::move( pool ) )
+    {
+    }
+
+  public:
+    void destroy( DestructorType parent, HandleType handle ) const VULKAN_HPP_NOEXCEPT
+    {
+      VULKAN_HPP_ASSERT( m_destroy && m_dispatch );
+      ( parent.*m_destroy )( m_pool.get(), 1u, &handle, *m_dispatch );
+    }
+
+  private:
+    DestroyFunctionPointerType<DispatchLoaderBase> m_destroy  = nullptr;
+    const DispatchLoaderBase *                     m_dispatch = nullptr;
+    SharedHandle<PoolType>                         m_pool{};
+  };
+
+#  if defined( __GNUC__ ) && !defined( __clang__ ) && !defined( __INTEL_COMPILER )
+#    pragma GCC diagnostic pop
+#  endif
+
+  //======================
+  //=== SHARED HANDLEs ===
+  //======================
+
+  //=== VK_VERSION_1_0 ===
+  template <>
+  class SharedHandleTraits<Instance>
+  {
+  public:
+    using DestructorType = NoDestructor;
+    using deleter        = ObjectDestroyShared<Instance>;
+  };
+
+  using SharedInstance = SharedHandle<Instance>;
+
+  template <>
+  class SharedHandleTraits<Device>
+  {
+  public:
+    using DestructorType = NoDestructor;
+    using deleter        = ObjectDestroyShared<Device>;
+  };
+
+  using SharedDevice = SharedHandle<Device>;
+
+  template <>
+  class SharedHandleTraits<DeviceMemory>
+  {
+  public:
+    using DestructorType = Device;
+    using deleter        = ObjectFreeShared<DeviceMemory>;
+  };
+
+  using SharedDeviceMemory = SharedHandle<DeviceMemory>;
+
+  template <>
+  class SharedHandleTraits<Fence>
+  {
+  public:
+    using DestructorType = Device;
+    using deleter        = ObjectDestroyShared<Fence>;
+  };
+
+  using SharedFence = SharedHandle<Fence>;
+
+  template <>
+  class SharedHandleTraits<Semaphore>
+  {
+  public:
+    using DestructorType = Device;
+    using deleter        = ObjectDestroyShared<Semaphore>;
+  };
+
+  using SharedSemaphore = SharedHandle<Semaphore>;
+
+  template <>
+  class SharedHandleTraits<Event>
+  {
+  public:
+    using DestructorType = Device;
+    using deleter        = ObjectDestroyShared<Event>;
+  };
+
+  using SharedEvent = SharedHandle<Event>;
+
+  template <>
+  class SharedHandleTraits<QueryPool>
+  {
+  public:
+    using DestructorType = Device;
+    using deleter        = ObjectDestroyShared<QueryPool>;
+  };
+
+  using SharedQueryPool = SharedHandle<QueryPool>;
+
+  template <>
+  class SharedHandleTraits<Buffer>
+  {
+  public:
+    using DestructorType = Device;
+    using deleter        = ObjectDestroyShared<Buffer>;
+  };
+
+  using SharedBuffer = SharedHandle<Buffer>;
+
+  template <>
+  class SharedHandleTraits<BufferView>
+  {
+  public:
+    using DestructorType = Device;
+    using deleter        = ObjectDestroyShared<BufferView>;
+  };
+
+  using SharedBufferView = SharedHandle<BufferView>;
+
+  template <>
+  class SharedHandleTraits<Image>
+  {
+  public:
+    using DestructorType = Device;
+    using deleter        = ObjectDestroyShared<Image>;
+  };
+
+  using SharedImage = SharedHandle<Image>;
+
+  template <>
+  class SharedHandleTraits<ImageView>
+  {
+  public:
+    using DestructorType = Device;
+    using deleter        = ObjectDestroyShared<ImageView>;
+  };
+
+  using SharedImageView = SharedHandle<ImageView>;
+
+  template <>
+  class SharedHandleTraits<ShaderModule>
+  {
+  public:
+    using DestructorType = Device;
+    using deleter        = ObjectDestroyShared<ShaderModule>;
+  };
+
+  using SharedShaderModule = SharedHandle<ShaderModule>;
+
+  template <>
+  class SharedHandleTraits<PipelineCache>
+  {
+  public:
+    using DestructorType = Device;
+    using deleter        = ObjectDestroyShared<PipelineCache>;
+  };
+
+  using SharedPipelineCache = SharedHandle<PipelineCache>;
+
+  template <>
+  class SharedHandleTraits<Pipeline>
+  {
+  public:
+    using DestructorType = Device;
+    using deleter        = ObjectDestroyShared<Pipeline>;
+  };
+
+  using SharedPipeline = SharedHandle<Pipeline>;
+
+  template <>
+  class SharedHandleTraits<PipelineLayout>
+  {
+  public:
+    using DestructorType = Device;
+    using deleter        = ObjectDestroyShared<PipelineLayout>;
+  };
+
+  using SharedPipelineLayout = SharedHandle<PipelineLayout>;
+
+  template <>
+  class SharedHandleTraits<Sampler>
+  {
+  public:
+    using DestructorType = Device;
+    using deleter        = ObjectDestroyShared<Sampler>;
+  };
+
+  using SharedSampler = SharedHandle<Sampler>;
+
+  template <>
+  class SharedHandleTraits<DescriptorPool>
+  {
+  public:
+    using DestructorType = Device;
+    using deleter        = ObjectDestroyShared<DescriptorPool>;
+  };
+
+  using SharedDescriptorPool = SharedHandle<DescriptorPool>;
+
+  template <>
+  class SharedHandleTraits<DescriptorSet>
+  {
+  public:
+    using DestructorType = Device;
+    using deleter        = PoolFreeShared<DescriptorSet, DescriptorPool>;
+  };
+
+  using SharedDescriptorSet = SharedHandle<DescriptorSet>;
+
+  template <>
+  class SharedHandleTraits<DescriptorSetLayout>
+  {
+  public:
+    using DestructorType = Device;
+    using deleter        = ObjectDestroyShared<DescriptorSetLayout>;
+  };
+
+  using SharedDescriptorSetLayout = SharedHandle<DescriptorSetLayout>;
+
+  template <>
+  class SharedHandleTraits<Framebuffer>
+  {
+  public:
+    using DestructorType = Device;
+    using deleter        = ObjectDestroyShared<Framebuffer>;
+  };
+
+  using SharedFramebuffer = SharedHandle<Framebuffer>;
+
+  template <>
+  class SharedHandleTraits<RenderPass>
+  {
+  public:
+    using DestructorType = Device;
+    using deleter        = ObjectDestroyShared<RenderPass>;
+  };
+
+  using SharedRenderPass = SharedHandle<RenderPass>;
+
+  template <>
+  class SharedHandleTraits<CommandPool>
+  {
+  public:
+    using DestructorType = Device;
+    using deleter        = ObjectDestroyShared<CommandPool>;
+  };
+
+  using SharedCommandPool = SharedHandle<CommandPool>;
+
+  template <>
+  class SharedHandleTraits<CommandBuffer>
+  {
+  public:
+    using DestructorType = Device;
+    using deleter        = PoolFreeShared<CommandBuffer, CommandPool>;
+  };
+
+  using SharedCommandBuffer = SharedHandle<CommandBuffer>;
+
+  //=== VK_VERSION_1_1 ===
+  template <>
+  class SharedHandleTraits<SamplerYcbcrConversion>
+  {
+  public:
+    using DestructorType = Device;
+    using deleter        = ObjectDestroyShared<SamplerYcbcrConversion>;
+  };
+
+  using SharedSamplerYcbcrConversion    = SharedHandle<SamplerYcbcrConversion>;
+  using SharedSamplerYcbcrConversionKHR = SharedHandle<SamplerYcbcrConversion>;
+
+  template <>
+  class SharedHandleTraits<DescriptorUpdateTemplate>
+  {
+  public:
+    using DestructorType = Device;
+    using deleter        = ObjectDestroyShared<DescriptorUpdateTemplate>;
+  };
+
+  using SharedDescriptorUpdateTemplate    = SharedHandle<DescriptorUpdateTemplate>;
+  using SharedDescriptorUpdateTemplateKHR = SharedHandle<DescriptorUpdateTemplate>;
+
+  //=== VK_VERSION_1_3 ===
+  template <>
+  class SharedHandleTraits<PrivateDataSlot>
+  {
+  public:
+    using DestructorType = Device;
+    using deleter        = ObjectDestroyShared<PrivateDataSlot>;
+  };
+
+  using SharedPrivateDataSlot    = SharedHandle<PrivateDataSlot>;
+  using SharedPrivateDataSlotEXT = SharedHandle<PrivateDataSlot>;
+
+  //=== VK_KHR_surface ===
+  template <>
+  class SharedHandleTraits<SurfaceKHR>
+  {
+  public:
+    using DestructorType = Instance;
+    using deleter        = ObjectDestroyShared<SurfaceKHR>;
+  };
+
+  using SharedSurfaceKHR = SharedHandle<SurfaceKHR>;
+
+  //=== VK_KHR_swapchain ===
+  template <>
+  class SharedHandleTraits<SwapchainKHR>
+  {
+  public:
+    using DestructorType = Device;
+    using deleter        = ObjectDestroyShared<SwapchainKHR>;
+  };
+
+  using SharedSwapchainKHR = SharedHandle<SwapchainKHR>;
+
+  //=== VK_EXT_debug_report ===
+  template <>
+  class SharedHandleTraits<DebugReportCallbackEXT>
+  {
+  public:
+    using DestructorType = Instance;
+    using deleter        = ObjectDestroyShared<DebugReportCallbackEXT>;
+  };
+
+  using SharedDebugReportCallbackEXT = SharedHandle<DebugReportCallbackEXT>;
+
+  //=== VK_KHR_video_queue ===
+  template <>
+  class SharedHandleTraits<VideoSessionKHR>
+  {
+  public:
+    using DestructorType = Device;
+    using deleter        = ObjectDestroyShared<VideoSessionKHR>;
+  };
+
+  using SharedVideoSessionKHR = SharedHandle<VideoSessionKHR>;
+
+  template <>
+  class SharedHandleTraits<VideoSessionParametersKHR>
+  {
+  public:
+    using DestructorType = Device;
+    using deleter        = ObjectDestroyShared<VideoSessionParametersKHR>;
+  };
+
+  using SharedVideoSessionParametersKHR = SharedHandle<VideoSessionParametersKHR>;
+
+  //=== VK_NVX_binary_import ===
+  template <>
+  class SharedHandleTraits<CuModuleNVX>
+  {
+  public:
+    using DestructorType = Device;
+    using deleter        = ObjectDestroyShared<CuModuleNVX>;
+  };
+
+  using SharedCuModuleNVX = SharedHandle<CuModuleNVX>;
+
+  template <>
+  class SharedHandleTraits<CuFunctionNVX>
+  {
+  public:
+    using DestructorType = Device;
+    using deleter        = ObjectDestroyShared<CuFunctionNVX>;
+  };
+
+  using SharedCuFunctionNVX = SharedHandle<CuFunctionNVX>;
+
+  //=== VK_EXT_debug_utils ===
+  template <>
+  class SharedHandleTraits<DebugUtilsMessengerEXT>
+  {
+  public:
+    using DestructorType = Instance;
+    using deleter        = ObjectDestroyShared<DebugUtilsMessengerEXT>;
+  };
+
+  using SharedDebugUtilsMessengerEXT = SharedHandle<DebugUtilsMessengerEXT>;
+
+  //=== VK_KHR_acceleration_structure ===
+  template <>
+  class SharedHandleTraits<AccelerationStructureKHR>
+  {
+  public:
+    using DestructorType = Device;
+    using deleter        = ObjectDestroyShared<AccelerationStructureKHR>;
+  };
+
+  using SharedAccelerationStructureKHR = SharedHandle<AccelerationStructureKHR>;
+
+  //=== VK_EXT_validation_cache ===
+  template <>
+  class SharedHandleTraits<ValidationCacheEXT>
+  {
+  public:
+    using DestructorType = Device;
+    using deleter        = ObjectDestroyShared<ValidationCacheEXT>;
+  };
+
+  using SharedValidationCacheEXT = SharedHandle<ValidationCacheEXT>;
+
+  //=== VK_NV_ray_tracing ===
+  template <>
+  class SharedHandleTraits<AccelerationStructureNV>
+  {
+  public:
+    using DestructorType = Device;
+    using deleter        = ObjectDestroyShared<AccelerationStructureNV>;
+  };
+
+  using SharedAccelerationStructureNV = SharedHandle<AccelerationStructureNV>;
+
+  //=== VK_KHR_deferred_host_operations ===
+  template <>
+  class SharedHandleTraits<DeferredOperationKHR>
+  {
+  public:
+    using DestructorType = Device;
+    using deleter        = ObjectDestroyShared<DeferredOperationKHR>;
+  };
+
+  using SharedDeferredOperationKHR = SharedHandle<DeferredOperationKHR>;
+
+  //=== VK_NV_device_generated_commands ===
+  template <>
+  class SharedHandleTraits<IndirectCommandsLayoutNV>
+  {
+  public:
+    using DestructorType = Device;
+    using deleter        = ObjectDestroyShared<IndirectCommandsLayoutNV>;
+  };
+
+  using SharedIndirectCommandsLayoutNV = SharedHandle<IndirectCommandsLayoutNV>;
+
+#  if defined( VK_USE_PLATFORM_FUCHSIA )
+  //=== VK_FUCHSIA_buffer_collection ===
+  template <>
+  class SharedHandleTraits<BufferCollectionFUCHSIA>
+  {
+  public:
+    using DestructorType = Device;
+    using deleter        = ObjectDestroyShared<BufferCollectionFUCHSIA>;
+  };
+
+  using SharedBufferCollectionFUCHSIA = SharedHandle<BufferCollectionFUCHSIA>;
+#  endif /*VK_USE_PLATFORM_FUCHSIA*/
+
+  //=== VK_EXT_opacity_micromap ===
+  template <>
+  class SharedHandleTraits<MicromapEXT>
+  {
+  public:
+    using DestructorType = Device;
+    using deleter        = ObjectDestroyShared<MicromapEXT>;
+  };
+
+  using SharedMicromapEXT = SharedHandle<MicromapEXT>;
+
+  //=== VK_NV_optical_flow ===
+  template <>
+  class SharedHandleTraits<OpticalFlowSessionNV>
+  {
+  public:
+    using DestructorType = Device;
+    using deleter        = ObjectDestroyShared<OpticalFlowSessionNV>;
+  };
+
+  using SharedOpticalFlowSessionNV = SharedHandle<OpticalFlowSessionNV>;
+
+  //=== VK_EXT_shader_object ===
+  template <>
+  class SharedHandleTraits<ShaderEXT>
+  {
+  public:
+    using DestructorType = Device;
+    using deleter        = ObjectDestroyShared<ShaderEXT>;
+  };
+
+  using SharedShaderEXT = SharedHandle<ShaderEXT>;
+
+  enum class SwapchainOwns
+  {
+    no,
+    yes,
+  };
+
+  struct ImageHeader : SharedHeader<DestructorTypeOf<VULKAN_HPP_NAMESPACE::Image>, typename SharedHandleTraits<VULKAN_HPP_NAMESPACE::Image>::deleter>
+  {
+    ImageHeader(
+      SharedHandle<DestructorTypeOf<VULKAN_HPP_NAMESPACE::Image>>       parent,
+      typename SharedHandleTraits<VULKAN_HPP_NAMESPACE::Image>::deleter deleter        = typename SharedHandleTraits<VULKAN_HPP_NAMESPACE::Image>::deleter(),
+      SwapchainOwns                                                     swapchainOwned = SwapchainOwns::no ) VULKAN_HPP_NOEXCEPT
+      : SharedHeader<DestructorTypeOf<VULKAN_HPP_NAMESPACE::Image>, typename SharedHandleTraits<VULKAN_HPP_NAMESPACE::Image>::deleter>( std::move( parent ),
+                                                                                                                                        std::move( deleter ) )
+      , swapchainOwned( swapchainOwned )
+    {
+    }
+
+    SwapchainOwns swapchainOwned = SwapchainOwns::no;
+  };
+
+  template <>
+  class SharedHandle<VULKAN_HPP_NAMESPACE::Image> : public SharedHandleBase<VULKAN_HPP_NAMESPACE::Image, ImageHeader>
+  {
+    using BaseType    = SharedHandleBase<VULKAN_HPP_NAMESPACE::Image, ImageHeader>;
+    using DeleterType = typename SharedHandleTraits<VULKAN_HPP_NAMESPACE::Image>::deleter;
+    friend BaseType;
+
+  public:
+    SharedHandle() = default;
+
+    explicit SharedHandle( VULKAN_HPP_NAMESPACE::Image                                 handle,
+                           SharedHandle<DestructorTypeOf<VULKAN_HPP_NAMESPACE::Image>> parent,
+                           SwapchainOwns                                               swapchain_owned = SwapchainOwns::no,
+                           DeleterType                                                 deleter         = DeleterType() ) VULKAN_HPP_NOEXCEPT
+      : BaseType( handle, std::move( parent ), std::move( deleter ), swapchain_owned )
+    {
+    }
+
+  protected:
+    static void internalDestroy( const ImageHeader & control, VULKAN_HPP_NAMESPACE::Image handle ) VULKAN_HPP_NOEXCEPT
+    {
+      if ( control.swapchainOwned == SwapchainOwns::no )
+      {
+        control.deleter.destroy( control.parent.get(), handle );
+      }
+    }
+  };
+
+  struct SwapchainHeader
+  {
+    SwapchainHeader( SharedHandle<VULKAN_HPP_NAMESPACE::SurfaceKHR>                           surface,
+                     SharedHandle<DestructorTypeOf<VULKAN_HPP_NAMESPACE::SwapchainKHR>>       parent,
+                     typename SharedHandleTraits<VULKAN_HPP_NAMESPACE::SwapchainKHR>::deleter deleter =
+                       typename SharedHandleTraits<VULKAN_HPP_NAMESPACE::SwapchainKHR>::deleter() ) VULKAN_HPP_NOEXCEPT
+      : surface( std::move( surface ) )
+      , parent( std::move( parent ) )
+      , deleter( std::move( deleter ) )
+    {
+    }
+
+    SharedHandle<VULKAN_HPP_NAMESPACE::SurfaceKHR>                           surface{};
+    SharedHandle<DestructorTypeOf<VULKAN_HPP_NAMESPACE::SwapchainKHR>>       parent{};
+    typename SharedHandleTraits<VULKAN_HPP_NAMESPACE::SwapchainKHR>::deleter deleter{};
+  };
+
+  template <>
+  class SharedHandle<VULKAN_HPP_NAMESPACE::SwapchainKHR> : public SharedHandleBase<VULKAN_HPP_NAMESPACE::SwapchainKHR, SwapchainHeader>
+  {
+    using BaseType    = SharedHandleBase<VULKAN_HPP_NAMESPACE::SwapchainKHR, SwapchainHeader>;
+    using DeleterType = typename SharedHandleTraits<VULKAN_HPP_NAMESPACE::SwapchainKHR>::deleter;
+    friend BaseType;
+
+  public:
+    SharedHandle() = default;
+
+    explicit SharedHandle( VULKAN_HPP_NAMESPACE::SwapchainKHR                                 handle,
+                           SharedHandle<DestructorTypeOf<VULKAN_HPP_NAMESPACE::SwapchainKHR>> parent,
+                           SharedHandle<VULKAN_HPP_NAMESPACE::SurfaceKHR>                     surface,
+                           DeleterType                                                        deleter = DeleterType() ) VULKAN_HPP_NOEXCEPT
+      : BaseType( handle, std::move( surface ), std::move( parent ), std::move( deleter ) )
+    {
+    }
+
+  public:
+    const SharedHandle<VULKAN_HPP_NAMESPACE::SurfaceKHR> & getSurface() const VULKAN_HPP_NOEXCEPT
+    {
+      return getHeader().surface;
+    }
+
+  protected:
+    using BaseType::internalDestroy;
+  };
+
+  template <typename HandleType, typename DestructorType>
+  class SharedHandleBaseNoDestroy : public SharedHandleBase<HandleType, DestructorType>
+  {
+  public:
+    using SharedHandleBase<HandleType, DestructorType>::SharedHandleBase;
+
+    const DestructorType & getDestructorType() const VULKAN_HPP_NOEXCEPT
+    {
+      return SharedHandleBase<HandleType, DestructorType>::getHeader();
+    }
+
+  protected:
+    static void internalDestroy( const DestructorType &, HandleType ) VULKAN_HPP_NOEXCEPT {}
+  };
+
+  //=== VK_VERSION_1_0 ===
+
+  template <>
+  class SharedHandle<PhysicalDevice> : public SharedHandleBaseNoDestroy<PhysicalDevice, SharedInstance>
+  {
+    friend SharedHandleBase<PhysicalDevice, SharedInstance>;
+
+  public:
+    SharedHandle() = default;
+
+    explicit SharedHandle( PhysicalDevice handle, SharedInstance parent ) noexcept
+      : SharedHandleBaseNoDestroy<PhysicalDevice, SharedInstance>( handle, std::move( parent ) )
+    {
+    }
+  };
+
+  using SharedPhysicalDevice = SharedHandle<PhysicalDevice>;
+
+  template <>
+  class SharedHandle<Queue> : public SharedHandleBaseNoDestroy<Queue, SharedDevice>
+  {
+    friend SharedHandleBase<Queue, SharedDevice>;
+
+  public:
+    SharedHandle() = default;
+
+    explicit SharedHandle( Queue handle, SharedDevice parent ) noexcept : SharedHandleBaseNoDestroy<Queue, SharedDevice>( handle, std::move( parent ) ) {}
+  };
+
+  using SharedQueue = SharedHandle<Queue>;
+
+  //=== VK_KHR_display ===
+
+  template <>
+  class SharedHandle<DisplayKHR> : public SharedHandleBaseNoDestroy<DisplayKHR, SharedPhysicalDevice>
+  {
+    friend SharedHandleBase<DisplayKHR, SharedPhysicalDevice>;
+
+  public:
+    SharedHandle() = default;
+
+    explicit SharedHandle( DisplayKHR handle, SharedPhysicalDevice parent ) noexcept
+      : SharedHandleBaseNoDestroy<DisplayKHR, SharedPhysicalDevice>( handle, std::move( parent ) )
+    {
+    }
+  };
+
+  using SharedDisplayKHR = SharedHandle<DisplayKHR>;
+
+  template <>
+  class SharedHandle<DisplayModeKHR> : public SharedHandleBaseNoDestroy<DisplayModeKHR, SharedDisplayKHR>
+  {
+    friend SharedHandleBase<DisplayModeKHR, SharedDisplayKHR>;
+
+  public:
+    SharedHandle() = default;
+
+    explicit SharedHandle( DisplayModeKHR handle, SharedDisplayKHR parent ) noexcept
+      : SharedHandleBaseNoDestroy<DisplayModeKHR, SharedDisplayKHR>( handle, std::move( parent ) )
+    {
+    }
+  };
+
+  using SharedDisplayModeKHR = SharedHandle<DisplayModeKHR>;
+
+  //=== VK_INTEL_performance_query ===
+
+  template <>
+  class SharedHandle<PerformanceConfigurationINTEL> : public SharedHandleBaseNoDestroy<PerformanceConfigurationINTEL, SharedDevice>
+  {
+    friend SharedHandleBase<PerformanceConfigurationINTEL, SharedDevice>;
+
+  public:
+    SharedHandle() = default;
+
+    explicit SharedHandle( PerformanceConfigurationINTEL handle, SharedDevice parent ) noexcept
+      : SharedHandleBaseNoDestroy<PerformanceConfigurationINTEL, SharedDevice>( handle, std::move( parent ) )
+    {
+    }
+  };
+
+  using SharedPerformanceConfigurationINTEL = SharedHandle<PerformanceConfigurationINTEL>;
+#endif  // !VULKAN_HPP_NO_SMART_HANDLE
+}  // namespace VULKAN_HPP_NAMESPACE
+#endif  // VULKAN_SHARED_HPP
index 99642e0..a4ea657 100644 (file)
@@ -44,6 +44,7 @@ export namespace VULKAN_HPP_NAMESPACE
   using VULKAN_HPP_NAMESPACE::ArrayProxy;
   using VULKAN_HPP_NAMESPACE::ArrayProxyNoTemporaries;
   using VULKAN_HPP_NAMESPACE::Optional;
+  using VULKAN_HPP_NAMESPACE::SharedHandle;
   using VULKAN_HPP_NAMESPACE::StridedArrayProxy;
   using VULKAN_HPP_NAMESPACE::StructureChain;
   using VULKAN_HPP_NAMESPACE::UniqueHandle;
@@ -51,9 +52,13 @@ export namespace VULKAN_HPP_NAMESPACE
 
 #if !defined( VULKAN_HPP_NO_SMART_HANDLE )
   using VULKAN_HPP_NAMESPACE::ObjectDestroy;
+  using VULKAN_HPP_NAMESPACE::ObjectDestroyShared;
   using VULKAN_HPP_NAMESPACE::ObjectFree;
+  using VULKAN_HPP_NAMESPACE::ObjectFreeShared;
   using VULKAN_HPP_NAMESPACE::ObjectRelease;
+  using VULKAN_HPP_NAMESPACE::ObjectReleaseShared;
   using VULKAN_HPP_NAMESPACE::PoolFree;
+  using VULKAN_HPP_NAMESPACE::PoolFreeShared;
 #endif /*VULKAN_HPP_NO_SMART_HANDLE*/
 
   //==================
@@ -1344,6 +1349,65 @@ export namespace VULKAN_HPP_NAMESPACE
   using VULKAN_HPP_NAMESPACE::UniqueHandleTraits;
 #endif /*VULKAN_HPP_NO_SMART_HANDLE*/
 
+  //======================
+  //=== SHARED HANDLEs ===
+  //======================
+
+#if !defined( VULKAN_HPP_NO_SMART_HANDLE )
+
+  //=== VK_VERSION_1_0 ===
+  using VULKAN_HPP_NAMESPACE::SharedBuffer;
+  using VULKAN_HPP_NAMESPACE::SharedBufferView;
+  using VULKAN_HPP_NAMESPACE::SharedCommandBuffer;
+  using VULKAN_HPP_NAMESPACE::SharedCommandPool;
+  using VULKAN_HPP_NAMESPACE::SharedDescriptorPool;
+  using VULKAN_HPP_NAMESPACE::SharedDescriptorSet;
+  using VULKAN_HPP_NAMESPACE::SharedDescriptorSetLayout;
+  using VULKAN_HPP_NAMESPACE::SharedDevice;
+  using VULKAN_HPP_NAMESPACE::SharedDeviceMemory;
+  using VULKAN_HPP_NAMESPACE::SharedEvent;
+  using VULKAN_HPP_NAMESPACE::SharedFence;
+  using VULKAN_HPP_NAMESPACE::SharedFramebuffer;
+  using VULKAN_HPP_NAMESPACE::SharedImage;
+  using VULKAN_HPP_NAMESPACE::SharedImageView;
+  using VULKAN_HPP_NAMESPACE::SharedInstance;
+  using VULKAN_HPP_NAMESPACE::SharedPhysicalDevice;
+  using VULKAN_HPP_NAMESPACE::SharedPipeline;
+  using VULKAN_HPP_NAMESPACE::SharedPipelineCache;
+  using VULKAN_HPP_NAMESPACE::SharedPipelineLayout;
+  using VULKAN_HPP_NAMESPACE::SharedQueryPool;
+  using VULKAN_HPP_NAMESPACE::SharedQueue;
+  using VULKAN_HPP_NAMESPACE::SharedRenderPass;
+  using VULKAN_HPP_NAMESPACE::SharedSampler;
+  using VULKAN_HPP_NAMESPACE::SharedSemaphore;
+  using VULKAN_HPP_NAMESPACE::SharedShaderModule;
+
+  //=== VK_VERSION_1_1 ===
+  using VULKAN_HPP_NAMESPACE::SharedSamplerYcbcrConversion;
+
+  //=== VK_VERSION_1_3 ===
+  using VULKAN_HPP_NAMESPACE::SharedPrivateDataSlot;
+
+  //=== VK_KHR_surface ===
+  using VULKAN_HPP_NAMESPACE::SharedSurfaceKHR;
+
+  //=== VK_KHR_swapchain ===
+  using VULKAN_HPP_NAMESPACE::SharedSwapchainKHR;
+
+  //=== VK_KHR_display ===
+  using VULKAN_HPP_NAMESPACE::SharedDisplayKHR;
+  using VULKAN_HPP_NAMESPACE::SharedDisplayModeKHR;
+
+  //=== VK_EXT_debug_utils ===
+  using VULKAN_HPP_NAMESPACE::SharedDebugUtilsMessengerEXT;
+
+#  if defined( VK_USE_PLATFORM_SCI )
+  //=== VK_NV_external_sci_sync2 ===
+  using VULKAN_HPP_NAMESPACE::SharedSemaphoreSciSyncPoolNV;
+#  endif /*VK_USE_PLATFORM_SCI*/
+  using VULKAN_HPP_NAMESPACE::SharedHandleTraits;
+#endif /*VULKAN_HPP_NO_SMART_HANDLE*/
+
   //===========================
   //=== COMMAND Definitions ===
   //===========================
index 8c6a433..bf1eaca 100644 (file)
@@ -6601,7 +6601,7 @@ namespace VULKAN_HPP_NAMESPACE
 #  elif defined( __APPLE__ )
         m_library = dlopen( "libvulkan.dylib", RTLD_NOW | RTLD_LOCAL );
 #  elif defined( _WIN32 )
-          m_library = ::LoadLibraryA( "vulkan-1.dll" );
+        m_library = ::LoadLibraryA( "vulkan-1.dll" );
 #  else
 #    error unsupported platform
 #  endif
diff --git a/vulkan/vulkansc_shared.hpp b/vulkan/vulkansc_shared.hpp
new file mode 100644 (file)
index 0000000..b664254
--- /dev/null
@@ -0,0 +1,903 @@
+// Copyright 2015-2023 The Khronos Group Inc.
+//
+// SPDX-License-Identifier: Apache-2.0 OR MIT
+//
+
+// This header is generated from the Khronos Vulkan XML API Registry.
+
+#ifndef VULKAN_SHARED_HPP
+#define VULKAN_SHARED_HPP
+
+#include <atomic>  // std::atomic_size_t
+#include <vulkan/vulkansc.hpp>
+
+namespace VULKAN_HPP_NAMESPACE
+{
+#if !defined( VULKAN_HPP_NO_SMART_HANDLE )
+
+  template <typename HandleType>
+  class SharedHandleTraits;
+
+  class NoDestructor
+  {
+  };
+
+  template <typename HandleType, typename = void>
+  struct HasDestructorType : std::false_type
+  {
+  };
+
+  template <typename HandleType>
+  struct HasDestructorType<HandleType, decltype( (void)typename SharedHandleTraits<HandleType>::DestructorType() )> : std::true_type
+  {
+  };
+
+  template <typename HandleType, typename Enable = void>
+  struct GetDestructorType
+  {
+    using type = NoDestructor;
+  };
+
+  template <typename HandleType>
+  struct GetDestructorType<HandleType, typename std::enable_if<HasDestructorType<HandleType>::value>::type>
+  {
+    using type = typename SharedHandleTraits<HandleType>::DestructorType;
+  };
+
+  template <class HandleType>
+  using DestructorTypeOf = typename GetDestructorType<HandleType>::type;
+
+  template <class HandleType>
+  struct HasDestructor : std::integral_constant<bool, !std::is_same<DestructorTypeOf<HandleType>, NoDestructor>::value>
+  {
+  };
+
+  //=====================================================================================================================
+
+  template <typename HandleType>
+  class SharedHandle;
+
+  template <typename DestructorType, typename Deleter>
+  struct SharedHeader
+  {
+    SharedHandle<DestructorType> parent;
+    Deleter                      deleter;
+  };
+
+  template <typename Deleter>
+  struct SharedHeader<NoDestructor, Deleter>
+  {
+    Deleter deleter;
+  };
+
+  //=====================================================================================================================
+
+  template <typename HeaderType>
+  class ReferenceCounter
+  {
+  public:
+    template <typename... Args>
+    ReferenceCounter( Args &&... control_args ) : m_header( std::forward<Args>( control_args )... ){};
+    ReferenceCounter( const ReferenceCounter & )             = delete;
+    ReferenceCounter & operator=( const ReferenceCounter & ) = delete;
+
+  public:
+    size_t addRef() VULKAN_HPP_NOEXCEPT
+    {
+      // Relaxed memory order is sufficient since this does not impose any ordering on other operations
+      return m_ref_cnt.fetch_add( 1, std::memory_order_relaxed );
+    }
+
+    size_t release() VULKAN_HPP_NOEXCEPT
+    {
+      // A release memory order to ensure that all releases are ordered
+      return m_ref_cnt.fetch_sub( 1, std::memory_order_release );
+    }
+
+  public:
+    std::atomic_size_t m_ref_cnt{ 1 };
+    HeaderType         m_header{};
+  };
+
+  //=====================================================================================================================
+
+  template <typename HandleType, typename HeaderType, typename ForwardType = SharedHandle<HandleType>>
+  class SharedHandleBase
+  {
+  public:
+    SharedHandleBase() = default;
+
+    template <typename... Args>
+    SharedHandleBase( HandleType handle, Args &&... control_args )
+      : m_control( new ReferenceCounter<HeaderType>( std::forward<Args>( control_args )... ) ), m_handle( handle )
+    {
+    }
+
+    SharedHandleBase( const SharedHandleBase & o ) VULKAN_HPP_NOEXCEPT
+    {
+      o.addRef();
+      m_handle  = o.m_handle;
+      m_control = o.m_control;
+    }
+
+    SharedHandleBase( SharedHandleBase && o ) VULKAN_HPP_NOEXCEPT
+      : m_control( o.m_control )
+      , m_handle( o.m_handle )
+    {
+      o.m_handle  = nullptr;
+      o.m_control = nullptr;
+    }
+
+    SharedHandleBase & operator=( const SharedHandleBase & o ) VULKAN_HPP_NOEXCEPT
+    {
+      SharedHandleBase( o ).swap( *this );
+      return *this;
+    }
+
+    SharedHandleBase & operator=( SharedHandleBase && o ) VULKAN_HPP_NOEXCEPT
+    {
+      SharedHandleBase( std::move( o ) ).swap( *this );
+      return *this;
+    }
+
+    ~SharedHandleBase()
+    {
+      // only this function owns the last reference to the control block
+      // the same principle is used in the default deleter of std::shared_ptr
+      if ( m_control && ( m_control->release() == 1 ) )
+      {
+        // noop in x86, but does thread synchronization in ARM
+        // it is required to ensure that last thread is getting to destroy the control block
+        // by ordering all atomic operations before this fence
+        std::atomic_thread_fence( std::memory_order_acquire );
+        ForwardType::internalDestroy( getHeader(), m_handle );
+        delete m_control;
+      }
+    }
+
+  public:
+    HandleType get() const VULKAN_HPP_NOEXCEPT
+    {
+      return m_handle;
+    }
+
+    HandleType operator*() const VULKAN_HPP_NOEXCEPT
+    {
+      return m_handle;
+    }
+
+    explicit operator bool() const VULKAN_HPP_NOEXCEPT
+    {
+      return bool( m_handle );
+    }
+
+    const HandleType * operator->() const VULKAN_HPP_NOEXCEPT
+    {
+      return &m_handle;
+    }
+
+    HandleType * operator->() VULKAN_HPP_NOEXCEPT
+    {
+      return &m_handle;
+    }
+
+    void reset() VULKAN_HPP_NOEXCEPT
+    {
+      SharedHandleBase().swap( *this );
+    }
+
+    void swap( SharedHandleBase & o ) VULKAN_HPP_NOEXCEPT
+    {
+      std::swap( m_handle, o.m_handle );
+      std::swap( m_control, o.m_control );
+    }
+
+    template <typename T = HandleType>
+    typename std::enable_if<HasDestructor<T>::value, const SharedHandle<DestructorTypeOf<HandleType>> &>::type getDestructorType() const VULKAN_HPP_NOEXCEPT
+    {
+      return getHeader().parent;
+    }
+
+  protected:
+    template <typename T = HandleType>
+    static typename std::enable_if<!HasDestructor<T>::value, void>::type internalDestroy( const HeaderType & control, HandleType handle ) VULKAN_HPP_NOEXCEPT
+    {
+      control.deleter.destroy( handle );
+    }
+
+    template <typename T = HandleType>
+    static typename std::enable_if<HasDestructor<T>::value, void>::type internalDestroy( const HeaderType & control, HandleType handle ) VULKAN_HPP_NOEXCEPT
+    {
+      control.deleter.destroy( control.parent.get(), handle );
+    }
+
+    const HeaderType & getHeader() const VULKAN_HPP_NOEXCEPT
+    {
+      return m_control->m_header;
+    }
+
+  private:
+    void addRef() const VULKAN_HPP_NOEXCEPT
+    {
+      if ( m_control )
+        m_control->addRef();
+    }
+
+  protected:
+    ReferenceCounter<HeaderType> * m_control = nullptr;
+    HandleType                     m_handle{};
+  };
+
+  template <typename HandleType>
+  class SharedHandle : public SharedHandleBase<HandleType, SharedHeader<DestructorTypeOf<HandleType>, typename SharedHandleTraits<HandleType>::deleter>>
+  {
+  private:
+    using BaseType    = SharedHandleBase<HandleType, SharedHeader<DestructorTypeOf<HandleType>, typename SharedHandleTraits<HandleType>::deleter>>;
+    using DeleterType = typename SharedHandleTraits<HandleType>::deleter;
+    friend BaseType;
+
+  public:
+    SharedHandle() = default;
+
+    template <typename T = HandleType, typename = typename std::enable_if<HasDestructor<T>::value>::type>
+    explicit SharedHandle( HandleType handle, SharedHandle<DestructorTypeOf<HandleType>> parent, DeleterType deleter = DeleterType() ) VULKAN_HPP_NOEXCEPT
+      : BaseType( handle, std::move( parent ), std::move( deleter ) )
+    {
+    }
+
+    template <typename T = HandleType, typename = typename std::enable_if<!HasDestructor<T>::value>::type>
+    explicit SharedHandle( HandleType handle, DeleterType deleter = DeleterType() ) VULKAN_HPP_NOEXCEPT : BaseType( handle, std::move( deleter ) )
+    {
+    }
+
+  protected:
+    using BaseType::internalDestroy;
+  };
+
+  template <typename HandleType>
+  class SharedHandleTraits;
+
+  template <typename HandleType>
+  class ObjectDestroyShared
+  {
+  public:
+    using DestructorType = typename SharedHandleTraits<HandleType>::DestructorType;
+
+    template <class Dispatcher>
+    using DestroyFunctionPointerType =
+      typename std::conditional<HasDestructor<HandleType>::value,
+                                void ( DestructorType::* )( HandleType, const AllocationCallbacks *, const Dispatcher & ) const,
+                                void ( HandleType::* )( const AllocationCallbacks *, const Dispatcher & ) const>::type;
+
+    using SelectorType = typename std::conditional<HasDestructor<HandleType>::value, DestructorType, HandleType>::type;
+
+    template <typename Dispatcher = VULKAN_HPP_DEFAULT_DISPATCHER_TYPE>
+    ObjectDestroyShared( Optional<const AllocationCallbacks> allocationCallbacks VULKAN_HPP_DEFAULT_ARGUMENT_NULLPTR_ASSIGNMENT,
+                         const Dispatcher & dispatch                             VULKAN_HPP_DEFAULT_DISPATCHER_ASSIGNMENT )
+      : m_destroy( reinterpret_cast<decltype( m_destroy )>( static_cast<DestroyFunctionPointerType<Dispatcher>>( &SelectorType::destroy ) ) )
+      , m_dispatch( &dispatch )
+      , m_allocationCallbacks( allocationCallbacks )
+    {
+    }
+
+  public:
+    template <typename T = HandleType>
+    typename std::enable_if<HasDestructor<T>::value, void>::type destroy( DestructorType parent, HandleType handle ) const VULKAN_HPP_NOEXCEPT
+    {
+      VULKAN_HPP_ASSERT( m_destroy && m_dispatch );
+      ( parent.*m_destroy )( handle, m_allocationCallbacks, *m_dispatch );
+    }
+
+    template <typename T = HandleType>
+    typename std::enable_if<!HasDestructor<T>::value, void>::type destroy( HandleType handle ) const VULKAN_HPP_NOEXCEPT
+    {
+      VULKAN_HPP_ASSERT( m_destroy && m_dispatch );
+      ( handle.*m_destroy )( m_allocationCallbacks, *m_dispatch );
+    }
+
+  private:
+    DestroyFunctionPointerType<DispatchLoaderBase> m_destroy             = nullptr;
+    const DispatchLoaderBase *                     m_dispatch            = nullptr;
+    Optional<const AllocationCallbacks>            m_allocationCallbacks = nullptr;
+  };
+
+  template <typename HandleType>
+  class ObjectFreeShared
+  {
+  public:
+    using DestructorType = typename SharedHandleTraits<HandleType>::DestructorType;
+
+    template <class Dispatcher>
+    using DestroyFunctionPointerType = void ( DestructorType::* )( HandleType, const AllocationCallbacks *, const Dispatcher & ) const;
+
+    template <class Dispatcher = VULKAN_HPP_DEFAULT_DISPATCHER_TYPE>
+    ObjectFreeShared( Optional<const AllocationCallbacks> allocationCallbacks VULKAN_HPP_DEFAULT_ARGUMENT_NULLPTR_ASSIGNMENT,
+                      const Dispatcher & dispatch                             VULKAN_HPP_DEFAULT_DISPATCHER_ASSIGNMENT )
+      : m_destroy( reinterpret_cast<decltype( m_destroy )>( static_cast<DestroyFunctionPointerType<Dispatcher>>( &DestructorType::free ) ) )
+      , m_dispatch( &dispatch )
+      , m_allocationCallbacks( allocationCallbacks )
+    {
+    }
+
+  public:
+    void destroy( DestructorType parent, HandleType handle ) const VULKAN_HPP_NOEXCEPT
+    {
+      VULKAN_HPP_ASSERT( m_destroy && m_dispatch );
+      ( parent.*m_destroy )( handle, m_allocationCallbacks, *m_dispatch );
+    }
+
+  private:
+    DestroyFunctionPointerType<DispatchLoaderBase> m_destroy             = nullptr;
+    const DispatchLoaderBase *                     m_dispatch            = nullptr;
+    Optional<const AllocationCallbacks>            m_allocationCallbacks = nullptr;
+  };
+
+  template <typename HandleType>
+  class ObjectReleaseShared
+  {
+  public:
+    using DestructorType = typename SharedHandleTraits<HandleType>::DestructorType;
+
+    template <class Dispatcher>
+    using DestroyFunctionPointerType = void ( DestructorType::* )( HandleType, const Dispatcher & ) const;
+
+    template <class Dispatcher = VULKAN_HPP_DEFAULT_DISPATCHER_TYPE>
+    ObjectReleaseShared( const Dispatcher & dispatch VULKAN_HPP_DEFAULT_DISPATCHER_ASSIGNMENT )
+      : m_destroy( reinterpret_cast<decltype( m_destroy )>( static_cast<DestroyFunctionPointerType<Dispatcher>>( &DestructorType::release ) ) )
+      , m_dispatch( &dispatch )
+    {
+    }
+
+  public:
+    void destroy( DestructorType parent, HandleType handle ) const VULKAN_HPP_NOEXCEPT
+    {
+      VULKAN_HPP_ASSERT( m_destroy && m_dispatch );
+      ( parent.*m_destroy )( handle, *m_dispatch );
+    }
+
+  private:
+    DestroyFunctionPointerType<DispatchLoaderBase> m_destroy  = nullptr;
+    const DispatchLoaderBase *                     m_dispatch = nullptr;
+  };
+
+  template <typename HandleType, typename PoolType>
+  class PoolFreeShared
+  {
+  public:
+    using DestructorType = typename SharedHandleTraits<HandleType>::DestructorType;
+
+    template <class Dispatcher>
+    using ReturnType = decltype( std::declval<DestructorType>().free( PoolType(), 0u, nullptr, Dispatcher() ) );
+
+    template <class Dispatcher>
+    using DestroyFunctionPointerType = ReturnType<Dispatcher> ( DestructorType::* )( PoolType, uint32_t, const HandleType *, const Dispatcher & ) const;
+
+    PoolFreeShared() = default;
+
+    template <class Dispatcher = VULKAN_HPP_DEFAULT_DISPATCHER_TYPE>
+    PoolFreeShared( SharedHandle<PoolType> pool, const Dispatcher & dispatch VULKAN_HPP_DEFAULT_DISPATCHER_ASSIGNMENT )
+      : m_destroy( reinterpret_cast<decltype( m_destroy )>( static_cast<DestroyFunctionPointerType<Dispatcher>>( &DestructorType::free ) ) )
+      , m_dispatch( &dispatch )
+      , m_pool( std::move( pool ) )
+    {
+    }
+
+  public:
+    void destroy( DestructorType parent, HandleType handle ) const VULKAN_HPP_NOEXCEPT
+    {
+      VULKAN_HPP_ASSERT( m_destroy && m_dispatch );
+      ( parent.*m_destroy )( m_pool.get(), 1u, &handle, *m_dispatch );
+    }
+
+  private:
+    DestroyFunctionPointerType<DispatchLoaderBase> m_destroy  = nullptr;
+    const DispatchLoaderBase *                     m_dispatch = nullptr;
+    SharedHandle<PoolType>                         m_pool{};
+  };
+
+  //======================
+  //=== SHARED HANDLEs ===
+  //======================
+
+  //=== VK_VERSION_1_0 ===
+  template <>
+  class SharedHandleTraits<Instance>
+  {
+  public:
+    using DestructorType = NoDestructor;
+    using deleter        = ObjectDestroyShared<Instance>;
+  };
+
+  using SharedInstance = SharedHandle<Instance>;
+
+  template <>
+  class SharedHandleTraits<Device>
+  {
+  public:
+    using DestructorType = NoDestructor;
+    using deleter        = ObjectDestroyShared<Device>;
+  };
+
+  using SharedDevice = SharedHandle<Device>;
+
+  template <>
+  class SharedHandleTraits<Fence>
+  {
+  public:
+    using DestructorType = Device;
+    using deleter        = ObjectDestroyShared<Fence>;
+  };
+
+  using SharedFence = SharedHandle<Fence>;
+
+  template <>
+  class SharedHandleTraits<Semaphore>
+  {
+  public:
+    using DestructorType = Device;
+    using deleter        = ObjectDestroyShared<Semaphore>;
+  };
+
+  using SharedSemaphore = SharedHandle<Semaphore>;
+
+  template <>
+  class SharedHandleTraits<Event>
+  {
+  public:
+    using DestructorType = Device;
+    using deleter        = ObjectDestroyShared<Event>;
+  };
+
+  using SharedEvent = SharedHandle<Event>;
+
+  template <>
+  class SharedHandleTraits<Buffer>
+  {
+  public:
+    using DestructorType = Device;
+    using deleter        = ObjectDestroyShared<Buffer>;
+  };
+
+  using SharedBuffer = SharedHandle<Buffer>;
+
+  template <>
+  class SharedHandleTraits<BufferView>
+  {
+  public:
+    using DestructorType = Device;
+    using deleter        = ObjectDestroyShared<BufferView>;
+  };
+
+  using SharedBufferView = SharedHandle<BufferView>;
+
+  template <>
+  class SharedHandleTraits<Image>
+  {
+  public:
+    using DestructorType = Device;
+    using deleter        = ObjectDestroyShared<Image>;
+  };
+
+  using SharedImage = SharedHandle<Image>;
+
+  template <>
+  class SharedHandleTraits<ImageView>
+  {
+  public:
+    using DestructorType = Device;
+    using deleter        = ObjectDestroyShared<ImageView>;
+  };
+
+  using SharedImageView = SharedHandle<ImageView>;
+
+  template <>
+  class SharedHandleTraits<PipelineCache>
+  {
+  public:
+    using DestructorType = Device;
+    using deleter        = ObjectDestroyShared<PipelineCache>;
+  };
+
+  using SharedPipelineCache = SharedHandle<PipelineCache>;
+
+  template <>
+  class SharedHandleTraits<Pipeline>
+  {
+  public:
+    using DestructorType = Device;
+    using deleter        = ObjectDestroyShared<Pipeline>;
+  };
+
+  using SharedPipeline = SharedHandle<Pipeline>;
+
+  template <>
+  class SharedHandleTraits<PipelineLayout>
+  {
+  public:
+    using DestructorType = Device;
+    using deleter        = ObjectDestroyShared<PipelineLayout>;
+  };
+
+  using SharedPipelineLayout = SharedHandle<PipelineLayout>;
+
+  template <>
+  class SharedHandleTraits<Sampler>
+  {
+  public:
+    using DestructorType = Device;
+    using deleter        = ObjectDestroyShared<Sampler>;
+  };
+
+  using SharedSampler = SharedHandle<Sampler>;
+
+  template <>
+  class SharedHandleTraits<DescriptorSet>
+  {
+  public:
+    using DestructorType = Device;
+    using deleter        = PoolFreeShared<DescriptorSet, DescriptorPool>;
+  };
+
+  using SharedDescriptorSet = SharedHandle<DescriptorSet>;
+
+  template <>
+  class SharedHandleTraits<DescriptorSetLayout>
+  {
+  public:
+    using DestructorType = Device;
+    using deleter        = ObjectDestroyShared<DescriptorSetLayout>;
+  };
+
+  using SharedDescriptorSetLayout = SharedHandle<DescriptorSetLayout>;
+
+  template <>
+  class SharedHandleTraits<Framebuffer>
+  {
+  public:
+    using DestructorType = Device;
+    using deleter        = ObjectDestroyShared<Framebuffer>;
+  };
+
+  using SharedFramebuffer = SharedHandle<Framebuffer>;
+
+  template <>
+  class SharedHandleTraits<RenderPass>
+  {
+  public:
+    using DestructorType = Device;
+    using deleter        = ObjectDestroyShared<RenderPass>;
+  };
+
+  using SharedRenderPass = SharedHandle<RenderPass>;
+
+  template <>
+  class SharedHandleTraits<CommandBuffer>
+  {
+  public:
+    using DestructorType = Device;
+    using deleter        = PoolFreeShared<CommandBuffer, CommandPool>;
+  };
+
+  using SharedCommandBuffer = SharedHandle<CommandBuffer>;
+
+  //=== VK_VERSION_1_1 ===
+  template <>
+  class SharedHandleTraits<SamplerYcbcrConversion>
+  {
+  public:
+    using DestructorType = Device;
+    using deleter        = ObjectDestroyShared<SamplerYcbcrConversion>;
+  };
+
+  using SharedSamplerYcbcrConversion    = SharedHandle<SamplerYcbcrConversion>;
+  using SharedSamplerYcbcrConversionKHR = SharedHandle<SamplerYcbcrConversion>;
+
+  //=== VK_VERSION_1_3 ===
+  template <>
+  class SharedHandleTraits<PrivateDataSlot>
+  {
+  public:
+    using DestructorType = Device;
+    using deleter        = ObjectDestroyShared<PrivateDataSlot>;
+  };
+
+  using SharedPrivateDataSlot    = SharedHandle<PrivateDataSlot>;
+  using SharedPrivateDataSlotEXT = SharedHandle<PrivateDataSlot>;
+
+  //=== VK_KHR_surface ===
+  template <>
+  class SharedHandleTraits<SurfaceKHR>
+  {
+  public:
+    using DestructorType = Instance;
+    using deleter        = ObjectDestroyShared<SurfaceKHR>;
+  };
+
+  using SharedSurfaceKHR = SharedHandle<SurfaceKHR>;
+
+  //=== VK_EXT_debug_utils ===
+  template <>
+  class SharedHandleTraits<DebugUtilsMessengerEXT>
+  {
+  public:
+    using DestructorType = Instance;
+    using deleter        = ObjectDestroyShared<DebugUtilsMessengerEXT>;
+  };
+
+  using SharedDebugUtilsMessengerEXT = SharedHandle<DebugUtilsMessengerEXT>;
+
+  enum class SwapchainOwns
+  {
+    no,
+    yes,
+  };
+
+  struct ImageHeader
+  {
+    SharedHandle<DeleteDestructorOf<VULKAN_HPP_NAMESPACE::Image>>     parent{};
+    typename SharedHandleTraits<VULKAN_HPP_NAMESPACE::Image>::deleter deleter{};
+    SwapchainOwns                                                     swapchainOwned = SwapchainOwns::no;
+  };
+
+  template <>
+  class SharedHandle<VULKAN_HPP_NAMESPACE::Image> : public SharedHandleBase<VULKAN_HPP_NAMESPACE::Image, ImageHeader>
+  {
+    using BaseType    = SharedHandleBase<VULKAN_HPP_NAMESPACE::Image, ImageHeader>;
+    using DeleterType = typename SharedHandleTraits<VULKAN_HPP_NAMESPACE::Image>::deleter;
+    friend BaseType;
+
+  public:
+    SharedHandle() = default;
+
+    explicit SharedHandle( VULKAN_HPP_NAMESPACE::Image                                   handle,
+                           SharedHandle<DeleteDestructorOf<VULKAN_HPP_NAMESPACE::Image>> parent,
+                           SwapchainOwns                                                 swapchain_owned = SwapchainOwns::no,
+                           DeleterType                                                   deleter         = DeleterType() ) VULKAN_HPP_NOEXCEPT
+      : BaseType( handle, std::move( parent ), std::move( deleter ), swapchain_owned )
+    {
+    }
+
+  protected:
+    static void internalDestroy( const ImageHeader & control, VULKAN_HPP_NAMESPACE::Image handle ) VULKAN_HPP_NOEXCEPT
+    {
+      if ( control.swapchainOwned == SwapchainOwns::no )
+      {
+        control.deleter.destroy( control.parent.get(), handle );
+      }
+    }
+  };
+
+  struct SwapchainHeader
+  {
+    SharedHandle<VULKAN_HPP_NAMESPACE::SurfaceKHR>                           surface{};
+    SharedHandle<DeleteDestructorOf<VULKAN_HPP_NAMESPACE::SwapchainKHR>>     parent{};
+    typename SharedHandleTraits<VULKAN_HPP_NAMESPACE::SwapchainKHR>::deleter deleter{};
+  };
+
+  template <>
+  class SharedHandle<VULKAN_HPP_NAMESPACE::SwapchainKHR> : public SharedHandleBase<VULKAN_HPP_NAMESPACE::SwapchainKHR, SwapchainHeader>
+  {
+    using BaseType    = SharedHandleBase<VULKAN_HPP_NAMESPACE::SwapchainKHR, SwapchainHeader>;
+    using DeleterType = typename SharedHandleTraits<VULKAN_HPP_NAMESPACE::SwapchainKHR>::deleter;
+    friend BaseType;
+
+  public:
+    SharedHandle() = default;
+
+    explicit SharedHandle( VULKAN_HPP_NAMESPACE::SwapchainKHR                                   handle,
+                           SharedHandle<DeleteDestructorOf<VULKAN_HPP_NAMESPACE::SwapchainKHR>> parent,
+                           SharedHandle<VULKAN_HPP_NAMESPACE::SurfaceKHR>                       surface,
+                           DeleterType                                                          deleter = DeleterType() ) VULKAN_HPP_NOEXCEPT
+      : BaseType( handle, std::move( surface ), std::move( parent ), std::move( deleter ) )
+    {
+    }
+
+  public:
+    const SharedHandle<VULKAN_HPP_NAMESPACE::SurfaceKHR> & getSurface() const VULKAN_HPP_NOEXCEPT
+    {
+      return getHeader().surface;
+    }
+
+  protected:
+    using BaseType::internalDestroy;
+  };
+
+  template <typename HandleType, typename DestructorType>
+  class SharedHandleBaseNoDestroy : public SharedHandleBase<HandleType, DestructorType>
+  {
+  public:
+    using SharedHandleBase<HandleType, DestructorType>::SharedHandleBase;
+
+    const DestructorType & getDestructorType() const VULKAN_HPP_NOEXCEPT
+    {
+      return SharedHandleBase<HandleType, DestructorType>::getHeader();
+    }
+
+  protected:
+    static void internalDestroy( const DestructorType &, HandleType ) VULKAN_HPP_NOEXCEPT {}
+  };
+
+  //=== VK_VERSION_1_0 ===
+
+  template <>
+  class SharedHandle<PhysicalDevice> : public SharedHandleBaseNoDestroy<PhysicalDevice, SharedInstance>
+  {
+    friend SharedHandleBase<PhysicalDevice, SharedInstance>;
+
+  public:
+    SharedHandle() = default;
+
+    explicit SharedHandle( PhysicalDevice handle, SharedInstance parent ) noexcept
+      : SharedHandleBaseNoDestroy<PhysicalDevice, SharedInstance>( handle, std::move( parent ) )
+    {
+    }
+  };
+
+  using SharedPhysicalDevice = SharedHandle<PhysicalDevice>;
+
+  template <>
+  class SharedHandle<Queue> : public SharedHandleBaseNoDestroy<Queue, SharedDevice>
+  {
+    friend SharedHandleBase<Queue, SharedDevice>;
+
+  public:
+    SharedHandle() = default;
+
+    explicit SharedHandle( Queue handle, SharedDevice parent ) noexcept : SharedHandleBaseNoDestroy<Queue, SharedDevice>( handle, std::move( parent ) ) {}
+  };
+
+  using SharedQueue = SharedHandle<Queue>;
+
+  template <>
+  class SharedHandle<DeviceMemory> : public SharedHandleBaseNoDestroy<DeviceMemory, SharedDevice>
+  {
+    friend SharedHandleBase<DeviceMemory, SharedDevice>;
+
+  public:
+    SharedHandle() = default;
+
+    explicit SharedHandle( DeviceMemory handle, SharedDevice parent ) noexcept
+      : SharedHandleBaseNoDestroy<DeviceMemory, SharedDevice>( handle, std::move( parent ) )
+    {
+    }
+  };
+
+  using SharedDeviceMemory = SharedHandle<DeviceMemory>;
+
+  template <>
+  class SharedHandle<QueryPool> : public SharedHandleBaseNoDestroy<QueryPool, SharedDevice>
+  {
+    friend SharedHandleBase<QueryPool, SharedDevice>;
+
+  public:
+    SharedHandle() = default;
+
+    explicit SharedHandle( QueryPool handle, SharedDevice parent ) noexcept : SharedHandleBaseNoDestroy<QueryPool, SharedDevice>( handle, std::move( parent ) )
+    {
+    }
+  };
+
+  using SharedQueryPool = SharedHandle<QueryPool>;
+
+  template <>
+  class SharedHandle<ShaderModule> : public SharedHandleBaseNoDestroy<ShaderModule, SharedDevice>
+  {
+    friend SharedHandleBase<ShaderModule, SharedDevice>;
+
+  public:
+    SharedHandle() = default;
+
+    explicit SharedHandle( ShaderModule handle, SharedDevice parent ) noexcept
+      : SharedHandleBaseNoDestroy<ShaderModule, SharedDevice>( handle, std::move( parent ) )
+    {
+    }
+  };
+
+  using SharedShaderModule = SharedHandle<ShaderModule>;
+
+  template <>
+  class SharedHandle<DescriptorPool> : public SharedHandleBaseNoDestroy<DescriptorPool, SharedDevice>
+  {
+    friend SharedHandleBase<DescriptorPool, SharedDevice>;
+
+  public:
+    SharedHandle() = default;
+
+    explicit SharedHandle( DescriptorPool handle, SharedDevice parent ) noexcept
+      : SharedHandleBaseNoDestroy<DescriptorPool, SharedDevice>( handle, std::move( parent ) )
+    {
+    }
+  };
+
+  using SharedDescriptorPool = SharedHandle<DescriptorPool>;
+
+  template <>
+  class SharedHandle<CommandPool> : public SharedHandleBaseNoDestroy<CommandPool, SharedDevice>
+  {
+    friend SharedHandleBase<CommandPool, SharedDevice>;
+
+  public:
+    SharedHandle() = default;
+
+    explicit SharedHandle( CommandPool handle, SharedDevice parent ) noexcept
+      : SharedHandleBaseNoDestroy<CommandPool, SharedDevice>( handle, std::move( parent ) )
+    {
+    }
+  };
+
+  using SharedCommandPool = SharedHandle<CommandPool>;
+
+  //=== VK_KHR_swapchain ===
+
+  template <>
+  class SharedHandle<SwapchainKHR> : public SharedHandleBaseNoDestroy<SwapchainKHR, SharedDevice>
+  {
+    friend SharedHandleBase<SwapchainKHR, SharedDevice>;
+
+  public:
+    SharedHandle() = default;
+
+    explicit SharedHandle( SwapchainKHR handle, SharedDevice parent ) noexcept
+      : SharedHandleBaseNoDestroy<SwapchainKHR, SharedDevice>( handle, std::move( parent ) )
+    {
+    }
+  };
+
+  using SharedSwapchainKHR = SharedHandle<SwapchainKHR>;
+
+  //=== VK_KHR_display ===
+
+  template <>
+  class SharedHandle<DisplayKHR> : public SharedHandleBaseNoDestroy<DisplayKHR, SharedPhysicalDevice>
+  {
+    friend SharedHandleBase<DisplayKHR, SharedPhysicalDevice>;
+
+  public:
+    SharedHandle() = default;
+
+    explicit SharedHandle( DisplayKHR handle, SharedPhysicalDevice parent ) noexcept
+      : SharedHandleBaseNoDestroy<DisplayKHR, SharedPhysicalDevice>( handle, std::move( parent ) )
+    {
+    }
+  };
+
+  using SharedDisplayKHR = SharedHandle<DisplayKHR>;
+
+  template <>
+  class SharedHandle<DisplayModeKHR> : public SharedHandleBaseNoDestroy<DisplayModeKHR, SharedDisplayKHR>
+  {
+    friend SharedHandleBase<DisplayModeKHR, SharedDisplayKHR>;
+
+  public:
+    SharedHandle() = default;
+
+    explicit SharedHandle( DisplayModeKHR handle, SharedDisplayKHR parent ) noexcept
+      : SharedHandleBaseNoDestroy<DisplayModeKHR, SharedDisplayKHR>( handle, std::move( parent ) )
+    {
+    }
+  };
+
+  using SharedDisplayModeKHR = SharedHandle<DisplayModeKHR>;
+
+#  if defined( VK_USE_PLATFORM_SCI )
+  //=== VK_NV_external_sci_sync2 ===
+
+  template <>
+  class SharedHandle<SemaphoreSciSyncPoolNV> : public SharedHandleBaseNoDestroy<SemaphoreSciSyncPoolNV, SharedDevice>
+  {
+    friend SharedHandleBase<SemaphoreSciSyncPoolNV, SharedDevice>;
+
+  public:
+    SharedHandle() = default;
+
+    explicit SharedHandle( SemaphoreSciSyncPoolNV handle, SharedDevice parent ) noexcept
+      : SharedHandleBaseNoDestroy<SemaphoreSciSyncPoolNV, SharedDevice>( handle, std::move( parent ) )
+    {
+    }
+  };
+
+  using SharedSemaphoreSciSyncPoolNV = SharedHandle<SemaphoreSciSyncPoolNV>;
+#  endif /*VK_USE_PLATFORM_SCI*/
+#endif   // !VULKAN_HPP_NO_SMART_HANDLE
+}  // namespace VULKAN_HPP_NAMESPACE
+#endif  // VULKAN_SHARED_HPP