vk: Refactor physical device selection (#1671)
Rather than electing the first physical device it finds, and falling back on the first-listed GPU: a series of stable-partitions are done so that the "least compromising" GPU is selected based on a series of criteria. It will now maximally try to find a GPU that(in order of priority): * Is a discrete GPU * Supports `fragmentStoresAndAtomics` * Supports `R5G5B5`/`R5G6B5A1`/`R4G4B4A4` In the case that a system has two dGPUs and one of them supports optimal-formats, the optimal-format one is selected In the case that a system has an iGPU and the dGPU and they both support optimal formats, the dGPU is selected. In the case that a system has an iGPU and the dGPU and the dGPU doesn't support optimal formats, the dGPU is still selected.
This commit is contained in:
parent
ff6a3119b0
commit
556e2ead56
|
@ -207,25 +207,50 @@ bool VulkanContext::InitInstance(const char** extensions, uint32_t extensions_co
|
|||
#endif
|
||||
#endif
|
||||
|
||||
const auto devices = instance->enumeratePhysicalDevices();
|
||||
auto devices = instance->enumeratePhysicalDevices();
|
||||
if (devices.empty())
|
||||
{
|
||||
ERROR_LOG(RENDERER, "Vulkan error: no physical devices found");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Choose a discrete gpu if there's one, otherwise just pick the first one
|
||||
physicalDevice = nullptr;
|
||||
for (const auto& phyDev : devices)
|
||||
{
|
||||
if (phyDev.getProperties().deviceType == vk::PhysicalDeviceType::eDiscreteGpu)
|
||||
// The order of physical-devices provided by the driver should be somewhat preserved with stable-partitions/stable-sorts
|
||||
|
||||
// Prefer GPUs that support optimal R5G5B5/R5G6B5A1/R4G4B4A4
|
||||
const auto supportsOptimalFormat = [](vk::Format format)
|
||||
{
|
||||
physicalDevice = phyDev;
|
||||
break;
|
||||
return [format](const vk::PhysicalDevice& physicalDevice) -> bool
|
||||
{
|
||||
const vk::FormatProperties formatProperties = physicalDevice.getFormatProperties(format);
|
||||
return (formatProperties.optimalTilingFeatures & vk::FormatFeatureFlagBits::eSampledImage)
|
||||
&& (formatProperties.optimalTilingFeatures & vk::FormatFeatureFlagBits::eBlitDst)
|
||||
&& (formatProperties.optimalTilingFeatures & vk::FormatFeatureFlagBits::eBlitSrc);
|
||||
};
|
||||
};
|
||||
std::stable_partition(devices.begin(), devices.end(), supportsOptimalFormat(vk::Format::eR5G6B5UnormPack16));
|
||||
std::stable_partition(devices.begin(), devices.end(), supportsOptimalFormat(vk::Format::eR5G5B5A1UnormPack16));
|
||||
std::stable_partition(devices.begin(), devices.end(), supportsOptimalFormat(vk::Format::eR4G4B4A4UnormPack16));
|
||||
|
||||
// Prefer GPUs that support fragmentStoresAndAtomics
|
||||
std::stable_partition(
|
||||
devices.begin(), devices.end(),
|
||||
[](const vk::PhysicalDevice& physicalDevice) -> bool
|
||||
{
|
||||
return !!physicalDevice.getFeatures().fragmentStoresAndAtomics;
|
||||
}
|
||||
}
|
||||
if (!physicalDevice)
|
||||
physicalDevice = devices.front();
|
||||
);
|
||||
|
||||
// Finally, prefer Discrete GPUs
|
||||
std::stable_partition(
|
||||
devices.begin(), devices.end(),
|
||||
[](const vk::PhysicalDevice& physicalDevice) -> bool
|
||||
{
|
||||
return physicalDevice.getProperties().deviceType == vk::PhysicalDeviceType::eDiscreteGpu;
|
||||
}
|
||||
);
|
||||
|
||||
// Top of the device-list is the _most_ qualified GPU
|
||||
physicalDevice = devices.front();
|
||||
|
||||
vk::PhysicalDeviceProperties properties = physicalDevice.getProperties();
|
||||
if (vulkan11 && properties.apiVersion >= VK_API_VERSION_1_1)
|
||||
|
|
Loading…
Reference in New Issue