#pragma once #include <stdafx.h> #define MAX_TEXTURES 1024 #define MAX_MESHES 100000 // 100,000 #include "Device.h" #include "RenderGraph.h" #include "IO.h" #include "VulkanWindow.h" #include "SwapChain.h" #include "InputHandler.h" namespace fpr { struct Version { uint32_t m_variant; uint32_t m_major; uint32_t m_minor; uint32_t m_patch; Version() = default; Version(uint32_t variant, uint32_t major, uint32_t minor, uint32_t patch); uint32_t MakeVersion() const FPR_NOEXCEPT; }; // Context singleton, cannot be derived from, has no public constructor. Init() has to be called before it is used. class Context final { static VulkanWindow* s_window; static std::string s_app_name; static fpr::Version s_app_version; static std::string s_engine_name; static fpr::Version s_engine_version; static fpr::Version s_vulkan_version; // Vulkan validation layer handling. Massive performance overhead so turned off if not in debug. #ifdef NDEBUG const bool validation_layers_enabled = false; const std::vector<const char*> m_validation_layers; #else const bool validation_layers_enabled = true; const std::vector<const char*> m_validation_layers = { "VK_LAYER_KHRONOS_validation" }; #endif vk::UniqueInstance m_instance; std::vector<const char*> m_extensions; // Vulkan struct initialiser helper function. [[nodiscard]] vk::ApplicationInfo ApplicationInfo( const char* application_name, const Version& app_version, const char* engine_name, const Version& engine_version, const Version& api_version) FPR_NOEXCEPT; [[nodiscard]] std::vector<const char*> GetRequiredExtensions(const std::vector<const char*>& validation_layers) FPR_NOEXCEPT; [[nodiscard]] inline bool IsValidationLayersValid( const std::vector<const char*>& validation_layers, const std::vector<vk::LayerProperties>& available_layers) FPR_NOEXCEPT; bool IsVulkanSupported() const FPR_NOEXCEPT; [[nodiscard]] const vk::Instance& GetVulkanInstance() const FPR_NOEXCEPT; InputHandler m_camera_input_handler; vk::UniqueSwapchainKHR m_old_swapchain; ; public: // Type alias for what a PipelineCreation function should consume. // Type, name, settings, parent(optional); using PipelineCreationData = std::vector<std::tuple<EPipelineType, std::string_view, fpr::PipelineOptions, tl::optional<std::string>>>; private: std::unique_ptr<Device> m_device; vk::UniqueSurfaceKHR m_surface; vk::UniqueCommandPool m_command_pool; vk::UniqueCommandPool m_compute_comand_pool; std::unique_ptr<SwapChain> m_swapchain; std::function<PipelineCreationData(void)> m_pipeline_creation_fn; vk::UniqueDescriptorPool m_descriptor_pool; vk::UniqueCommandBuffer m_single_time_cmd_buffer; VulkanWindow* m_window; uint32_t m_dynamic_alignment = sizeof(glm::mat4); // Default pipeline creation callback for "out-of-the-box" renderer usage. static std::function<PipelineCreationData(void)> DEFAULT_PIPELINE_CREATION_CALLBACK; Context( VulkanWindow* Window, const std::string& app_name, fpr::Version app_version, const std::string& engine_name, fpr::Version engine_version, fpr::Version vulkan_version); ~Context() = default; void CreateSingleTimeCommandBuffer(); // Myers' singleton pattern, requires a public "Get" function with a private constructor and public "Init()" function. // Ensures no memory. static Context& GetImpl( VulkanWindow* Window = nullptr, const std::string& app_name = s_app_name, fpr::Version app_version = s_app_version, const std::string& engine_name = s_engine_name, fpr::Version engine_version = s_engine_version, fpr::Version vulkan_version = s_vulkan_version); void CreateModelDescriptorSet(); void CreateCameraDescriptorSet(); void CreateCameraDescriptorSetLayout(); void CreateModelDescriptorSetLayout(); void CreateDepthSamplerLayout(); void CreateDepthSamplerDescriptorSet(); public: static constexpr glm::vec3 FORWARD_VECTOR = glm::vec3(0, 0, 1); static constexpr glm::vec3 UP_VECTOR = glm::vec3(0, 1, 0); static constexpr glm::vec3 RIGHT_VECTOR = glm::vec3(1, 0, 0); void CreateDescriptorSets(); struct PerModelData { glm::mat4* model_matrix; } PER_MODEL_UBO; fpr::Scene* m_loaded_scene; static Context& Get(); static void Init( VulkanWindow* Window, const std::string& app_name, fpr::Version app_version, const std::string& engine_name, fpr::Version engine_version, fpr::Version vulkan_version); std::unique_ptr<RenderGraph> m_render_graph; VulkanWindow* GetWindow(); SwapChain* GetSwapChain(); void CreateGraphicsCmdPool(); void CreateSwapChain(); void CreateComputeCmdPool(); void CreateDescriptorPools(); void CreateTextureSampler(); void RecreateSwapchain(); void CreatePipelines(std::function<PipelineCreationData(void)> fn = DEFAULT_PIPELINE_CREATION_CALLBACK); void CreateSceneBuffers(); vk::CommandPool& GetGraphicsCmdPool() FPR_NOEXCEPT; vk::CommandPool& GetComputeCmdPool() FPR_NOEXCEPT; vk::DescriptorPool& GetDescriptorPool(); vk::SurfaceKHR& GetSurface() FPR_NOEXCEPT; [[nodiscard]] Device* GetDevice() const FPR_NOEXCEPT; [[nodiscard]] uint32_t GetRequiredDynamicAlignment() const FPR_NOEXCEPT; void SetDynamicAlignment(uint32_t) FPR_NOEXCEPT; Context(const Context& other) = delete; Context& operator=(const Context& other) = delete; vk::Instance& GetInstance(); vk::CommandBuffer& BeginSingleTimeCommands(); void EndSingleTimeCommands(); InputHandler& GetCameraInputHandler(); }; } // namespace fpr