diff options
Diffstat (limited to 'src/vulkan/device.cc')
-rw-r--r-- | src/vulkan/device.cc | 161 |
1 files changed, 151 insertions, 10 deletions
diff --git a/src/vulkan/device.cc b/src/vulkan/device.cc index e211e4e..c83e9a1 100644 --- a/src/vulkan/device.cc +++ b/src/vulkan/device.cc @@ -14,16 +14,61 @@ #include "src/vulkan/device.h" +#include <cassert> +#include <cstring> #include <memory> #include <set> #include <vector> #include "src/make_unique.h" +#include "src/vulkan/log.h" namespace amber { namespace vulkan { namespace { +const char* const kRequiredValidationLayers[] = { +#ifdef __ANDROID__ + // Note that the order of enabled layers is important. It is + // based on Android NDK Vulkan document. + "VK_LAYER_GOOGLE_threading", "VK_LAYER_LUNARG_parameter_validation", + "VK_LAYER_LUNARG_object_tracker", "VK_LAYER_LUNARG_core_validation", + "VK_LAYER_GOOGLE_unique_objects", +#else // __ANDROID__ + "VK_LAYER_LUNARG_standard_validation", +#endif // __ANDROID__ +}; + +const size_t kNumberOfRequiredValidationLayers = + sizeof(kRequiredValidationLayers) / sizeof(const char*); + +const char* kExtensionForValidationLayer = "VK_EXT_debug_report"; + +VKAPI_ATTR VkBool32 VKAPI_CALL debugCallback(VkDebugReportFlagsEXT flag, + VkDebugReportObjectTypeEXT, + uint64_t, + size_t, + int32_t, + const char* layerPrefix, + const char* msg, + void*) { + std::string flag_message; + switch (flag) { + case VK_DEBUG_REPORT_ERROR_BIT_EXT: + flag_message = "[ERROR]"; + break; + case VK_DEBUG_REPORT_WARNING_BIT_EXT: + flag_message = "[WARNING]"; + break; + default: + flag_message = "[UNKNOWN]"; + break; + } + + LogError(flag_message + " validation layer (" + layerPrefix + "):\n" + msg); + return VK_FALSE; +} + VkPhysicalDeviceFeatures RequestedFeatures( const std::vector<Feature>& required_features) { VkPhysicalDeviceFeatures requested_features = {}; @@ -491,6 +536,61 @@ bool AreAllExtensionsSupported( return required_extension_set.empty(); } +Result AreAllValidationLayersSupported() { + std::vector<VkLayerProperties> available_layer_properties; + uint32_t available_layer_count = 0; + if (vkEnumerateInstanceLayerProperties(&available_layer_count, nullptr) != + VK_SUCCESS) { + return Result("Vulkan: vkEnumerateInstanceLayerProperties fail"); + } + available_layer_properties.resize(available_layer_count); + if (vkEnumerateInstanceLayerProperties(&available_layer_count, + available_layer_properties.data()) != + VK_SUCCESS) { + return Result("Vulkan: vkEnumerateInstanceLayerProperties fail"); + } + + std::set<std::string> required_layer_set( + kRequiredValidationLayers, + &kRequiredValidationLayers[kNumberOfRequiredValidationLayers]); + for (const auto& property : available_layer_properties) { + required_layer_set.erase(property.layerName); + } + + if (required_layer_set.empty()) + return {}; + + std::string missing_layers; + for (const auto& missing_layer : required_layer_set) + missing_layers = missing_layers + missing_layer + ",\n\t\t"; + return Result("Vulkan: missing validation layers:\n\t\t" + missing_layers); +} + +bool AreAllValidationExtensionsSupported() { + for (const auto& layer : kRequiredValidationLayers) { + uint32_t available_extension_count = 0; + std::vector<VkExtensionProperties> extension_properties; + + if (vkEnumerateInstanceExtensionProperties( + layer, &available_extension_count, nullptr) != VK_SUCCESS) { + return false; + } + extension_properties.resize(available_extension_count); + if (vkEnumerateInstanceExtensionProperties( + layer, &available_extension_count, extension_properties.data()) != + VK_SUCCESS) { + return false; + } + + for (const auto& ext : extension_properties) { + if (!strcmp(kExtensionForValidationLayer, ext.extensionName)) + return true; + } + } + + return false; +} + } // namespace Device::Device() = default; @@ -512,6 +612,14 @@ Device::~Device() = default; void Device::Shutdown() { if (destroy_device_) { vkDestroyDevice(device_, nullptr); + + auto vkDestroyDebugReportCallbackEXT = + reinterpret_cast<PFN_vkDestroyDebugReportCallbackEXT>( + vkGetInstanceProcAddr(instance_, + "vkDestroyDebugReportCallbackEXT")); + assert(vkDestroyDebugReportCallbackEXT); + vkDestroyDebugReportCallbackEXT(instance_, callback_, nullptr); + vkDestroyInstance(instance_, nullptr); } } @@ -523,6 +631,10 @@ Result Device::Initialize(const std::vector<Feature>& required_features, if (!r.IsSuccess()) return r; + r = CreateDebugReportCallback(); + if (!r.IsSuccess()) + return r; + r = ChoosePhysicalDevice(required_features, required_extensions); if (!r.IsSuccess()) return r; @@ -577,21 +689,50 @@ bool Device::ChooseQueueFamilyIndex(const VkPhysicalDevice& physical_device) { } Result Device::CreateInstance() { - VkApplicationInfo appInfo = {}; - appInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO; - appInfo.apiVersion = VK_MAKE_VERSION(1, 0, 0); - - VkInstanceCreateInfo instInfo = {}; - instInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO; - instInfo.pApplicationInfo = &appInfo; - // TODO(jaebaek): Enable layers, extensions - - if (vkCreateInstance(&instInfo, nullptr, &instance_) != VK_SUCCESS) + VkApplicationInfo app_info = {}; + app_info.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO; + app_info.apiVersion = VK_MAKE_VERSION(1, 0, 0); + + Result r = AreAllValidationLayersSupported(); + if (!r.IsSuccess()) + return r; + + if (!AreAllValidationExtensionsSupported()) + return Result("Vulkan: extensions of validation layers are not supported"); + + VkInstanceCreateInfo instance_info = {}; + instance_info.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO; + instance_info.pApplicationInfo = &app_info; + instance_info.enabledLayerCount = kNumberOfRequiredValidationLayers; + instance_info.ppEnabledLayerNames = kRequiredValidationLayers; + instance_info.enabledExtensionCount = 1U; + instance_info.ppEnabledExtensionNames = &kExtensionForValidationLayer; + + if (vkCreateInstance(&instance_info, nullptr, &instance_) != VK_SUCCESS) return Result("Vulkan::Calling vkCreateInstance Fail"); return {}; } +Result Device::CreateDebugReportCallback() { + VkDebugReportCallbackCreateInfoEXT info = {}; + info.sType = VK_STRUCTURE_TYPE_DEBUG_REPORT_CALLBACK_CREATE_INFO_EXT; + info.flags = VK_DEBUG_REPORT_ERROR_BIT_EXT | VK_DEBUG_REPORT_WARNING_BIT_EXT; + info.pfnCallback = debugCallback; + + auto vkCreateDebugReportCallbackEXT = + reinterpret_cast<PFN_vkCreateDebugReportCallbackEXT>( + vkGetInstanceProcAddr(instance_, "vkCreateDebugReportCallbackEXT")); + if (!vkCreateDebugReportCallbackEXT) + return Result("Vulkan: vkCreateDebugReportCallbackEXT is nullptr"); + + if (vkCreateDebugReportCallbackEXT(instance_, &info, nullptr, &callback_) != + VK_SUCCESS) { + return Result("Vulkan: vkCreateDebugReportCallbackEXT fail"); + } + return {}; +} + Result Device::ChoosePhysicalDevice( const std::vector<Feature>& required_features, const std::vector<std::string>& required_extensions) { |