Skip to content

Commit

Permalink
Move vk_safe_struct to VUL
Browse files Browse the repository at this point in the history
This code was being generated in both Vulkan-ValidationLayers
and Vulkan-ExtensionLayer. Further uses are on the horizon so
lets stop the copypasta.

Also, add functions to manipulate extension lists and pNext chains,
since many client layers have been doing that themselves.
  • Loading branch information
jeremyg-lunarg committed Mar 26, 2024
1 parent 4befdac commit 9a88106
Show file tree
Hide file tree
Showing 27 changed files with 91,133 additions and 68 deletions.
10 changes: 10 additions & 0 deletions BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import("//build_overrides/vulkan_utility_libraries.gni")

config("vulkan_utility_libraries_config") {
include_dirs = [ "include" ]
defines = [ "VK_ENABLE_BETA_EXTENSIONS" ]
}

static_library("vulkan_layer_settings") {
Expand All @@ -14,8 +15,11 @@ static_library("vulkan_layer_settings") {
sources = [
"include/vulkan/layer/vk_layer_settings.h",
"include/vulkan/layer/vk_layer_settings.hpp",
"include/vulkan/utility/vk_concurrent_unordered_map.hpp",
"include/vulkan/utility/vk_dispatch_table.h",
"include/vulkan/utility/vk_format_utils.h",
"include/vulkan/utility/vk_safe_struct.hpp",
"include/vulkan/utility/vk_safe_struct_utils.hpp",
"include/vulkan/utility/vk_struct_helper.hpp",
"include/vulkan/vk_enum_string_helper.h",
"scripts/gn/stub.cpp",
Expand All @@ -25,5 +29,11 @@ static_library("vulkan_layer_settings") {
"src/layer/layer_settings_util.hpp",
"src/layer/vk_layer_settings.cpp",
"src/layer/vk_layer_settings_helper.cpp",
"src/vulkan/vk_safe_struct_core.cpp",
"src/vulkan/vk_safe_struct_ext.cpp",
"src/vulkan/vk_safe_struct_khr.cpp",
"src/vulkan/vk_safe_struct_utils.cpp",
"src/vulkan/vk_safe_struct_vendor.cpp",
"src/vulkan/vk_safe_struct_manual.cpp",
]
}
3 changes: 2 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -48,9 +48,10 @@ if (VUL_IS_TOP_LEVEL)
# Create VulkanUtilityLibraries-targets.cmake
set_target_properties(VulkanLayerSettings PROPERTIES EXPORT_NAME "LayerSettings")
set_target_properties(VulkanUtilityHeaders PROPERTIES EXPORT_NAME "UtilityHeaders")
set_target_properties(VulkanSafeStruct PROPERTIES EXPORT_NAME "SafeStruct")
set_target_properties(VulkanCompilerConfiguration PROPERTIES EXPORT_NAME "CompilerConfiguration")
install(
TARGETS VulkanLayerSettings VulkanUtilityHeaders VulkanCompilerConfiguration
TARGETS VulkanLayerSettings VulkanUtilityHeaders VulkanSafeStruct VulkanCompilerConfiguration
EXPORT VulkanUtilityLibraries-targets
INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
)
Expand Down
26 changes: 17 additions & 9 deletions include/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,15 @@
target_include_directories(VulkanLayerSettings PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>)

target_sources(VulkanLayerSettings PRIVATE
vulkan/layer/vk_layer_settings.h
vulkan/layer/vk_layer_settings.hpp
vulkan/layer/vk_layer_settings.h
vulkan/layer/vk_layer_settings.hpp
)

target_include_directories(VulkanSafeStruct PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>)

target_sources(VulkanSafeStruct PRIVATE
vulkan/utility/vk_safe_struct.hpp
vulkan/utility/vk_safe_struct_utils.hpp
)

set(CMAKE_FOLDER "${CMAKE_FOLDER}/VulkanUtilityHeaders")
Expand All @@ -17,15 +24,16 @@ add_library(Vulkan::UtilityHeaders ALIAS VulkanUtilityHeaders)

# https://cmake.org/cmake/help/latest/release/3.19.html#other
if (CMAKE_VERSION VERSION_GREATER_EQUAL "3.19")
target_sources(VulkanUtilityHeaders PRIVATE
vulkan/utility/vk_dispatch_table.h
vulkan/vk_enum_string_helper.h
vulkan/utility/vk_format_utils.h
vulkan/utility/vk_struct_helper.hpp
)
target_sources(VulkanUtilityHeaders PRIVATE
vulkan/vk_enum_string_helper.h
vulkan/utility/vk_concurrent_unordered_map.hpp
vulkan/utility/vk_dispatch_table.h
vulkan/utility/vk_format_utils.h
vulkan/utility/vk_struct_helper.hpp
)
endif()

target_link_Libraries(VulkanUtilityHeaders INTERFACE Vulkan::Headers)
target_link_libraries(VulkanUtilityHeaders INTERFACE Vulkan::Headers)

target_include_directories(VulkanUtilityHeaders INTERFACE $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>)

201 changes: 201 additions & 0 deletions include/vulkan/utility/vk_concurrent_unordered_map.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,201 @@
/* Copyright (c) 2015-2017, 2019-2024 The Khronos Group Inc.
* Copyright (c) 2015-2017, 2019-2024 Valve Corporation
* Copyright (c) 2015-2017, 2019-2024 LunarG, Inc.
* Modifications Copyright (C) 2022 RasterGrid Kft.
*
* SPDX-License-Identifier: Apache-2.0
*
*/

#pragma once

#include <array>
#include <functional>
#include <mutex>
#include <shared_mutex>
#include <unordered_map>
#include <vector>

namespace vku {
namespace concurrent {
// https://en.cppreference.com/w/cpp/thread/hardware_destructive_interference_size
// https://en.wikipedia.org/wiki/False_sharing
// TODO use C++20 to check for std::hardware_destructive_interference_size feature support.
constexpr std::size_t get_hardware_destructive_interference_size() { return 64; }

// Limited concurrent unordered_map that supports internally-synchronized
// insert/erase/access. Splits locking across N buckets and uses shared_mutex
// for read/write locking. Iterators are not supported. The following
// operations are supported:
//
// insert_or_assign: Insert a new element or update an existing element.
// insert: Insert a new element and return whether it was inserted.
// erase: Remove an element.
// contains: Returns true if the key is in the map.
// find: Returns != end() if found, value is in ret->second.
// pop: Erases and returns the erased value if found.
//
// find/end: find returns a vaguely iterator-like type that can be compared to
// end and can use iter->second to retrieve the reference. This is to ease porting
// for existing code that combines the existence check and lookup in a single
// operation (and thus a single lock). i.e.:
//
// auto iter = map.find(key);
// if (iter != map.end()) {
// T t = iter->second;
// ...
//
// snapshot: Return an array of elements (key, value pairs) that satisfy an optional
// predicate. This can be used as a substitute for iterators in exceptional cases.
template <typename Key, typename T, int BUCKETSLOG2 = 2, typename Map = std::unordered_map<Key, T>>
class unordered_map {
// Aliases to avoid excessive typing. We can't easily auto these away because
// there are virtual methods in ValidationObject which return lock guards
// and those cannot use return type deduction.
using ReadLockGuard = std::shared_lock<std::shared_mutex>;
using WriteLockGuard = std::unique_lock<std::shared_mutex>;

public:
template <typename... Args>
void insert_or_assign(const Key &key, Args &&...args) {
uint32_t h = ConcurrentMapHashObject(key);
WriteLockGuard lock(locks[h].lock);
maps[h][key] = {std::forward<Args>(args)...};
}

template <typename... Args>
bool insert(const Key &key, Args &&...args) {
uint32_t h = ConcurrentMapHashObject(key);
WriteLockGuard lock(locks[h].lock);
auto ret = maps[h].emplace(key, std::forward<Args>(args)...);
return ret.second;
}

// returns size_type
size_t erase(const Key &key) {
uint32_t h = ConcurrentMapHashObject(key);
WriteLockGuard lock(locks[h].lock);
return maps[h].erase(key);
}

bool contains(const Key &key) const {
uint32_t h = ConcurrentMapHashObject(key);
ReadLockGuard lock(locks[h].lock);
return maps[h].count(key) != 0;
}

// type returned by find() and end().
class FindResult {
public:
FindResult(bool a, T b) : result(a, std::move(b)) {}

// == and != only support comparing against end()
bool operator==(const FindResult &other) const {
if (result.first == false && other.result.first == false) {
return true;
}
return false;
}
bool operator!=(const FindResult &other) const { return !(*this == other); }

// Make -> act kind of like an iterator.
std::pair<bool, T> *operator->() { return &result; }
const std::pair<bool, T> *operator->() const { return &result; }

private:
// (found, reference to element)
std::pair<bool, T> result;
};

// find()/end() return a FindResult containing a copy of the value. For end(),
// return a default value.
FindResult end() const { return FindResult(false, T()); }
FindResult cend() const { return end(); }

FindResult find(const Key &key) const {
uint32_t h = ConcurrentMapHashObject(key);
ReadLockGuard lock(locks[h].lock);

auto itr = maps[h].find(key);
const bool found = itr != maps[h].end();

if (found) {
return FindResult(true, itr->second);
} else {
return end();
}
}

FindResult pop(const Key &key) {
uint32_t h = ConcurrentMapHashObject(key);
WriteLockGuard lock(locks[h].lock);

auto itr = maps[h].find(key);
const bool found = itr != maps[h].end();

if (found) {
auto ret = FindResult(true, itr->second);
maps[h].erase(itr);
return ret;
} else {
return end();
}
}

std::vector<std::pair<const Key, T>> snapshot(std::function<bool(T)> f = nullptr) const {
std::vector<std::pair<const Key, T>> ret;
for (int h = 0; h < BUCKETS; ++h) {
ReadLockGuard lock(locks[h].lock);
for (const auto &j : maps[h]) {
if (!f || f(j.second)) {
ret.emplace_back(j.first, j.second);
}
}
}
return ret;
}

void clear() {
for (int h = 0; h < BUCKETS; ++h) {
WriteLockGuard lock(locks[h].lock);
maps[h].clear();
}
}

size_t size() const {
size_t result = 0;
for (int h = 0; h < BUCKETS; ++h) {
ReadLockGuard lock(locks[h].lock);
result += maps[h].size();
}
return result;
}

bool empty() const {
bool result = 0;
for (int h = 0; h < BUCKETS; ++h) {
ReadLockGuard lock(locks[h].lock);
result |= maps[h].empty();
}
return result;
}

private:
static const int BUCKETS = (1 << BUCKETSLOG2);

Map maps[BUCKETS];
struct alignas(get_hardware_destructive_interference_size()) AlignedSharedMutex {
std::shared_mutex lock;
};
mutable std::array<AlignedSharedMutex, BUCKETS> locks;

uint32_t ConcurrentMapHashObject(const Key &object) const {
uint64_t u64 = (uint64_t)(uintptr_t)object;
uint32_t hash = (uint32_t)(u64 >> 32) + (uint32_t)u64;
hash ^= (hash >> BUCKETSLOG2) ^ (hash >> (2 * BUCKETSLOG2));
hash &= (BUCKETS - 1);
return hash;
}
};
} // namespace concurrent
} // namespace vku
Loading

0 comments on commit 9a88106

Please sign in to comment.