Line data Source code
1 : /* Copyright (C) 2023 Wildfire Games.
2 : * This file is part of 0 A.D.
3 : *
4 : * 0 A.D. is free software: you can redistribute it and/or modify
5 : * it under the terms of the GNU General Public License as published by
6 : * the Free Software Foundation, either version 2 of the License, or
7 : * (at your option) any later version.
8 : *
9 : * 0 A.D. is distributed in the hope that it will be useful,
10 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 : * GNU General Public License for more details.
13 : *
14 : * You should have received a copy of the GNU General Public License
15 : * along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
16 : */
17 :
18 : #include "precompiled.h"
19 :
20 : #include "DeviceSelection.h"
21 :
22 : #include "lib/code_annotation.h"
23 : #include "lib/config2.h"
24 : #include "renderer/backend/vulkan/Device.h"
25 : #include "renderer/backend/vulkan/Utilities.h"
26 : #include "scriptinterface/JSON.h"
27 : #include "scriptinterface/Object.h"
28 : #include "scriptinterface/ScriptInterface.h"
29 : #include "scriptinterface/ScriptRequest.h"
30 :
31 : #include <algorithm>
32 : #include <limits>
33 : #include <string>
34 : #include <type_traits>
35 : #include <vector>
36 :
37 : namespace Renderer
38 : {
39 :
40 : namespace Backend
41 : {
42 :
43 : namespace Vulkan
44 : {
45 :
46 : namespace
47 : {
48 :
49 0 : std::vector<std::string> GetPhysicalDeviceExtensions(VkPhysicalDevice device)
50 : {
51 0 : uint32_t extensionCount = 0;
52 0 : ENSURE_VK_SUCCESS(vkEnumerateDeviceExtensionProperties(device, nullptr, &extensionCount, nullptr));
53 0 : std::vector<VkExtensionProperties> extensions(extensionCount);
54 0 : ENSURE_VK_SUCCESS(vkEnumerateDeviceExtensionProperties(device, nullptr, &extensionCount, extensions.data()));
55 :
56 0 : std::vector<std::string> availableExtensions;
57 0 : availableExtensions.reserve(extensions.size());
58 0 : for (const VkExtensionProperties& extension : extensions)
59 0 : availableExtensions.emplace_back(extension.extensionName);
60 0 : std::sort(availableExtensions.begin(), availableExtensions.end());
61 0 : return availableExtensions;
62 : }
63 :
64 0 : uint32_t GetDeviceTypeScore(const VkPhysicalDeviceType deviceType)
65 : {
66 0 : uint32_t score = 0;
67 : // We prefer discrete GPU over integrated, and integrated over others.
68 0 : switch (deviceType)
69 : {
70 0 : case VK_PHYSICAL_DEVICE_TYPE_OTHER:
71 0 : score = 1;
72 0 : break;
73 0 : case VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU:
74 0 : score = 4;
75 0 : break;
76 0 : case VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU:
77 0 : score = 5;
78 0 : break;
79 0 : case VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU:
80 0 : score = 3;
81 0 : break;
82 0 : case VK_PHYSICAL_DEVICE_TYPE_CPU:
83 0 : score = 2;
84 0 : break;
85 0 : default:
86 0 : break;
87 : }
88 0 : return score;
89 : }
90 :
91 0 : VkDeviceSize GetDeviceTotalMemory(
92 : const VkPhysicalDeviceMemoryProperties& memoryProperties)
93 : {
94 0 : VkDeviceSize totalMemory = 0;
95 0 : for (uint32_t heapIndex = 0; heapIndex < memoryProperties.memoryHeapCount; ++heapIndex)
96 0 : if (memoryProperties.memoryHeaps[heapIndex].flags & VK_MEMORY_HEAP_DEVICE_LOCAL_BIT)
97 0 : totalMemory += memoryProperties.memoryHeaps[heapIndex].size;
98 0 : return totalMemory;
99 : }
100 :
101 0 : VkDeviceSize GetHostTotalMemory(
102 : const VkPhysicalDeviceMemoryProperties& memoryProperties)
103 : {
104 0 : VkDeviceSize totalMemory = 0;
105 0 : for (uint32_t heapIndex = 0; heapIndex < memoryProperties.memoryHeapCount; ++heapIndex)
106 0 : if ((memoryProperties.memoryHeaps[heapIndex].flags & VK_MEMORY_HEAP_DEVICE_LOCAL_BIT) == 0)
107 0 : totalMemory += memoryProperties.memoryHeaps[heapIndex].size;
108 0 : return totalMemory;
109 : }
110 :
111 : // We don't support some types in JS, so wrap them to have in the report.
112 : template<typename T, typename Tag = void>
113 : struct ReportFormatHelper
114 : {
115 : std::string operator()(const T&) const { return "unknown"; }
116 : };
117 :
118 : template<typename T>
119 : struct ReportFormatHelper<T, typename std::enable_if_t<std::is_floating_point_v<T>>>
120 : {
121 0 : float operator()(const T& value) const { return static_cast<float>(value); }
122 : };
123 :
124 : template<typename T>
125 : struct ReportFormatHelper<T, typename std::enable_if_t<std::is_integral_v<T>>>
126 : {
127 : static constexpr bool IsSigned = std::is_signed_v<T>;
128 : using ResultType = std::conditional_t<IsSigned, int32_t, uint32_t>;
129 0 : uint32_t operator()(const T& value) const
130 : {
131 0 : if (value > std::numeric_limits<ResultType>::max())
132 0 : return std::numeric_limits<ResultType>::max();
133 : if constexpr (IsSigned)
134 : {
135 : if (value < std::numeric_limits<ResultType>::min())
136 : return std::numeric_limits<ResultType>::min();
137 : }
138 0 : return static_cast<ResultType>(value);
139 : }
140 : };
141 :
142 : template<typename T>
143 : struct ReportFormatHelper<T, typename std::enable_if_t<std::is_enum_v<T>>>
144 : {
145 : using HelperType = ReportFormatHelper<std::underlying_type_t<T>>;
146 : using ResultType = std::invoke_result_t<HelperType, std::underlying_type_t<T>>;
147 : ResultType operator()(const T& value) const
148 : {
149 : HelperType helper{};
150 : return helper(value);
151 : }
152 : };
153 :
154 : template<typename T>
155 : struct ReportFormatHelper<T, typename std::enable_if_t<std::is_array_v<T>>>
156 : {
157 : using HelperType = ReportFormatHelper<std::remove_extent_t<T>>;
158 : using ElementType = std::invoke_result_t<HelperType, std::remove_extent_t<T>>;
159 0 : std::vector<ElementType> operator()(const T& value) const
160 : {
161 0 : std::vector<ElementType> arr;
162 0 : arr.reserve(std::size(value));
163 : HelperType helper{};
164 0 : for (const auto& element : value)
165 0 : arr.emplace_back(helper(element));
166 0 : return arr;
167 : }
168 : };
169 :
170 0 : SAvailablePhysicalDevice MakeAvailablePhysicalDevice(
171 : const uint32_t physicalDeviceIndex, VkPhysicalDevice physicalDevice,
172 : VkSurfaceKHR surface, const std::vector<const char*>& requiredDeviceExtensions)
173 : {
174 0 : SAvailablePhysicalDevice availablePhysicalDevice{};
175 :
176 0 : availablePhysicalDevice.index = physicalDeviceIndex;
177 0 : availablePhysicalDevice.device = physicalDevice;
178 0 : availablePhysicalDevice.hasOutputToSurfaceSupport = false;
179 0 : availablePhysicalDevice.extensions = GetPhysicalDeviceExtensions(availablePhysicalDevice.device);
180 0 : auto hasExtension = [&extensions = availablePhysicalDevice.extensions](const char* name) -> bool
181 0 : {
182 0 : return std::find(extensions.begin(), extensions.end(), name) != extensions.end();
183 0 : };
184 :
185 0 : availablePhysicalDevice.hasRequiredExtensions =
186 0 : std::all_of(requiredDeviceExtensions.begin(), requiredDeviceExtensions.end(), hasExtension);
187 :
188 0 : vkGetPhysicalDeviceMemoryProperties(
189 : availablePhysicalDevice.device, &availablePhysicalDevice.memoryProperties);
190 0 : availablePhysicalDevice.deviceTotalMemory =
191 0 : GetDeviceTotalMemory(availablePhysicalDevice.memoryProperties);
192 0 : availablePhysicalDevice.hostTotalMemory =
193 0 : GetHostTotalMemory(availablePhysicalDevice.memoryProperties);
194 :
195 0 : VkPhysicalDeviceDescriptorIndexingPropertiesEXT descriptorIndexingProperties{};
196 0 : descriptorIndexingProperties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_INDEXING_PROPERTIES_EXT;
197 :
198 0 : VkPhysicalDeviceProperties2 deviesProperties2{};
199 0 : deviesProperties2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2;
200 0 : deviesProperties2.pNext = &descriptorIndexingProperties;
201 0 : vkGetPhysicalDeviceProperties2(availablePhysicalDevice.device, &deviesProperties2);
202 0 : availablePhysicalDevice.properties = deviesProperties2.properties;
203 0 : availablePhysicalDevice.descriptorIndexingProperties = descriptorIndexingProperties;
204 :
205 0 : VkPhysicalDeviceDescriptorIndexingFeaturesEXT descriptorIndexingFeatures{};
206 0 : descriptorIndexingFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_INDEXING_FEATURES_EXT;
207 :
208 0 : VkPhysicalDeviceFeatures2 deviceFeatures2{};
209 0 : deviceFeatures2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2;
210 0 : deviceFeatures2.pNext = &descriptorIndexingFeatures;
211 0 : vkGetPhysicalDeviceFeatures2(availablePhysicalDevice.device, &deviceFeatures2);
212 0 : availablePhysicalDevice.features = deviceFeatures2.features;
213 0 : availablePhysicalDevice.descriptorIndexingFeatures = descriptorIndexingFeatures;
214 :
215 0 : uint32_t queueFamilyCount = 0;
216 0 : vkGetPhysicalDeviceQueueFamilyProperties(availablePhysicalDevice.device, &queueFamilyCount, nullptr);
217 0 : availablePhysicalDevice.queueFamilies.resize(queueFamilyCount);
218 0 : vkGetPhysicalDeviceQueueFamilyProperties(
219 : availablePhysicalDevice.device, &queueFamilyCount, availablePhysicalDevice.queueFamilies.data());
220 :
221 0 : availablePhysicalDevice.graphicsQueueFamilyIndex = availablePhysicalDevice.queueFamilies.size();
222 0 : availablePhysicalDevice.presentQueueFamilyIndex = availablePhysicalDevice.queueFamilies.size();
223 0 : for (size_t familyIdx = 0; familyIdx < availablePhysicalDevice.queueFamilies.size(); ++familyIdx)
224 : {
225 0 : const VkQueueFamilyProperties& queueFamily = availablePhysicalDevice.queueFamilies[familyIdx];
226 0 : if (surface != VK_NULL_HANDLE)
227 : {
228 0 : VkBool32 hasOutputToSurfaceSupport = false;
229 0 : ENSURE_VK_SUCCESS(vkGetPhysicalDeviceSurfaceSupportKHR(
230 : availablePhysicalDevice.device, familyIdx, surface, &hasOutputToSurfaceSupport));
231 0 : availablePhysicalDevice.hasOutputToSurfaceSupport = hasOutputToSurfaceSupport;
232 0 : if ((queueFamily.queueFlags & VK_QUEUE_GRAPHICS_BIT) && hasOutputToSurfaceSupport)
233 : {
234 0 : availablePhysicalDevice.graphicsQueueFamilyIndex = familyIdx;
235 0 : availablePhysicalDevice.presentQueueFamilyIndex = familyIdx;
236 : }
237 : }
238 : }
239 :
240 0 : ENSURE_VK_SUCCESS(vkGetPhysicalDeviceSurfaceCapabilitiesKHR(
241 : availablePhysicalDevice.device, surface, &availablePhysicalDevice.surfaceCapabilities));
242 :
243 0 : uint32_t surfaceFormatCount = 0;
244 0 : ENSURE_VK_SUCCESS(vkGetPhysicalDeviceSurfaceFormatsKHR(
245 : availablePhysicalDevice.device, surface, &surfaceFormatCount, nullptr));
246 0 : if (surfaceFormatCount > 0)
247 : {
248 0 : availablePhysicalDevice.surfaceFormats.resize(surfaceFormatCount);
249 0 : ENSURE_VK_SUCCESS(vkGetPhysicalDeviceSurfaceFormatsKHR(
250 : availablePhysicalDevice.device, surface, &surfaceFormatCount, availablePhysicalDevice.surfaceFormats.data()));
251 : }
252 :
253 0 : uint32_t presentModeCount = 0;
254 0 : ENSURE_VK_SUCCESS(vkGetPhysicalDeviceSurfacePresentModesKHR(
255 : availablePhysicalDevice.device, surface, &presentModeCount, nullptr));
256 0 : if (presentModeCount > 0)
257 : {
258 0 : availablePhysicalDevice.presentModes.resize(presentModeCount);
259 0 : ENSURE_VK_SUCCESS(vkGetPhysicalDeviceSurfacePresentModesKHR(
260 : availablePhysicalDevice.device, surface, &presentModeCount, availablePhysicalDevice.presentModes.data()));
261 : }
262 :
263 0 : return availablePhysicalDevice;
264 : }
265 :
266 : } // anonymous namespace
267 :
268 0 : std::vector<SAvailablePhysicalDevice> GetAvailablePhysicalDevices(
269 : VkInstance instance, VkSurfaceKHR surface,
270 : const std::vector<const char*>& requiredDeviceExtensions)
271 : {
272 0 : uint32_t physicalDeviceCount = 0;
273 0 : ENSURE_VK_SUCCESS(vkEnumeratePhysicalDevices(instance, &physicalDeviceCount, nullptr));
274 0 : if (physicalDeviceCount == 0)
275 0 : return {};
276 :
277 0 : std::vector<SAvailablePhysicalDevice> availablePhysicalDevices;
278 0 : availablePhysicalDevices.reserve(physicalDeviceCount);
279 :
280 0 : std::vector<VkPhysicalDevice> physicalDevices(physicalDeviceCount);
281 0 : ENSURE_VK_SUCCESS(vkEnumeratePhysicalDevices(instance, &physicalDeviceCount, physicalDevices.data()));
282 0 : for (uint32_t physicalDeviceIndex = 0; physicalDeviceIndex < physicalDeviceCount; ++physicalDeviceIndex)
283 : {
284 0 : availablePhysicalDevices.emplace_back(MakeAvailablePhysicalDevice(
285 0 : physicalDeviceIndex, physicalDevices[physicalDeviceIndex], surface, requiredDeviceExtensions));
286 : }
287 :
288 0 : return availablePhysicalDevices;
289 : }
290 :
291 0 : bool IsPhysicalDeviceUnsupported(const SAvailablePhysicalDevice& device)
292 : {
293 0 : if (!device.hasRequiredExtensions)
294 0 : return true;
295 : // We can't draw something without graphics queue. And currently we don't
296 : // support separate queues for graphics and present.
297 0 : if (device.graphicsQueueFamilyIndex != device.presentQueueFamilyIndex)
298 0 : return true;
299 0 : if (device.graphicsQueueFamilyIndex == device.queueFamilies.size())
300 0 : return true;
301 0 : if (!device.hasOutputToSurfaceSupport)
302 0 : return true;
303 0 : if (device.properties.limits.maxBoundDescriptorSets < 4)
304 0 : return true;
305 : // It's guaranteed to have sRGB but we don't support it yet.
306 0 : return std::none_of(device.surfaceFormats.begin(), device.surfaceFormats.end(), IsSurfaceFormatSupported);
307 : }
308 :
309 0 : bool ComparePhysicalDevices(
310 : const SAvailablePhysicalDevice& device1,
311 : const SAvailablePhysicalDevice& device2)
312 : {
313 0 : const uint32_t deviceTypeScore1 = GetDeviceTypeScore(device1.properties.deviceType);
314 0 : const uint32_t deviceTypeScore2 = GetDeviceTypeScore(device2.properties.deviceType);
315 0 : if (deviceTypeScore1 != deviceTypeScore2)
316 0 : return deviceTypeScore1 > deviceTypeScore2;
317 : // We use a total device memory amount to compare. We assume that more memory
318 : // means better performance as previous metrics are equal.
319 0 : return device1.deviceTotalMemory > device2.deviceTotalMemory;
320 : }
321 :
322 0 : bool IsSurfaceFormatSupported(
323 : const VkSurfaceFormatKHR& surfaceFormat)
324 : {
325 : return
326 0 : surfaceFormat.colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR &&
327 0 : (surfaceFormat.format == VK_FORMAT_R8G8B8A8_UNORM ||
328 0 : surfaceFormat.format == VK_FORMAT_B8G8R8A8_UNORM);
329 : }
330 :
331 0 : void ReportAvailablePhysicalDevice(const SAvailablePhysicalDevice& device,
332 : const ScriptRequest& rq, JS::HandleValue settings)
333 : {
334 0 : Script::SetProperty(rq, settings, "name", device.properties.deviceName);
335 0 : Script::SetProperty(rq, settings, "version",
336 0 : std::to_string(VK_API_VERSION_VARIANT(device.properties.apiVersion)) +
337 0 : "." + std::to_string(VK_API_VERSION_MAJOR(device.properties.apiVersion)) +
338 0 : "." + std::to_string(VK_API_VERSION_MINOR(device.properties.apiVersion)) +
339 0 : "." + std::to_string(VK_API_VERSION_PATCH(device.properties.apiVersion)));
340 0 : Script::SetProperty(rq, settings, "apiVersion", device.properties.apiVersion);
341 0 : Script::SetProperty(rq, settings, "driverVersion", device.properties.driverVersion);
342 0 : Script::SetProperty(rq, settings, "vendorID", device.properties.vendorID);
343 0 : Script::SetProperty(rq, settings, "deviceID", device.properties.deviceID);
344 0 : Script::SetProperty(rq, settings, "deviceType", static_cast<int32_t>(device.properties.deviceType));
345 0 : Script::SetProperty(rq, settings, "index", device.index);
346 :
347 0 : JS::RootedValue memory(rq.cx);
348 0 : Script::CreateObject(rq, &memory);
349 :
350 0 : JS::RootedValue memoryTypes(rq.cx);
351 0 : Script::CreateArray(rq, &memoryTypes, device.memoryProperties.memoryTypeCount);
352 0 : for (uint32_t memoryTypeIndex = 0; memoryTypeIndex < device.memoryProperties.memoryTypeCount; ++memoryTypeIndex)
353 : {
354 0 : const VkMemoryType& type = device.memoryProperties.memoryTypes[memoryTypeIndex];
355 0 : JS::RootedValue memoryType(rq.cx);
356 0 : Script::CreateObject(rq, &memoryType);
357 0 : Script::SetProperty(rq, memoryType, "propertyFlags", static_cast<uint32_t>(type.propertyFlags));
358 0 : Script::SetProperty(rq, memoryType, "heapIndex", type.heapIndex);
359 0 : Script::SetPropertyInt(rq, memoryTypes, memoryTypeIndex, memoryType);
360 : }
361 0 : JS::RootedValue memoryHeaps(rq.cx);
362 0 : Script::CreateArray(rq, &memoryHeaps, device.memoryProperties.memoryHeapCount);
363 0 : for (uint32_t memoryHeapIndex = 0; memoryHeapIndex < device.memoryProperties.memoryHeapCount; ++memoryHeapIndex)
364 : {
365 0 : const VkMemoryHeap& heap = device.memoryProperties.memoryHeaps[memoryHeapIndex];
366 0 : JS::RootedValue memoryHeap(rq.cx);
367 0 : Script::CreateObject(rq, &memoryHeap);
368 : // We can't serialize uint64_t in JS, so put data in KiB.
369 0 : Script::SetProperty(rq, memoryHeap, "size", static_cast<uint32_t>(heap.size / 1024));
370 0 : Script::SetProperty(rq, memoryHeap, "flags", static_cast<uint32_t>(heap.flags));
371 0 : Script::SetPropertyInt(rq, memoryHeaps, memoryHeapIndex, memoryHeap);
372 : }
373 :
374 0 : Script::SetProperty(rq, memory, "types", memoryTypes);
375 0 : Script::SetProperty(rq, memory, "heaps", memoryHeaps);
376 0 : Script::SetProperty(rq, settings, "memory", memory);
377 :
378 0 : JS::RootedValue constants(rq.cx);
379 0 : Script::CreateObject(rq, &constants);
380 :
381 0 : JS::RootedValue limitsConstants(rq.cx);
382 0 : Script::CreateObject(rq, &limitsConstants);
383 : #define REPORT_LIMITS_CONSTANT(NAME) \
384 : do \
385 : { \
386 : const ReportFormatHelper<decltype(device.properties.limits.NAME)> helper{}; \
387 : Script::SetProperty(rq, limitsConstants, #NAME, helper(device.properties.limits.NAME)); \
388 : } while (0)
389 0 : REPORT_LIMITS_CONSTANT(maxImageDimension1D);
390 0 : REPORT_LIMITS_CONSTANT(maxImageDimension2D);
391 0 : REPORT_LIMITS_CONSTANT(maxImageDimension3D);
392 0 : REPORT_LIMITS_CONSTANT(maxImageDimensionCube);
393 0 : REPORT_LIMITS_CONSTANT(maxImageArrayLayers);
394 0 : REPORT_LIMITS_CONSTANT(maxUniformBufferRange);
395 0 : REPORT_LIMITS_CONSTANT(maxStorageBufferRange);
396 0 : REPORT_LIMITS_CONSTANT(maxPushConstantsSize);
397 0 : REPORT_LIMITS_CONSTANT(maxMemoryAllocationCount);
398 0 : REPORT_LIMITS_CONSTANT(maxSamplerAllocationCount);
399 0 : REPORT_LIMITS_CONSTANT(bufferImageGranularity);
400 0 : REPORT_LIMITS_CONSTANT(maxBoundDescriptorSets);
401 0 : REPORT_LIMITS_CONSTANT(maxPerStageDescriptorSamplers);
402 0 : REPORT_LIMITS_CONSTANT(maxPerStageDescriptorUniformBuffers);
403 0 : REPORT_LIMITS_CONSTANT(maxPerStageDescriptorStorageBuffers);
404 0 : REPORT_LIMITS_CONSTANT(maxPerStageDescriptorSampledImages);
405 0 : REPORT_LIMITS_CONSTANT(maxPerStageDescriptorStorageImages);
406 0 : REPORT_LIMITS_CONSTANT(maxPerStageDescriptorInputAttachments);
407 0 : REPORT_LIMITS_CONSTANT(maxPerStageResources);
408 0 : REPORT_LIMITS_CONSTANT(maxDescriptorSetSamplers);
409 0 : REPORT_LIMITS_CONSTANT(maxDescriptorSetUniformBuffers);
410 0 : REPORT_LIMITS_CONSTANT(maxDescriptorSetUniformBuffersDynamic);
411 0 : REPORT_LIMITS_CONSTANT(maxDescriptorSetStorageBuffers);
412 0 : REPORT_LIMITS_CONSTANT(maxDescriptorSetStorageBuffersDynamic);
413 0 : REPORT_LIMITS_CONSTANT(maxDescriptorSetSampledImages);
414 0 : REPORT_LIMITS_CONSTANT(maxDescriptorSetStorageImages);
415 0 : REPORT_LIMITS_CONSTANT(maxDescriptorSetInputAttachments);
416 0 : REPORT_LIMITS_CONSTANT(maxVertexInputAttributes);
417 0 : REPORT_LIMITS_CONSTANT(maxVertexInputBindings);
418 0 : REPORT_LIMITS_CONSTANT(maxVertexInputAttributeOffset);
419 0 : REPORT_LIMITS_CONSTANT(maxVertexInputBindingStride);
420 0 : REPORT_LIMITS_CONSTANT(maxComputeSharedMemorySize);
421 0 : REPORT_LIMITS_CONSTANT(maxComputeWorkGroupCount);
422 0 : REPORT_LIMITS_CONSTANT(maxComputeWorkGroupInvocations);
423 0 : REPORT_LIMITS_CONSTANT(maxComputeWorkGroupSize);
424 0 : REPORT_LIMITS_CONSTANT(maxDrawIndexedIndexValue);
425 0 : REPORT_LIMITS_CONSTANT(maxSamplerLodBias);
426 0 : REPORT_LIMITS_CONSTANT(maxSamplerAnisotropy);
427 0 : REPORT_LIMITS_CONSTANT(minMemoryMapAlignment);
428 0 : REPORT_LIMITS_CONSTANT(minTexelBufferOffsetAlignment);
429 0 : REPORT_LIMITS_CONSTANT(minUniformBufferOffsetAlignment);
430 0 : REPORT_LIMITS_CONSTANT(minStorageBufferOffsetAlignment);
431 0 : REPORT_LIMITS_CONSTANT(maxFramebufferWidth);
432 0 : REPORT_LIMITS_CONSTANT(maxFramebufferHeight);
433 0 : REPORT_LIMITS_CONSTANT(maxFramebufferLayers);
434 0 : REPORT_LIMITS_CONSTANT(framebufferColorSampleCounts);
435 0 : REPORT_LIMITS_CONSTANT(framebufferDepthSampleCounts);
436 0 : REPORT_LIMITS_CONSTANT(framebufferStencilSampleCounts);
437 0 : REPORT_LIMITS_CONSTANT(framebufferNoAttachmentsSampleCounts);
438 0 : REPORT_LIMITS_CONSTANT(maxColorAttachments);
439 0 : REPORT_LIMITS_CONSTANT(sampledImageColorSampleCounts);
440 0 : REPORT_LIMITS_CONSTANT(sampledImageDepthSampleCounts);
441 0 : REPORT_LIMITS_CONSTANT(sampledImageStencilSampleCounts);
442 0 : REPORT_LIMITS_CONSTANT(storageImageSampleCounts);
443 0 : REPORT_LIMITS_CONSTANT(optimalBufferCopyOffsetAlignment);
444 0 : REPORT_LIMITS_CONSTANT(optimalBufferCopyRowPitchAlignment);
445 : #undef REPORT_LIMITS_CONSTANT
446 0 : Script::SetProperty(rq, constants, "limits", limitsConstants);
447 :
448 0 : JS::RootedValue descriptorIndexingConstants(rq.cx);
449 0 : Script::CreateObject(rq, &descriptorIndexingConstants);
450 : #define REPORT_DESCRIPTOR_INDEXING_CONSTANT(NAME) \
451 : do \
452 : { \
453 : const ReportFormatHelper<decltype(device.descriptorIndexingProperties.NAME)> helper{}; \
454 : Script::SetProperty(rq, descriptorIndexingConstants, #NAME, helper(device.descriptorIndexingProperties.NAME)); \
455 : } while (0)
456 0 : REPORT_DESCRIPTOR_INDEXING_CONSTANT(maxUpdateAfterBindDescriptorsInAllPools);
457 0 : REPORT_DESCRIPTOR_INDEXING_CONSTANT(shaderSampledImageArrayNonUniformIndexingNative);
458 0 : REPORT_DESCRIPTOR_INDEXING_CONSTANT(maxPerStageDescriptorUpdateAfterBindSamplers);
459 0 : REPORT_DESCRIPTOR_INDEXING_CONSTANT(maxPerStageDescriptorUpdateAfterBindSampledImages);
460 0 : REPORT_DESCRIPTOR_INDEXING_CONSTANT(maxPerStageDescriptorUpdateAfterBindUniformBuffers);
461 0 : REPORT_DESCRIPTOR_INDEXING_CONSTANT(maxPerStageUpdateAfterBindResources);
462 0 : REPORT_DESCRIPTOR_INDEXING_CONSTANT(maxDescriptorSetUpdateAfterBindSamplers);
463 0 : REPORT_DESCRIPTOR_INDEXING_CONSTANT(maxDescriptorSetUpdateAfterBindSampledImages);
464 0 : REPORT_DESCRIPTOR_INDEXING_CONSTANT(maxDescriptorSetUpdateAfterBindUniformBuffers);
465 0 : REPORT_DESCRIPTOR_INDEXING_CONSTANT(maxDescriptorSetUpdateAfterBindUniformBuffersDynamic);
466 : #undef REPORT_DESCRIPTOR_INDEXING_CONSTANT
467 0 : Script::SetProperty(rq, constants, "descriptor_indexing", descriptorIndexingConstants);
468 :
469 0 : Script::SetProperty(rq, settings, "constants", constants);
470 :
471 0 : JS::RootedValue features(rq.cx);
472 0 : Script::CreateObject(rq, &features);
473 : #define REPORT_FEATURE(NAME) \
474 : Script::SetProperty(rq, features, #NAME, static_cast<bool>(device.features.NAME));
475 0 : REPORT_FEATURE(imageCubeArray);
476 0 : REPORT_FEATURE(geometryShader);
477 0 : REPORT_FEATURE(tessellationShader);
478 0 : REPORT_FEATURE(logicOp);
479 0 : REPORT_FEATURE(multiDrawIndirect);
480 0 : REPORT_FEATURE(depthClamp);
481 0 : REPORT_FEATURE(depthBiasClamp);
482 0 : REPORT_FEATURE(samplerAnisotropy);
483 0 : REPORT_FEATURE(textureCompressionETC2);
484 0 : REPORT_FEATURE(textureCompressionASTC_LDR);
485 0 : REPORT_FEATURE(textureCompressionBC);
486 0 : REPORT_FEATURE(pipelineStatisticsQuery);
487 : #undef REPORT_FEATURE
488 :
489 : #define REPORT_DESCRIPTOR_INDEXING_FEATURE(NAME) \
490 : Script::SetProperty(rq, features, #NAME, static_cast<bool>(device.descriptorIndexingFeatures.NAME));
491 0 : REPORT_DESCRIPTOR_INDEXING_FEATURE(shaderSampledImageArrayNonUniformIndexing);
492 0 : REPORT_DESCRIPTOR_INDEXING_FEATURE(descriptorBindingUniformBufferUpdateAfterBind);
493 0 : REPORT_DESCRIPTOR_INDEXING_FEATURE(descriptorBindingSampledImageUpdateAfterBind);
494 0 : REPORT_DESCRIPTOR_INDEXING_FEATURE(descriptorBindingPartiallyBound);
495 0 : REPORT_DESCRIPTOR_INDEXING_FEATURE(descriptorBindingUpdateUnusedWhilePending);
496 0 : REPORT_DESCRIPTOR_INDEXING_FEATURE(descriptorBindingPartiallyBound);
497 0 : REPORT_DESCRIPTOR_INDEXING_FEATURE(descriptorBindingVariableDescriptorCount);
498 0 : REPORT_DESCRIPTOR_INDEXING_FEATURE(runtimeDescriptorArray);
499 : #undef REPORT_DESCRIPTOR_INDEXING_FEATURE
500 :
501 0 : Script::SetProperty(rq, settings, "features", features);
502 :
503 0 : JS::RootedValue presentModes(rq.cx);
504 0 : Script::CreateArray(rq, &presentModes, device.presentModes.size());
505 0 : for (size_t index = 0; index < device.presentModes.size(); ++index)
506 : {
507 0 : Script::SetPropertyInt(
508 0 : rq, presentModes, index, static_cast<uint32_t>(device.presentModes[index]));
509 : }
510 0 : Script::SetProperty(rq, settings, "present_modes", presentModes);
511 :
512 0 : JS::RootedValue surfaceFormats(rq.cx);
513 0 : Script::CreateArray(rq, &surfaceFormats, device.surfaceFormats.size());
514 0 : for (size_t index = 0; index < device.surfaceFormats.size(); ++index)
515 : {
516 0 : JS::RootedValue surfaceFormat(rq.cx);
517 0 : Script::CreateObject(rq, &surfaceFormat);
518 0 : Script::SetProperty(
519 0 : rq, surfaceFormat, "format", static_cast<uint32_t>(device.surfaceFormats[index].format));
520 0 : Script::SetProperty(
521 0 : rq, surfaceFormat, "color_space", static_cast<uint32_t>(device.surfaceFormats[index].colorSpace));
522 0 : Script::SetPropertyInt(rq, surfaceFormats, index, surfaceFormat);
523 : }
524 0 : Script::SetProperty(rq, settings, "surface_formats", surfaceFormats);
525 :
526 0 : JS::RootedValue surfaceCapabilities(rq.cx);
527 0 : Script::CreateObject(rq, &surfaceCapabilities);
528 : #define REPORT_SURFACE_CAPABILITIES_CONSTANT(NAME) \
529 : do \
530 : { \
531 : const ReportFormatHelper<decltype(device.surfaceCapabilities.NAME)> helper{}; \
532 : Script::SetProperty(rq, surfaceCapabilities, #NAME, helper(device.surfaceCapabilities.NAME)); \
533 : } while (0)
534 0 : REPORT_SURFACE_CAPABILITIES_CONSTANT(minImageCount);
535 0 : REPORT_SURFACE_CAPABILITIES_CONSTANT(maxImageCount);
536 0 : REPORT_SURFACE_CAPABILITIES_CONSTANT(maxImageArrayLayers);
537 0 : REPORT_SURFACE_CAPABILITIES_CONSTANT(supportedTransforms);
538 0 : REPORT_SURFACE_CAPABILITIES_CONSTANT(supportedCompositeAlpha);
539 0 : REPORT_SURFACE_CAPABILITIES_CONSTANT(supportedUsageFlags);
540 : #undef REPORT_SURFACE_CAPABILITIES_CONSTANT
541 0 : Script::SetProperty(rq, settings, "surface_capabilities", surfaceCapabilities);
542 0 : }
543 :
544 : } // namespace Vulkan
545 :
546 : } // namespace Backend
547 :
548 3 : } // namespace Renderer
|