Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 34 additions & 0 deletions .clang-tidy
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# Copyright 2026 The Khronos Group Inc.
# Copyright 2026 Valve Corporation
# Copyright 2026 LunarG, Inc.
#
# SPDX-License-Identifier: Apache-2.0

---
Checks: >
bugprone-*,
cert-*,
clang-analyzer-*,
concurrency-*,
misc-*,
performance-*,
portability-*,
readability-inconsistent-declaration-parameter-name,
readability-isolate-declaration,
readability-non-const-parameter,
readability-redundant-casting,
readability-redundant-declaration,
readability-redundant-parentheses,
readability-suspicious-call-argument,
-bugprone-easily-swappable-parameters,
-cert-int09-c,
-misc-include-cleaner,
-misc-use-internal-linkage,
-misc-use-anonymous-namespace,
-misc-non-private-member-variables-in-classes,
-performance-enum-size,
-portability-avoid-pragma-once
WarningsAsErrors: '*'
HeaderFilterRegex: '.*/include/.*'
ExcludeHeaderFilterRegex: 'external/.*'
FormatStyle: none
25 changes: 24 additions & 1 deletion .github/workflows/format.yml → .github/workflows/lint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
#
# SPDX-License-Identifier: Apache-2.0

name: format
name: lint

on:
push:
Expand Down Expand Up @@ -32,3 +32,26 @@ jobs:
# turns a violation into a nonzero exit.
git ls-files -z -- '*.c' '*.h' '*.cpp' '*.hpp' |
xargs -0 -r clang-format --dry-run --Werror

clang-tidy:
name: clang-tidy
runs-on: ubuntu-26.04
timeout-minutes: 30

env:
CLANG_TIDY_VERSION: 22

steps:
- uses: actions/checkout@v7
- uses: actions/setup-python@v7
with:
python-version: '3.10'
- run: |
cmake -S. -B build \
-D CMAKE_BUILD_TYPE=Release \
-D UPDATE_DEPS=ON \
-D VUL_WERROR=ON \
-D BUILD_TESTS=ON \
-D USE_CLANG_TIDY=ON \
-D CLANG_TIDY_EXE=$(command -v clang-tidy-${CLANG_TIDY_VERSION})
- run: cmake --build build
10 changes: 10 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,16 @@ if (VUL_ENABLE_UBSAN)
endif()
endif()

option(USE_CLANG_TIDY "Run clang-tidy on the loader sources as part of the build")
if (USE_CLANG_TIDY)
if (CMAKE_VERSION VERSION_LESS "3.27")
message(FATAL_ERROR "USE_CLANG_TIDY requires CMake 3.27 or newer (for the SKIP_LINTING source property)")
endif()
find_program(CLANG_TIDY_EXE NAMES clang-tidy REQUIRED)
set(CMAKE_C_CLANG_TIDY "${CLANG_TIDY_EXE}")
set(CMAKE_CXX_CLANG_TIDY "${CLANG_TIDY_EXE}")
endif()

add_subdirectory(src)
add_subdirectory(include)

Expand Down
2 changes: 1 addition & 1 deletion include/vulkan/layer/vk_layer_settings.h
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ const VkLayerSettingsCreateInfoEXT *vkuNextLayerSettingsCreateInfo(const VkLayer

// Return the list of Unknown setting in VkLayerSettingsCreateInfoEXT
VkResult vkuGetUnknownSettings(VkuLayerSettingSet layerSettingSet, uint32_t layerSettingsCount, const char **pLayerSettings,
const VkLayerSettingsCreateInfoEXT *pFirstCreateInfo, uint32_t *pUnknownSettingCount,
const VkLayerSettingsCreateInfoEXT *pCreateInfo, uint32_t *pUnknownSettingCount,
const char **pUnknownSettings);

#ifdef __cplusplus
Expand Down
1 change: 0 additions & 1 deletion include/vulkan/layer/vk_layer_settings.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@
#include "vk_layer_settings.h"

#include <string>
#include <utility>
#include <vector>

VkResult vkuGetLayerSettingValue(VkuLayerSettingSet layerSettingSet, const char *pSettingName, bool &settingValue);
Expand Down
28 changes: 14 additions & 14 deletions include/vulkan/utility/vk_concurrent_unordered_map.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ constexpr std::size_t get_hardware_destructive_interference_size() { return 64;
//
// 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>>
template <typename Key, typename T, unsigned 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
Expand All @@ -67,9 +67,9 @@ class unordered_map {

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)...);
const uint32_t h = ConcurrentMapHashObject(key);
const WriteLockGuard lock(locks[h].lock);
const auto ret = maps[h].emplace(key, std::forward<Args>(args)...);
return ret.second;
}

