mirror of
https://github.com/KhronosGroup/Vulkan-Utility-Libraries.git
synced 2025-05-14 08:48:39 +00:00
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:
parent
dc1acf9e37
commit
6774c9b24b
8 changed files with 2116 additions and 0 deletions
1
BUILD.gn
1
BUILD.gn
|
@ -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",
|
||||
|
|
|
@ -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()
|
||||
|
||||
|
|
1865
include/vulkan/utility/vk_struct_helper.hpp
Normal file
1865
include/vulkan/utility/vk_struct_helper.hpp
Normal file
File diff suppressed because it is too large
Load diff
|
@ -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()):
|
||||
|
|
129
scripts/generators/struct_helper_generator.py
Normal file
129
scripts/generators/struct_helper_generator.py
Normal 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))
|
|
@ -7,3 +7,4 @@ add_subdirectory(layer)
|
|||
add_subdirectory(generated)
|
||||
add_subdirectory(vk_dispatch_table)
|
||||
add_subdirectory(format_utils)
|
||||
add_subdirectory(struct_helper)
|
||||
|
|
23
tests/struct_helper/CMakeLists.txt
Normal file
23
tests/struct_helper/CMakeLists.txt
Normal 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)
|
91
tests/struct_helper/struct_helper.cpp
Normal file
91
tests/struct_helper/struct_helper.cpp
Normal 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);
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue