From 4151b1037035e9e33e7f26614bf3377a3f6963e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Dubouchet?= Date: Fri, 5 Jan 2024 10:48:59 +0100 Subject: [PATCH] Now work with VK_LAYER_KHRONOS_validation. --- src/frame/vulkan/CMakeLists.txt | 1 + src/frame/vulkan/device.cpp | 115 ++++++++++----------- src/frame/vulkan/device.h | 46 ++++----- src/frame/vulkan/sdl_vulkan_none.cpp | 69 +++++++------ src/frame/vulkan/sdl_vulkan_none.h | 19 ++-- src/frame/vulkan/sdl_vulkan_window.cpp | 84 ++++++++------- src/frame/vulkan/sdl_vulkan_window.h | 20 ++-- src/frame/vulkan/vulkan_window_interface.h | 16 +++ src/frame/vulkan/window_factory.cpp | 26 ++--- 9 files changed, 201 insertions(+), 195 deletions(-) create mode 100644 src/frame/vulkan/vulkan_window_interface.h diff --git a/src/frame/vulkan/CMakeLists.txt b/src/frame/vulkan/CMakeLists.txt index d5d08e4..d1ad2b7 100644 --- a/src/frame/vulkan/CMakeLists.txt +++ b/src/frame/vulkan/CMakeLists.txt @@ -10,6 +10,7 @@ add_library(FrameVulkan sdl_vulkan_none.cpp sdl_vulkan_window.h sdl_vulkan_window.cpp + vulkan_window_interface.h window_factory.h window_factory.cpp ) diff --git a/src/frame/vulkan/device.cpp b/src/frame/vulkan/device.cpp index fd1c22d..05cd36b 100644 --- a/src/frame/vulkan/device.cpp +++ b/src/frame/vulkan/device.cpp @@ -3,76 +3,39 @@ namespace frame::vulkan { -Device::Device( - void* vk_instance, - glm::uvec2 size, - vk::SurfaceKHR& surface, - vk::DispatchLoaderDynamic& dispatch) - : vk_instance_(static_cast(vk_instance)), size_(size), - vk_surface_(surface), vk_dispatch_loader_(dispatch) -{ - logger_->info("Creating Vulkan Device"); - std::vector physical_devices = - vk_instance_.enumeratePhysicalDevices(); - if (physical_devices.empty()) +Device::Device(glm::uvec2 size) : size_(size) +{ + // Log the Vulkan version. + logger_->info("Creating Vulkan Device ({}, {})", size.x, size.y); + auto api_version = vk_context_.enumerateInstanceVersion(); + logger_->info( + "Vulkan version: {}.{} total: {}", + VK_VERSION_MAJOR(api_version), + VK_VERSION_MINOR(api_version), + api_version); + // List all available extensions. + std::vector availableExtensions = + vk::enumerateInstanceExtensionProperties(); + logger_->info("Available Extensions:"); + for (const auto& extension : availableExtensions) { - throw std::runtime_error("No Vulkan Physical Device found"); + std::string extension_name = extension.extensionName; + logger_->info("\t[{}]", extension_name); } - // Check and select physical device properties. - int last_best_score = 0; - for (const auto& physical_device : physical_devices) + // List all available layers. + std::vector availableLayers = + vk::enumerateInstanceLayerProperties(); + logger_->info("Available Layers:"); + for (const auto& layer : availableLayers) { - int score = 0; - logger_->info( - "Physical Device: {}", - static_cast(physical_device.getProperties().deviceName)); - if (physical_device.getProperties().deviceType == - vk::PhysicalDeviceType::eDiscreteGpu) - { - logger_->info("\tis a GPU"); - score += 10000; - } - score += physical_device.getProperties().limits.maxImageDimension2D; - if (physical_device.getFeatures().geometryShader) - { - if (score > last_best_score) - { - last_best_score = score; - vk_physical_device_ = physical_device; - } - } - } - if (!vk_physical_device_) - { - throw std::runtime_error("No Vulkan Physical Device found"); - } - // Select a queue family. - std::vector queue_families = - vk_physical_device_.getQueueFamilyProperties(vk_dispatch_loader_); - int i = 0; - int selected_index = -1; - for (auto& queue_family : queue_families) - { - if (queue_family.queueFlags & vk::QueueFlagBits::eGraphics) - { - selected_index = i; - } - i++; + std::string layer_name = layer.layerName; + logger_->info("\t[{}]", layer_name); } - if (selected_index == -1) - { - throw std::runtime_error("No Vulkan Queue Family found"); - } - // Get the device. - vk::DeviceQueueCreateInfo device_queue_create_info( - {}, selected_index, 1, &queue_family_priority_); - vk::DeviceCreateInfo device_create_info({}, 1, &device_queue_create_info); - vk_unique_device_ = vk_physical_device_.createDeviceUnique( - device_create_info, nullptr, vk_dispatch_loader_); } Device::~Device() { + logger_->info("Destroying Vulkan Device"); } void Device::SetStereo( @@ -84,6 +47,34 @@ void Device::SetStereo( throw std::runtime_error("Not implemented!"); } +void Device::Init(vk::InstanceCreateInfo instance_create_info) +{ + logger_->info("Initializing Vulkan Device"); + // Create the instance. + vk_instance_.emplace(vk_context_, instance_create_info); + // Get all vk::PhysicalDeviceGroupProperties from a vk::raii::Instance + // instance. + std::vector + physical_device_group_properties = + vk_instance_.value().enumeratePhysicalDeviceGroups(); + logger_->info( + "Number of physical devices: {}", + physical_device_group_properties.size()); + for (const auto& physical_device_group : physical_device_group_properties) + { + logger_->info( + "\t- group({})", physical_device_group.physicalDeviceCount); + for (std::uint32_t i = 0; i < physical_device_group.physicalDeviceCount; + ++i) + { + std::string device_name = physical_device_group.physicalDevices[i] + .getProperties() + .deviceName; + logger_->info("\t\t- {}", device_name); + } + } +} + void Device::Clear( const glm::vec4& color /*= glm::vec4(.2f, 0.f, .2f, 1.0f)*/) const { diff --git a/src/frame/vulkan/device.h b/src/frame/vulkan/device.h index 25d6d76..e45e4fd 100644 --- a/src/frame/vulkan/device.h +++ b/src/frame/vulkan/device.h @@ -5,6 +5,8 @@ #include "frame/camera.h" #include "frame/device_interface.h" #include "frame/logger.h" +#include "frame/vulkan/vulkan_window_interface.h" +#include "frame/window_interface.h" namespace frame::vulkan { @@ -18,20 +20,19 @@ class Device : public DeviceInterface public: /** * @brief Constructor will initialize the Vulkan context. - * @param vk_instance: The vk::Instance passed as a void*. + * @param sdl_vulkan_window: Window interface to the windowing system. * @param size: Window size. - * @param surface: Surface for the drawing. - * @param dispatch: Dispatch from vulkan. - */ - Device( - void* vk_instance, - glm::uvec2 size, - vk::SurfaceKHR& surface, - vk::DispatchLoaderDynamic& dispatch); + */ + Device(glm::uvec2 size); //! @brief Destructor this is where the memory is freed. virtual ~Device(); public: + /** + * @brief Initialize the device by passing the instance create info. + * @param instance_create_info: The instance create info. + */ + void Init(vk::InstanceCreateInfo instance_create_info); /** * @brief Set the stereo mode (by default this is NONE), interocular * distance and focus point. @@ -77,6 +78,11 @@ class Device : public DeviceInterface * @param name: The name of the plugin to remove. */ void RemovePluginByName(const std::string& name) final; + /** + * @brief Display to the screen. + * @param dt: Delta time from the beginning of the software in seconds. + */ + void Display(double dt = 0.0) final; /** @brief Cleanup the mess. */ void Cleanup() final; /** @@ -89,11 +95,6 @@ class Device : public DeviceInterface * @return The size of the window. */ glm::uvec2 GetSize() const final; - /** - * @brief Display to the screen. - * @param dt: Delta time from the beginning of the software in seconds. - */ - void Display(double dt = 0.0) final; /** * @brief Make a screen shot to a file. * @param file: File name of the screenshot (usually with the *.png) @@ -140,13 +141,12 @@ class Device : public DeviceInterface return *level_.get(); } /** - * @brief Get the current context. - * @return A pointer to the current context (this is used by the - * windowing system). + * @brief Get a device context on the underlying graphic API. + * @return A device context on the underlying graphic API. */ void* GetDeviceContext() const final { - return vk_instance_; + throw std::runtime_error("Not implemented!"); } /** * @brief Get the enum describing the stereo situation. @@ -187,13 +187,6 @@ class Device : public DeviceInterface std::unique_ptr level_ = nullptr; // Storage of the plugin. std::vector> plugin_interfaces_ = {}; - // Vulkan stuff. - vk::Instance vk_instance_ = {}; - vk::PhysicalDevice vk_physical_device_ = {}; - float queue_family_priority_ = 1.0f; - vk::UniqueHandle vk_unique_device_; - vk::SurfaceKHR& vk_surface_; - vk::DispatchLoaderDynamic& vk_dispatch_loader_; // Size. glm::uvec2 size_ = {0, 0}; const proto::PixelElementSize pixel_element_size_ = @@ -207,6 +200,9 @@ class Device : public DeviceInterface bool invert_left_right_ = false; // Logger for the device. const Logger& logger_ = Logger::GetInstance(); + // Vulkan crap. + vk::raii::Context vk_context_; + std::optional vk_instance_; }; } // End namespace frame::vulkan. diff --git a/src/frame/vulkan/sdl_vulkan_none.cpp b/src/frame/vulkan/sdl_vulkan_none.cpp index 8994271..df5fb9d 100644 --- a/src/frame/vulkan/sdl_vulkan_none.cpp +++ b/src/frame/vulkan/sdl_vulkan_none.cpp @@ -1,6 +1,7 @@ #include "frame/vulkan/sdl_vulkan_none.h" #include "frame/vulkan/debug_callback.h" +#include "frame/vulkan/device.h" #include namespace frame::vulkan @@ -34,39 +35,46 @@ SDLVulkanNone::SDLVulkanNone(glm::uvec2 size) : size_(size) throw std::runtime_error( fmt::format("Couldn't initialize window: {}", SDL_GetError())); } +} - std::vector sdlExtensions; - unsigned int sdlExtensionCount = 0; - SDL_Vulkan_GetInstanceExtensions(sdl_window_, &sdlExtensionCount, nullptr); - sdlExtensions.resize(sdlExtensionCount); +vk::InstanceCreateInfo SDLVulkanNone::GetInstanceCreateInfo( + vk::ApplicationInfo app_info) const +{ + static std::vector sdl_extensions; + unsigned int sdl_extension_count = 0; SDL_Vulkan_GetInstanceExtensions( - sdl_window_, &sdlExtensionCount, sdlExtensions.data()); - - vk::ApplicationInfo appInfo( - "Frame Vulkan", - VK_MAKE_VERSION(1, 0, 0), - "Frame (SDL Vulkan None)", - VK_MAKE_VERSION(1, 0, 0), - VK_API_VERSION_1_3); - - vk::InstanceCreateInfo instanceCreateInfo( + sdl_window_, &sdl_extension_count, nullptr); + sdl_extensions.resize(sdl_extension_count); + SDL_Vulkan_GetInstanceExtensions( + sdl_window_, &sdl_extension_count, sdl_extensions.data()); +#ifdef _DEBUG + // Enable the debug callback extension. + sdl_extensions.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME); +#endif + static std::vector layers; +#ifdef _DEBUG + layers.push_back("VK_LAYER_KHRONOS_validation"); +#endif + return vk::InstanceCreateInfo( {}, - &appInfo, - 0, - nullptr, - static_cast(sdlExtensions.size()), - sdlExtensions.data()); - - vk_instance_ = vk::raii::Instance(vk_context_, instanceCreateInfo); + &app_info, + static_cast(layers.size()), + layers.data(), + static_cast(sdl_extensions.size()), + sdl_extensions.data()); +} - // Select Physical Device - std::vector physicalDevices = - vk_instance_.value().enumeratePhysicalDevices(); - if (physicalDevices.empty()) +void SDLVulkanNone::SetUniqueDevice(std::unique_ptr&& device) +{ + device_ = std::move(device); + vulkan::Device* vulkan_device = + dynamic_cast(device_.get()); + if (!vulkan_device) { - throw std::runtime_error("Failed to find GPUs with Vulkan support!"); + std::runtime_error("Device is not a vulkan device."); } - vk::raii::PhysicalDevice& physicalDevice = physicalDevices[0]; + + vulkan_device->Init(GetInstanceCreateInfo()); } SDLVulkanNone::~SDLVulkanNone() @@ -93,12 +101,7 @@ void SDLVulkanNone::Run(std::function /* lambda*/) void* SDLVulkanNone::GetGraphicContext() const { - if (vk_instance_) - { - return vk_instance_.value().operator*(); - } - throw std::runtime_error( - "Try to access an uninitialized pointer to a vulkan instance."); + return sdl_window_; } } // End namespace frame::vulkan. diff --git a/src/frame/vulkan/sdl_vulkan_none.h b/src/frame/vulkan/sdl_vulkan_none.h index 202679d..d846aa8 100644 --- a/src/frame/vulkan/sdl_vulkan_none.h +++ b/src/frame/vulkan/sdl_vulkan_none.h @@ -6,12 +6,13 @@ #include #include "frame/logger.h" +#include "frame/vulkan/vulkan_window_interface.h" #include "frame/window_interface.h" namespace frame::vulkan { -class SDLVulkanNone : public WindowInterface +class SDLVulkanNone : public VulkanWindowInterface { public: SDLVulkanNone(glm::uvec2 size); @@ -20,6 +21,14 @@ class SDLVulkanNone : public WindowInterface public: void Run(std::function lambda) override; void* GetGraphicContext() const override; + vk::InstanceCreateInfo GetInstanceCreateInfo( + vk::ApplicationInfo app_info = { + "Frame Vulkan", + VK_MAKE_VERSION(1, 0, 0), + "Frame (SDL Vulkan None)", + VK_MAKE_VERSION(1, 0, 0), + VK_API_VERSION_1_3}) const override; + void SetUniqueDevice(std::unique_ptr&& device) override; public: void SetInputInterface( @@ -31,10 +40,6 @@ class SDLVulkanNone : public WindowInterface { throw std::runtime_error("Not implemented yet!"); } - void SetUniqueDevice(std::unique_ptr&& device) override - { - device_ = std::move(device); - } DeviceInterface& GetDevice() override { return *device_.get(); @@ -78,10 +83,6 @@ class SDLVulkanNone : public WindowInterface std::unique_ptr input_interface_ = nullptr; SDL_Window* sdl_window_ = nullptr; frame::Logger& logger_ = frame::Logger::GetInstance(); - vk::raii::Context vk_context_; - // Trick around the fact that they don't have a default constructor. - std::optional vk_instance_; - std::optional vk_surface_KHR_; }; } // namespace frame::vulkan. diff --git a/src/frame/vulkan/sdl_vulkan_window.cpp b/src/frame/vulkan/sdl_vulkan_window.cpp index a5b3478..b231903 100644 --- a/src/frame/vulkan/sdl_vulkan_window.cpp +++ b/src/frame/vulkan/sdl_vulkan_window.cpp @@ -40,38 +40,6 @@ SDLVulkanWindow::SDLVulkanWindow(glm::uvec2 size) : size_(size) fmt::format("Couldn't initialize window: {}", SDL_GetError())); } - std::vector sdlExtensions; - unsigned int sdlExtensionCount = 0; - SDL_Vulkan_GetInstanceExtensions(sdl_window_, &sdlExtensionCount, nullptr); - sdlExtensions.resize(sdlExtensionCount); - SDL_Vulkan_GetInstanceExtensions( - sdl_window_, &sdlExtensionCount, sdlExtensions.data()); - - vk::ApplicationInfo appInfo( - "Frame Vulkan", - VK_MAKE_VERSION(1, 0, 0), - "Frame (SDL Vulkan None)", - VK_MAKE_VERSION(1, 0, 0), - VK_API_VERSION_1_3); - - vk::InstanceCreateInfo instanceCreateInfo( - {}, - &appInfo, - 0, - nullptr, - static_cast(sdlExtensions.size()), - sdlExtensions.data()); - - vk_instance_ = vk::raii::Instance(vk_context_, instanceCreateInfo); - - // Select Physical Device - std::vector physicalDevices = - vk_instance_.value().enumeratePhysicalDevices(); - if (physicalDevices.empty()) - { - throw std::runtime_error("Failed to find GPUs with Vulkan support!"); - } - vk::raii::PhysicalDevice& physicalDevice = physicalDevices[0]; // Get the hwnd. #if defined(_WIN32) || defined(_WIN64) SDL_SysWMinfo wmInfo; @@ -79,6 +47,12 @@ SDLVulkanWindow::SDLVulkanWindow(glm::uvec2 size) : size_(size) SDL_GetWindowWMInfo(sdl_window_, &wmInfo); hwnd_ = wmInfo.info.win.window; #endif + // Query the desktop size, used in full screen desktop mode. + int i = SDL_GetWindowDisplayIndex(sdl_window_); + SDL_Rect j; + SDL_GetDisplayBounds(i, &j); + desktop_size_.x = j.w; + desktop_size_.y = j.h; } SDLVulkanWindow::~SDLVulkanWindow() @@ -88,6 +62,45 @@ SDLVulkanWindow::~SDLVulkanWindow() SDL_Quit(); } +vk::InstanceCreateInfo SDLVulkanWindow::GetInstanceCreateInfo( + vk::ApplicationInfo app_info) const +{ + static std::vector sdl_extensions{}; + std::uint32_t sdl_extension_count = 0; + SDL_Vulkan_GetInstanceExtensions( + sdl_window_, &sdl_extension_count, nullptr); + sdl_extensions.resize(sdl_extension_count); + SDL_Vulkan_GetInstanceExtensions( + sdl_window_, &sdl_extension_count, sdl_extensions.data()); +#ifdef _DEBUG + // Enable the debug callback extension. + sdl_extensions.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME); +#endif + static std::vector layers{}; +#ifdef _DEBUG + layers.push_back("VK_LAYER_KHRONOS_validation"); +#endif + return vk::InstanceCreateInfo( + {}, + &app_info, + static_cast(layers.size()), + layers.data(), + static_cast(sdl_extensions.size()), + sdl_extensions.data()); +} + +void SDLVulkanWindow::SetUniqueDevice(std::unique_ptr&& device) +{ + device_ = std::move(device); + vulkan::Device* vulkan_device = + dynamic_cast(device_.get()); + if (!vulkan_device) + { + std::runtime_error("Device is not a vulkan device."); + } + vulkan_device->Init(GetInstanceCreateInfo()); +} + void SDLVulkanWindow::Run(std::function lambda /* = []{}*/) { // Called only once at the beginning. @@ -159,12 +172,7 @@ void SDLVulkanWindow::Run(std::function lambda /* = []{}*/) void* SDLVulkanWindow::GetGraphicContext() const { - if (vk_instance_) - { - return vk_instance_.value().operator*(); - } - throw std::runtime_error( - "Try to access an uninitialized pointer to a vulkan instance."); + return sdl_window_; } void SDLVulkanWindow::Resize(glm::uvec2 size, FullScreenEnum fullscreen_enum) diff --git a/src/frame/vulkan/sdl_vulkan_window.h b/src/frame/vulkan/sdl_vulkan_window.h index 451197d..d440fc4 100644 --- a/src/frame/vulkan/sdl_vulkan_window.h +++ b/src/frame/vulkan/sdl_vulkan_window.h @@ -11,11 +11,13 @@ #include "frame/logger.h" #include "frame/window_interface.h" +#include "frame/vulkan/vulkan_window_interface.h" +#include "frame/vulkan/device.h" namespace frame::vulkan { -class SDLVulkanWindow : public WindowInterface +class SDLVulkanWindow : public VulkanWindowInterface { public: SDLVulkanWindow(glm::uvec2 size); @@ -31,11 +33,7 @@ class SDLVulkanWindow : public WindowInterface { throw std::runtime_error("Not implemented yet!"); } - void SetUniqueDevice(std::unique_ptr&& device) override - { - device_ = std::move(device); - } - DeviceInterface& GetDevice() override + DeviceInterface& GetDevice() override { return *device_.get(); } @@ -69,6 +67,14 @@ class SDLVulkanWindow : public WindowInterface void* GetGraphicContext() const override; void Resize(glm::uvec2 size, FullScreenEnum fullscreen_enum) override; FullScreenEnum GetFullScreenEnum() const override; + vk::InstanceCreateInfo GetInstanceCreateInfo( + vk::ApplicationInfo app_info = { + "Frame Vulkan", + VK_MAKE_VERSION(1, 0, 0), + "Frame (SDL Vulkan Window)", + VK_MAKE_VERSION(1, 0, 0), + VK_API_VERSION_1_3}) const override; + void SetUniqueDevice(std::unique_ptr&& device) override; protected: bool RunEvent(const SDL_Event& event, const double dt); @@ -93,8 +99,6 @@ class SDLVulkanWindow : public WindowInterface HWND hwnd_ = nullptr; #endif frame::Logger& logger_ = frame::Logger::GetInstance(); - vk::raii::Context vk_context_; - std::optional vk_instance_; std::optional vk_surface_KHR_; }; diff --git a/src/frame/vulkan/vulkan_window_interface.h b/src/frame/vulkan/vulkan_window_interface.h new file mode 100644 index 0000000..74a798a --- /dev/null +++ b/src/frame/vulkan/vulkan_window_interface.h @@ -0,0 +1,16 @@ +#pragma once + +#include + +#include "frame/window_interface.h" + +namespace frame::vulkan +{ + +struct VulkanWindowInterface : public WindowInterface +{ + virtual vk::InstanceCreateInfo GetInstanceCreateInfo( + vk::ApplicationInfo app_info) const = 0; +}; + +} // namespace frame::vulkan diff --git a/src/frame/vulkan/window_factory.cpp b/src/frame/vulkan/window_factory.cpp index 5ba5356..b7e095b 100644 --- a/src/frame/vulkan/window_factory.cpp +++ b/src/frame/vulkan/window_factory.cpp @@ -17,31 +17,17 @@ namespace frame::vulkan std::unique_ptr CreateSDL2VulkanWindow(glm::uvec2 size) { - auto window = std::make_unique(size); - auto context = window->GetGraphicContext(); - auto& dispatch = window->GetVulkanDispatch(); - auto& surface = window->GetVulkanSurfaceKHR(); - if (!context) - { - return nullptr; - } - window->SetUniqueDevice( - std::make_unique(context, size, surface, dispatch)); + auto device = std::make_unique(size); + auto window = std::make_unique(size); + window->SetUniqueDevice(std::move(device)); return window; } std::unique_ptr CreateSDL2VulkanNone(glm::uvec2 size) { - auto window = std::make_unique(size); - auto context = window->GetGraphicContext(); - auto& dispatch = window->GetVulkanDispatch(); - auto& surface = window->GetVulkanSurfaceKHR(); - if (!context) - { - return nullptr; - } - window->SetUniqueDevice( - std::make_unique(context, size, surface, dispatch)); + auto device = std::make_unique(size); + auto window = std::make_unique(size); + window->SetUniqueDevice(std::move(device)); return window; }