vladislavbelov
ffc4a56b9f
Fixes #6846 Differential Revision: https://code.wildfiregames.com/D5185 This was SVN commit r27965.
565 lines
23 KiB
C++
565 lines
23 KiB
C++
/* 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
|