Skip to content

Commit

Permalink
Add specializations of std::hash for all the structs and handles in t…
Browse files Browse the repository at this point in the history
…he vk-namespace.
  • Loading branch information
asuessenbach committed Nov 13, 2024
1 parent a4d53f4 commit 385f594
Show file tree
Hide file tree
Showing 7 changed files with 4,360 additions and 74 deletions.
103 changes: 102 additions & 1 deletion VulkanHppGenerator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -725,7 +725,7 @@ module;

#include <vulkan/vulkan_hpp_macros.hpp>

#if defined( __cpp_lib_modules )
#if defined( __cpp_lib_modules ) && !defined( VULKAN_HPP_ENABLE_STD_MODULE )
#define VULKAN_HPP_ENABLE_STD_MODULE
#endif

Expand All @@ -749,10 +749,16 @@ export namespace VULKAN_HPP_NAMESPACE
} // namespace VULKAN_HPP_RAII_NAMESPACE
#endif
} // namespace VULKAN_HPP_NAMESPACE

export namespace std
{
${hashSpecializations}
}
)";

auto const str = replaceWithMap( vulkanCppmTemplate,
{ { "api", m_api },
{ "hashSpecializations", generateCppModuleHashSpecializations() },
{ "licenseHeader", m_vulkanLicenseHeader },
{ "raiiUsings", generateCppModuleRaiiUsings() },
{ "usings", generateCppModuleUsings() } } );
Expand Down Expand Up @@ -6026,6 +6032,101 @@ std::string VulkanHppGenerator::generateCppModuleRaiiUsings() const
return usings;
}

std::string VulkanHppGenerator::generateCppModuleHandleHashSpecializations() const
{
const std::string hashesTemplate = R"(
//========================================
//=== HASH specializations for handles ===
//========================================

${specializations}
)";

auto const generateSpecializations = [this]( std::vector<RequireData> const & requireData, std::string const & title )
{
auto specializations = std::string{};
for ( auto const & require : requireData )
{
for ( auto const & type : require.types )
{
if ( auto const & handleIt = m_handles.find( type.name ); handleIt != m_handles.end() )
{
specializations += " template <> struct hash<VULKAN_HPP_NAMESPACE::" + stripPrefix( handleIt->first, "Vk" ) + ">;\n";
}
}
}
return addTitleAndProtection( title, specializations );
};

std::string specializations;
for ( auto const & feature : m_features )
{
specializations += generateSpecializations( feature.requireData, feature.name );
}
for ( auto const & extension : m_extensions )
{
specializations += generateSpecializations( extension.requireData, extension.name );
}
return replaceWithMap( hashesTemplate, { { "specializations", specializations } } );
}

std::string VulkanHppGenerator::generateCppModuleHashSpecializations() const
{
std::string const hasSpecializationsTemplate = R"(
//=======================================
//=== HASH specialization for Flags types ===
//=======================================

template <typename BitType>
struct hash<VULKAN_HPP_NAMESPACE::Flags<BitType>>;

${handleHashSpecializations}
${structHashSpecializations}
)";

return replaceWithMap( hasSpecializationsTemplate,
{ { "handleHashSpecializations", generateCppModuleHandleHashSpecializations() },
{ "structHashSpecializations", generateCppModuleStructHashSpecializations() } } );
}

std::string VulkanHppGenerator::generateCppModuleStructHashSpecializations() const
{
const std::string hashesTemplate = R"(
//========================================
//=== HASH specializations for structs ===
//========================================

${specializations}
)";

auto const generateSpecializations = [this]( std::vector<RequireData> const & requireData, std::string const & title )
{
auto specializations = std::string{};
for ( auto const & require : requireData )
{
for ( auto const & type : require.types )
{
if ( auto const & structIt = m_structs.find( type.name ); structIt != m_structs.end() )
{
specializations += " template <> struct hash<VULKAN_HPP_NAMESPACE::" + stripPrefix( structIt->first, "Vk" ) + ">;\n";
}
}
}
return addTitleAndProtection( title, specializations );
};

std::string specializations;
for ( auto const & feature : m_features )
{
specializations += generateSpecializations( feature.requireData, feature.name );
}
for ( auto const & extension : m_extensions )
{
specializations += generateSpecializations( extension.requireData, extension.name );
}
return replaceWithMap( hashesTemplate, { { "specializations", specializations } } );
}

