Shared Handles (#1619)

* 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
This commit is contained in:
Ilya Doroshenko 2023-09-19 13:04:36 +02:00 committed by GitHub
parent d60453f6ea
commit 5d0d3b7bd9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 3355 additions and 9 deletions

View File

@ -436,6 +436,70 @@ For each function which constructs a Vulkan handle of type `vk::Type` Vulkan-Hpp
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.
### SharedHandle
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`.
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.
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)
There are no functions which return a `vk::SharedHandle` directly yet. Instead, you can construct a `vk::SharedHandle` from a `vk::Handle`:
```c++
vk::Buffer buffer = device.createBuffer(...);
vk::SharedBuffer sharedBuffer(buffer, device); // sharedBuffer now owns the buffer
```
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:
```c++
vk::Image image = swapchain.getImages(...)[0]; // get the first image from the swapchain
vk::SharedImage sharedImage(image, device, SwapChainOwns::yes); // sharedImage now owns the image, but won't destroy it
```
There is also a specialization for `vk::SwapchainKHR` which takes an additional argument to specify a surface:
```c++
vk::SwapchainKHR swapchain = device.createSwapchainKHR(...);
vk::SharedSwapchainKHR sharedSwapchain(swapchain, device, surface); // sharedSwapchain now owns the swapchain and surface
```
You can create a `vk::SharedHandle` overload for your own handle type or own shared handles by providing several template arguments to SharedHandleBase:
- A handle type
- A parent handle type or a header structure, that contains parent
- A class itself for CRTP
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.
```c++
// Example of a custom shared device, that takes in an instance as a parent
class shared_handle<VkDevice> : public vk::SharedHandleBase<VkDevice, vk::SharedInstance, shared_handle<VkDevice>>
{
using base = vk::SharedHandleBase<VkDevice, vk::SharedInstance, shared_handle<VkDevice>>;
friend base;
public:
shared_handle() = default;
explicit shared_handle(VkDevice handle, vk::SharedInstance parent) noexcept
: base(handle, std::move(parent)) {}
const auto& getParent() const noexcept {
return getHeader();
}
protected:
static void internalDestroy(const vk::SharedInstance& /*control*/, VkDevice handle) noexcept {
vkDestroyDevice(handle);
}
};
```
The API will be extended to provide creation functions in the future.
### Custom allocators
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:

View 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();

View 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,

View 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 )

View File

@ -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 )

View File

@ -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 );
}
}

150
snippets/SharedDestroy.hpp Normal file
View File

@ -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

247
snippets/SharedHandle.hpp Normal file
View File

@ -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;
};

View File

@ -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 {}
};

View 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 ===
//===========================

View 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

1069
vulkan/vulkan_shared.hpp Normal file

File diff suppressed because it is too large Load Diff

View 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 ===
//===========================

View 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

903
vulkan/vulkansc_shared.hpp Normal file
View File

@ -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