|
|
@@ -210,6 +210,7 @@ VKDevice::VKDevice(VkInstance instance_, u32 instance_version_, vk::PhysicalDevi
|
|
|
VkSurfaceKHR surface, const vk::InstanceDispatch& dld_)
|
|
|
: instance{instance_}, dld{dld_}, physical{physical_}, properties{physical.GetProperties()},
|
|
|
instance_version{instance_version_}, format_properties{GetFormatProperties(physical, dld)} {
|
|
|
+ CheckSuitability();
|
|
|
SetupFamilies(surface);
|
|
|
SetupFeatures();
|
|
|
|
|
|
@@ -548,64 +549,41 @@ bool VKDevice::IsFormatSupported(VkFormat wanted_format, VkFormatFeatureFlags wa
|
|
|
return (supported_usage & wanted_usage) == wanted_usage;
|
|
|
}
|
|
|
|
|
|
-bool VKDevice::IsSuitable(vk::PhysicalDevice physical, VkSurfaceKHR surface) {
|
|
|
- bool is_suitable = true;
|
|
|
+void VKDevice::CheckSuitability() const {
|
|
|
std::bitset<REQUIRED_EXTENSIONS.size()> available_extensions;
|
|
|
-
|
|
|
- for (const auto& prop : physical.EnumerateDeviceExtensionProperties()) {
|
|
|
+ for (const VkExtensionProperties& property : physical.EnumerateDeviceExtensionProperties()) {
|
|
|
for (std::size_t i = 0; i < REQUIRED_EXTENSIONS.size(); ++i) {
|
|
|
if (available_extensions[i]) {
|
|
|
continue;
|
|
|
}
|
|
|
- const std::string_view name{prop.extensionName};
|
|
|
+ const std::string_view name{property.extensionName};
|
|
|
available_extensions[i] = name == REQUIRED_EXTENSIONS[i];
|
|
|
}
|
|
|
}
|
|
|
- if (!available_extensions.all()) {
|
|
|
- for (std::size_t i = 0; i < REQUIRED_EXTENSIONS.size(); ++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) {
|
|
|
+ for (size_t i = 0; i < REQUIRED_EXTENSIONS.size(); ++i) {
|
|
|
+ if (available_extensions[i]) {
|
|
|
continue;
|
|
|
}
|
|
|
- has_graphics |= family.queueFlags & VK_QUEUE_GRAPHICS_BIT;
|
|
|
- has_present |= physical.GetSurfaceSupportKHR(i, surface);
|
|
|
+ LOG_ERROR(Render_Vulkan, "Missing required extension: {}", REQUIRED_EXTENSIONS[i]);
|
|
|
+ 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.
|
|
|
- const auto properties{physical.GetProperties()};
|
|
|
- const auto& limits{properties.limits};
|
|
|
+ const VkPhysicalDeviceLimits& limits{properties.limits};
|
|
|
|
|
|
constexpr u32 required_ubo_size = 65536;
|
|
|
if (limits.maxUniformBufferRange < required_ubo_size) {
|
|
|
LOG_ERROR(Render_Vulkan, "Device UBO size {} is too small, {} is required",
|
|
|
limits.maxUniformBufferRange, required_ubo_size);
|
|
|
- is_suitable = false;
|
|
|
+ throw vk::Exception(VK_ERROR_FEATURE_NOT_PRESENT);
|
|
|
}
|
|
|
-
|
|
|
constexpr u32 required_num_viewports = 16;
|
|
|
if (limits.maxViewports < required_num_viewports) {
|
|
|
LOG_INFO(Render_Vulkan, "Device number of viewports {} is too small, {} is required",
|
|
|
limits.maxViewports, required_num_viewports);
|
|
|
- is_suitable = false;
|
|
|
+ throw vk::Exception(VK_ERROR_FEATURE_NOT_PRESENT);
|
|
|
}
|
|
|
-
|
|
|
- const auto features{physical.GetFeatures()};
|
|
|
- const std::array feature_report = {
|
|
|
+ const VkPhysicalDeviceFeatures features{physical.GetFeatures()};
|
|
|
+ const std::array feature_report{
|
|
|
std::make_pair(features.vertexPipelineStoresAndAtomics, "vertexPipelineStoresAndAtomics"),
|
|
|
std::make_pair(features.imageCubeArray, "imageCubeArray"),
|
|
|
std::make_pair(features.independentBlend, "independentBlend"),
|
|
|
@@ -623,19 +601,13 @@ bool VKDevice::IsSuitable(vk::PhysicalDevice physical, VkSurfaceKHR surface) {
|
|
|
std::make_pair(features.shaderStorageImageWriteWithoutFormat,
|
|
|
"shaderStorageImageWriteWithoutFormat"),
|
|
|
};
|
|
|
- for (const auto& [supported, name] : feature_report) {
|
|
|
- if (supported) {
|
|
|
+ for (const auto& [is_supported, name] : feature_report) {
|
|
|
+ if (is_supported) {
|
|
|
continue;
|
|
|
}
|
|
|
LOG_ERROR(Render_Vulkan, "Missing required feature: {}", name);
|
|
|
- is_suitable = false;
|
|
|
- }
|
|
|
-
|
|
|
- if (!is_suitable) {
|
|
|
- LOG_ERROR(Render_Vulkan, "{} is not suitable", properties.deviceName);
|
|
|
+ throw vk::Exception(VK_ERROR_FEATURE_NOT_PRESENT);
|
|
|
}
|
|
|
-
|
|
|
- return is_suitable;
|
|
|
}
|
|
|
|
|
|
std::vector<const char*> VKDevice::LoadExtensions() {
|
|
|
@@ -794,28 +766,34 @@ std::vector<const char*> VKDevice::LoadExtensions() {
|
|
|
}
|
|
|
|
|
|
void VKDevice::SetupFamilies(VkSurfaceKHR surface) {
|
|
|
- std::optional<u32> graphics_family_, present_family_;
|
|
|
-
|
|
|
const std::vector queue_family_properties = physical.GetQueueFamilyProperties();
|
|
|
- for (u32 i = 0; i < static_cast<u32>(queue_family_properties.size()); ++i) {
|
|
|
- if (graphics_family_ && present_family_)
|
|
|
+ std::optional<u32> graphics;
|
|
|
+ std::optional<u32> present;
|
|
|
+ for (u32 index = 0; index < static_cast<u32>(queue_family_properties.size()); ++index) {
|
|
|
+ if (graphics && present) {
|
|
|
break;
|
|
|
-
|
|
|
- const auto& queue_family = queue_family_properties[i];
|
|
|
- if (queue_family.queueCount == 0)
|
|
|
+ }
|
|
|
+ const VkQueueFamilyProperties& queue_family = queue_family_properties[index];
|
|
|
+ if (queue_family.queueCount == 0) {
|
|
|
continue;
|
|
|
-
|
|
|
+ }
|
|
|
if (queue_family.queueFlags & VK_QUEUE_GRAPHICS_BIT) {
|
|
|
- graphics_family_ = i;
|
|
|
+ graphics = index;
|
|
|
}
|
|
|
- if (physical.GetSurfaceSupportKHR(i, surface)) {
|
|
|
- present_family_ = i;
|
|
|
+ if (physical.GetSurfaceSupportKHR(index, surface)) {
|
|
|
+ present = index;
|
|
|
}
|
|
|
}
|
|
|
- ASSERT(graphics_family_ && present_family_);
|
|
|
-
|
|
|
- graphics_family = *graphics_family_;
|
|
|
- present_family = *present_family_;
|
|
|
+ if (!graphics) {
|
|
|
+ LOG_ERROR(Render_Vulkan, "Device lacks a graphics queue");
|
|
|
+ throw vk::Exception(VK_ERROR_FEATURE_NOT_PRESENT);
|
|
|
+ }
|
|
|
+ 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() {
|