util: Add vk_struct_helper.hpp

Move the vk_typemap_helper.h file in Vulkan-ValidationLayers over to this
repo with a different name to reflect the use of it

Changes from that include:
 * Rename the functions to be more obvious as to what they do
 * Placing them in the `vku` namespace
 * Adding the `InitStructHelper` class which deduces the type based on the
   variable that is being initialized
 * Compiler error if there is no corresponding sType
This commit is contained in:
unknown 2023-09-13 15:06:52 -06:00 committed by Charles Giessen
parent dc1acf9e37
commit 6774c9b24b
8 changed files with 2116 additions and 0 deletions

View file

@ -17,6 +17,7 @@ static_library("vulkan_layer_settings") {
"include/vulkan/layer/vk_layer_settings_ext.h",
"include/vulkan/utility/vk_dispatch_table.h",
"include/vulkan/utility/vk_format_utils.h",
"include/vulkan/utility/vk_struct_helper.hpp",
"include/vulkan/vk_enum_string_helper.h",
"src/layer/layer_settings_manager.cpp",
"src/layer/layer_settings_manager.hpp",

View file

@ -24,6 +24,7 @@ if (CMAKE_VERSION VERSION_GREATER_EQUAL "3.19")
vulkan/utility/vk_dispatch_table.h
vulkan/vk_enum_string_helper.h
vulkan/utility/vk_format_utils.h
vulkan/utility/vk_struct_helper.hpp
)
endif()

File diff suppressed because it is too large Load diff

View file

@ -25,6 +25,7 @@ def RunGenerators(api: str, registry: str, targetFilter: str) -> None:
from generators.dispatch_table_generator import DispatchTableOutputGenerator
from generators.enum_string_helper_generator import EnumStringHelperOutputGenerator
from generators.format_utils_generator import FormatUtilsOutputGenerator
from generators.struct_helper_generator import StructHelperOutputGenerator
# Build up a list of all generators and custom options
generators = {
@ -40,6 +41,10 @@ def RunGenerators(api: str, registry: str, targetFilter: str) -> None:
'generator' : FormatUtilsOutputGenerator,
'directory' : 'include/vulkan/utility',
},
'vk_struct_helper.hpp' : {
'generator' : StructHelperOutputGenerator,
'directory' : 'include/vulkan/utility',
},
}
if (targetFilter and targetFilter not in generators.keys()):

View file

@ -0,0 +1,129 @@
#!/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 StructHelperOutputGenerator(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 <> inline 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
\n''')
out.append('// NOLINTEND') # Wrap for clang-tidy to ignore
self.write("".join(out))

View file

@ -7,3 +7,4 @@ add_subdirectory(layer)
add_subdirectory(generated)
add_subdirectory(vk_dispatch_table)
add_subdirectory(format_utils)
add_subdirectory(struct_helper)

View file

@ -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_struct_helper struct_helper.cpp)
target_link_libraries(test_struct_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_struct_helper)

View file

@ -0,0 +1,91 @@
// 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_struct_helper.hpp>
#include <limits>
TEST(struct_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(struct_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));
}
TEST(struct_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)));
}
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(struct_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);
}