GCC Code Coverage Report


ernie/
Coverage:
low: ≥ 0%
medium: ≥ 75.0%
high: ≥ 90.0%
Lines:
69 / 106
65.1%
Branches:
31 / 94
33.0%
Functions:
11 / 12
91.7%

device/instance.cpp
Line Branch Exec Source
1 // SPDX-License-Identifier: BSD-3-Clause
2 /// @file instance.cpp
3 /// @brief Creating the instance, with validation configured through layer settings.
4 #include "ernie/device/instance.h"
5
6 #include "ernie/util/algorithm.h"
7 #include "ernie/util/on_failure.h"
8
9 #include <algorithm>
10 #include <array>
11 #include <string_view>
12 #include <utility>
13
14 namespace ernie {
15 namespace {
16
17 constexpr const char* kValidationLayer = "VK_LAYER_KHRONOS_validation";
18
19 template <typename Properties, typename Name>
20 158 bool Has(const std::vector<Properties>& list, std::string_view name, Name Properties::* field) {
21 158 return std::ranges::any_of(list, [&](const Properties& p) { return name == p.*field; });
22 }
23
24 82 std::vector<VkExtensionProperties> Extensions(const char* layer = nullptr) {
25 82 std::uint32_t count = 0;
26 82 vkEnumerateInstanceExtensionProperties(layer, &count, nullptr);
27 82 std::vector<VkExtensionProperties> extensions(count);
28
1/2
✓ Branch 1 taken 82 times.
✗ Branch 2 not taken.
82 vkEnumerateInstanceExtensionProperties(layer, &count, extensions.data());
29 82 return extensions;
30 ✗ }
31
32 76 bool HasValidationLayer() {
33 76 std::uint32_t count = 0;
34 76 vkEnumerateInstanceLayerProperties(&count, nullptr);
35 76 std::vector<VkLayerProperties> layers(count);
36
1/2
✓ Branch 1 taken 76 times.
✗ Branch 2 not taken.
76 vkEnumerateInstanceLayerProperties(&count, layers.data());
37 76 return Has(layers, kValidationLayer, &VkLayerProperties::layerName);
38 76 }
39
40 } // namespace
41
42
1/2
✓ Branch 1 taken 82 times.
✗ Branch 2 not taken.
82 Instance::Instance(const InstanceOptions& options) {
43
2/4
✓ Branch 1 taken 82 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 82 times.
82 if (volkInitialize() != VK_SUCCESS) {
44
0/2
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ throw DeviceError(DeviceErrorKind::Unsupported, "No Vulkan loader is installed");
45 }
46 82 std::vector<const char*> extensions =
47
1/4
✓ Branch 1 taken 82 times.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
82 Map(options.extensions, [](const std::string& name) { return name.c_str(); });
48
1/2
✓ Branch 1 taken 82 times.
✗ Branch 2 not taken.
82 const std::vector<VkExtensionProperties> available = Extensions();
49 82 VkInstanceCreateFlags flags = 0;
50 // Drivers layered over Metal (MoltenVK, Mesa on macOS) are listed only with portability
51 // enumeration.
52
1/2
✓ Branch 1 taken 82 times.
✗ Branch 2 not taken.
82 if (Has(available, VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME,
53 &VkExtensionProperties::extensionName)) {
54
1/2
✓ Branch 1 taken 82 times.
✗ Branch 2 not taken.
82 extensions.push_back(VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME);
55 82 flags |= VK_INSTANCE_CREATE_ENUMERATE_PORTABILITY_BIT_KHR;
56 }
57
4/6
✓ Branch 0 taken 76 times.
✓ Branch 1 taken 6 times.
✓ Branch 3 taken 76 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 76 times.
82 const bool validation = options.validation && HasValidationLayer();
58
0/2
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ const bool settings =
59
0/4
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ validation && Has(Extensions(kValidationLayer), VK_EXT_LAYER_SETTINGS_EXTENSION_NAME,
60 &VkExtensionProperties::extensionName);
61
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 82 times.
82 if (validation) {
62
0/2
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ extensions.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
63 }
64
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 82 times.
82 if (settings) {
65
0/2
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ extensions.push_back(VK_EXT_LAYER_SETTINGS_EXTENSION_NAME);
66 }
67 // Synchronization validation catches missing barriers, which ordinary validation does not.
68 82 const VkBool32 on = VK_TRUE;
69 82 const std::array layerSettings{
70 VkLayerSettingEXT{kValidationLayer, "validate_sync", VK_LAYER_SETTING_TYPE_BOOL32_EXT, 1,
71 &on},
72 82 };
73
1/2
✓ Branch 0 taken 82 times.
✗ Branch 1 not taken.
82 const VkLayerSettingsCreateInfoEXT layerSettingsInfo{
74 .sType = VK_STRUCTURE_TYPE_LAYER_SETTINGS_CREATE_INFO_EXT,
75 .settingCount = static_cast<std::uint32_t>(layerSettings.size()),
76 82 .pSettings = layerSettings.data()};
77 82 const VkApplicationInfo application{.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO,
78 .pApplicationName = "ernie",
79 .pEngineName = "ernie",
80 .apiVersion = VK_API_VERSION_1_3};
81 82 const VkInstanceCreateInfo info{.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO,
82
1/2
✓ Branch 0 taken 82 times.
✗ Branch 1 not taken.
82 .pNext = settings ? &layerSettingsInfo : nullptr,
83 .flags = flags,
84 .pApplicationInfo = &application,
85 82 .enabledLayerCount = validation ? 1u : 0u,
86 82 .ppEnabledLayerNames = validation ? &kValidationLayer : nullptr,
87 .enabledExtensionCount =
88
1/2
✓ Branch 1 taken 82 times.
✗ Branch 2 not taken.
82 static_cast<std::uint32_t>(extensions.size()),
89
3/6
✓ Branch 0 taken 82 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 82 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 82 times.
✗ Branch 6 not taken.
246 .ppEnabledExtensionNames = extensions.data()};
90
2/4
✓ Branch 1 taken 82 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 82 times.
✗ Branch 5 not taken.
82 CheckVk(vkCreateInstance(&info, nullptr, &instance_), "Creating a Vulkan 1.3 instance");
91
1/2
✓ Branch 2 taken 82 times.
✗ Branch 3 not taken.
82 const OnFailure freeInstance([&] { vkDestroyInstance(instance_, nullptr); });
92 // Device functions too, through the loader's dispatch: they then work for every device, where
93 // volkLoadDevice would tie the process to one.
94
1/2
✓ Branch 1 taken 82 times.
✗ Branch 2 not taken.
82 volkLoadInstance(instance_);
95
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 82 times.
82 if (validation) {
96 ✗ const auto load = [&](const char* name) { return vkGetInstanceProcAddr(instance_, name); };
97
0/2
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ const auto createMessenger = reinterpret_cast<PFN_vkCreateDebugUtilsMessengerEXT>(
98 ✗ load("vkCreateDebugUtilsMessengerEXT"));
99
0/2
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ destroyMessenger_ = reinterpret_cast<PFN_vkDestroyDebugUtilsMessengerEXT>(
100 ✗ load("vkDestroyDebugUtilsMessengerEXT"));
101
0/2
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ setName_ = reinterpret_cast<PFN_vkSetDebugUtilsObjectNameEXT>(
102 ✗ load("vkSetDebugUtilsObjectNameEXT"));
103
0/2
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ beginLabel_ = reinterpret_cast<PFN_vkCmdBeginDebugUtilsLabelEXT>(
104 ✗ load("vkCmdBeginDebugUtilsLabelEXT"));
105
0/2
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ endLabel_ =
106 ✗ reinterpret_cast<PFN_vkCmdEndDebugUtilsLabelEXT>(load("vkCmdEndDebugUtilsLabelEXT"));
107 ✗ const VkDebugUtilsMessengerCreateInfoEXT messenger{
108 .sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT,
109 .messageSeverity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT |
110 VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT,
111 .messageType = VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT |
112 VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT,
113 .pfnUserCallback = &Instance::Report,
114 ✗ .pUserData = this};
115
0/4
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ CheckVk(createMessenger(instance_, &messenger, nullptr, &messenger_),
116 "Creating the validation messenger");
117 }
118 82 }
119
120 82 Instance::~Instance() {
121
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 82 times.
82 if (messenger_ != VK_NULL_HANDLE) {
122 ✗ destroyMessenger_(instance_, messenger_, nullptr);
123 }
124 82 vkDestroyInstance(instance_, nullptr);
125 82 }
126
127 689 void Instance::Name(VkDevice device, VkObjectType type, std::uint64_t handle,
128 std::string_view name) const {
129
1/2
✓ Branch 0 taken 689 times.
✗ Branch 1 not taken.
689 if (setName_ == nullptr) {
130 689 return;
131 }
132 ✗ const std::string text(name);
133 ✗ const VkDebugUtilsObjectNameInfoEXT info{.sType =
134 VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT,
135 .objectType = type,
136 .objectHandle = handle,
137
0/2
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ .pObjectName = text.c_str()};
138
0/2
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ setName_(device, &info);
139 ✗ }
140
141 450 void Instance::BeginLabel(VkCommandBuffer commands, const char* name) const {
142
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 450 times.
450 if (beginLabel_ != nullptr) {
143 ✗ const VkDebugUtilsLabelEXT label{.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_LABEL_EXT,
144 ✗ .pLabelName = name};
145 ✗ beginLabel_(commands, &label);
146 }
147 450 }
148
149 450 void Instance::EndLabel(VkCommandBuffer commands) const {
150
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 450 times.
450 if (endLabel_ != nullptr) {
151 ✗ endLabel_(commands);
152 }
153 450 }
154
155 82 std::vector<VkPhysicalDevice> Instance::PhysicalDevices() const {
156 82 std::uint32_t count = 0;
157 82 vkEnumeratePhysicalDevices(instance_, &count, nullptr);
158 82 std::vector<VkPhysicalDevice> devices(count);
159
1/2
✓ Branch 1 taken 82 times.
✗ Branch 2 not taken.
82 vkEnumeratePhysicalDevices(instance_, &count, devices.data());
160 82 return devices;
161 ✗ }
162
163 67 std::vector<std::string> Instance::TakeMessages() {
164 67 const std::lock_guard lock(mutex_);
165 67 return std::exchange(messages_, {});
166 67 }
167
168 ✗ VkBool32 Instance::Report(VkDebugUtilsMessageSeverityFlagBitsEXT, VkDebugUtilsMessageTypeFlagsEXT,
169 const VkDebugUtilsMessengerCallbackDataEXT* data, void* self) {
170 ✗ auto& instance = *static_cast<Instance*>(self);
171 ✗ const std::lock_guard lock(instance.mutex_);
172
0/2
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ instance.messages_.emplace_back(data->pMessage);
173 ✗ return VK_FALSE;
174 ✗ }
175
176 } // namespace ernie
177