std::string VulkanHppGenerator::generateDataDeclarations( CommandData const & commandData,
std::vector<size_t> const & returnParams,
std::map<size_t, VectorParamData> const & vectorParams,
Expand Down
3 changes: 3 additions & 0 deletions VulkanHppGenerator.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -753,6 +753,9 @@ class VulkanHppGenerator
std::string generateCppModuleUsings() const;
std::string generateCppModuleRaiiUsings() const;
std::string generateCppModuleSharedHandleUsings() const;
std::string generateCppModuleHandleHashSpecializations() const;
std::string generateCppModuleHashSpecializations() const;
std::string generateCppModuleStructHashSpecializations() const;
std::string generateDataDeclarations( CommandData const & commandData,
std::vector<size_t> const & returnParams,
std::map<size_t, VectorParamData> const & vectorParams,
Expand Down
20 changes: 19 additions & 1 deletion tests/Cpp20Modules/Cpp20Modules.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,22 @@
// Copyright(c) 2024, 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.
//
// VulkanHpp Test : Cpp20Module
// Compile test on using c++20 modules

import vulkan_hpp;

#include <iostream>
#include <vulkan/vulkan_hpp_macros.hpp>

static std::string AppName = "Cpp20Modules";
Expand All @@ -12,6 +28,8 @@ VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE

int main( int /*argc*/, char ** /*argv*/ )
{
std::cout << "test Cpp20Module" << std::endl;

/* VULKAN_HPP_KEY_START */
try
{
Expand Down
116 changes: 79 additions & 37 deletions tests/CppStdModule/CppStdModule.cpp
Original file line number Diff line number Diff line change
@@ -1,59 +1,101 @@
// Copyright(c) 2024, 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.
//
// VulkanHpp Test : CppStdModule
// Compile test on using c++20 modules

import std;
import vulkan_hpp;

#if defined( _MSC_VER )
# pragma warning( disable : 4189 ) // local variable is initialized but not referenced
#elif defined( __GNUC__ )
# pragma GCC diagnostic ignored "-Wunused-variable"
#else
// unknow compiler... just ignore the warnings for yourselves ;)
#endif

#include <assert.h>
#include <vulkan/vulkan_hpp_macros.hpp>

static std::string AppName = "CppStdModule";
static std::string AppName = "CppStdModule";
static std::string EngineName = "Vulkan.cppm";

#if VULKAN_HPP_DISPATCH_LOADER_DYNAMIC == 1
VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE
#endif

int main(int /*argc*/, char** /*argv*/)
int main( int /*argc*/, char ** /*argv*/ )
{
/* VULKAN_HPP_KEY_START */
try
{
std::cout << "test CppStdModule" << std::endl;

/* VULKAN_HPP_KEY_START */
try
{
#if ( VULKAN_HPP_DISPATCH_LOADER_DYNAMIC == 1 )
// initialize minimal set of function pointers
VULKAN_HPP_DEFAULT_DISPATCHER.init();
// initialize minimal set of function pointers
VULKAN_HPP_DEFAULT_DISPATCHER.init();
#endif

// initialize the vk::ApplicationInfo structure
vk::ApplicationInfo applicationInfo(AppName.c_str(), 1, EngineName.c_str(), 1, vk::makeApiVersion(1, 0, 0, 0));
// initialize the vk::ApplicationInfo structure
vk::ApplicationInfo applicationInfo( AppName.c_str(), 1, EngineName.c_str(), 1, vk::makeApiVersion( 1, 0, 0, 0 ) );

// initialize the vk::InstanceCreateInfo
vk::InstanceCreateInfo instanceCreateInfo({}, &applicationInfo);
// initialize the vk::InstanceCreateInfo
vk::InstanceCreateInfo instanceCreateInfo( {}, &applicationInfo );

// create an Instance
vk::Instance instance = vk::createInstance(instanceCreateInfo);
// create an Instance
vk::Instance instance = vk::createInstance( instanceCreateInfo );

#if ( VULKAN_HPP_DISPATCH_LOADER_DYNAMIC == 1 )
// initialize function pointers for instance
VULKAN_HPP_DEFAULT_DISPATCHER.init(instance);
// initialize function pointers for instance
VULKAN_HPP_DEFAULT_DISPATCHER.init( instance );
#endif

// destroy it again
instance.destroy();
}
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);
}

/* VULKAN_HPP_KEY_END */

return 0;
// some minimal check for std::hash on a vk-type
auto h1 = std::hash<vk::Instance>{}( instance );
auto h2 = std::hash<VkInstance>{}( static_cast<VkInstance>( instance ) );
assert( h1 == h2 );

std::unordered_set<vk::Instance> uset;
uset.insert( instance );

std::unordered_map<vk::Instance, size_t> umap;
umap[instance] = 1;

vk::FormatFeatureFlags fff;
auto hf = std::hash<vk::FormatFeatureFlags>{}( fff );

// destroy it again
instance.destroy();
}
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 );
}

/* VULKAN_HPP_KEY_END */

return 0;
}
Loading

0 comments on commit 385f594

Please sign in to comment.