Skip to content

Commit

Permalink
[WIP] Work in progress
Browse files Browse the repository at this point in the history
  • Loading branch information
IAmNotHanni committed Jul 24, 2024
1 parent 9849f5f commit 5933fb9
Show file tree
Hide file tree
Showing 15 changed files with 253 additions and 298 deletions.
20 changes: 14 additions & 6 deletions include/inexor/vulkan-renderer/application.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@
#include "inexor/vulkan-renderer/world/collision_query.hpp"
#include "inexor/vulkan-renderer/world/cube.hpp"
#include "inexor/vulkan-renderer/wrapper/instance.hpp"
#include "inexor/vulkan-renderer/wrapper/surface.hpp"
#include "inexor/vulkan-renderer/wrapper/swapchain.hpp"
#include "inexor/vulkan-renderer/wrapper/window.hpp"
#include "inexor/vulkan-renderer/wrapper/window_surface.hpp"

// Forward declarations
namespace inexor::vulkan_renderer::input {
Expand All @@ -21,6 +21,14 @@ class KeyboardMouseInputData;

namespace inexor::vulkan_renderer {

// Using declarations
using input::KeyboardMouseInputData;
using wrapper::Device;
using wrapper::Instance;
using wrapper::Surface;
using wrapper::Swapchain;
using wrapper::Window;

class Application {
private:
TimeStep m_stopwatch;
Expand All @@ -32,11 +40,11 @@ class Application {
bool m_debug_report_callback_initialised{false};

std::unique_ptr<Camera> m_camera;
std::unique_ptr<wrapper::Window> m_window;
std::unique_ptr<wrapper::Instance> m_instance;
std::unique_ptr<wrapper::Device> m_device;
std::unique_ptr<wrapper::WindowSurface> m_surface;
std::shared_ptr<wrapper::Swapchain> m_swapchain;
std::unique_ptr<Window> m_window;
std::unique_ptr<Instance> m_instance;
std::unique_ptr<Device> m_device;
std::shared_ptr<Swapchain> m_swapchain;
std::shared_ptr<Surface> m_surface;
std::unique_ptr<renderers::ImGuiRenderer> m_imgui_overlay;

std::vector<OctreeGpuVertex> m_octree_vertices;
Expand Down
94 changes: 51 additions & 43 deletions include/inexor/vulkan-renderer/wrapper/device.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -80,20 +80,22 @@ class Device {
VkPhysicalDevice m_physical_device{VK_NULL_HANDLE};
VmaAllocator m_allocator{VK_NULL_HANDLE};
std::string m_gpu_name;

VkPhysicalDeviceFeatures m_enabled_features{};
VkPhysicalDeviceProperties m_properties{};
VkSampleCountFlagBits m_max_usable_sample_count{VK_SAMPLE_COUNT_1_BIT};
VkSampleCountFlagBits m_max_available_sample_count{VK_SAMPLE_COUNT_1_BIT};

VkQueue m_compute_queue{VK_NULL_HANDLE};
VkQueue m_graphics_queue{VK_NULL_HANDLE};
VkQueue m_present_queue{VK_NULL_HANDLE};
VkQueue m_transfer_queue{VK_NULL_HANDLE};
VkQueue m_sprase_binding_queue{VK_NULL_HANDLE};

std::uint32_t m_present_queue_family_index{0};
std::uint32_t m_graphics_queue_family_index{0};
std::uint32_t m_transfer_queue_family_index{0};
std::uint32_t m_compute_queue_family_index{0};
// TODO: Implement sparse binding queue if required
std::uint32_t m_sparse_binding_queue_family{0};

/// According to NVidia, we should aim for one command pool per thread
/// https://developer.nvidia.com/blog/vulkan-dos-donts/
Expand All @@ -114,49 +116,33 @@ class Device {
const CommandPool &thread_local_command_pool(VkQueueFlagBits queue_type) const;

public:
/// Pick the best physical device automatically
/// @param physical_device_infos The data of the physical devices
/// @param required_features The required device features
/// @param required_extensions The required device extensions
/// @exception std::runtime_error There are no physical devices are available at all
/// @exception std::runtime_error No suitable physical device could be determined
/// @return The chosen physical device which is most suitable
static VkPhysicalDevice pick_best_physical_device(std::vector<DeviceInfo> &&physical_device_infos,
const VkPhysicalDeviceFeatures &required_features,
std::span<const char *> required_extensions);

/// Pick the best physical device automatically
/// @param inst The Vulkan instance
/// @param surface The window surface
/// @param required_features The required device features
/// @param required_extensions The required device extensions
/// @return The chosen physical device which is most suitable
static VkPhysicalDevice pick_best_physical_device(const Instance &inst,
VkSurfaceKHR surface,
const VkPhysicalDeviceFeatures &required_features,
std::span<const char *> required_extensions);

/// Default constructor
/// @param inst The Vulkan instance
/// @param surface The window surface
/// @param prefer_distinct_transfer_queue Specifies if a distinct transfer queue will be preferred
/// @param physical_device The physical device
/// @param required_extensions The required device extensions
/// @param required_features The required device features which the physical device must all support
/// @param optional_features The optional device features which do not necessarily have to be present
/// @exception std::runtime_error The physical device is not suitable
/// @exception std::runtime_error No graphics queue could be found
/// @exception std::runtime_error No presentation queue could be found
/// @exception VulkanException vkCreateDevice call failed
/// @exception VulkanException vmaCreateAllocator call failed
/// @note The creation of the physical device will not fail if one of the optional device features is not available
/// @param inst The Vulkan instance wrapper
/// @param surface The surface
/// @param physical_device The physical device to choose
/// @param required_extensions The required extensions
/// @note If any of the required extensions is not available, an exception is thrown!
/// @param required_features The required features
/// @note If any of the required features is not available, an exception is thrown!
/// @param optional_extensions The optional extensions (empty by default)
/// @param optional_features The optional features (``std::nullopt`` by default)
/// @param on_optional_extension_unavailable A callback function to call in case an optional extension is not
/// available. The callback function can return true, in which case constructor continue, or return false, in which
/// case an exception is thrown.
/// @param on_optional_feature_unavailable A callback function to call in case an optional feature is not available.
/// The callback function can return true, in which case constructor continue, or return false, in which case an
/// exception is thrown.
Device(const Instance &inst,
VkSurfaceKHR surface,
bool prefer_distinct_transfer_queue,
VkPhysicalDevice physical_device,
std::span<const char *> required_extensions,
const VkPhysicalDeviceFeatures &required_features,
const VkPhysicalDeviceFeatures &optional_features = {});
std::span<const char *> optional_extensions = {},
std::optional<VkPhysicalDeviceFeatures> optional_features = std::nullopt,
std::optional<std::function<bool(const std::string &extension_name)>> on_optional_extension_unavailable =
std::nullopt,
std::optional<std::function<bool(const std::string &feature_name)>> on_optional_feature_unavailable =
std::nullopt);

Device(const Device &) = delete;
// TODO: Implement me!
Expand Down Expand Up @@ -225,11 +211,33 @@ class Device {
/// @return ``true`` if presentation is supported
[[nodiscard]] bool is_presentation_supported(VkSurfaceKHR surface, std::uint32_t queue_family_index) const;

/// Returns the maximum sample count usable by the platform
[[nodiscard]] VkSampleCountFlagBits max_usable_sample_count() const {
return m_max_usable_sample_count;
/// Return the maximum sample count that is available
[[nodiscard]] VkSampleCountFlagBits max_available_sample_count() const {
return m_max_available_sample_count;
}

/// Pick the best physical device automatically
/// @param physical_device_infos The data of the physical devices
/// @param required_features The required device features
/// @param required_extensions The required device extensions
/// @exception std::runtime_error There are no physical devices are available at all
/// @exception std::runtime_error No suitable physical device could be determined
/// @return The chosen physical device which is most suitable
static VkPhysicalDevice pick_best_physical_device(std::vector<DeviceInfo> &&physical_device_infos,
const VkPhysicalDeviceFeatures &required_features,
std::span<const char *> required_extensions);

/// Pick the best physical device automatically
/// @param inst The Vulkan instance
/// @param surface The window surface
/// @param required_features The required device features
/// @param required_extensions The required device extensions
/// @return The chosen physical device which is most suitable
static VkPhysicalDevice pick_best_physical_device(const Instance &inst,
VkSurfaceKHR surface,
const VkPhysicalDeviceFeatures &required_features,
std::span<const char *> required_extensions);

/// Automatically detect the type of a Vulkan object and set the internal debug name to it
/// @tparam VulkanObjectType The Vulkan object type. This template parameter will be automatically translated into
/// the matching ``VkObjectType`` using ``vk_tools::get_vulkan_object_type(vk_object)``. This is the most advanced
Expand All @@ -239,7 +247,7 @@ class Device {
/// @param name The internal debug name of the Vulkan object (must not be empty!)
template <typename VulkanObjectType>
void set_debug_name(const VulkanObjectType vk_object, const std::string &name) const {
// The get_vulkan_object_type template allows us to turn the template parameter into a VK_OBJECT_TYPE
// The get_vulkan_object_type template allows us to convert the template parameter into a VK_OBJECT_TYPE
// There is no other trivial way in C++ to do this as far as we know
return set_debug_utils_object_name(vk_tools::get_vulkan_object_type(vk_object),
reinterpret_cast<std::uint64_t>(vk_object), name);
Expand Down
37 changes: 19 additions & 18 deletions include/inexor/vulkan-renderer/wrapper/instance.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,33 +11,22 @@ namespace inexor::vulkan_renderer::wrapper {
/// RAII wrapper class for VkInstance and VkDebugUtilsMessengerEXT
class Instance {
private:
VkInstance m_inst{VK_NULL_HANDLE};
VkInstance m_instance{VK_NULL_HANDLE};
VkDebugUtilsMessengerEXT m_debug_callback{VK_NULL_HANDLE};

public:
static constexpr std::uint32_t REQUIRED_VK_API_VERSION{VK_API_VERSION_1_3};

/// @brief Check if a certain instance layer is available on the system.
/// @param layer_name The name of the instance layer.
/// @return ``true`` if the instance layer is supported.
[[nodiscard]] static bool is_layer_supported(const std::string &layer_name);

/// @brief Check if a certain instance extension is supported on the system.
/// @param extension_name The name of the instance extension.
/// @return ``true`` if the instance extension is supported.
[[nodiscard]] static bool is_extension_supported(const std::string &extension_name);

/// @brief Construct the Vulkan instance and specify the requested instance layers and instance extensions.
/// Construct the Vulkan instance and specify the requested instance layers and instance extensions.
/// @param application_name The Vulkan application's internal application name
/// @param engine_name The Vulkan application's internal engine name
/// @param application_version The Vulkan application's internal version
/// @param engine_version The Vulkan application's internal engine version
/// @param enable_validation_layers True if validation layers should be enabled
/// @param debug_callback The debug utils messenger callback (VK_EXT_debug_utils)
/// @param requested_instance_extensions The instance extensions which are requested (empty by default)
/// @param requested_instance_layers The instance layers which are requested (empty by default)
Instance(const std::string &application_name, const std::string &engine_name, std::uint32_t application_version,
std::uint32_t engine_version, bool enable_validation_layers,
Instance(const std::string &application_name,
const std::string &engine_name,
std::uint32_t application_version,
std::uint32_t engine_version,
PFN_vkDebugUtilsMessengerCallbackEXT debug_callback,
const std::vector<std::string> &requested_instance_extensions = {},
const std::vector<std::string> &requested_instance_layers = {});
Expand All @@ -53,8 +42,20 @@ class Instance {

// TODO: Remove get methods and use access to private members via friend declarations!
[[nodiscard]] VkInstance instance() const {
return m_inst;
return m_instance;
}

/// Check if a certain instance layer is available on the system
/// @param layer_name The name of the instance layer
/// @return ``true`` if the instance layer is supported
[[nodiscard]] static bool is_layer_supported(const std::string &layer_name);

/// Check if a certain instance extension is supported on the system
/// @param extension_name The name of the instance extension
/// @return ``true`` if the instance extension is supported
[[nodiscard]] static bool is_extension_supported(const std::string &extension_name);

static constexpr std::uint32_t REQUIRED_VK_API_VERSION{VK_API_VERSION_1_3};
};

} // namespace inexor::vulkan_renderer::wrapper
35 changes: 35 additions & 0 deletions include/inexor/vulkan-renderer/wrapper/surface.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
#pragma once

#include <GLFW/glfw3.h>
#include <volk.h>

namespace inexor::vulkan_renderer::wrapper {

/// RAII wrapper class for VkSurfaceKHR
class Surface {

private:
const VkInstance m_instance{VK_NULL_HANDLE};
GLFWwindow *m_window{nullptr};
VkSurfaceKHR m_surface{VK_NULL_HANDLE};

public:
/// Create a GLFW surface
/// @param instance The Vulkan instance
/// @param window The GLFW window to create the surface with
Surface(VkInstance instance, GLFWwindow *window);
Surface(const Surface &) = delete;
// TODO: Implement me!
Surface(Surface &&) noexcept;
~Surface();

Surface &operator=(const Surface &) = delete;
// TODO: Implement me!
Surface &operator=(Surface &&) noexcept;

[[nodiscard]] VkSurfaceKHR surface() const {
return m_surface;
}
};

} // namespace inexor::vulkan_renderer::wrapper
8 changes: 2 additions & 6 deletions include/inexor/vulkan-renderer/wrapper/swapchain.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ namespace inexor::vulkan_renderer::wrapper {

// Forward declaration
class Device;
class Window;

// Using declarations
using commands::CommandBuffer;
Expand Down Expand Up @@ -72,12 +73,7 @@ class Swapchain {
/// @param width The swapchain image width
/// @param height The swapchain image height
/// @param vsync_enabled ``true`` if vertical synchronization is enabled
Swapchain(Device &device,
std::string name,
VkSurfaceKHR surface,
std::uint32_t width,
std::uint32_t height,
bool vsync_enabled);
Swapchain(Device &device, std::string name, const VkSurfaceKHR surface, const Window &wnd, bool vsync_enabled);

Swapchain(const Swapchain &) = delete;
Swapchain(Swapchain &&) noexcept;
Expand Down
Loading

0 comments on commit 5933fb9

Please sign in to comment.