vk_device: Stop initialization when device is not suitable
VKDevice::IsSuitable was not being called. To address this issue, check suitability before initialization and throw an exception if it fails. By doing this, we can deduplicate some code on queue searches. Previosuly we would first search if a present and graphics queue existed, then on initialization we would search again to find the index.
This commit is contained in:
parent
53ea06dc17
commit
f687392e6f
|
@ -210,6 +210,7 @@ VKDevice::VKDevice(VkInstance instance_, u32 instance_version_, vk::PhysicalDevi
|
||||||
VkSurfaceKHR surface, const vk::InstanceDispatch& dld_)
|
VkSurfaceKHR surface, const vk::InstanceDispatch& dld_)
|
||||||
: instance{instance_}, dld{dld_}, physical{physical_}, properties{physical.GetProperties()},
|
: instance{instance_}, dld{dld_}, physical{physical_}, properties{physical.GetProperties()},
|
||||||
instance_version{instance_version_}, format_properties{GetFormatProperties(physical, dld)} {
|
instance_version{instance_version_}, format_properties{GetFormatProperties(physical, dld)} {
|
||||||
|
CheckSuitability();
|
||||||
SetupFamilies(surface);
|
SetupFamilies(surface);
|
||||||
SetupFeatures();
|
SetupFeatures();
|
||||||
|
|
||||||
|
@ -548,64 +549,41 @@ bool VKDevice::IsFormatSupported(VkFormat wanted_format, VkFormatFeatureFlags wa
|
||||||
return (supported_usage & wanted_usage) == wanted_usage;
|
return (supported_usage & wanted_usage) == wanted_usage;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool VKDevice::IsSuitable(vk::PhysicalDevice physical, VkSurfaceKHR surface) {
|
void VKDevice::CheckSuitability() const {
|
||||||
bool is_suitable = true;
|
|
||||||
std::bitset<REQUIRED_EXTENSIONS.size()> available_extensions;
|
std::bitset<REQUIRED_EXTENSIONS.size()> available_extensions;
|
||||||
|
for (const VkExtensionProperties& property : physical.EnumerateDeviceExtensionProperties()) {
|
||||||
for (const auto& prop : physical.EnumerateDeviceExtensionProperties()) {
|
|
||||||
for (std::size_t i = 0; i < REQUIRED_EXTENSIONS.size(); ++i) {
|
for (std::size_t i = 0; i < REQUIRED_EXTENSIONS.size(); ++i) {
|
||||||
if (available_extensions[i]) {
|
if (available_extensions[i]) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
const std::string_view name{prop.extensionName};
|
const std::string_view name{property.extensionName};
|
||||||
available_extensions[i] = name == REQUIRED_EXTENSIONS[i];
|
available_extensions[i] = name == REQUIRED_EXTENSIONS[i];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!available_extensions.all()) {
|
for (size_t i = 0; i < REQUIRED_EXTENSIONS.size(); ++i) {
|
||||||
for (std::size_t i = 0; i < REQUIRED_EXTENSIONS.size(); ++i) {
|
if (available_extensions[i]) {
|
||||||
if (available_extensions[i]) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
LOG_ERROR(Render_Vulkan, "Missing required extension: {}", REQUIRED_EXTENSIONS[i]);
|
|
||||||
is_suitable = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool has_graphics{}, has_present{};
|
|
||||||
const std::vector queue_family_properties = physical.GetQueueFamilyProperties();
|
|
||||||
for (u32 i = 0; i < static_cast<u32>(queue_family_properties.size()); ++i) {
|
|
||||||
const auto& family = queue_family_properties[i];
|
|
||||||
if (family.queueCount == 0) {
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
has_graphics |= family.queueFlags & VK_QUEUE_GRAPHICS_BIT;
|
LOG_ERROR(Render_Vulkan, "Missing required extension: {}", REQUIRED_EXTENSIONS[i]);
|
||||||
has_present |= physical.GetSurfaceSupportKHR(i, surface);
|
throw vk::Exception(VK_ERROR_EXTENSION_NOT_PRESENT);
|
||||||
}
|
}
|
||||||
if (!has_graphics || !has_present) {
|
|
||||||
LOG_ERROR(Render_Vulkan, "Device lacks a graphics and present queue");
|
|
||||||
is_suitable = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO(Rodrigo): Check if the device matches all requeriments.
|
// TODO(Rodrigo): Check if the device matches all requeriments.
|
||||||
const auto properties{physical.GetProperties()};
|
const VkPhysicalDeviceLimits& limits{properties.limits};
|
||||||
const auto& limits{properties.limits};
|
|
||||||
|
|
||||||
constexpr u32 required_ubo_size = 65536;
|
constexpr u32 required_ubo_size = 65536;
|
||||||
if (limits.maxUniformBufferRange < required_ubo_size) {
|
if (limits.maxUniformBufferRange < required_ubo_size) {
|
||||||
LOG_ERROR(Render_Vulkan, "Device UBO size {} is too small, {} is required",
|
LOG_ERROR(Render_Vulkan, "Device UBO size {} is too small, {} is required",
|
||||||
limits.maxUniformBufferRange, required_ubo_size);
|
limits.maxUniformBufferRange, required_ubo_size);
|
||||||
is_suitable = false;
|
throw vk::Exception(VK_ERROR_FEATURE_NOT_PRESENT);
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr u32 required_num_viewports = 16;
|
constexpr u32 required_num_viewports = 16;
|
||||||
if (limits.maxViewports < required_num_viewports) {
|
if (limits.maxViewports < required_num_viewports) {
|
||||||
LOG_INFO(Render_Vulkan, "Device number of viewports {} is too small, {} is required",
|
LOG_INFO(Render_Vulkan, "Device number of viewports {} is too small, {} is required",
|
||||||
limits.maxViewports, required_num_viewports);
|
limits.maxViewports, required_num_viewports);
|
||||||
is_suitable = false;
|
throw vk::Exception(VK_ERROR_FEATURE_NOT_PRESENT);
|
||||||
}
|
}
|
||||||
|
const VkPhysicalDeviceFeatures features{physical.GetFeatures()};
|
||||||
const auto features{physical.GetFeatures()};
|
const std::array feature_report{
|
||||||
const std::array feature_report = {
|
|
||||||
std::make_pair(features.vertexPipelineStoresAndAtomics, "vertexPipelineStoresAndAtomics"),
|
std::make_pair(features.vertexPipelineStoresAndAtomics, "vertexPipelineStoresAndAtomics"),
|
||||||
std::make_pair(features.imageCubeArray, "imageCubeArray"),
|
std::make_pair(features.imageCubeArray, "imageCubeArray"),
|
||||||
std::make_pair(features.independentBlend, "independentBlend"),
|
std::make_pair(features.independentBlend, "independentBlend"),
|
||||||
|
@ -623,19 +601,13 @@ bool VKDevice::IsSuitable(vk::PhysicalDevice physical, VkSurfaceKHR surface) {
|
||||||
std::make_pair(features.shaderStorageImageWriteWithoutFormat,
|
std::make_pair(features.shaderStorageImageWriteWithoutFormat,
|
||||||
"shaderStorageImageWriteWithoutFormat"),
|
"shaderStorageImageWriteWithoutFormat"),
|
||||||
};
|
};
|
||||||
for (const auto& [supported, name] : feature_report) {
|
for (const auto& [is_supported, name] : feature_report) {
|
||||||
if (supported) {
|
if (is_supported) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
LOG_ERROR(Render_Vulkan, "Missing required feature: {}", name);
|
LOG_ERROR(Render_Vulkan, "Missing required feature: {}", name);
|
||||||
is_suitable = false;
|
throw vk::Exception(VK_ERROR_FEATURE_NOT_PRESENT);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!is_suitable) {
|
|
||||||
LOG_ERROR(Render_Vulkan, "{} is not suitable", properties.deviceName);
|
|
||||||
}
|
|
||||||
|
|
||||||
return is_suitable;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<const char*> VKDevice::LoadExtensions() {
|
std::vector<const char*> VKDevice::LoadExtensions() {
|
||||||
|
@ -794,28 +766,34 @@ std::vector<const char*> VKDevice::LoadExtensions() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void VKDevice::SetupFamilies(VkSurfaceKHR surface) {
|
void VKDevice::SetupFamilies(VkSurfaceKHR surface) {
|
||||||
std::optional<u32> graphics_family_, present_family_;
|
|
||||||
|
|
||||||
const std::vector queue_family_properties = physical.GetQueueFamilyProperties();
|
const std::vector queue_family_properties = physical.GetQueueFamilyProperties();
|
||||||
for (u32 i = 0; i < static_cast<u32>(queue_family_properties.size()); ++i) {
|
std::optional<u32> graphics;
|
||||||
if (graphics_family_ && present_family_)
|
std::optional<u32> present;
|
||||||
|
for (u32 index = 0; index < static_cast<u32>(queue_family_properties.size()); ++index) {
|
||||||
|
if (graphics && present) {
|
||||||
break;
|
break;
|
||||||
|
|
||||||
const auto& queue_family = queue_family_properties[i];
|
|
||||||
if (queue_family.queueCount == 0)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (queue_family.queueFlags & VK_QUEUE_GRAPHICS_BIT) {
|
|
||||||
graphics_family_ = i;
|
|
||||||
}
|
}
|
||||||
if (physical.GetSurfaceSupportKHR(i, surface)) {
|
const VkQueueFamilyProperties& queue_family = queue_family_properties[index];
|
||||||
present_family_ = i;
|
if (queue_family.queueCount == 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (queue_family.queueFlags & VK_QUEUE_GRAPHICS_BIT) {
|
||||||
|
graphics = index;
|
||||||
|
}
|
||||||
|
if (physical.GetSurfaceSupportKHR(index, surface)) {
|
||||||
|
present = index;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ASSERT(graphics_family_ && present_family_);
|
if (!graphics) {
|
||||||
|
LOG_ERROR(Render_Vulkan, "Device lacks a graphics queue");
|
||||||
graphics_family = *graphics_family_;
|
throw vk::Exception(VK_ERROR_FEATURE_NOT_PRESENT);
|
||||||
present_family = *present_family_;
|
}
|
||||||
|
if (!present) {
|
||||||
|
LOG_ERROR(Render_Vulkan, "Device lacks a present queue");
|
||||||
|
throw vk::Exception(VK_ERROR_FEATURE_NOT_PRESENT);
|
||||||
|
}
|
||||||
|
graphics_family = *graphics;
|
||||||
|
present_family = *present;
|
||||||
}
|
}
|
||||||
|
|
||||||
void VKDevice::SetupFeatures() {
|
void VKDevice::SetupFeatures() {
|
||||||
|
|
|
@ -229,10 +229,10 @@ public:
|
||||||
return use_asynchronous_shaders;
|
return use_asynchronous_shaders;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Checks if the physical device is suitable.
|
|
||||||
static bool IsSuitable(vk::PhysicalDevice physical, VkSurfaceKHR surface);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
/// Checks if the physical device is suitable.
|
||||||
|
void CheckSuitability() const;
|
||||||
|
|
||||||
/// Loads extensions into a vector and stores available ones in this object.
|
/// Loads extensions into a vector and stores available ones in this object.
|
||||||
std::vector<const char*> LoadExtensions();
|
std::vector<const char*> LoadExtensions();
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue