chrono_batch_render/
Coverage:
low: ≥ 0%
medium: ≥ 75.0%
high: ≥ 90.0%
Lines:
113 / 156
72.4%
Branches:
52 / 111
46.8%
Functions:
8 / 8
100.0%

device/vulkan/adapters.cpp
Line Branch Exec Source
1 // SPDX-License-Identifier: BSD-3-Clause
2 #include "chrono_batch_render/device/vulkan/device.h"
3
4 #include <algorithm>
5 #include <string>
6
7 #include "chrono_batch_render/util/library.h"
8 #include "chrono_batch_render/util/text.h"
9 #include "chrono_batch_render/util/version.h"
10
11 namespace chrono::batch_render::device::vulkan {
12 namespace {
13
14 constexpr uint32_t kVendorNvidia = 0x10de;
15 constexpr uint32_t kVendorIntel = 0x8086;
16
17 42 Version DecodeDriverVersion(uint32_t vendor, uint32_t packed) {
18
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 42 times.
42 if (vendor == kVendorNvidia) {
19 ✗ return {int(packed >> 22), int(packed >> 14 & 0xff), int(packed >> 6 & 0xff)};
20 }
21 #if defined(_WIN32)
22 if (vendor == kVendorIntel) {
23 return {int(packed >> 14), int(packed & 0x3fff)};
24 }
25 #else
26 42 static_cast<void>(kVendorIntel);
27 #endif
28 42 return DecodeVersion(packed);
29 }
30
31 42 std::string DriverName(VkDriverId id, const char* name) {
32
1/14
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 42 times.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
42 switch (id) {
33 ✗ case VK_DRIVER_ID_NVIDIA_PROPRIETARY:
34 ✗ return "nvidia";
35 ✗ case VK_DRIVER_ID_AMD_PROPRIETARY:
36 ✗ return "amd";
37 ✗ case VK_DRIVER_ID_AMD_OPEN_SOURCE:
38 ✗ return "amdvlk";
39 ✗ case VK_DRIVER_ID_MESA_RADV:
40 ✗ return "radv";
41 ✗ case VK_DRIVER_ID_INTEL_PROPRIETARY_WINDOWS:
42 ✗ return "intel";
43 ✗ case VK_DRIVER_ID_INTEL_OPEN_SOURCE_MESA:
44 ✗ return "anv";
45 ✗ case VK_DRIVER_ID_MESA_NVK:
46 ✗ return "nvk";
47 42 case VK_DRIVER_ID_MESA_LLVMPIPE:
48 42 return "llvmpipe";
49 ✗ case VK_DRIVER_ID_MOLTENVK:
50 ✗ return "moltenvk";
51 ✗ case VK_DRIVER_ID_MESA_HONEYKRISP:
52 ✗ return "honeykrisp";
53 ✗ case VK_DRIVER_ID_MESA_DOZEN:
54 ✗ return "dozen";
55 ✗ case VK_DRIVER_ID_MESA_VENUS:
56 ✗ return "venus";
57 ✗ case VK_DRIVER_ID_GOOGLE_SWIFTSHADER:
58 ✗ return "swiftshader";
59 ✗ default:
60 ✗ return Lowercase(name);
61 }
62 }
63
64 42 AdapterType ToAdapterType(VkPhysicalDeviceType type) {
65
1/5
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✓ Branch 2 taken 42 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
42 switch (type) {
66 case VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU:
67 return AdapterType::Discrete;
68 ✗ case VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU:
69 ✗ return AdapterType::Integrated;
70 ✗ case VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU:
71 ✗ return AdapterType::Virtual;
72 42 case VK_PHYSICAL_DEVICE_TYPE_CPU:
73 42 return AdapterType::Cpu;
74 ✗ default:
75 ✗ return AdapterType::Other;
76 }
77 }
78
79 42 void DescribeMemory(VkPhysicalDevice device, AdapterInfo& adapter) {
80 42 VkPhysicalDeviceMemoryProperties memory;
81 42 vkGetPhysicalDeviceMemoryProperties(device, &memory);
82 42 uint64_t local = 0;
83
2/2
✓ Branch 0 taken 42 times.
✓ Branch 1 taken 42 times.
84 for (uint32_t heap = 0; heap < memory.memoryHeapCount; ++heap) {
84
1/2
✓ Branch 0 taken 42 times.
✗ Branch 1 not taken.
42 if ((memory.memoryHeaps[heap].flags & VK_MEMORY_HEAP_DEVICE_LOCAL_BIT) != 0) {
85
1/2
✓ Branch 0 taken 42 times.
✗ Branch 1 not taken.
84 local = std::max(local, memory.memoryHeaps[heap].size);
86 }
87 }
88 // NOLINTNEXTLINE(bugprone-signed-bitwise)
89 42 constexpr VkMemoryPropertyFlags kMapped = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT |
90 VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT |
91 VK_MEMORY_PROPERTY_HOST_COHERENT_BIT;
92 42 uint64_t mapped = 0;
93
2/2
✓ Branch 0 taken 42 times.
✓ Branch 1 taken 42 times.
84 for (uint32_t type = 0; type < memory.memoryTypeCount; ++type) {
94
1/2
✓ Branch 0 taken 42 times.
✗ Branch 1 not taken.
42 if ((memory.memoryTypes[type].propertyFlags & kMapped) == kMapped) {
95
1/2
✓ Branch 0 taken 42 times.
✗ Branch 1 not taken.
84 mapped = std::max(mapped, memory.memoryHeaps[memory.memoryTypes[type].heapIndex].size);
96 }
97 }
98 42 adapter.memoryBytes = local;
99 42 adapter.features.unifiedMemory =
100 42 adapter.type == AdapterType::Integrated || adapter.type == AdapterType::Cpu;
101 84 adapter.features.hostMappedMemory =
102
1/6
✗ Branch 0 not taken.
✓ Branch 1 taken 42 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
42 adapter.features.unifiedMemory || (local > 0 && mapped >= local / 10 * 9);
103 42 }
104
105 42 void DescribeFeatures(AdapterInfo& adapter, const Extensions& extensions,
106 const FeatureChain& supported,
107 const VkPhysicalDeviceVulkan12Properties& vulkan12,
108 const VkPhysicalDeviceVulkan13Properties& vulkan13) {
109 42 Features& features = adapter.features;
110 42 const bool rayQueries = std::ranges::all_of(
111 126 kRayQueryExtensions, [&](const char* name) { return extensions.Has(name); });
112
2/4
✓ Branch 0 taken 42 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 42 times.
✗ Branch 3 not taken.
42 features.hardwareTraversal = rayQueries && supported.rayQuery.rayQuery &&
113
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 42 times.
42 supported.accelerationStructure.accelerationStructure;
114 #if defined(_WIN32)
115 features.externalMemory = extensions.Has("VK_KHR_external_memory_win32");
116 #else
117 42 features.externalMemory = extensions.Has(VK_KHR_EXTERNAL_MEMORY_FD_EXTENSION_NAME);
118 #endif
119
120 42 const VkPhysicalDeviceVulkan12Features& indexing = supported.vulkan12;
121 126 features.hardwareTextures = indexing.runtimeDescriptorArray &&
122
1/2
✓ Branch 0 taken 42 times.
✗ Branch 1 not taken.
42 indexing.descriptorBindingPartiallyBound &&
123
2/4
✓ Branch 0 taken 42 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 42 times.
✗ Branch 3 not taken.
84 indexing.descriptorBindingSampledImageUpdateAfterBind &&
124
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 42 times.
42 indexing.shaderSampledImageArrayNonUniformIndexing;
125 84 adapter.limits.maxTextures =
126 features.hardwareTextures
127
1/2
✓ Branch 0 taken 42 times.
✗ Branch 1 not taken.
42 ? std::min({kMaxTextures, vulkan12.maxPerStageDescriptorUpdateAfterBindSampledImages,
128 42 vulkan12.maxDescriptorSetUpdateAfterBindSampledImages})
129 : 0;
130
131 42 features.blockCompression = supported.base.features.textureCompressionBC;
132 42 features.anisotropicFiltering = supported.base.features.samplerAnisotropy;
133 42 features.float64 = supported.base.features.shaderFloat64;
134 42 features.atomicFloat32Add = supported.atomicFloat.shaderBufferFloat32AtomicAdd;
135 42 features.atomicInt64 = supported.vulkan12.shaderBufferInt64Atomics;
136 42 features.shaderClock = supported.clock.shaderDeviceClock;
137 42 features.kernelStatistics = supported.executables.pipelineExecutableInfo;
138 42 features.waveSizeMin = vulkan13.minSubgroupSize;
139 42 features.waveSizeMax = vulkan13.maxSubgroupSize;
140 42 }
141
142 42 std::vector<std::string> MissingFeatures(VkPhysicalDevice device, const FeatureChain& supported) {
143 42 std::vector<std::string> missing;
144
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 42 times.
42 if (!supported.vulkan12.bufferDeviceAddress) {
145
0/1
✗ Branch 1 not taken.
✗ missing.emplace_back("buffer device addresses");
146 }
147
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 42 times.
42 if (!supported.vulkan12.timelineSemaphore) {
148
0/1
✗ Branch 1 not taken.
✗ missing.emplace_back("timeline semaphores");
149 }
150
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 42 times.
42 if (!supported.vulkan13.synchronization2) {
151
0/1
✗ Branch 1 not taken.
✗ missing.emplace_back("synchronization2");
152 }
153
2/4
✓ Branch 0 taken 42 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 42 times.
42 if (!supported.vulkan13.subgroupSizeControl || !supported.vulkan13.computeFullSubgroups) {
154
0/1
✗ Branch 1 not taken.
✗ missing.emplace_back("full subgroups");
155 }
156
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 42 times.
42 if (!supported.base.features.shaderInt64) {
157
0/1
✗ Branch 1 not taken.
✗ missing.emplace_back("64-bit integers in shaders");
158 }
159
2/3
✓ Branch 1 taken 42 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 42 times.
42 if (!ComputeQueueFamily(device)) {
160
0/1
✗ Branch 1 not taken.
✗ missing.emplace_back("a compute queue");
161 }
162 42 return missing;
163 ✗ }
164
165 42 AdapterInfo Describe(VkPhysicalDevice device, uint32_t ordinal) {
166 42 VkPhysicalDeviceProperties properties;
167 42 vkGetPhysicalDeviceProperties(device, &properties);
168
169 42 AdapterInfo adapter;
170 42 adapter.backend = Backend::Vulkan;
171 42 adapter.ordinal = ordinal;
172
1/1
✓ Branch 1 taken 42 times.
42 adapter.name = properties.deviceName;
173 42 adapter.type = ToAdapterType(properties.deviceType);
174
1/1
✓ Branch 1 taken 42 times.
42 adapter.apiVersion = DecodeVersion(properties.apiVersion);
175 42 adapter.driverVersion = DecodeDriverVersion(properties.vendorID, properties.driverVersion);
176 42 adapter.limits.maxGroupSize = properties.limits.maxComputeWorkGroupInvocations;
177 42 adapter.limits.maxParamBytes = properties.limits.maxPushConstantsSize;
178 42 adapter.limits.maxAnisotropy = properties.limits.maxSamplerAnisotropy;
179
1/1
✓ Branch 1 taken 42 times.
42 DescribeMemory(device, adapter);
180
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 42 times.
42 if (adapter.apiVersion < kMinimumInstanceVersion) {
181
0/1
✗ Branch 1 not taken.
✗ adapter.unsupported = TooOld("its Vulkan", adapter.apiVersion, kMinimumInstanceVersion);
182 ✗ return adapter;
183 }
184
185 42 VkPhysicalDeviceVulkan13Properties vulkan13{
186 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_3_PROPERTIES};
187 42 VkPhysicalDeviceVulkan12Properties vulkan12{
188 42 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_PROPERTIES, &vulkan13};
189 42 VkPhysicalDeviceVulkan11Properties vulkan11{
190 42 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_1_PROPERTIES, &vulkan12};
191 42 VkPhysicalDeviceProperties2 properties2{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2,
192 42 &vulkan11};
193
1/1
✓ Branch 1 taken 42 times.
42 vkGetPhysicalDeviceProperties2(device, &properties2);
194 42 std::copy(std::begin(vulkan11.deviceUUID), std::end(vulkan11.deviceUUID), adapter.uuid.begin());
195
1/1
✓ Branch 1 taken 42 times.
42 adapter.architecture = DriverName(vulkan12.driverID, vulkan12.driverName);
196 42 adapter.limits.maxBufferBytes = vulkan13.maxBufferSize;
197 42 adapter.limits.maxReservedBytes = adapter.limits.maxBufferBytes;
198
199
1/1
✓ Branch 1 taken 42 times.
42 const Extensions extensions(device);
200 42 FeatureChain supported;
201
1/1
✓ Branch 5 taken 42 times.
294 supported.Link([&](const char* name) { return extensions.Has(name); });
202
1/1
✓ Branch 1 taken 42 times.
42 vkGetPhysicalDeviceFeatures2(device, &supported.base);
203
1/1
✓ Branch 1 taken 42 times.
42 DescribeFeatures(adapter, extensions, supported, vulkan12, vulkan13);
204 84 adapter.features.presentation =
205
3/4
✓ Branch 1 taken 42 times.
✓ Branch 4 taken 42 times.
✓ Branch 6 taken 42 times.
✗ Branch 7 not taken.
84 Extensions().Has(VK_KHR_SURFACE_EXTENSION_NAME) &&
206
3/5
✓ Branch 0 taken 42 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 42 times.
✓ Branch 5 taken 42 times.
✗ Branch 6 not taken.
84 extensions.Has(VK_KHR_SWAPCHAIN_EXTENSION_NAME) && supported.vulkan13.dynamicRendering &&
207
2/5
✓ Branch 1 taken 42 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 42 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
42 ComputeQueueFamily(device, VK_QUEUE_COMPUTE_BIT | VK_QUEUE_GRAPHICS_BIT).has_value();
208
209
1/1
✓ Branch 1 taken 42 times.
42 const std::vector<std::string> missing = MissingFeatures(device, supported);
210
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 42 times.
42 if (!missing.empty()) {
211
0/2
✗ Branch 1 not taken.
✗ Branch 4 not taken.
✗ adapter.unsupported = "it lacks " + Join(missing);
212 }
213 42 return adapter;
214 42 }
215
216 }
217
218 42 std::vector<AdapterInfo> ListAdapters() {
219 42 GetApi();
220 42 const std::vector<VkPhysicalDevice> devices = PhysicalDevices(Instance(false));
221 42 std::vector<AdapterInfo> adapters;
222
1/1
✓ Branch 1 taken 42 times.
42 adapters.reserve(devices.size());
223
2/2
✓ Branch 0 taken 42 times.
✓ Branch 1 taken 42 times.
84 for (uint32_t ordinal = 0; ordinal < devices.size(); ++ordinal) {
224
1/1
✓ Branch 1 taken 42 times.
84 adapters.push_back(Describe(devices[ordinal], ordinal));
225 }
226 42 return adapters;
227 42 }
228
229 }
230