-
Notifications
You must be signed in to change notification settings - Fork 28
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Move the vk_typemap_helper.h file in Vulkan-ValidationLayers over to this repo. Changes from that include: * Renaming functions * Placing them in the `vku` namespace * Adding the `InitStructHelper` class which deduces the type based on the variable that is being initialized * Added compatibility versions for renamed functions - allows using this library with minimal changes to source code. * If a type isn't defined then compiler error is emitted
- Loading branch information
1 parent
b78ed1a
commit d8062e9
Showing
7 changed files
with
2,208 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,154 @@ | ||
#!/usr/bin/python3 -i | ||
# | ||
# Copyright (c) 2015-2023 The Khronos Group Inc. | ||
# Copyright (c) 2015-2023 Valve Corporation | ||
# Copyright (c) 2015-2023 LunarG, Inc. | ||
# Copyright (c) 2015-2023 Google Inc. | ||
# Copyright (c) 2023-2023 RasterGrid Kft. | ||
# | ||
# 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. | ||
|
||
import os | ||
from generators.base_generator import BaseGenerator | ||
|
||
class TypemapHelperOutputGenerator(BaseGenerator): | ||
def __init__(self): | ||
BaseGenerator.__init__(self) | ||
|
||
def generate(self): | ||
out = [] | ||
out.append(f'''// *** THIS FILE IS GENERATED - DO NOT EDIT *** | ||
// See {os.path.basename(__file__)} for modifications | ||
// Copyright 2023 The Khronos Group Inc. | ||
// Copyright 2023 Valve Corporation | ||
// Copyright 2023 LunarG, Inc. | ||
// | ||
// SPDX-License-Identifier: Apache-2.0 | ||
''') | ||
out.append('// NOLINTBEGIN') # Wrap for clang-tidy to ignore | ||
out.append(''' | ||
#pragma once | ||
#include <vulkan/vulkan.h> | ||
namespace vku { | ||
template <typename T> | ||
VkStructureType GetSType() { | ||
static_assert(sizeof(T) == 0, "GetSType() is being used with an unsupported Type! Is the code-gen up to date?"); | ||
return VK_STRUCTURE_TYPE_APPLICATION_INFO; | ||
}\n''') | ||
|
||
for struct in [x for x in self.vk.structs.values() if x.sType]: | ||
out.extend([f'#ifdef {struct.protect}'] if struct.protect else []) | ||
out.append(f''' | ||
template <> VkStructureType GetSType<{struct.name}>() {{ return {struct.sType}; }}\n''') | ||
out.extend([f'#endif // {struct.protect}\n'] if struct.protect else []) | ||
|
||
out.append(''' | ||
// Find an entry of the given type in the const pNext chain | ||
// returns nullptr if the entry is not found | ||
template <typename T> const T *FindStructInPNextChain(const void *next) { | ||
const VkBaseOutStructure *current = reinterpret_cast<const VkBaseOutStructure *>(next); | ||
VkStructureType desired_sType = GetSType<T>(); | ||
while (current) { | ||
if (desired_sType == current->sType) { | ||
return reinterpret_cast<const T*>(current); | ||
} | ||
current = current->pNext; | ||
} | ||
return nullptr; | ||
} | ||
// Find an entry of the given type in the non-const pNext chain | ||
// returns nullptr if the entry is not found | ||
template <typename T> T *FindStructInPNextChain(void *next) { | ||
VkBaseOutStructure *current = reinterpret_cast<VkBaseOutStructure *>(next); | ||
VkStructureType desired_sType = GetSType<T>(); | ||
while (current) { | ||
if (desired_sType == current->sType) { | ||
return reinterpret_cast<T*>(current); | ||
} | ||
current = current->pNext; | ||
} | ||
return nullptr; | ||
} | ||
// Find last element of pNext chain | ||
inline VkBaseOutStructure *FindLastStructInPNextChain(void *next) { | ||
auto *current = reinterpret_cast<VkBaseOutStructure *>(next); | ||
auto *prev = current; | ||
while (current) { | ||
prev = current; | ||
current = reinterpret_cast<VkBaseOutStructure *>(current->pNext); | ||
} | ||
return prev; | ||
} | ||
// Init the header of an sType struct | ||
template <typename T> | ||
T InitStruct(void *p_next = nullptr) { | ||
T out = {}; | ||
out.sType = GetSType<T>(); | ||
out.pNext = p_next; | ||
return out; | ||
} | ||
// Init the header of an sType struct with pNext and optional fields | ||
template <typename T, typename... StructFields> | ||
T InitStruct(void *p_next, StructFields... fields) { | ||
T out = {GetSType<T>(), p_next, fields...}; | ||
return out; | ||
} | ||
class InitStructHelper { | ||
void* p_next = nullptr; | ||
public: | ||
InitStructHelper() = default; | ||
InitStructHelper(void *p_next) : p_next(p_next) {}; | ||
template <typename T> | ||
operator T() { | ||
return InitStruct<T>(p_next); | ||
} | ||
}; | ||
} // namespace vku | ||
// Init the header of an sType struct with pNext and optional fields | ||
template <typename T, typename... StructFields> | ||
T LvlInitStruct(void *p_next, StructFields... fields) { | ||
T out = {vku::GetSType<T>(), p_next, fields...}; | ||
return out; | ||
} | ||
// Init the header of an sType struct | ||
template <typename T> | ||
T LvlInitStruct(void *p_next = nullptr) { | ||
T out = {}; | ||
out.sType = vku::GetSType<T>(); | ||
out.pNext = p_next; | ||
return out; | ||
} | ||
// Find an entry of the given type in the const pNext chain | ||
template <typename T> const T *LvlFindInChain(const void *next) { return vku::FindStructInPNextChain<T>(next); } | ||
// Find an entry of the given type in the pNext chain | ||
template <typename T> T *LvlFindModInChain(void *next) { return vku::FindStructInPNextChain<T>(next); } | ||
// Find last element of pNext chain | ||
inline VkBaseOutStructure *LvlFindLastInChain(void *next) { return vku::FindLastStructInPNextChain(next); } | ||
\n''') | ||
|
||
out.append('// NOLINTEND') # Wrap for clang-tidy to ignore | ||
self.write("".join(out)) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
# Copyright 2023 The Khronos Group Inc. | ||
# Copyright 2023 Valve Corporation | ||
# Copyright 2023 LunarG, Inc. | ||
# | ||
# SPDX-License-Identifier: Apache-2.0 | ||
|
||
find_package(GTest REQUIRED CONFIG) | ||
|
||
include(GoogleTest) | ||
|
||
add_executable(test_typemap_helper typemap_helper.cpp) | ||
|
||
target_link_libraries(test_typemap_helper PRIVATE | ||
GTest::gtest | ||
GTest::gtest_main | ||
Vulkan::UtilityHeaders | ||
) | ||
|
||
if(${CMAKE_C_COMPILER_ID} MATCHES "(GNU|Clang)") | ||
add_compile_options(-Wpedantic -Wall -Wextra -Werror) | ||
endif() | ||
|
||
gtest_discover_tests(test_typemap_helper) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,134 @@ | ||
// Copyright 2023 The Khronos Group Inc. | ||
// Copyright 2023 Valve Corporation | ||
// Copyright 2023 LunarG, Inc. | ||
// | ||
// SPDX-License-Identifier: Apache-2.0 | ||
// | ||
|
||
#include <gtest/gtest.h> | ||
|
||
#include <vulkan/utility/vk_typemap_helper.hpp> | ||
|
||
#include <limits> | ||
|
||
TEST(typemap_helper, structure_type_matches) { | ||
ASSERT_EQ(VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO, vku::GetSType<VkInstanceCreateInfo>()); | ||
|
||
VkDeviceCreateInfo device_create_info = vku::InitStructHelper(); | ||
ASSERT_EQ(VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO, device_create_info.sType); | ||
|
||
VkImageDrmFormatModifierExplicitCreateInfoEXT image_drm_format_modifier_explicit_create_info = vku::InitStructHelper{}; | ||
|
||
VkImageCreateInfo image_create_info = vku::InitStructHelper(&image_drm_format_modifier_explicit_create_info); | ||
ASSERT_EQ(VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, image_create_info.sType); | ||
ASSERT_EQ(&image_drm_format_modifier_explicit_create_info, image_create_info.pNext); | ||
|
||
auto buffer_create_info = vku::InitStruct<VkBufferCreateInfo>( | ||
nullptr, static_cast<VkBufferCreateFlags>(VK_BUFFER_CREATE_SPARSE_BINDING_BIT), std::numeric_limits<uint64_t>::max(), | ||
static_cast<VkBufferUsageFlags>(VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT), VK_SHARING_MODE_EXCLUSIVE, 0U, nullptr); | ||
ASSERT_EQ(VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, buffer_create_info.sType); | ||
ASSERT_EQ(VK_BUFFER_CREATE_SPARSE_BINDING_BIT, buffer_create_info.flags); | ||
ASSERT_EQ(std::numeric_limits<uint64_t>::max(), buffer_create_info.size); | ||
ASSERT_EQ(VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, buffer_create_info.usage); | ||
ASSERT_EQ(VK_SHARING_MODE_EXCLUSIVE, buffer_create_info.sharingMode); | ||
ASSERT_EQ(0, buffer_create_info.queueFamilyIndexCount); | ||
ASSERT_EQ(nullptr, buffer_create_info.pQueueFamilyIndices); | ||
} | ||
|
||
TEST(typemap_helper, find_struct_in_pnext_chain) { | ||
VkPhysicalDeviceIDProperties id_props = vku::InitStructHelper(); | ||
VkPhysicalDeviceDriverProperties driver_props = vku::InitStructHelper(&id_props); | ||
VkPhysicalDeviceCustomBorderColorPropertiesEXT custom_border_color_props = vku::InitStructHelper(&driver_props); | ||
VkPhysicalDeviceMultiDrawPropertiesEXT multi_draw_props = vku::InitStructHelper(&custom_border_color_props); | ||
VkPhysicalDeviceProperties2 props2 = vku::InitStructHelper(&multi_draw_props); | ||
|
||
ASSERT_EQ(&id_props, vku::FindStructInPNextChain<VkPhysicalDeviceIDProperties>(props2.pNext)); | ||
ASSERT_EQ(&driver_props, vku::FindStructInPNextChain<VkPhysicalDeviceDriverProperties>(props2.pNext)); | ||
ASSERT_EQ(&custom_border_color_props, | ||
vku::FindStructInPNextChain<VkPhysicalDeviceCustomBorderColorPropertiesEXT>(props2.pNext)); | ||
ASSERT_EQ(&multi_draw_props, vku::FindStructInPNextChain<VkPhysicalDeviceMultiDrawPropertiesEXT>(props2.pNext)); | ||
|
||
ASSERT_EQ(reinterpret_cast<VkBaseOutStructure*>(&id_props), vku::FindLastStructInPNextChain(props2.pNext)); | ||
|
||
// Make sure the LvlFindModInChain function works | ||
ASSERT_EQ(&id_props, LvlFindModInChain<VkPhysicalDeviceIDProperties>(props2.pNext)); | ||
ASSERT_EQ(&driver_props, LvlFindModInChain<VkPhysicalDeviceDriverProperties>(props2.pNext)); | ||
ASSERT_EQ(&custom_border_color_props, LvlFindModInChain<VkPhysicalDeviceCustomBorderColorPropertiesEXT>(props2.pNext)); | ||
ASSERT_EQ(&multi_draw_props, LvlFindModInChain<VkPhysicalDeviceMultiDrawPropertiesEXT>(props2.pNext)); | ||
|
||
ASSERT_EQ(reinterpret_cast<VkBaseOutStructure*>(&id_props), LvlFindLastInChain(props2.pNext)); | ||
} | ||
|
||
TEST(typemap_helper, find_const_struct_in_pnext_chain) { | ||
VkImageViewUsageCreateInfo image_view_usage_create_info = vku::InitStructHelper(); | ||
VkImageViewSlicedCreateInfoEXT image_view_sliced_create_info = vku::InitStructHelper(&image_view_usage_create_info); | ||
VkSamplerYcbcrConversionInfo sampler_ycbcr_conversion_info = vku::InitStructHelper(&image_view_sliced_create_info); | ||
VkOpaqueCaptureDescriptorDataCreateInfoEXT opaque_capture_descriptor_data_create_info = | ||
vku::InitStructHelper(&sampler_ycbcr_conversion_info); | ||
VkImageViewCreateInfo image_view = vku::InitStructHelper(&opaque_capture_descriptor_data_create_info); | ||
|
||
ASSERT_EQ(static_cast<const void*>(&image_view_usage_create_info), | ||
vku::FindStructInPNextChain<VkImageViewUsageCreateInfo>(image_view.pNext)); | ||
ASSERT_EQ(static_cast<const void*>(&image_view_sliced_create_info), | ||
vku::FindStructInPNextChain<VkImageViewSlicedCreateInfoEXT>(image_view.pNext)); | ||
ASSERT_EQ(static_cast<const void*>(&sampler_ycbcr_conversion_info), | ||
vku::FindStructInPNextChain<VkSamplerYcbcrConversionInfo>(image_view.pNext)); | ||
ASSERT_EQ(static_cast<const void*>(&opaque_capture_descriptor_data_create_info), | ||
vku::FindStructInPNextChain<VkOpaqueCaptureDescriptorDataCreateInfoEXT>(image_view.pNext)); | ||
|
||
ASSERT_EQ(reinterpret_cast<VkBaseOutStructure*>(&image_view_usage_create_info), | ||
vku::FindLastStructInPNextChain(const_cast<void*>(image_view.pNext))); | ||
|
||
// Make sure the LvlFindInChain function works | ||
ASSERT_EQ(static_cast<const void*>(&image_view_usage_create_info), | ||
LvlFindInChain<VkImageViewUsageCreateInfo>(image_view.pNext)); | ||
ASSERT_EQ(static_cast<const void*>(&image_view_sliced_create_info), | ||
LvlFindInChain<VkImageViewSlicedCreateInfoEXT>(image_view.pNext)); | ||
ASSERT_EQ(static_cast<const void*>(&sampler_ycbcr_conversion_info), | ||
LvlFindInChain<VkSamplerYcbcrConversionInfo>(image_view.pNext)); | ||
ASSERT_EQ(static_cast<const void*>(&opaque_capture_descriptor_data_create_info), | ||
LvlFindInChain<VkOpaqueCaptureDescriptorDataCreateInfoEXT>(image_view.pNext)); | ||
|
||
ASSERT_EQ(reinterpret_cast<VkBaseOutStructure*>(&image_view_usage_create_info), | ||
LvlFindLastInChain(const_cast<void*>(image_view.pNext))); | ||
} | ||
|
||
TEST(typemap_helper, lvl_init_struct_still_works) { | ||
auto device_create_info = LvlInitStruct<VkDeviceCreateInfo>(); | ||
ASSERT_EQ(VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO, device_create_info.sType); | ||
|
||
auto image_drm_format_modifier_explicit_create_info = LvlInitStruct<VkImageDrmFormatModifierExplicitCreateInfoEXT>(); | ||
|
||
auto image_create_info = LvlInitStruct<VkImageCreateInfo>(&image_drm_format_modifier_explicit_create_info); | ||
ASSERT_EQ(VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, image_create_info.sType); | ||
ASSERT_EQ(&image_drm_format_modifier_explicit_create_info, image_create_info.pNext); | ||
|
||
auto buffer_create_info = LvlInitStruct<VkBufferCreateInfo>( | ||
nullptr, static_cast<VkBufferCreateFlags>(VK_BUFFER_CREATE_SPARSE_BINDING_BIT), std::numeric_limits<uint64_t>::max(), | ||
static_cast<VkBufferUsageFlags>(VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT), VK_SHARING_MODE_EXCLUSIVE, 0U, nullptr); | ||
ASSERT_EQ(VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, buffer_create_info.sType); | ||
ASSERT_EQ(VK_BUFFER_CREATE_SPARSE_BINDING_BIT, buffer_create_info.flags); | ||
ASSERT_EQ(std::numeric_limits<uint64_t>::max(), buffer_create_info.size); | ||
ASSERT_EQ(VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, buffer_create_info.usage); | ||
ASSERT_EQ(VK_SHARING_MODE_EXCLUSIVE, buffer_create_info.sharingMode); | ||
ASSERT_EQ(0, buffer_create_info.queueFamilyIndexCount); | ||
ASSERT_EQ(nullptr, buffer_create_info.pQueueFamilyIndices); | ||
} | ||
|
||
struct SomeVkTypes { | ||
VkImageViewUsageCreateInfo t0{}; | ||
VkImageDrmFormatModifierExplicitCreateInfoEXT t1 = vku::InitStructHelper(); | ||
VkBufferCreateInfo t2 = vku::InitStruct<VkBufferCreateInfo>(); | ||
inline static const auto t3 = vku::InitStruct<VkInstanceCreateInfo>(); | ||
inline static const VkDeviceCreateInfo t4 = vku::InitStructHelper(); | ||
}; | ||
|
||
TEST(typemap_helper, struct_defaults_correct) { | ||
SomeVkTypes s; | ||
|
||
ASSERT_EQ(s.t0.sType, VK_STRUCTURE_TYPE_APPLICATION_INFO); // should be zero because we didn't initialize it | ||
ASSERT_EQ(s.t1.sType, VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_EXPLICIT_CREATE_INFO_EXT); | ||
ASSERT_EQ(s.t2.sType, VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO); | ||
ASSERT_EQ(s.t3.sType, VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO); | ||
ASSERT_EQ(s.t4.sType, VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO); | ||
} |