Expand Down Expand Up @@ -115,10 +115,10 @@ class unordered_map {
FindResult cend() const { return end(); }

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

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

if (found) {
Expand All @@ -129,10 +129,10 @@ class unordered_map {
}

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

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

if (found) {
Expand Down Expand Up @@ -183,7 +183,7 @@ class unordered_map {
}

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

Map maps[BUCKETS];
struct alignas(get_hardware_destructive_interference_size()) AlignedSharedMutex {
Expand All @@ -192,10 +192,10 @@ class unordered_map {
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;
const uint64_t u64 = (uint64_t)(uintptr_t)object;
uint32_t hash = (uint32_t)(u64 >> 32u) + (uint32_t)u64;
hash ^= (hash >> BUCKETSLOG2) ^ (hash >> (2 * BUCKETSLOG2));
hash &= (BUCKETS - 1);
hash &= (BUCKETS - 1u);
return hash;
}
};
Expand Down
2 changes: 1 addition & 1 deletion include/vulkan/utility/vk_format_utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -269,7 +269,7 @@ static inline uint32_t vkuFormatPlaneCount(VkFormat format);
// Returns whether a VkFormat is multiplane
// Note - Formats like VK_FORMAT_G8B8G8R8_422_UNORM are NOT multi-planar, they require a
// VkSamplerYcbcrConversion and you should use vkuFormatRequiresYcbcrConversion instead
static inline bool vkuFormatIsMultiplane(VkFormat format) { return ((vkuFormatPlaneCount(format)) > 1u); }
static inline bool vkuFormatIsMultiplane(VkFormat format) { return (vkuFormatPlaneCount(format) > 1u); }

// Returns a VkFormat that is compatible with a given plane of a multiplane format
// Will return VK_FORMAT_UNDEFINED if given a plane aspect that doesn't exist for the format
Expand Down
20 changes: 1 addition & 19 deletions include/vulkan/utility/vk_safe_struct.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -23393,32 +23393,14 @@ struct safe_VkClusterAccelerationStructureMoveObjectsInputNV {
return reinterpret_cast<VkClusterAccelerationStructureMoveObjectsInputNV const*>(this);
}
};
union safe_VkClusterAccelerationStructureOpInputNV {
safe_VkClusterAccelerationStructureClustersBottomLevelInputNV* pClustersBottomLevel;
safe_VkClusterAccelerationStructureTriangleClusterInputNV* pTriangleClusters;
safe_VkClusterAccelerationStructureMoveObjectsInputNV* pMoveObjects;

safe_VkClusterAccelerationStructureOpInputNV(const VkClusterAccelerationStructureOpInputNV* in_struct,
PNextCopyState* copy_state = {});
safe_VkClusterAccelerationStructureOpInputNV(const safe_VkClusterAccelerationStructureOpInputNV& copy_src);
safe_VkClusterAccelerationStructureOpInputNV& operator=(const safe_VkClusterAccelerationStructureOpInputNV& copy_src);
safe_VkClusterAccelerationStructureOpInputNV();
~safe_VkClusterAccelerationStructureOpInputNV();
void initialize(const VkClusterAccelerationStructureOpInputNV* in_struct, PNextCopyState* copy_state = {});
void initialize(const safe_VkClusterAccelerationStructureOpInputNV* copy_src, PNextCopyState* copy_state = {});
VkClusterAccelerationStructureOpInputNV* ptr() { return reinterpret_cast<VkClusterAccelerationStructureOpInputNV*>(this); }
VkClusterAccelerationStructureOpInputNV const* ptr() const {
return reinterpret_cast<VkClusterAccelerationStructureOpInputNV const*>(this);
}
};
struct safe_VkClusterAccelerationStructureInputInfoNV {
VkStructureType sType;
void* pNext{};
uint32_t maxAccelerationStructureCount;
VkBuildAccelerationStructureFlagsKHR flags;
VkClusterAccelerationStructureOpTypeNV opType;
VkClusterAccelerationStructureOpModeNV opMode;
safe_VkClusterAccelerationStructureOpInputNV opInput;
VkClusterAccelerationStructureOpInputNV opInput;

safe_VkClusterAccelerationStructureInputInfoNV(const VkClusterAccelerationStructureInputInfoNV* in_struct,
PNextCopyState* copy_state = {}, bool copy_pnext = true);
Expand Down
8 changes: 4 additions & 4 deletions include/vulkan/utility/vk_safe_struct_utils.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@
#include <cstdlib>
#include <cstring>
#include <functional>
#include <vector>

namespace vku {

Expand Down Expand Up @@ -77,14 +76,15 @@ uint32_t FindExtension(CreateInfo& ci, const char* extension_name) {
template <typename CreateInfo>
bool AddExtension(CreateInfo& ci, const char* extension_name) {
assert(ci.ptr()); // All safe struct have a ptr() method. Prevent use with non-safe structs.
uint32_t pos = FindExtension(ci, extension_name);
const uint32_t pos = FindExtension(ci, extension_name);
if (pos < ci.enabledExtensionCount) {
// already present
return false;
}
char** exts = new char*[ci.enabledExtensionCount + 1];
if (ci.ppEnabledExtensionNames) {
memcpy(exts, ci.ppEnabledExtensionNames, sizeof(char*) * ci.enabledExtensionCount);
memcpy(static_cast<void*>(exts), static_cast<const void*>(ci.ppEnabledExtensionNames),
sizeof(char*) * ci.enabledExtensionCount);
}
exts[ci.enabledExtensionCount] = SafeStringCopy(extension_name);
delete[] ci.ppEnabledExtensionNames;
Expand All @@ -96,7 +96,7 @@ bool AddExtension(CreateInfo& ci, const char* extension_name) {
template <typename CreateInfo>
bool RemoveExtension(CreateInfo& ci, const char* extension_name) {
assert(ci.ptr()); // All safe struct have a ptr() method. Prevent use with non-safe structs.
uint32_t pos = FindExtension(ci, extension_name);
const uint32_t pos = FindExtension(ci, extension_name);
if (pos >= ci.enabledExtensionCount) {
// not present
return false;
Expand Down
13 changes: 7 additions & 6 deletions include/vulkan/utility/vk_small_containers.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,17 +45,18 @@ class vector {

vector(const vector &other) : size_(0), capacity_(N), working_store_(GetSmallStore()) { PushBackFrom(other); }

vector(vector &&other) : size_(0), capacity_(N), working_store_(GetSmallStore()) {
vector(vector &&other) noexcept : size_(0), capacity_(N), working_store_(GetSmallStore()) {
if (other.large_store_) {
MoveLargeStore(other);
// Per the spec, when constructing from other, other is guaranteed to be empty after the constructor runs
other.clear();
} else {
PushBackFrom(std::move(other));
}
// Per the spec, when constructing from other, other is guaranteed to be empty after the constructor runs
other.clear();
}

vector(size_type size, const value_type &value = value_type()) : size_(0), capacity_(N), working_store_(GetSmallStore()) {
explicit vector(size_type size, const value_type &value = value_type()) noexcept
: size_(0), capacity_(N), working_store_(GetSmallStore()) {
reserve(size);
auto dest = GetWorkingStore();
for (size_type i = 0; i < size; i++) {
Expand Down Expand Up @@ -115,7 +116,7 @@ class vector {
return *this;
}

vector &operator=(vector &&other) {
vector &operator=(vector &&other) noexcept {
if (this != &other) {
// Note: move assign doesn't require other to become empty (as does move construction)
// so we'll leave other alone except in the large store case, while moving the object
Expand Down Expand Up @@ -271,7 +272,7 @@ class vector {
} else if ((capacity_ > kSmallCapacity) && (capacity_ > size_)) {
auto source = GetWorkingStore();
// Keep the source from disappearing until the end of the function
auto old_store = std::unique_ptr<BackingStore[]>(std::move(large_store_));
const auto old_store = std::unique_ptr<BackingStore[]>(std::move(large_store_));
assert(!large_store_);
if (size_ < kSmallCapacity) {
capacity_ = kSmallCapacity;
Expand Down
Loading
Loading