0ad/source/renderer/backend/vulkan/DeviceSelection.cpp
bb 157c6af18e Make the space in 0 A.D. non-breaking throughout the codebase.
Avoid cases of filenames
Update years in terms and other legal(ish) documents
Don't update years in license headers, since change is not meaningful

Will add linter rule in seperate commit

Happy recompiling everyone!

Original Patch By: Nescio
Comment By: Gallaecio
Differential Revision: D2620
This was SVN commit r27786.
2023-07-27 20:54:46 +00:00

564 lines
23 KiB
C++
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/* Copyright (C) 2023 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* 0 A.D. is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
*/
#include "precompiled.h"
#include "DeviceSelection.h"
#include "lib/code_annotation.h"
#include "lib/config2.h"
#include "renderer/backend/vulkan/Device.h"
#include "renderer/backend/vulkan/Utilities.h"
#include "scriptinterface/JSON.h"
#include "scriptinterface/Object.h"
#include "scriptinterface/ScriptInterface.h"
#include "scriptinterface/ScriptRequest.h"
#include <algorithm>
#include <limits>
#include <string>
#include <type_traits>
#include <vector>
namespace Renderer
{
namespace Backend
{
namespace Vulkan
{
namespace
{
std::vector<std::string> GetPhysicalDeviceExtensions(VkPhysicalDevice device)
{
uint32_t extensionCount = 0;
ENSURE_VK_SUCCESS(vkEnumerateDeviceExtensionProperties(device, nullptr, &extensionCount, nullptr));
std::vector<VkExtensionProperties> extensions(extensionCount);
ENSURE_VK_SUCCESS(vkEnumerateDeviceExtensionProperties(device, nullptr, &extensionCount, extensions.data()));
std::vector<std::string> availableExtensions;
availableExtensions.reserve(extensions.size());
for (const VkExtensionProperties& extension : extensions)
availableExtensions.emplace_back(extension.extensionName);
std::sort(availableExtensions.begin(), availableExtensions.end());
return availableExtensions;
}
uint32_t GetDeviceTypeScore(const VkPhysicalDeviceType deviceType)
{
uint32_t score = 0;
// We prefer discrete GPU over integrated, and integrated over others.
switch (deviceType)
{
case VK_PHYSICAL_DEVICE_TYPE_OTHER:
score = 1;
break;
case VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU:
score = 4;
break;
case VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU:
score = 5;
break;
case VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU:
score = 3;
break;
case VK_PHYSICAL_DEVICE_TYPE_CPU:
score = 2;
break;
default:
break;
}
return score;
}
VkDeviceSize GetDeviceTotalMemory(
const VkPhysicalDeviceMemoryProperties& memoryProperties)
{
VkDeviceSize totalMemory = 0;
for (uint32_t heapIndex = 0; heapIndex < memoryProperties.memoryHeapCount; ++heapIndex)
if (memoryProperties.memoryHeaps[heapIndex].flags & VK_MEMORY_HEAP_DEVICE_LOCAL_BIT)
totalMemory += memoryProperties.memoryHeaps[heapIndex].size;
return totalMemory;
}
VkDeviceSize GetHostTotalMemory(
const VkPhysicalDeviceMemoryProperties& memoryProperties)
{
VkDeviceSize totalMemory = 0;
for (uint32_t heapIndex = 0; heapIndex < memoryProperties.memoryHeapCount; ++heapIndex)
if ((memoryProperties.memoryHeaps[heapIndex].flags & VK_MEMORY_HEAP_DEVICE_LOCAL_BIT) == 0)
totalMemory += memoryProperties.memoryHeaps[heapIndex].size;
return totalMemory;
}
// We don't support some types in JS, so wrap them to have in the report.
template<typename T, typename Tag = void>
struct ReportFormatHelper
{
std::string operator()(const T&) const { return "unknown"; }
};
template<typename T>
struct ReportFormatHelper<T, typename std::enable_if_t<std::is_floating_point_v<T>>>
{
float operator()(const T& value) const { return static_cast<float>(value); }
};
template<typename T>
struct ReportFormatHelper<T, typename std::enable_if_t<std::is_integral_v<T>>>
{
static constexpr bool IsSigned = std::is_signed_v<T>;
using ResultType = std::conditional_t<IsSigned, int32_t, uint32_t>;
uint32_t operator()(const T& value) const
{
if (value > std::numeric_limits<ResultType>::max())
return std::numeric_limits<ResultType>::max();
if constexpr (IsSigned)
{
if (value < std::numeric_limits<ResultType>::min())
return std::numeric_limits<ResultType>::min();
}
return static_cast<ResultType>(value);
}
};
template<typename T>
struct ReportFormatHelper<T, typename std::enable_if_t<std::is_enum_v<T>>>
{
using HelperType = ReportFormatHelper<std::underlying_type_t<T>>;
using ResultType = std::invoke_result_t<HelperType, std::underlying_type_t<T>>;
ResultType operator()(const T& value) const
{
HelperType helper{};
return helper(value);
}
};
template<typename T>
struct ReportFormatHelper<T, typename std::enable_if_t<std::is_array_v<T>>>
{
using HelperType = ReportFormatHelper<std::remove_extent_t<T>>;
using ElementType = std::invoke_result_t<HelperType, std::remove_extent_t<T>>;
std::vector<ElementType> operator()(const T& value) const
{
std::vector<ElementType> arr;
arr.reserve(std::size(value));
HelperType helper{};
for (const auto& element : value)
arr.emplace_back(helper(element));
return arr;
}
};
SAvailablePhysicalDevice MakeAvailablePhysicalDevice(
const uint32_t physicalDeviceIndex, VkPhysicalDevice physicalDevice,
VkSurfaceKHR surface, const std::vector<const char*>& requiredDeviceExtensions)
{
SAvailablePhysicalDevice availablePhysicalDevice{};
availablePhysicalDevice.index = physicalDeviceIndex;
availablePhysicalDevice.device = physicalDevice;
availablePhysicalDevice.hasOutputToSurfaceSupport = false;
availablePhysicalDevice.extensions = GetPhysicalDeviceExtensions(availablePhysicalDevice.device);
auto hasExtension = [&extensions = availablePhysicalDevice.extensions](const char* name) -> bool
{
return std::find(extensions.begin(), extensions.end(), name) != extensions.end();
};
availablePhysicalDevice.hasRequiredExtensions =
std::all_of(requiredDeviceExtensions.begin(), requiredDeviceExtensions.end(), hasExtension);
vkGetPhysicalDeviceMemoryProperties(
availablePhysicalDevice.device, &availablePhysicalDevice.memoryProperties);
availablePhysicalDevice.deviceTotalMemory =
GetDeviceTotalMemory(availablePhysicalDevice.memoryProperties);
availablePhysicalDevice.hostTotalMemory =
GetHostTotalMemory(availablePhysicalDevice.memoryProperties);
if (hasExtension(VK_EXT_DESCRIPTOR_INDEXING_EXTENSION_NAME))
{
VkPhysicalDeviceDescriptorIndexingPropertiesEXT descriptorIndexingProperties{};
descriptorIndexingProperties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_INDEXING_PROPERTIES_EXT;
VkPhysicalDeviceProperties2 devicesProperties2{};
devicesProperties2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2;
devicesProperties2.pNext = &descriptorIndexingProperties;
vkGetPhysicalDeviceProperties2(availablePhysicalDevice.device, &devicesProperties2);
availablePhysicalDevice.properties = devicesProperties2.properties;
availablePhysicalDevice.descriptorIndexingProperties = descriptorIndexingProperties;
VkPhysicalDeviceDescriptorIndexingFeaturesEXT descriptorIndexingFeatures{};
descriptorIndexingFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_INDEXING_FEATURES_EXT;
VkPhysicalDeviceFeatures2 deviceFeatures2{};
deviceFeatures2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2;
deviceFeatures2.pNext = &descriptorIndexingFeatures;
vkGetPhysicalDeviceFeatures2(availablePhysicalDevice.device, &deviceFeatures2);
availablePhysicalDevice.features = deviceFeatures2.features;
availablePhysicalDevice.descriptorIndexingFeatures = descriptorIndexingFeatures;
}
else
{
vkGetPhysicalDeviceProperties(availablePhysicalDevice.device, &availablePhysicalDevice.properties);
vkGetPhysicalDeviceFeatures(availablePhysicalDevice.device, &availablePhysicalDevice.features);
}
uint32_t queueFamilyCount = 0;
vkGetPhysicalDeviceQueueFamilyProperties(availablePhysicalDevice.device, &queueFamilyCount, nullptr);
availablePhysicalDevice.queueFamilies.resize(queueFamilyCount);
vkGetPhysicalDeviceQueueFamilyProperties(
availablePhysicalDevice.device, &queueFamilyCount, availablePhysicalDevice.queueFamilies.data());
availablePhysicalDevice.graphicsQueueFamilyIndex = availablePhysicalDevice.queueFamilies.size();
availablePhysicalDevice.presentQueueFamilyIndex = availablePhysicalDevice.queueFamilies.size();
if (surface != VK_NULL_HANDLE)
{
for (size_t familyIdx = 0; familyIdx < availablePhysicalDevice.queueFamilies.size(); ++familyIdx)
{
const VkQueueFamilyProperties& queueFamily = availablePhysicalDevice.queueFamilies[familyIdx];
VkBool32 hasOutputToSurfaceSupport = false;
ENSURE_VK_SUCCESS(vkGetPhysicalDeviceSurfaceSupportKHR(
availablePhysicalDevice.device, familyIdx, surface, &hasOutputToSurfaceSupport));
if ((queueFamily.queueFlags & VK_QUEUE_GRAPHICS_BIT) && hasOutputToSurfaceSupport)
{
availablePhysicalDevice.hasOutputToSurfaceSupport = hasOutputToSurfaceSupport;
availablePhysicalDevice.graphicsQueueFamilyIndex = familyIdx;
availablePhysicalDevice.presentQueueFamilyIndex = familyIdx;
break;
}
}
}
ENSURE_VK_SUCCESS(vkGetPhysicalDeviceSurfaceCapabilitiesKHR(
availablePhysicalDevice.device, surface, &availablePhysicalDevice.surfaceCapabilities));
uint32_t surfaceFormatCount = 0;
ENSURE_VK_SUCCESS(vkGetPhysicalDeviceSurfaceFormatsKHR(
availablePhysicalDevice.device, surface, &surfaceFormatCount, nullptr));
if (surfaceFormatCount > 0)
{
availablePhysicalDevice.surfaceFormats.resize(surfaceFormatCount);
ENSURE_VK_SUCCESS(vkGetPhysicalDeviceSurfaceFormatsKHR(
availablePhysicalDevice.device, surface, &surfaceFormatCount, availablePhysicalDevice.surfaceFormats.data()));
}
uint32_t presentModeCount = 0;
ENSURE_VK_SUCCESS(vkGetPhysicalDeviceSurfacePresentModesKHR(
availablePhysicalDevice.device, surface, &presentModeCount, nullptr));
if (presentModeCount > 0)
{
availablePhysicalDevice.presentModes.resize(presentModeCount);
ENSURE_VK_SUCCESS(vkGetPhysicalDeviceSurfacePresentModesKHR(
availablePhysicalDevice.device, surface, &presentModeCount, availablePhysicalDevice.presentModes.data()));
}
return availablePhysicalDevice;
}
} // anonymous namespace
std::vector<SAvailablePhysicalDevice> GetAvailablePhysicalDevices(
VkInstance instance, VkSurfaceKHR surface,
const std::vector<const char*>& requiredDeviceExtensions)
{
uint32_t physicalDeviceCount = 0;
ENSURE_VK_SUCCESS(vkEnumeratePhysicalDevices(instance, &physicalDeviceCount, nullptr));
if (physicalDeviceCount == 0)
return {};
std::vector<SAvailablePhysicalDevice> availablePhysicalDevices;
availablePhysicalDevices.reserve(physicalDeviceCount);
std::vector<VkPhysicalDevice> physicalDevices(physicalDeviceCount);
ENSURE_VK_SUCCESS(vkEnumeratePhysicalDevices(instance, &physicalDeviceCount, physicalDevices.data()));
for (uint32_t physicalDeviceIndex = 0; physicalDeviceIndex < physicalDeviceCount; ++physicalDeviceIndex)
{
availablePhysicalDevices.emplace_back(MakeAvailablePhysicalDevice(
physicalDeviceIndex, physicalDevices[physicalDeviceIndex], surface, requiredDeviceExtensions));
}
return availablePhysicalDevices;
}
bool IsPhysicalDeviceUnsupported(const SAvailablePhysicalDevice& device)
{
if (!device.hasRequiredExtensions)
return true;
// We can't draw something without graphics queue. And currently we don't
// support separate queues for graphics and present.
if (device.graphicsQueueFamilyIndex != device.presentQueueFamilyIndex)
return true;
if (device.graphicsQueueFamilyIndex == device.queueFamilies.size())
return true;
if (!device.hasOutputToSurfaceSupport)
return true;
if (device.properties.limits.maxBoundDescriptorSets < 4)
return true;
// It's guaranteed to have sRGB but we don't support it yet.
return std::none_of(device.surfaceFormats.begin(), device.surfaceFormats.end(), IsSurfaceFormatSupported);
}
bool ComparePhysicalDevices(
const SAvailablePhysicalDevice& device1,
const SAvailablePhysicalDevice& device2)
{
const uint32_t deviceTypeScore1 = GetDeviceTypeScore(device1.properties.deviceType);
const uint32_t deviceTypeScore2 = GetDeviceTypeScore(device2.properties.deviceType);
if (deviceTypeScore1 != deviceTypeScore2)
return deviceTypeScore1 > deviceTypeScore2;
// We use a total device memory amount to compare. We assume that more memory
// means better performance as previous metrics are equal.
if (device1.deviceTotalMemory != device2.deviceTotalMemory)
return device1.deviceTotalMemory > device2.deviceTotalMemory;
return device1.index < device2.index;
}
bool IsSurfaceFormatSupported(
const VkSurfaceFormatKHR& surfaceFormat)
{
return
surfaceFormat.colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR &&
(surfaceFormat.format == VK_FORMAT_R8G8B8A8_UNORM ||
surfaceFormat.format == VK_FORMAT_B8G8R8A8_UNORM);
}
void ReportAvailablePhysicalDevice(const SAvailablePhysicalDevice& device,
const ScriptRequest& rq, JS::HandleValue settings)
{
Script::SetProperty(rq, settings, "name", device.properties.deviceName);
Script::SetProperty(rq, settings, "version",
std::to_string(VK_API_VERSION_VARIANT(device.properties.apiVersion)) +
"." + std::to_string(VK_API_VERSION_MAJOR(device.properties.apiVersion)) +
"." + std::to_string(VK_API_VERSION_MINOR(device.properties.apiVersion)) +
"." + std::to_string(VK_API_VERSION_PATCH(device.properties.apiVersion)));
Script::SetProperty(rq, settings, "apiVersion", device.properties.apiVersion);
Script::SetProperty(rq, settings, "driverVersion", device.properties.driverVersion);
Script::SetProperty(rq, settings, "vendorID", device.properties.vendorID);
Script::SetProperty(rq, settings, "deviceID", device.properties.deviceID);
Script::SetProperty(rq, settings, "deviceType", static_cast<int32_t>(device.properties.deviceType));
Script::SetProperty(rq, settings, "index", device.index);
JS::RootedValue memory(rq.cx);
Script::CreateObject(rq, &memory);
JS::RootedValue memoryTypes(rq.cx);
Script::CreateArray(rq, &memoryTypes, device.memoryProperties.memoryTypeCount);
for (uint32_t memoryTypeIndex = 0; memoryTypeIndex < device.memoryProperties.memoryTypeCount; ++memoryTypeIndex)
{
const VkMemoryType& type = device.memoryProperties.memoryTypes[memoryTypeIndex];
JS::RootedValue memoryType(rq.cx);
Script::CreateObject(rq, &memoryType);
Script::SetProperty(rq, memoryType, "propertyFlags", static_cast<uint32_t>(type.propertyFlags));
Script::SetProperty(rq, memoryType, "heapIndex", type.heapIndex);
Script::SetPropertyInt(rq, memoryTypes, memoryTypeIndex, memoryType);
}
JS::RootedValue memoryHeaps(rq.cx);
Script::CreateArray(rq, &memoryHeaps, device.memoryProperties.memoryHeapCount);
for (uint32_t memoryHeapIndex = 0; memoryHeapIndex < device.memoryProperties.memoryHeapCount; ++memoryHeapIndex)
{
const VkMemoryHeap& heap = device.memoryProperties.memoryHeaps[memoryHeapIndex];
JS::RootedValue memoryHeap(rq.cx);
Script::CreateObject(rq, &memoryHeap);
// We can't serialize uint64_t in JS, so put data in KiB.
Script::SetProperty(rq, memoryHeap, "size", static_cast<uint32_t>(heap.size / 1024));
Script::SetProperty(rq, memoryHeap, "flags", static_cast<uint32_t>(heap.flags));
Script::SetPropertyInt(rq, memoryHeaps, memoryHeapIndex, memoryHeap);
}
Script::SetProperty(rq, memory, "types", memoryTypes);
Script::SetProperty(rq, memory, "heaps", memoryHeaps);
Script::SetProperty(rq, settings, "memory", memory);
JS::RootedValue constants(rq.cx);
Script::CreateObject(rq, &constants);
JS::RootedValue limitsConstants(rq.cx);
Script::CreateObject(rq, &limitsConstants);
#define REPORT_LIMITS_CONSTANT(NAME) \
do \
{ \
const ReportFormatHelper<decltype(device.properties.limits.NAME)> helper{}; \
Script::SetProperty(rq, limitsConstants, #NAME, helper(device.properties.limits.NAME)); \
} while (0)
REPORT_LIMITS_CONSTANT(maxImageDimension1D);
REPORT_LIMITS_CONSTANT(maxImageDimension2D);
REPORT_LIMITS_CONSTANT(maxImageDimension3D);
REPORT_LIMITS_CONSTANT(maxImageDimensionCube);
REPORT_LIMITS_CONSTANT(maxImageArrayLayers);
REPORT_LIMITS_CONSTANT(maxUniformBufferRange);
REPORT_LIMITS_CONSTANT(maxStorageBufferRange);
REPORT_LIMITS_CONSTANT(maxPushConstantsSize);
REPORT_LIMITS_CONSTANT(maxMemoryAllocationCount);
REPORT_LIMITS_CONSTANT(maxSamplerAllocationCount);
REPORT_LIMITS_CONSTANT(bufferImageGranularity);
REPORT_LIMITS_CONSTANT(maxBoundDescriptorSets);
REPORT_LIMITS_CONSTANT(maxPerStageDescriptorSamplers);
REPORT_LIMITS_CONSTANT(maxPerStageDescriptorUniformBuffers);
REPORT_LIMITS_CONSTANT(maxPerStageDescriptorStorageBuffers);
REPORT_LIMITS_CONSTANT(maxPerStageDescriptorSampledImages);
REPORT_LIMITS_CONSTANT(maxPerStageDescriptorStorageImages);
REPORT_LIMITS_CONSTANT(maxPerStageDescriptorInputAttachments);
REPORT_LIMITS_CONSTANT(maxPerStageResources);
REPORT_LIMITS_CONSTANT(maxDescriptorSetSamplers);
REPORT_LIMITS_CONSTANT(maxDescriptorSetUniformBuffers);
REPORT_LIMITS_CONSTANT(maxDescriptorSetUniformBuffersDynamic);
REPORT_LIMITS_CONSTANT(maxDescriptorSetStorageBuffers);
REPORT_LIMITS_CONSTANT(maxDescriptorSetStorageBuffersDynamic);
REPORT_LIMITS_CONSTANT(maxDescriptorSetSampledImages);
REPORT_LIMITS_CONSTANT(maxDescriptorSetStorageImages);
REPORT_LIMITS_CONSTANT(maxDescriptorSetInputAttachments);
REPORT_LIMITS_CONSTANT(maxVertexInputAttributes);
REPORT_LIMITS_CONSTANT(maxVertexInputBindings);
REPORT_LIMITS_CONSTANT(maxVertexInputAttributeOffset);
REPORT_LIMITS_CONSTANT(maxVertexInputBindingStride);
REPORT_LIMITS_CONSTANT(maxComputeSharedMemorySize);
REPORT_LIMITS_CONSTANT(maxComputeWorkGroupCount);
REPORT_LIMITS_CONSTANT(maxComputeWorkGroupInvocations);
REPORT_LIMITS_CONSTANT(maxComputeWorkGroupSize);
REPORT_LIMITS_CONSTANT(maxDrawIndexedIndexValue);
REPORT_LIMITS_CONSTANT(maxSamplerLodBias);
REPORT_LIMITS_CONSTANT(maxSamplerAnisotropy);
REPORT_LIMITS_CONSTANT(minMemoryMapAlignment);
REPORT_LIMITS_CONSTANT(minTexelBufferOffsetAlignment);
REPORT_LIMITS_CONSTANT(minUniformBufferOffsetAlignment);
REPORT_LIMITS_CONSTANT(minStorageBufferOffsetAlignment);
REPORT_LIMITS_CONSTANT(maxFramebufferWidth);
REPORT_LIMITS_CONSTANT(maxFramebufferHeight);
REPORT_LIMITS_CONSTANT(maxFramebufferLayers);
REPORT_LIMITS_CONSTANT(framebufferColorSampleCounts);
REPORT_LIMITS_CONSTANT(framebufferDepthSampleCounts);
REPORT_LIMITS_CONSTANT(framebufferStencilSampleCounts);
REPORT_LIMITS_CONSTANT(framebufferNoAttachmentsSampleCounts);
REPORT_LIMITS_CONSTANT(maxColorAttachments);
REPORT_LIMITS_CONSTANT(sampledImageColorSampleCounts);
REPORT_LIMITS_CONSTANT(sampledImageDepthSampleCounts);
REPORT_LIMITS_CONSTANT(sampledImageStencilSampleCounts);
REPORT_LIMITS_CONSTANT(storageImageSampleCounts);
REPORT_LIMITS_CONSTANT(optimalBufferCopyOffsetAlignment);
REPORT_LIMITS_CONSTANT(optimalBufferCopyRowPitchAlignment);
#undef REPORT_LIMITS_CONSTANT
Script::SetProperty(rq, constants, "limits", limitsConstants);
JS::RootedValue descriptorIndexingConstants(rq.cx);
Script::CreateObject(rq, &descriptorIndexingConstants);
#define REPORT_DESCRIPTOR_INDEXING_CONSTANT(NAME) \
do \
{ \
const ReportFormatHelper<decltype(device.descriptorIndexingProperties.NAME)> helper{}; \
Script::SetProperty(rq, descriptorIndexingConstants, #NAME, helper(device.descriptorIndexingProperties.NAME)); \
} while (0)
REPORT_DESCRIPTOR_INDEXING_CONSTANT(maxUpdateAfterBindDescriptorsInAllPools);
REPORT_DESCRIPTOR_INDEXING_CONSTANT(shaderSampledImageArrayNonUniformIndexingNative);
REPORT_DESCRIPTOR_INDEXING_CONSTANT(maxPerStageDescriptorUpdateAfterBindSamplers);
REPORT_DESCRIPTOR_INDEXING_CONSTANT(maxPerStageDescriptorUpdateAfterBindSampledImages);
REPORT_DESCRIPTOR_INDEXING_CONSTANT(maxPerStageDescriptorUpdateAfterBindUniformBuffers);
REPORT_DESCRIPTOR_INDEXING_CONSTANT(maxPerStageUpdateAfterBindResources);
REPORT_DESCRIPTOR_INDEXING_CONSTANT(maxDescriptorSetUpdateAfterBindSamplers);
REPORT_DESCRIPTOR_INDEXING_CONSTANT(maxDescriptorSetUpdateAfterBindSampledImages);
REPORT_DESCRIPTOR_INDEXING_CONSTANT(maxDescriptorSetUpdateAfterBindUniformBuffers);
REPORT_DESCRIPTOR_INDEXING_CONSTANT(maxDescriptorSetUpdateAfterBindUniformBuffersDynamic);
#undef REPORT_DESCRIPTOR_INDEXING_CONSTANT
Script::SetProperty(rq, constants, "descriptor_indexing", descriptorIndexingConstants);
Script::SetProperty(rq, settings, "constants", constants);
JS::RootedValue features(rq.cx);
Script::CreateObject(rq, &features);
#define REPORT_FEATURE(NAME) \
Script::SetProperty(rq, features, #NAME, static_cast<bool>(device.features.NAME));
REPORT_FEATURE(robustBufferAccess);
REPORT_FEATURE(fullDrawIndexUint32);
REPORT_FEATURE(imageCubeArray);
REPORT_FEATURE(geometryShader);
REPORT_FEATURE(tessellationShader);
REPORT_FEATURE(logicOp);
REPORT_FEATURE(multiDrawIndirect);
REPORT_FEATURE(depthClamp);
REPORT_FEATURE(depthBiasClamp);
REPORT_FEATURE(fillModeNonSolid);
REPORT_FEATURE(samplerAnisotropy);
REPORT_FEATURE(textureCompressionETC2);
REPORT_FEATURE(textureCompressionASTC_LDR);
REPORT_FEATURE(textureCompressionBC);
REPORT_FEATURE(pipelineStatisticsQuery);
REPORT_FEATURE(shaderUniformBufferArrayDynamicIndexing);
REPORT_FEATURE(shaderSampledImageArrayDynamicIndexing);
#undef REPORT_FEATURE
#define REPORT_DESCRIPTOR_INDEXING_FEATURE(NAME) \
Script::SetProperty(rq, features, #NAME, static_cast<bool>(device.descriptorIndexingFeatures.NAME));
REPORT_DESCRIPTOR_INDEXING_FEATURE(shaderSampledImageArrayNonUniformIndexing);
REPORT_DESCRIPTOR_INDEXING_FEATURE(descriptorBindingUniformBufferUpdateAfterBind);
REPORT_DESCRIPTOR_INDEXING_FEATURE(descriptorBindingSampledImageUpdateAfterBind);
REPORT_DESCRIPTOR_INDEXING_FEATURE(descriptorBindingPartiallyBound);
REPORT_DESCRIPTOR_INDEXING_FEATURE(descriptorBindingUpdateUnusedWhilePending);
REPORT_DESCRIPTOR_INDEXING_FEATURE(descriptorBindingPartiallyBound);
REPORT_DESCRIPTOR_INDEXING_FEATURE(descriptorBindingVariableDescriptorCount);
REPORT_DESCRIPTOR_INDEXING_FEATURE(runtimeDescriptorArray);
#undef REPORT_DESCRIPTOR_INDEXING_FEATURE
Script::SetProperty(rq, settings, "features", features);
JS::RootedValue presentModes(rq.cx);
Script::CreateArray(rq, &presentModes, device.presentModes.size());
for (size_t index = 0; index < device.presentModes.size(); ++index)
{
Script::SetPropertyInt(
rq, presentModes, index, static_cast<uint32_t>(device.presentModes[index]));
}
Script::SetProperty(rq, settings, "present_modes", presentModes);
JS::RootedValue surfaceFormats(rq.cx);
Script::CreateArray(rq, &surfaceFormats, device.surfaceFormats.size());
for (size_t index = 0; index < device.surfaceFormats.size(); ++index)
{
JS::RootedValue surfaceFormat(rq.cx);
Script::CreateObject(rq, &surfaceFormat);
Script::SetProperty(
rq, surfaceFormat, "format", static_cast<uint32_t>(device.surfaceFormats[index].format));
Script::SetProperty(
rq, surfaceFormat, "color_space", static_cast<uint32_t>(device.surfaceFormats[index].colorSpace));
Script::SetPropertyInt(rq, surfaceFormats, index, surfaceFormat);
}
Script::SetProperty(rq, settings, "surface_formats", surfaceFormats);
JS::RootedValue surfaceCapabilities(rq.cx);
Script::CreateObject(rq, &surfaceCapabilities);
#define REPORT_SURFACE_CAPABILITIES_CONSTANT(NAME) \
do \
{ \
const ReportFormatHelper<decltype(device.surfaceCapabilities.NAME)> helper{}; \
Script::SetProperty(rq, surfaceCapabilities, #NAME, helper(device.surfaceCapabilities.NAME)); \
} while (0)
REPORT_SURFACE_CAPABILITIES_CONSTANT(minImageCount);
REPORT_SURFACE_CAPABILITIES_CONSTANT(maxImageCount);
REPORT_SURFACE_CAPABILITIES_CONSTANT(maxImageArrayLayers);
REPORT_SURFACE_CAPABILITIES_CONSTANT(supportedTransforms);
REPORT_SURFACE_CAPABILITIES_CONSTANT(supportedCompositeAlpha);
REPORT_SURFACE_CAPABILITIES_CONSTANT(supportedUsageFlags);
#undef REPORT_SURFACE_CAPABILITIES_CONSTANT
Script::SetProperty(rq, settings, "surface_capabilities", surfaceCapabilities);
}
} // namespace Vulkan
} // namespace Backend
} // namespace Renderer