diff --git a/Resources/Editor/Settings/EnvironmentMaps/piazza_bologni_1k.hdr b/Resources/Editor/Settings/EnvironmentMaps/piazza_bologni_1k.hdr new file mode 100644 index 00000000..e5d66075 Binary files /dev/null and b/Resources/Editor/Settings/EnvironmentMaps/piazza_bologni_1k.hdr differ diff --git a/Resources/Editor/Settings/EnvironmentMaps/piazza_bologni_4k.hdr b/Resources/Editor/Settings/EnvironmentMaps/piazza_bologni_4k.hdr new file mode 100644 index 00000000..860dfa92 Binary files /dev/null and b/Resources/Editor/Settings/EnvironmentMaps/piazza_bologni_4k.hdr differ diff --git a/Resources/Editor/Settings/EnvironmentMaps/rural_asphalt_road_4k.hdr b/Resources/Editor/Settings/EnvironmentMaps/rural_asphalt_road_4k.hdr new file mode 100644 index 00000000..921f7a69 Binary files /dev/null and b/Resources/Editor/Settings/EnvironmentMaps/rural_asphalt_road_4k.hdr differ diff --git a/Resources/Shaders/cubemap.frag b/Resources/Shaders/cubemap.frag new file mode 100644 index 00000000..d7c3ecf7 --- /dev/null +++ b/Resources/Shaders/cubemap.frag @@ -0,0 +1,12 @@ +#version 460 + +layout (location = 0) in vec3 dir; + +layout (location = 0) out vec4 outColor; + +layout(set = 0, binding = 5) uniform samplerCube CubemapTexture; + +void main() +{ + outColor = texture(CubemapTexture, dir); +} \ No newline at end of file diff --git a/Resources/Shaders/cubemap.vert b/Resources/Shaders/cubemap.vert new file mode 100644 index 00000000..f656facd --- /dev/null +++ b/Resources/Shaders/cubemap.vert @@ -0,0 +1,21 @@ +#version 460 +#extension GL_GOOGLE_include_directive : require +#include "vertex_common.glsl" + + +layout (location = 0) out vec3 dir; + +void main() +{ + float cubeScale = 100.0; + + DrawData dd = DrawDataBuffer.Data[gl_BaseInstance]; + + uint refIdx = dd.IndexOffset + gl_VertexIndex; + uint verIdx = IndexBuffer.Data[refIdx] + dd.VertexOffset; + DrawVertex v = VertexBuffer.Data[verIdx]; + + vec3 vertexPosition = vec3(v.x, v.y, v.z); + gl_Position = Camera.Projection * Camera.View * vec4(cubeScale * vertexPosition, 1.0f); + dir = vec3(vertexPosition.x, vertexPosition.y, vertexPosition.z); +} diff --git a/Resources/Shaders/imgui.frag b/Resources/Shaders/imgui.frag new file mode 100644 index 00000000..39c0e0bb --- /dev/null +++ b/Resources/Shaders/imgui.frag @@ -0,0 +1,8 @@ +#version 460 core +layout(location = 0) out vec4 fColor; +layout(set=0, binding=0) uniform sampler2D sTexture; +layout(location = 0) in struct { vec4 Color; vec2 UV; } In; +void main() +{ + fColor = In.Color * texture(sTexture, In.UV.st); +} \ No newline at end of file diff --git a/Resources/Shaders/imgui.vert b/Resources/Shaders/imgui.vert new file mode 100644 index 00000000..2a59dad7 --- /dev/null +++ b/Resources/Shaders/imgui.vert @@ -0,0 +1,15 @@ +#version 460 core +layout(location = 0) in vec2 aPos; +layout(location = 1) in vec2 aUV; +layout(location = 2) in vec4 aColor; +layout(push_constant) uniform uPushConstant { vec2 uScale; vec2 uTranslate; } pc; + +out gl_PerVertex { vec4 gl_Position; }; +layout(location = 0) out struct { vec4 Color; vec2 UV; } Out; + +void main() +{ + Out.Color = aColor; + Out.UV = aUV; + gl_Position = vec4(aPos * pc.uScale + pc.uTranslate, 0, 1); +} \ No newline at end of file diff --git a/Tetragrama/src/Components/SceneViewportUIComponent.cpp b/Tetragrama/src/Components/SceneViewportUIComponent.cpp index 58411c83..115b31ec 100644 --- a/Tetragrama/src/Components/SceneViewportUIComponent.cpp +++ b/Tetragrama/src/Components/SceneViewportUIComponent.cpp @@ -23,7 +23,7 @@ namespace Tetragrama::Components { if ((m_viewport_size.x != m_content_region_available_size.x) || (m_viewport_size.y != m_content_region_available_size.y)) { - m_viewport_size = m_content_region_available_size; + m_viewport_size = m_content_region_available_size; m_request_renderer_resize = true; } else @@ -42,13 +42,13 @@ namespace Tetragrama::Components if (m_is_window_hovered && m_is_window_focused) { - Messengers::IMessenger::SendAsync>( - EDITOR_COMPONENT_SCENEVIEWPORT_FOCUSED, Messengers::GenericMessage{true}); + Messengers::IMessenger::SendAsync>( + EDITOR_RENDER_LAYER_SCENE_REQUEST_FOCUS, Messengers::GenericMessage{true}); } else { - Messengers::IMessenger::SendAsync>( - EDITOR_COMPONENT_SCENEVIEWPORT_UNFOCUSED, Messengers::GenericMessage{false}); + Messengers::IMessenger::SendAsync>( + EDITOR_RENDER_LAYER_SCENE_REQUEST_UNFOCUS, Messengers::GenericMessage{false}); } if (m_is_window_clicked && m_is_window_hovered && m_is_window_focused) @@ -59,7 +59,7 @@ namespace Tetragrama::Components auto mouse_bounded_x = static_cast(mouse_position.x); auto mouse_bounded_y = static_cast(mouse_position.y); - auto message_data = std::array{mouse_bounded_x, mouse_bounded_y}; + auto message_data = std::array{mouse_bounded_x, mouse_bounded_y}; Messengers::IMessenger::SendAsync>( EDITOR_COMPONENT_SCENEVIEWPORT_CLICKED, Messengers::ArrayValueMessage{message_data}); } @@ -85,19 +85,8 @@ namespace Tetragrama::Components // Scene texture representation if (!m_scene_texture || m_refresh_texture_handle) { - auto frame_output = GraphicRenderer::GetFrameOutput(); - auto texture = frame_output->GetColorAttachmentCollection().at(0); - - if (m_refresh_texture_handle) - { - VkDescriptorSet old_scene_texture = VK_NULL_HANDLE; - std::swap(m_scene_texture, old_scene_texture); - m_refresh_texture_handle = false; - - VulkanDevice::EnqueueForDeletion(DeviceResourceType::DESCRIPTORSET, DirtyResource{.Handle = old_scene_texture, .Data1 = ImGUIRenderer::s_descriptor_pool}); - } - auto texture_buffer = texture->GetImage2DBuffer(); - m_scene_texture = ImGui_ImplVulkan_AddTexture(texture_buffer->GetSampler(), texture_buffer->GetImageViewHandle(), VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); + m_scene_texture = GraphicRenderer::GetImguiFrameOutput(); + m_refresh_texture_handle = false; } ImGui::Image(m_scene_texture, m_viewport_size, ImVec2(0, 1), ImVec2(1, 0)); diff --git a/Tetragrama/src/EditorCameraController.cpp b/Tetragrama/src/EditorCameraController.cpp index 33410239..59bc219b 100644 --- a/Tetragrama/src/EditorCameraController.cpp +++ b/Tetragrama/src/EditorCameraController.cpp @@ -7,6 +7,7 @@ namespace Tetragrama { EditorCameraController::EditorCameraController(double distance, float yaw_angle_degree, float pitch_angle_degree) : PerspectiveCameraController(0.0f) { + m_process_event = true; m_controller_type = ZEngine::Controllers::CameraControllerType::PERSPECTIVE_CONTROLLER; m_perspective_camera = ZEngine::CreateRef( m_camera_fov, m_aspect_ratio, m_camera_near, m_camera_far, ZEngine::Maths::radians(yaw_angle_degree), ZEngine::Maths::radians(pitch_angle_degree)); diff --git a/Tetragrama/src/Layers/RenderLayer.cpp b/Tetragrama/src/Layers/RenderLayer.cpp index 79cc9d92..62785fd2 100644 --- a/Tetragrama/src/Layers/RenderLayer.cpp +++ b/Tetragrama/src/Layers/RenderLayer.cpp @@ -20,7 +20,6 @@ namespace Tetragrama::Layers void RenderLayer::Initialize() { - auto current_window = GetAttachedWindow(); m_editor_camera_controller = CreateRef(50.0, 45.f, 40.f); GraphicScene::Initialize(); @@ -49,8 +48,6 @@ namespace Tetragrama::Layers { auto camera = m_editor_camera_controller->GetCamera(); GraphicRenderer::DrawScene(camera, GraphicScene::GetRawData()); - - } std::future RenderLayer::SceneRequestResizeMessageHandlerAsync(Messengers::GenericMessage>& message) @@ -64,15 +61,13 @@ namespace Tetragrama::Layers std::future RenderLayer::SceneRequestFocusMessageHandlerAsync(Messengers::GenericMessage& message) { - // std::unique_lock lock(m_message_handler_mutex); - // GraphicScene::SetShouldReactToEvent(message.GetValue()); + m_editor_camera_controller->ResumeEventProcessing(); co_return; } std::future RenderLayer::SceneRequestUnfocusMessageHandlerAsync(Messengers::GenericMessage& message) { - // std::unique_lock lock(m_message_handler_mutex); - // GraphicScene::SetShouldReactToEvent(message.GetValue()); + m_editor_camera_controller->PauseEventProcessing(); co_return; } diff --git a/ZEngine/include/ZEngine/Controllers/PerspectiveCameraController.h b/ZEngine/include/ZEngine/Controllers/PerspectiveCameraController.h index 621fad3f..1815dbfa 100644 --- a/ZEngine/include/ZEngine/Controllers/PerspectiveCameraController.h +++ b/ZEngine/include/ZEngine/Controllers/PerspectiveCameraController.h @@ -1,4 +1,5 @@ #pragma once +#include #include #include #include @@ -10,18 +11,18 @@ namespace ZEngine::Controllers class PerspectiveCameraController : public ICameraController, public Inputs::IMouseEventCallback, public Window::ICoreWindowEventCallback { public: - explicit PerspectiveCameraController() - :m_perspective_camera(new Rendering::Cameras::PerspectiveCamera(m_camera_fov, m_aspect_ratio, m_camera_near, m_camera_far)) + explicit PerspectiveCameraController() : m_perspective_camera(new Rendering::Cameras::PerspectiveCamera(m_camera_fov, m_aspect_ratio, m_camera_near, m_camera_far)) { - m_controller_type = CameraControllerType::PERSPECTIVE_CONTROLLER; m_position = {0.0f, 0.0f, 1.5f}; + m_controller_type = CameraControllerType::PERSPECTIVE_CONTROLLER; + m_process_event = true; } - explicit PerspectiveCameraController(Rendering::Cameras::PerspectiveCamera* const camera) - :m_perspective_camera(camera) + explicit PerspectiveCameraController(Rendering::Cameras::PerspectiveCamera* const camera) : m_perspective_camera(camera) { m_position = {0.0f, 0.0f, 1.5f}; m_controller_type = CameraControllerType::PERSPECTIVE_CONTROLLER; + m_process_event = true; } explicit PerspectiveCameraController(float aspect_ratio, Rendering::Cameras::PerspectiveCamera* const camera) @@ -29,6 +30,7 @@ namespace ZEngine::Controllers { m_position = {0.0f, 0.0f, 1.5f}; m_controller_type = CameraControllerType::PERSPECTIVE_CONTROLLER; + m_process_event = true; } explicit PerspectiveCameraController(float aspect_ratio) @@ -36,6 +38,7 @@ namespace ZEngine::Controllers { m_position = {0.0f, 0.0f, 1.5f}; m_controller_type = CameraControllerType::PERSPECTIVE_CONTROLLER; + m_process_event = true; } virtual ~PerspectiveCameraController() = default; @@ -63,6 +66,9 @@ namespace ZEngine::Controllers void SetViewport(float width, float height); void SetTarget(const glm::vec3& target); + virtual void ResumeEventProcessing(); + virtual void PauseEventProcessing(); + public: bool OnMouseButtonPressed(Event::MouseButtonPressedEvent&) override { @@ -107,10 +113,12 @@ namespace ZEngine::Controllers } protected: - float m_camera_fov{45.0f}; - float m_camera_near{0.1f}; - float m_camera_far{5000.0f}; - glm::vec3 m_camera_target{0.0f, 0.0f, 0.0f}; + float m_camera_fov{45.0f}; + float m_camera_near{0.1f}; + float m_camera_far{5000.0f}; + std::recursive_mutex m_event_mutex; + bool m_process_event{true}; + glm::vec3 m_camera_target{0.0f, 0.0f, 0.0f}; ZEngine::Ref m_perspective_camera; }; } // namespace ZEngine::Controllers diff --git a/ZEngine/include/ZEngine/Hardwares/VulkanDevice.h b/ZEngine/include/ZEngine/Hardwares/VulkanDevice.h index 543f7981..68f91ddc 100644 --- a/ZEngine/include/ZEngine/Hardwares/VulkanDevice.h +++ b/ZEngine/include/ZEngine/Hardwares/VulkanDevice.h @@ -10,17 +10,14 @@ #include #include -#include -#include -#include - namespace ZEngine::Hardwares { struct DirtyResource { - void* Handle = nullptr; - void* Data1 = nullptr; + uint32_t FrameIndex = UINT32_MAX; + void* Handle = nullptr; + void* Data1 = nullptr; std::chrono::steady_clock::time_point MarkedAsDirtyTime; Rendering::DeviceResourceType Type; }; @@ -55,6 +52,21 @@ namespace ZEngine::Hardwares } }; + struct QueueSubmitInfo + { + bool IsImmediate{false}; + uint32_t DestinationStageMask; + Rendering::QueueType Type; + Rendering::Buffers::CommandBuffer& Buffer; + }; + + struct QueueSubmission + { + Rendering::Primitives::Semaphore* SignalSemaphore{nullptr}; + Rendering::Primitives::Fence* SignalFence{nullptr}; + VkSubmitInfo Submit; + }; + struct VulkanDevice { VulkanDevice() = delete; @@ -65,19 +77,22 @@ namespace ZEngine::Hardwares static void Deinitialize(); static void Dispose(); + static void SetCurrentFrameIndex(uint32_t frame); + static uint32_t GetCurrentFrameIndex(); static VkPhysicalDevice GetNativePhysicalDeviceHandle(); static const VkPhysicalDeviceProperties& GetPhysicalDeviceProperties(); static const VkPhysicalDeviceMemoryProperties& GetPhysicalDeviceMemoryProperties(); static VkDevice GetNativeDeviceHandle(); static VkInstance GetNativeInstanceHandle(); - static void QueueSubmit( + static bool QueueSubmit( Rendering::QueueType queue_type, const VkPipelineStageFlags wait_stage_flage, - VkCommandBuffer const buffer_handle, - Rendering::Primitives::Semaphore* const wait_semaphore, - Rendering::Primitives::Semaphore* const signal_semaphore, - Rendering::Primitives::Fence* const fence); + Rendering::Buffers::CommandBuffer& command_buffer, + bool as_instant_submission = false, + Rendering::Primitives::Semaphore* const wait_semaphore = nullptr, + Rendering::Primitives::Semaphore* const signal_semaphore = nullptr, + Rendering::Primitives::Fence* const fence = nullptr); static void EnqueueForDeletion(Rendering::DeviceResourceType resource_type, void* const resource_handle); static void EnqueueForDeletion(Rendering::DeviceResourceType resource_type, DirtyResource resource); @@ -85,12 +100,18 @@ namespace ZEngine::Hardwares static void EnqueueBufferForDeletion(BufferView& buffer); static void EnqueueBufferImageForDeletion(BufferImage& buffer); - static void Present(VkSwapchainKHR swapchain, uint32_t* frame_image_index, const std::vector& wait_semaphore_collection); + static bool Present( + VkSwapchainKHR swapchain, + uint32_t* frame_image_index, + Rendering::Primitives::Semaphore* const wait_semaphore, + Rendering::Primitives::Semaphore* const render_complete_semaphore, + Rendering::Primitives::Fence* const frame_fence); static Rendering::Pools::CommandPool* CreateCommandPool(Rendering::QueueType queue_type, uint64_t swapchain_id, bool present_on_swapchain); - static std::vector> GetAllCommandPools(uint64_t swapchain_id = 0); static void DisposeCommandPool(const Rendering::Pools::CommandPool* pool); + static Rendering::Pools::CommandPool* GetCommandPool(Rendering::QueueType queue_type); + static QueueView GetQueue(Rendering::QueueType type); static void QueueWait(Rendering::QueueType type); static void QueueWaitAll(); @@ -113,20 +134,14 @@ namespace ZEngine::Hardwares VkSharingMode image_sharing_mode, VkSampleCountFlagBits image_sample_count, VkMemoryPropertyFlags requested_properties, - VkImageAspectFlagBits image_aspect_flag); - - static VkSampler CreateImageSampler(); - static VkFormat FindSupportedFormat(const std::vector& format_collection, VkImageTiling image_tiling, VkFormatFeatureFlags feature_flags); - static VkFormat FindDepthFormat(); - static VkImageView CreateImageView(VkImage image, VkFormat image_format, VkImageAspectFlagBits image_aspect_flag); - static void CopyBufferToImage( - const Rendering::QueueType& queue_type, - const BufferView& source, - BufferImage& destination, - uint32_t width, - uint32_t height, - uint32_t start_copy_after_barrier_index = 0, - const std::vector& memory_barriers = {}); + VkImageAspectFlagBits image_aspect_flag, + uint32_t layer_count = 1U, + VkImageCreateFlags image_create_flag_bit = 0); + + static VkSampler CreateImageSampler(); + static VkFormat FindSupportedFormat(const std::vector& format_collection, VkImageTiling image_tiling, VkFormatFeatureFlags feature_flags); + static VkFormat FindDepthFormat(); + static VkImageView CreateImageView(VkImage image, VkFormat image_format, VkImageAspectFlagBits image_aspect_flag, uint32_t layer_count = 1U); static VkFramebuffer CreateFramebuffer( const std::vector& attachments, const VkRenderPass& render_pass, @@ -134,60 +149,56 @@ namespace ZEngine::Hardwares uint32_t height, uint32_t layer_number = 1); - static Rendering::Buffers::CommandBuffer* BeginInstantCommandBuffer(Rendering::QueueType type); - static void EndInstantCommandBuffer(Rendering::Buffers::CommandBuffer* const command); + static Ref BeginInstantCommandBuffer(Rendering::QueueType type); + static void EndInstantCommandBuffer(Ref& command); static VmaAllocator GetVmaAllocator(); - private: - static std::string m_application_name; - static VulkanLayer m_layer; - static VkInstance m_vulkan_instance; - static VkSurfaceKHR m_surface; - static uint32_t m_graphic_family_index; - static uint32_t m_transfer_family_index; - static std::map m_queue_map; - static VkDevice m_logical_device; - static VkPhysicalDevice m_physical_device; - static VkPhysicalDeviceProperties m_physical_device_properties; - static VkPhysicalDeviceFeatures m_physical_device_feature; - static VkPhysicalDeviceMemoryProperties m_physical_device_memory_properties; - static VkDebugUtilsMessengerEXT m_debug_messenger; - static std::map> m_deletion_resource_queue; - static std::queue s_dirty_resource_collection; - static std::queue s_dirty_buffer_queue; - static std::queue s_dirty_buffer_image_queue; static std::vector> m_command_pool_collection; - static PFN_vkCreateDebugUtilsMessengerEXT __createDebugMessengerPtr; - static PFN_vkDestroyDebugUtilsMessengerEXT __destroyDebugMessengerPtr; - static std::vector m_surface_format_collection; - static std::vector m_present_mode_collection; - static VkSurfaceFormatKHR m_surface_format; - static VkPresentModeKHR m_present_mode; - static VkDescriptorPool m_descriptor_pool; - static VmaAllocator s_vma_allocator; - static void __cleanupDirtyResource(std::chrono::steady_clock::time_point); - static void __cleanupBufferDirtyResource(std::chrono::steady_clock::time_point); - static void __cleanupBufferImageDirtyResource(std::chrono::steady_clock::time_point); - static VKAPI_ATTR VkBool32 VKAPI_CALL __debugCallback( - VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity, - VkDebugUtilsMessageTypeFlagsEXT messageType, - const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData, - void* pUserData); - - private: - static std::mutex m_queue_mutex; - static std::mutex m_command_pool_mutex; - static std::mutex m_deletion_queue_mutex; - static std::map> m_in_device_command_pool_map; - static std::condition_variable m_cond; - static std::atomic_bool m_is_executing_instant_command; - static std::mutex m_instant_command_mutex; private: - static std::jthread s_cleanup_thread; - static std::condition_variable s_cleanup_cond; - static std::atomic_bool s_cleanup_thread_shutdown; - static std::chrono::seconds s_cleanup_timeout; + static std::string m_application_name; + static VulkanLayer m_layer; + static VkInstance m_vulkan_instance; + static VkSurfaceKHR m_surface; + static uint32_t m_graphic_family_index; + static uint32_t m_transfer_family_index; + static uint32_t s_current_frame_index; + static std::map m_queue_map; + static VkDevice m_logical_device; + static VkPhysicalDevice m_physical_device; + static VkPhysicalDeviceProperties m_physical_device_properties; + static VkPhysicalDeviceFeatures m_physical_device_feature; + static VkPhysicalDeviceMemoryProperties m_physical_device_memory_properties; + static VkDebugUtilsMessengerEXT m_debug_messenger; + static std::map> m_deletion_resource_queue; + static std::deque s_dirty_resource_collection; + static std::deque s_dirty_buffer_queue; + static std::deque s_dirty_buffer_image_queue; + static PFN_vkCreateDebugUtilsMessengerEXT __createDebugMessengerPtr; + static PFN_vkDestroyDebugUtilsMessengerEXT __destroyDebugMessengerPtr; + static std::vector m_surface_format_collection; + static std::vector m_present_mode_collection; + static VkSurfaceFormatKHR m_surface_format; + static VkPresentModeKHR m_present_mode; + static VkDescriptorPool m_descriptor_pool; + static VmaAllocator s_vma_allocator; + static std::mutex m_frame_value_mutex; + static std::mutex m_queue_mutex; + static std::mutex m_command_pool_mutex; + static std::mutex m_deletion_queue_mutex; + static std::map> m_in_device_command_pool_map; + static std::condition_variable m_cond; + static std::atomic_bool m_is_executing_instant_command; + static std::mutex m_instant_command_mutex; + static std::map>> s_queue_submit_info_pool; + static void __cleanupDirtyResource(); + static void __cleanupBufferDirtyResource(); + static void __cleanupBufferImageDirtyResource(); + static VKAPI_ATTR VkBool32 VKAPI_CALL __debugCallback( + VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity, + VkDebugUtilsMessageTypeFlagsEXT messageType, + const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData, + void* pUserData); }; } // namespace ZEngine::Hardwares diff --git a/ZEngine/include/ZEngine/Helpers/MemoryOperations.h b/ZEngine/include/ZEngine/Helpers/MemoryOperations.h index b092b64c..6cb02ea9 100644 --- a/ZEngine/include/ZEngine/Helpers/MemoryOperations.h +++ b/ZEngine/include/ZEngine/Helpers/MemoryOperations.h @@ -1,7 +1,10 @@ +#pragma once +#include + +#ifdef __STDC_LIB_EXT1__ #define __STDC_WANT_LIB_EXT1__ 1 #include -#include -#include +#endif namespace ZEngine::Helpers { @@ -14,7 +17,7 @@ namespace ZEngine::Helpers #define SECURE_C11_FUNCTIONS_AVAILABLE 0 #endif - int secure_memset(void* destination, int value, size_t count, size_t destinationSize) + inline int secure_memset(void* destination, int value, size_t count, size_t destinationSize) { if (!destination) { @@ -29,7 +32,7 @@ namespace ZEngine::Helpers return (std::memset(destination, value, count) == destination) ? MEMORY_OP_SUCCESS : MEMORY_OP_FAILURE; } - int secure_memcpy(void* dest, size_t destSize, const void* src, size_t count) + inline int secure_memcpy(void* dest, size_t destSize, const void* src, size_t count) { if (!dest || !src) { @@ -50,7 +53,7 @@ namespace ZEngine::Helpers #endif } - int secure_memmove(void* dest, size_t destSize, const void* src, size_t count) + inline int secure_memmove(void* dest, size_t destSize, const void* src, size_t count) { if (!dest || !src) { @@ -70,7 +73,7 @@ namespace ZEngine::Helpers #endif } - int secure_strncpy(char* dest, size_t destSize, const char* src, size_t count) + inline int secure_strncpy(char* dest, size_t destSize, const char* src, size_t count) { if (!dest || !src) { @@ -89,7 +92,7 @@ namespace ZEngine::Helpers return (std::strncpy(dest, src, count) == dest) ? MEMORY_OP_SUCCESS : MEMORY_OP_FAILURE; #endif } - size_t secure_strlen(const char* str) + inline size_t secure_strlen(const char* str) { if (!str) { @@ -98,7 +101,7 @@ namespace ZEngine::Helpers return std::strlen(str); } - int secure_strcpy(char* dest, size_t destSize, const char* src) + inline int secure_strcpy(char* dest, size_t destSize, const char* src) { if (!dest || !src) { @@ -119,7 +122,7 @@ namespace ZEngine::Helpers #endif } - int secure_memcmp(const void* ptr1, size_t ptr1Size, const void* ptr2, size_t ptr2Size, size_t num) + inline int secure_memcmp(const void* ptr1, size_t ptr1Size, const void* ptr2, size_t ptr2Size, size_t num) { if (!ptr1 || !ptr2) { diff --git a/ZEngine/include/ZEngine/Layers/ImguiLayer.h b/ZEngine/include/ZEngine/Layers/ImguiLayer.h index b53856cc..cf98c58f 100644 --- a/ZEngine/include/ZEngine/Layers/ImguiLayer.h +++ b/ZEngine/include/ZEngine/Layers/ImguiLayer.h @@ -64,15 +64,8 @@ namespace ZEngine::Layers bool OnWindowMaximized(Event::WindowMaximizedEvent&) override; bool OnWindowRestored(Event::WindowRestoredEvent&) override; - virtual void StyleDarkTheme(); - private: static bool m_initialized; std::vector> m_ui_components; - static void __ImGUIRendererCreateWindowCallback(ImGuiViewport* viewport); - static void __ImGUIPlatformDestroyWindowCallback(ImGuiViewport* viewport); - static void __ImGUIPlatformRenderWindowCallback(ImGuiViewport* viewport, void* args); - static void __ImGUIPlatformSwapBuffersCallback(ImGuiViewport* viewport, void* args); - static void __ImGUIPlatformSetWindowSizeCallback(ImGuiViewport* viewport, ImVec2 size); }; } // namespace ZEngine::Layers diff --git a/ZEngine/include/ZEngine/Rendering/Buffers/Bitmap.h b/ZEngine/include/ZEngine/Rendering/Buffers/Bitmap.h new file mode 100644 index 00000000..83ad6df9 --- /dev/null +++ b/ZEngine/include/ZEngine/Rendering/Buffers/Bitmap.h @@ -0,0 +1,321 @@ +#pragma once +#include +#include +#include +#include +#include +#include + +namespace ZEngine::Rendering::Buffers +{ + + enum BitmapType + { + TEXTURE_2D, + CUBE + }; + + enum BitmapFormat + { + UNSIGNED_BYTE, + FLOAT + }; + + struct BitmapPixel + { + /* + * Mapping pixel coordinates on a specific face of a cubemap to 3D Cartesian coordinates + * + * The A and B values are normalized coordinates in the range [-1, 1], calculated from pixel coordinates (i, j) and the face size. + * + * Reference: "Real-Time Rendering, Fourth Edition" by Tomas Akenine-M�ller, Eric Haines, Naty Hoffman + */ + static glm::vec3 FaceCoordToXYZ(int i, int j, int face_id, int face_size) + { + const float A = 2.0f * float(i) / face_size; + const float B = 2.0f * float(j) / face_size; + + /* + * The right face of the cube is mapped to the negative x-axis, so the x-coordinate is set to -1.0f. + * The y and z coordinates are set based on the normalized pixel coordinates. + */ + if (face_id == 0) + return glm::vec3(-1.0f, A - 1.0f, B - 1.0f); + + /* + * The left face is mapped to the positive x-axis, so the x-coordinate is set to A - 1.0f. + * The y-coordinate is set to -1.0f, and the z-coordinate is set based on the normalized pixel coordinates. + */ + if (face_id == 1) + return glm::vec3(A - 1.0f, -1.0f, 1.0f - B); + + /* + * The top face is mapped to the positive y-axis, so the y-coordinate is set to A - 1.0f. + * The x-coordinate is set to 1.0f, and the z-coordinate is set based on the normalized pixel coordinates. + */ + if (face_id == 2) + return glm::vec3(1.0f, A - 1.0f, 1.0f - B); + + /* + * The bottom face is mapped to the negative y-axis, so the y-coordinate is set to 1.0f. + * The x-coordinate is set to 1.0f - A, and the z-coordinate is set based on the normalized pixel coordinates + */ + if (face_id == 3) + return glm::vec3(1.0f - A, 1.0f, 1.0f - B); + + /* + * The front face is mapped to the positive z-axis, so the z-coordinate is set to 1.0f. + *The x and y coordinates are set based on the normalized pixel coordinates. + */ + if (face_id == 4) + return glm::vec3(B - 1.0f, A - 1.0f, 1.0f); + + /* + * The back face is mapped to the negative z-axis, so the z-coordinate is set to -1.0f. + * The x and y coordinates are set based on the normalized pixel coordinates. + */ + if (face_id == 5) + return glm::vec3(1.0f - B, A - 1.0f, -1.0f); + + return glm::vec3{}; + } + }; + + struct Bitmap + { + Bitmap() = default; + Bitmap(int width, int height, int channel, BitmapFormat format) + : Width(width), Height(height), Channel(channel), Format(format), Buffer(width * height * channel * BytePerChannel(format)) + { + } + Bitmap(int width, int height, int depth, int channel, BitmapFormat format) + : Width(width), Height(height), Depth(depth), Channel(channel), Format(format), Buffer(width * height * depth * channel * BytePerChannel(format)) + { + } + Bitmap(int width, int height, int channel, BitmapFormat format, const void* data) + : Width(width), Height(height), Channel(channel), Format(format), Buffer(width * height * channel * BytePerChannel(format)) + { + if (data) + { + ZENGINE_VALIDATE_ASSERT( + Helpers::secure_memcpy(Buffer.data(), Buffer.size(), data, Buffer.size()) == Helpers::MEMORY_OP_SUCCESS, "Failed to perform memory copy operation") + } + } + ~Bitmap() = default; + + void SetPixel(int x, int y, const glm::vec4& pixel) + { + if (Format == BitmapFormat::UNSIGNED_BYTE) + { + const int ofs = Channel * (y * Width + x); + if (Channel > 0) + Buffer[ofs + 0] = uint8_t(pixel.x * 255.0f); + if (Channel > 1) + Buffer[ofs + 1] = uint8_t(pixel.y * 255.0f); + if (Channel > 2) + Buffer[ofs + 2] = uint8_t(pixel.z * 255.0f); + if (Channel > 3) + Buffer[ofs + 3] = uint8_t(pixel.w * 255.0f); + } + else if (Format == BitmapFormat::FLOAT) + { + const int ofs = Channel * (y * Width + x); + float* data = reinterpret_cast(Buffer.data()); + if (Channel > 0) + data[ofs + 0] = pixel.x; + if (Channel > 1) + data[ofs + 1] = pixel.y; + if (Channel > 2) + data[ofs + 2] = pixel.z; + if (Channel > 3) + data[ofs + 3] = pixel.w; + } + } + + glm::vec4 GetPixel(int x, int y) const + { + if (Format == BitmapFormat::UNSIGNED_BYTE) + { + const int ofs = Channel * (y * Width + x); + return glm::vec4( + Channel > 0 ? float(Buffer[ofs + 0]) / 255.0f : 0.0f, + Channel > 1 ? float(Buffer[ofs + 1]) / 255.0f : 0.0f, + Channel > 2 ? float(Buffer[ofs + 2]) / 255.0f : 0.0f, + Channel > 3 ? float(Buffer[ofs + 3]) / 255.0f : 0.0f); + } + else if (Format == BitmapFormat::FLOAT) + { + const int ofs = Channel * (y * Width + x); + const float* data = reinterpret_cast(Buffer.data()); + return glm::vec4( + Channel > 0 ? data[ofs + 0] : 0.0f, + Channel > 1 ? data[ofs + 1] : 0.0f, + Channel > 2 ? data[ofs + 2] : 0.0f, + Channel > 3 ? data[ofs + 3] : 0.0f); + } + + return glm::vec4(); + } + + inline static int BytePerChannel(BitmapFormat format) + { + if (format == BitmapFormat::UNSIGNED_BYTE) + { + return 1; + } + else if (format == BitmapFormat::FLOAT) + { + return 4; + } + + return 0; + } + + inline static Bitmap EquirectangularMapToVerticalCross(const Bitmap& input_map) + { + if (input_map.Type != BitmapType::TEXTURE_2D) + { + return Bitmap(); + } + + const int face_size = input_map.Width / 4; + + const int width = face_size * 3; + const int height = face_size * 4; + + Bitmap vertical_cross = Bitmap(width, height, input_map.Channel, input_map.Format); + + const glm::ivec2 face_offsets[] = { + glm::ivec2{face_size, face_size * 3}, + glm::ivec2{0, face_size}, + glm::ivec2{face_size, face_size}, + glm::ivec2{face_size * 2, face_size}, + glm::ivec2{face_size, 0}, + glm::ivec2{face_size, face_size * 2}}; + + const int clamped_width = input_map.Width - 1; + const int clamped_height = input_map.Height - 1; + + for (int face = 0; face < 6; ++face) + { + for (int i = 0; i < face_size; ++i) + { + for (int j = 0; j < face_size; ++j) + { + const glm::vec3 P = BitmapPixel::FaceCoordToXYZ(i, j, face, face_size); + const float R = hypot(P.x, P.y); + const float theta = atan2(P.y, P.x); + const float phi = atan2(P.z, R); + + const float Uf = float(2.0f * face_size * (theta + glm::pi()) / glm::pi()); + const float Vf = float(2.0f * face_size * (glm::pi() / 2.0f - phi) / glm::pi()); + + const int U1 = glm::clamp(int(floor(Uf)), 0, clamped_width); + const int V1 = glm::clamp(int(floor(Vf)), 0, clamped_height); + const int U2 = glm::clamp(U1 + 1, 0, clamped_width); + const int V2 = glm::clamp(V1 + 1, 0, clamped_height); + + const float s = Uf - U1; + const float t = Vf - V1; + + const glm::vec4 A = input_map.GetPixel(U1, V1); + const glm::vec4 B = input_map.GetPixel(U2, V1); + const glm::vec4 C = input_map.GetPixel(U1, V2); + const glm::vec4 D = input_map.GetPixel(U2, V2); + + const glm::vec4 color = A * (1 - s) * (1 - t) + B * (s) * (1 - t) + C * (1 - s) * t + D * (s) * (t); + vertical_cross.SetPixel(i + face_offsets[face].x, j + face_offsets[face].y, color); + } + } + } + return vertical_cross; + } + + inline static Bitmap VerticalCrossToCubemap(const Bitmap& input_map) + { + const int face_width = input_map.Width / 3; + const int face_height = input_map.Height / 4; + + Bitmap cubemap = Bitmap(face_width, face_height, 6, input_map.Channel, input_map.Format); + cubemap.Type = CUBE; + + const uint8_t* source = input_map.Buffer.data(); + uint8_t* destination = cubemap.Buffer.data(); + int pixel_size = cubemap.Channel * BytePerChannel(cubemap.Format); + + const int RIGHT_FACE = 0; + const int LEFT_FACE = 1; + const int UP_FACE = 2; + const int DOWN_FACE = 3; + const int FRONT_FACE = 4; + const int BACK_FACE = 5; + + for (int face = 0; face < 6; ++face) + { + for (int j = 0; j < face_height; ++j) + { + for (int i = 0; i < face_width; ++i) + { + int pixel_pos_x = 0; + int pixel_pos_y = 0; + + switch (face) + { + case RIGHT_FACE: + { + pixel_pos_x = i; + pixel_pos_y = face_height + j; + break; + } + case LEFT_FACE: + { + pixel_pos_x = 2 * face_width + i; + pixel_pos_y = 1 * face_height + j; + break; + } + case UP_FACE: + { + pixel_pos_x = 2 * face_width - (i + 1); + pixel_pos_y = 1 * face_height - (j + 1); + break; + } + case DOWN_FACE: + { + pixel_pos_x = 2 * face_width - (i + 1); + pixel_pos_y = 3 * face_height - (j + 1); + break; + } + case FRONT_FACE: + { + pixel_pos_x = 2 * face_width - (i + 1); + pixel_pos_y = input_map.Height - (j + 1); + break; + } + case BACK_FACE: + { + pixel_pos_x = face_width + i; + pixel_pos_y = face_height + j; + break; + } + } + ZENGINE_VALIDATE_ASSERT( + Helpers::secure_memcpy(destination, pixel_size, source + (pixel_pos_y * input_map.Width + pixel_pos_x) * pixel_size, pixel_size) == + Helpers::MEMORY_OP_SUCCESS, + "Failed to perform memory copy operation") + destination += pixel_size; + } + } + } + + return cubemap; + } + + int Width = 0; + int Height = 0; + int Depth = 1; + int Channel = 3; + BitmapType Type = BitmapType::TEXTURE_2D; + BitmapFormat Format = BitmapFormat::UNSIGNED_BYTE; + std::vector Buffer = {}; + }; +} // namespace ZEngine::Rendering::Buffers \ No newline at end of file diff --git a/ZEngine/include/ZEngine/Rendering/Buffers/CommandBuffer.h b/ZEngine/include/ZEngine/Rendering/Buffers/CommandBuffer.h index 4f7f4f19..e4d46456 100644 --- a/ZEngine/include/ZEngine/Rendering/Buffers/CommandBuffer.h +++ b/ZEngine/include/ZEngine/Rendering/Buffers/CommandBuffer.h @@ -4,6 +4,7 @@ #include #include #include +#include #include namespace ZEngine::Rendering::Renderers::RenderPasses @@ -11,41 +12,77 @@ namespace ZEngine::Rendering::Renderers::RenderPasses struct RenderPass; } +namespace ZEngine::Hardwares +{ + struct BufferView; + struct BufferImage; +} + namespace ZEngine::Rendering::Buffers { class IndirectBuffer; + class VertexBuffer; + class IndexBuffer; enum CommanBufferState : uint8_t { Idle = 0, Recording, - Ended, - Submitted + Executable, + Pending, + Invalid }; struct CommandBuffer : public Helpers::RefCounted { - CommandBuffer(VkCommandPool command_pool, Rendering::QueueType type, bool present_on_swapchain); + CommandBuffer(VkCommandPool command_pool, Rendering::QueueType type, bool one_time); ~CommandBuffer(); - VkCommandBuffer GetHandle() const; - void Begin(); - void End(); - void WaitForExecution(); - bool IsExecuting(); - void Submit(); - CommanBufferState GetState() const; + VkCommandBuffer GetHandle() const; + void Begin(); + void End(); + bool Completed(); + bool IsExecutable(); + bool IsRecording(); + void Submit(bool as_instant_command = false); + CommanBufferState GetState() const; + void ResetState(); + void SetState(const CommanBufferState& state); + + void SetSignalFence(const Ref& semaphore); + void SetSignalSemaphore(const Ref& semaphore); Primitives::Semaphore* GetSignalSemaphore() const; + Primitives::Fence* GetSignalFence(); void BeginRenderPass(const Ref&); void EndRenderPass(); void BindDescriptorSets(uint32_t frame_index = 0); + void BindDescriptorSet(const VkDescriptorSet& descriptor); void DrawIndirect(const Ref& buffer); void DrawIndexedIndirect(const Ref& buffer, uint32_t count); + void DrawIndexed(uint32_t indexCount, uint32_t instanceCount, uint32_t firstIndex, int32_t vertexOffset, uint32_t firstInstance); + + void TransitionImageLayout(const Primitives::ImageMemoryBarrier& image_barrier); + + void CopyBufferToImage( + const Hardwares::BufferView& source, + Hardwares::BufferImage& destination, + uint32_t width, + uint32_t height, + uint32_t layer_count, + VkImageLayout new_layout); + + void BindVertexBuffer(const Buffers::VertexBuffer& buffer); + void BindIndexBuffer(const Buffers::IndexBuffer& buffer, VkIndexType type); + void SetScissor(const VkRect2D& scissor); + + void PushConstants(VkShaderStageFlags stage_flags, uint32_t offset, uint32_t size, const void* data); private: + bool m_one_time_usage{false}; std::atomic_uint8_t m_command_buffer_state{CommanBufferState::Idle}; VkCommandBuffer m_command_buffer{VK_NULL_HANDLE}; + VkCommandPool m_command_pool{VK_NULL_HANDLE}; Rendering::QueueType m_queue_type; Ref m_signal_fence; Ref m_signal_semaphore; diff --git a/ZEngine/include/ZEngine/Rendering/Buffers/GraphicBuffer.h b/ZEngine/include/ZEngine/Rendering/Buffers/GraphicBuffer.h index 185eca08..36736955 100644 --- a/ZEngine/include/ZEngine/Rendering/Buffers/GraphicBuffer.h +++ b/ZEngine/include/ZEngine/Rendering/Buffers/GraphicBuffer.h @@ -1,5 +1,6 @@ #pragma once #include +#include namespace ZEngine::Rendering::Buffers { diff --git a/ZEngine/include/ZEngine/Rendering/Buffers/Image2DBuffer.h b/ZEngine/include/ZEngine/Rendering/Buffers/Image2DBuffer.h index d3f392f4..2b5c693f 100644 --- a/ZEngine/include/ZEngine/Rendering/Buffers/Image2DBuffer.h +++ b/ZEngine/include/ZEngine/Rendering/Buffers/Image2DBuffer.h @@ -7,7 +7,14 @@ namespace ZEngine::Rendering::Buffers struct Image2DBuffer : public Helpers::RefCounted { Image2DBuffer() = default; - Image2DBuffer(uint32_t width, uint32_t height, VkFormat format, VkImageUsageFlags usage_flag_bit, VkImageAspectFlagBits image_aspect_flag_bit); + Image2DBuffer( + uint32_t width, + uint32_t height, + VkFormat format, + VkImageUsageFlags usage_flag_bit, + VkImageAspectFlagBits image_aspect_flag_bit, + uint32_t layer_count = 1U, + VkImageCreateFlags image_create_flag_bit = 0); ~Image2DBuffer(); Hardwares::BufferImage& GetBuffer(); diff --git a/ZEngine/include/ZEngine/Rendering/Buffers/IndexBuffer.h b/ZEngine/include/ZEngine/Rendering/Buffers/IndexBuffer.h index a974a54d..973d6d36 100644 --- a/ZEngine/include/ZEngine/Rendering/Buffers/IndexBuffer.h +++ b/ZEngine/include/ZEngine/Rendering/Buffers/IndexBuffer.h @@ -19,7 +19,7 @@ namespace ZEngine::Rendering::Buffers return; } - if (this->m_byte_size < byte_size) + if (this->m_byte_size != byte_size) { /* * Tracking the size change.. @@ -44,7 +44,9 @@ namespace ZEngine::Rendering::Buffers vmaGetAllocationInfo(allocator, m_index_buffer.Allocation, &allocation_info); if (data && allocation_info.pMappedData) { - std::memcpy(allocation_info.pMappedData, data, this->m_byte_size); + ZENGINE_VALIDATE_ASSERT( + Helpers::secure_memcpy(allocation_info.pMappedData, allocation_info.size, data, this->m_byte_size) == Helpers::MEMORY_OP_SUCCESS, + "Failed to perform memory copy operation") } } else @@ -59,8 +61,11 @@ namespace ZEngine::Rendering::Buffers if (data && allocation_info.pMappedData) { - std::memcpy(allocation_info.pMappedData, data, this->m_byte_size); - ZENGINE_VALIDATE_ASSERT(vmaFlushAllocation(allocator, staging_buffer.Allocation, 0, VK_WHOLE_SIZE) == VK_SUCCESS, "Failed to flush allocation") + ZENGINE_VALIDATE_ASSERT( + Helpers::secure_memcpy(allocation_info.pMappedData, allocation_info.size, data, this->m_byte_size) == Helpers::MEMORY_OP_SUCCESS, + "Failed to perform memory copy operation") + ZENGINE_VALIDATE_ASSERT( + vmaFlushAllocation(allocator, staging_buffer.Allocation, 0, static_cast(this->m_byte_size)) == VK_SUCCESS, "Failed to flush allocation") Hardwares::VulkanDevice::CopyBuffer(staging_buffer, m_index_buffer, static_cast(this->m_byte_size)); } @@ -86,6 +91,12 @@ namespace ZEngine::Rendering::Buffers return reinterpret_cast(m_index_buffer.Handle); } + const VkDescriptorBufferInfo& GetDescriptorBufferInfo() + { + m_buffer_info = VkDescriptorBufferInfo{.buffer = m_index_buffer.Handle, .offset = 0, .range = this->m_byte_size}; + return m_buffer_info; + } + void Dispose() { CleanUpMemory(); @@ -103,5 +114,38 @@ namespace ZEngine::Rendering::Buffers private: Hardwares::BufferView m_index_buffer; + VkDescriptorBufferInfo m_buffer_info{}; + }; + + struct IndexBufferSet : public Helpers::RefCounted + { + IndexBufferSet(uint32_t count = 0) : m_buffer_set(count) {} + + IndexBuffer& operator[](uint32_t index) + { + assert(index < m_buffer_set.size()); + return m_buffer_set[index]; + } + + const std::vector& Data() const + { + return m_buffer_set; + } + + std::vector& Data() + { + return m_buffer_set; + } + + void Dispose() + { + for (auto& buffer : m_buffer_set) + { + buffer.Dispose(); + } + } + + private: + std::vector m_buffer_set; }; } // namespace ZEngine::Rendering::Buffers diff --git a/ZEngine/include/ZEngine/Rendering/Buffers/IndirectBuffer.h b/ZEngine/include/ZEngine/Rendering/Buffers/IndirectBuffer.h index 53e75284..0394f516 100644 --- a/ZEngine/include/ZEngine/Rendering/Buffers/IndirectBuffer.h +++ b/ZEngine/include/ZEngine/Rendering/Buffers/IndirectBuffer.h @@ -10,7 +10,7 @@ namespace ZEngine::Rendering::Buffers public: explicit IndirectBuffer() : IGraphicBuffer() {} - void SetData(const void* data, size_t byte_size) + void SetData(const VkDrawIndirectCommand* data, size_t byte_size) { if (byte_size == 0) @@ -27,6 +27,7 @@ namespace ZEngine::Rendering::Buffers CleanUpMemory(); this->m_byte_size = byte_size; + m_command_count = byte_size / sizeof(VkDrawIndirectCommand); m_indirect_buffer = Hardwares::VulkanDevice::CreateBuffer( static_cast(this->m_byte_size), VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT, @@ -43,7 +44,9 @@ namespace ZEngine::Rendering::Buffers vmaGetAllocationInfo(allocator, m_indirect_buffer.Allocation, &allocation_info); if (data && allocation_info.pMappedData) { - std::memcpy(allocation_info.pMappedData, data, this->m_byte_size); + ZENGINE_VALIDATE_ASSERT( + Helpers::secure_memcpy(allocation_info.pMappedData, allocation_info.size, data, this->m_byte_size) == Helpers::MEMORY_OP_SUCCESS, + "Failed to perform memory copy operation") } } else @@ -58,7 +61,9 @@ namespace ZEngine::Rendering::Buffers if (data && allocation_info.pMappedData) { - std::memcpy(allocation_info.pMappedData, data, this->m_byte_size); + ZENGINE_VALIDATE_ASSERT( + Helpers::secure_memcpy(allocation_info.pMappedData, allocation_info.size, data, this->m_byte_size) == Helpers::MEMORY_OP_SUCCESS, + "Failed to perform memory copy operation") ZENGINE_VALIDATE_ASSERT(vmaFlushAllocation(allocator, staging_buffer.Allocation, 0, VK_WHOLE_SIZE) == VK_SUCCESS, "Failed to flush allocation") Hardwares::VulkanDevice::CopyBuffer(staging_buffer, m_indirect_buffer, static_cast(this->m_byte_size)); } diff --git a/ZEngine/include/ZEngine/Rendering/Buffers/StorageBuffer.h b/ZEngine/include/ZEngine/Rendering/Buffers/StorageBuffer.h index 8741778c..c73d796b 100644 --- a/ZEngine/include/ZEngine/Rendering/Buffers/StorageBuffer.h +++ b/ZEngine/include/ZEngine/Rendering/Buffers/StorageBuffer.h @@ -43,7 +43,9 @@ namespace ZEngine::Rendering::Buffers vmaGetAllocationInfo(allocator, m_storage_buffer.Allocation, &allocation_info); if (data && allocation_info.pMappedData) { - std::memcpy(allocation_info.pMappedData, data, this->m_byte_size); + ZENGINE_VALIDATE_ASSERT( + Helpers::secure_memcpy(allocation_info.pMappedData, allocation_info.size, data, this->m_byte_size) == Helpers::MEMORY_OP_SUCCESS, + "Failed to perform memory copy operation") } } else @@ -58,8 +60,11 @@ namespace ZEngine::Rendering::Buffers if (data && allocation_info.pMappedData) { - std::memcpy(allocation_info.pMappedData, data, this->m_byte_size); - ZENGINE_VALIDATE_ASSERT(vmaFlushAllocation(allocator, staging_buffer.Allocation, 0, VK_WHOLE_SIZE) == VK_SUCCESS, "Failed to flush allocation") + ZENGINE_VALIDATE_ASSERT( + Helpers::secure_memcpy(allocation_info.pMappedData, allocation_info.size, data, this->m_byte_size) == Helpers::MEMORY_OP_SUCCESS, + "Failed to perform memory copy operation") + ZENGINE_VALIDATE_ASSERT( + vmaFlushAllocation(allocator, staging_buffer.Allocation, 0, static_cast(this->m_byte_size)) == VK_SUCCESS, "Failed to flush allocation") Hardwares::VulkanDevice::CopyBuffer(staging_buffer, m_storage_buffer, static_cast(this->m_byte_size)); } diff --git a/ZEngine/include/ZEngine/Rendering/Buffers/UniformBuffer.h b/ZEngine/include/ZEngine/Rendering/Buffers/UniformBuffer.h index 3a73afce..af9982ab 100644 --- a/ZEngine/include/ZEngine/Rendering/Buffers/UniformBuffer.h +++ b/ZEngine/include/ZEngine/Rendering/Buffers/UniformBuffer.h @@ -104,12 +104,17 @@ namespace ZEngine::Rendering::Buffers if (allocation_info.pMappedData) { - std::memset(allocation_info.pMappedData, 0, this->m_byte_size); + ZENGINE_VALIDATE_ASSERT( + Helpers::secure_memset(allocation_info.pMappedData, 0, this->m_byte_size, allocation_info.size) == + Helpers::MEMORY_OP_SUCCESS, + "Failed to perform memory set operation") } if (data && allocation_info.pMappedData) { - std::memcpy(allocation_info.pMappedData, data, this->m_byte_size); + ZENGINE_VALIDATE_ASSERT( + Helpers::secure_memcpy(allocation_info.pMappedData, allocation_info.size, data, this->m_byte_size) == Helpers::MEMORY_OP_SUCCESS, + "Failed to perform memory copy operation") } } diff --git a/ZEngine/include/ZEngine/Rendering/Buffers/VertexBuffer.h b/ZEngine/include/ZEngine/Rendering/Buffers/VertexBuffer.h index 5ec4f24e..c19e2e71 100644 --- a/ZEngine/include/ZEngine/Rendering/Buffers/VertexBuffer.h +++ b/ZEngine/include/ZEngine/Rendering/Buffers/VertexBuffer.h @@ -17,7 +17,7 @@ namespace ZEngine::Rendering::Buffers return; } - if (this->m_byte_size < byte_size) + if (this->m_byte_size != byte_size) { /* * Tracking the size change.. @@ -42,7 +42,9 @@ namespace ZEngine::Rendering::Buffers vmaGetAllocationInfo(allocator, m_vertex_buffer.Allocation, &allocation_info); if (data && allocation_info.pMappedData) { - std::memcpy(allocation_info.pMappedData, data, this->m_byte_size); + ZENGINE_VALIDATE_ASSERT( + Helpers::secure_memcpy(allocation_info.pMappedData, allocation_info.size, data, this->m_byte_size) == Helpers::MEMORY_OP_SUCCESS, + "Failed to perform memory copy operation") } } else @@ -57,8 +59,11 @@ namespace ZEngine::Rendering::Buffers if (data && allocation_info.pMappedData) { - std::memcpy(allocation_info.pMappedData, data, this->m_byte_size); - ZENGINE_VALIDATE_ASSERT(vmaFlushAllocation(allocator, staging_buffer.Allocation, 0, VK_WHOLE_SIZE) == VK_SUCCESS, "Failed to flush allocation") + ZENGINE_VALIDATE_ASSERT( + Helpers::secure_memcpy(allocation_info.pMappedData, allocation_info.size, data, this->m_byte_size) == Helpers::MEMORY_OP_SUCCESS, + "Failed to perform memory copy operation") + ZENGINE_VALIDATE_ASSERT( + vmaFlushAllocation(allocator, staging_buffer.Allocation, 0, static_cast(this->m_byte_size)) == VK_SUCCESS, "Failed to flush allocation") Hardwares::VulkanDevice::CopyBuffer(staging_buffer, m_vertex_buffer, static_cast(this->m_byte_size)); } @@ -84,6 +89,12 @@ namespace ZEngine::Rendering::Buffers return reinterpret_cast(m_vertex_buffer.Handle); } + const VkDescriptorBufferInfo& GetDescriptorBufferInfo() + { + m_buffer_info = VkDescriptorBufferInfo{.buffer = m_vertex_buffer.Handle, .offset = 0, .range = this->m_byte_size}; + return m_buffer_info; + } + void Dispose() { CleanUpMemory(); @@ -101,5 +112,38 @@ namespace ZEngine::Rendering::Buffers private: Hardwares::BufferView m_vertex_buffer; + VkDescriptorBufferInfo m_buffer_info{}; + }; + + struct VertexBufferSet : public Helpers::RefCounted + { + VertexBufferSet(uint32_t count = 0) : m_buffer_set(count) {} + + VertexBuffer& operator[](uint32_t index) + { + assert(index < m_buffer_set.size()); + return m_buffer_set[index]; + } + + const std::vector& Data() const + { + return m_buffer_set; + } + + std::vector& Data() + { + return m_buffer_set; + } + + void Dispose() + { + for (auto& buffer : m_buffer_set) + { + buffer.Dispose(); + } + } + + private: + std::vector m_buffer_set; }; } // namespace ZEngine::Rendering::Buffers diff --git a/ZEngine/include/ZEngine/Rendering/Pools/CommandPool.h b/ZEngine/include/ZEngine/Rendering/Pools/CommandPool.h index c2e46208..d454e1c7 100644 --- a/ZEngine/include/ZEngine/Rendering/Pools/CommandPool.h +++ b/ZEngine/include/ZEngine/Rendering/Pools/CommandPool.h @@ -1,6 +1,6 @@ #pragma once #include -#include +#include #include #include #include @@ -12,17 +12,13 @@ namespace ZEngine::Rendering::Pools CommandPool(Rendering::QueueType type, uint64_t swapchain_identifier = 0, bool present_on_swapchain = true); ~CommandPool(); - void Tick(); - Buffers::CommandBuffer* GetCurrentCommmandBuffer(); - std::vector GetAllWaitSemaphoreCollection(); - uint64_t GetSwapchainParent() const; + Buffers::CommandBuffer* GetCommmandBuffer(); + Ref GetOneTimeCommmandBuffer(); private: - bool first = true; - uint64_t m_swapchain_identifier{0}; - uint32_t m_current_command_buffer_index{0}; - VkCommandPool m_handle{VK_NULL_HANDLE}; - Rendering::QueueType m_queue_type; - std::array, 10> m_command_buffer_collection; + uint32_t m_max_command_buffer_count{UINT32_MAX}; + std::deque> m_allocated_command_buffers; + VkCommandPool m_handle{VK_NULL_HANDLE}; + Rendering::QueueType m_queue_type; }; } \ No newline at end of file diff --git a/ZEngine/include/ZEngine/Rendering/Primitives/Fence.h b/ZEngine/include/ZEngine/Rendering/Primitives/Fence.h index 05ca7761..4d3a45e9 100644 --- a/ZEngine/include/ZEngine/Rendering/Primitives/Fence.h +++ b/ZEngine/include/ZEngine/Rendering/Primitives/Fence.h @@ -13,12 +13,11 @@ namespace ZEngine::Rendering::Primitives struct Fence : public Helpers::RefCounted { - Fence(); + Fence(bool as_signaled = false); ~Fence(); bool IsSignaled(); bool Wait(uint64_t timeout = 1000000000); - void Reset(); void SetState(FenceState state); diff --git a/ZEngine/include/ZEngine/Rendering/Renderers/GraphicRenderer.h b/ZEngine/include/ZEngine/Rendering/Renderers/GraphicRenderer.h index 9be1affb..50c08abd 100644 --- a/ZEngine/include/ZEngine/Rendering/Renderers/GraphicRenderer.h +++ b/ZEngine/include/ZEngine/Rendering/Renderers/GraphicRenderer.h @@ -3,12 +3,14 @@ #include #include #include +#include namespace ZEngine::Rendering::Renderers { enum RenderTarget : uint32_t { FRAME_OUTPUT = 0, + ENVIROMENT_CUBEMAP, COUNT }; @@ -37,14 +39,26 @@ namespace ZEngine::Rendering::Renderers static const RendererInformation& GetRendererInformation(); static void Update(); + static void Upload(); + static void DrawScene(const Ref& camera, const Ref& data); + static void BeginImguiFrame(); + static void DrawUIFrame(); + static void EndImguiFrame(); + static VkDescriptorSet GetImguiFrameOutput(); + private: static uint32_t s_viewport_width; static uint32_t s_viewport_height; static RendererInformation s_renderer_information; static WeakRef s_main_window_swapchain; static std::array, RenderTarget::COUNT> s_render_target_collection; + static Ref s_UBCamera; + static Pools::CommandPool* s_command_pool; + static Buffers::CommandBuffer* s_current_command_buffer; + static Buffers::CommandBuffer* s_current_command_buffer_ui; static Ref s_scene_renderer; + static Ref s_imgui_renderer; }; } // namespace ZEngine::Rendering::Renderers diff --git a/ZEngine/include/ZEngine/Rendering/Renderers/ImGUIRenderer.h b/ZEngine/include/ZEngine/Rendering/Renderers/ImGUIRenderer.h index cab6fb1c..4923d5d0 100644 --- a/ZEngine/include/ZEngine/Rendering/Renderers/ImGUIRenderer.h +++ b/ZEngine/include/ZEngine/Rendering/Renderers/ImGUIRenderer.h @@ -1,44 +1,31 @@ #pragma once #include #include -#include +#include +#include +#include namespace ZEngine::Rendering::Renderers { - struct ImguiViewPortWindowChild + struct ImGUIRenderer : public Helpers::RefCounted { - ImguiViewPortWindowChild(void* viewport_handle); - ~ImguiViewPortWindowChild() = default; - void* RendererUserData{nullptr}; - Ref Swapchain; - Pools::CommandPool* CommandPool{nullptr}; - }; + void Initialize(const Ref& swapchain); + void Deinitialize(); - struct ImGUIRenderer - { - ImGUIRenderer() = delete; - ImGUIRenderer(const ImGUIRenderer&) = delete; - ~ImGUIRenderer() = delete; + void StyleDarkTheme(); - static void Initialize(void* window, const Ref& swapchain); - static void Deinitialize(); + void BeginFrame(Rendering::Buffers::CommandBuffer* const command_buffer); + void Draw(Rendering::Buffers::CommandBuffer* const commandbuffer, uint32_t frame_index); + void EndFrame(Rendering::Buffers::CommandBuffer* const command_buffer, uint32_t frame_index); - static void Tick(); - static void BeginFrame(); - static void Draw(uint32_t window_width, uint32_t window_height, const Ref& swapchain, void** user_data, void* draw_data); - static void DrawChildWindow(uint32_t width, uint32_t height, ImguiViewPortWindowChild** window_child, void* draw_data); - static void EndFrame(); + VkDescriptorSet UpdateFrameOutput(const Ref& buffer); private: - static void __ImGUIDestroyFontUploadObjects(); - static void __ImGUIRenderData(void* data, VkCommandBuffer command_buffer, VkPipeline pipeline); - static void __ImGUICreateOrResizeBuffer(VkBuffer& buffer, VkDeviceMemory& buffer_memory, VkDeviceSize& p_buffer_size, size_t new_size, VkBufferUsageFlagBits usage); - static void __ImGUIRenderDataChildViewport(void* data, void** user_data, VkCommandBuffer command_buffer, VkPipeline pipeline); - - public: - static Rendering::Buffers::CommandBuffer* s_command_buffer; - static Rendering::Pools::CommandPool* s_ui_command_pool; - static VkDescriptorPool s_descriptor_pool; + VkDescriptorSet m_frame_output{VK_NULL_HANDLE}; + VkDescriptorSet m_font_descriptor_set{VK_NULL_HANDLE}; + Ref m_vertex_buffer; + Ref m_index_buffer; + Ref m_ui_pass; }; } // namespace ZEngine::Rendering::Renderers diff --git a/ZEngine/include/ZEngine/Rendering/Renderers/Pipelines/RendererPipeline.h b/ZEngine/include/ZEngine/Rendering/Renderers/Pipelines/RendererPipeline.h index a672affa..86ee4b1e 100644 --- a/ZEngine/include/ZEngine/Rendering/Renderers/Pipelines/RendererPipeline.h +++ b/ZEngine/include/ZEngine/Rendering/Renderers/Pipelines/RendererPipeline.h @@ -23,6 +23,7 @@ namespace ZEngine::Rendering::Renderers::Pipelines VkPipelineLayout GetPipelineLayout() const; VkRenderPass GetRenderPassHandle() const; Ref GetTargetFrameBuffer() const; + Ref GetTargetSwapchain() const; Ref GetShader() const; public: @@ -34,5 +35,6 @@ namespace ZEngine::Rendering::Renderers::Pipelines Specifications::GraphicRendererPipelineSpecification m_pipeline_specification; Ref m_shader; Ref m_target_framebuffer; + Ref m_target_swapchain; }; } // namespace ZEngine::Rendering::Renderers::Pipelines \ No newline at end of file diff --git a/ZEngine/include/ZEngine/Rendering/Renderers/SceneRenderer.h b/ZEngine/include/ZEngine/Rendering/Renderers/SceneRenderer.h index 1a807343..ddee417f 100644 --- a/ZEngine/include/ZEngine/Rendering/Renderers/SceneRenderer.h +++ b/ZEngine/include/ZEngine/Rendering/Renderers/SceneRenderer.h @@ -26,25 +26,23 @@ namespace ZEngine::Rendering::Renderers SceneRenderer() = default; ~SceneRenderer() = default; - void Initialize(); + void Initialize(const Ref& camera); void Deinitialize(); void StartScene(const glm::vec3& camera_position, const glm::mat4& camera_view, const glm::mat4& camera_projection); void StartScene(const glm::vec4& camera_position, const glm::mat4& camera_view, const glm::mat4& camera_projection); - void RenderScene(const Ref& scene_data); - void EndScene(); + void StartScene(Buffers::CommandBuffer* const command_buffer); + void RenderScene(const Ref& scene_data, uint32_t current_frame_index = 0); + void EndScene(Buffers::CommandBuffer* const command_buffer, uint32_t current_frame_index = 0); void SetViewportSize(uint32_t width, uint32_t height); - void Tick(); private: - Pools::CommandPool* m_command_pool{nullptr}; - glm::vec4 m_camera_position{1.0f}; - glm::mat4 m_camera_view{1.0f}; - glm::mat4 m_camera_projection{1.0f}; + glm::vec4 m_camera_position{1.0f}; + glm::mat4 m_camera_view{1.0f}; + glm::mat4 m_camera_projection{1.0f}; /* * Scene Data Per Frame */ - Ref m_UB_Camera; Ref m_SBVertex; Ref m_SBIndex; Ref m_SBDrawData; @@ -70,7 +68,25 @@ namespace ZEngine::Rendering::Renderers const std::vector m_grid_drawData = {DrawData{.Index = 0, .VertexOffset = 0, .IndexOffset = 0, .VertexCount = 4, .IndexCount = 6}}; const std::vector m_grid_indirect_commmand = {VkDrawIndirectCommand{.vertexCount = 6, .instanceCount = 1, .firstVertex = 0, .firstInstance = 0}}; + /* + * Cubemap + */ + Ref cubemapSBVertex; + Ref cubemapSBIndex; + Ref cubemapSBDrawData; + Ref s_environment_map; + Ref s_cubemap_pass; + std::vector> s_cubemap_indirect_buffer; + const std::vector m_cubemap_vertex_data = { + -1.0, -1.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, -1.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, -1.0, 1.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, + -1.0, -1.0, -1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, -1.0, -1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 1.0, -1.0, 0.0, 0.0, 0.0, 0.0, 0.0, -1.0, 1.0, -1.0, 0.0, 0.0, 0.0, 0.0, 0.0, + }; + const std::vector m_cubemap_index_data = {0, 1, 2, 2, 3, 0, 1, 5, 6, 6, 2, 1, 7, 6, 5, 5, 4, 7, 4, 0, 3, 3, 7, 4, 4, 5, 1, 1, 0, 4, 3, 2, 6, 6, 7, 3}; + const std::vector m_cubmap_draw_data = {DrawData{.Index = 0, .VertexOffset = 0, .IndexOffset = 0, .VertexCount = 8, .IndexCount = 36}}; + const std::vector m_cubemap_indirect_commmand = {VkDrawIndirectCommand{.vertexCount = 36, .instanceCount = 1, .firstVertex = 0, .firstInstance = 0}}; + private: + int m_upload_once_per_frame_count{-1}; uint32_t m_last_uploaded_buffer_image_count{0}; std::vector m_last_drawn_vertices_count; std::vector m_last_drawn_index_count; diff --git a/ZEngine/include/ZEngine/Rendering/Shaders/Shader.h b/ZEngine/include/ZEngine/Rendering/Shaders/Shader.h index 0cc55e50..488ef64d 100644 --- a/ZEngine/include/ZEngine/Rendering/Shaders/Shader.h +++ b/ZEngine/include/ZEngine/Rendering/Shaders/Shader.h @@ -20,6 +20,9 @@ namespace ZEngine::Rendering::Shaders Specifications::LayoutBindingSpecification GetLayoutBindingSpecification(std::string_view name) const; std::vector GetDescriptorSetLayout() const; const std::map>& GetDescriptorSetMap() const; + std::map>& GetDescriptorSetMap(); + VkDescriptorPool GetDescriptorPool() const; + const std::vector& GetPushConstants() const; void Dispose(); static Ref Create(Specifications::ShaderSpecification&& spec); @@ -28,6 +31,7 @@ namespace ZEngine::Rendering::Shaders private: void CreateModule(); void CreateDescriptorSetLayouts(); + void CreatePushConstantRange(); private: Specifications::ShaderSpecification m_specification; @@ -37,6 +41,8 @@ namespace ZEngine::Rendering::Shaders std::map> m_layout_binding_specification_map; std::map m_descriptor_set_layout_map; // std::map> m_descriptor_set_map; //> + std::vector m_push_constant_specification_collection; + std::vector m_push_constant_collection; VkDescriptorPool m_descriptor_pool{VK_NULL_HANDLE}; }; diff --git a/ZEngine/include/ZEngine/Rendering/Specifications/FormatSpecification.h b/ZEngine/include/ZEngine/Rendering/Specifications/FormatSpecification.h index 357cd7b3..0b02a4d4 100644 --- a/ZEngine/include/ZEngine/Rendering/Specifications/FormatSpecification.h +++ b/ZEngine/include/ZEngine/Rendering/Specifications/FormatSpecification.h @@ -1,13 +1,19 @@ #pragma once +#include #include + namespace ZEngine::Rendering::Specifications { + #define VALUE_FROM_SPEC_MAP(x) static_cast(x) + enum class ImageFormat : uint32_t { UNDEFINED = 0, R8G8B8A8_UNORM, // color R8G8B8A8_SRGB, + R32G32B32A32_SFLOAT, + R32G32_SFLOAT, DEPTH16_UNORM, DEPTH16_UNORM_S8_UINT, DEPTH24_UNORM_S8_UINT, @@ -17,10 +23,17 @@ namespace ZEngine::Rendering::Specifications DEPTH_STENCIL_FROM_DEVICE }; + /* + * BytePerChannelMap follows ImageFormat enum alignment value + */ + static uint32_t BytePerChannelMap[] = {0u, 4u, 4u, (4u * sizeof(float))}; + static VkFormat ImageFormatMap[] = { VK_FORMAT_UNDEFINED, VK_FORMAT_R8G8B8A8_UNORM, VK_FORMAT_R8G8B8A8_SRGB, + VK_FORMAT_R32G32B32A32_SFLOAT, + VK_FORMAT_R32G32_SFLOAT, VK_FORMAT_D16_UNORM, VK_FORMAT_D16_UNORM_S8_UINT, VK_FORMAT_D24_UNORM_S8_UINT, diff --git a/ZEngine/include/ZEngine/Rendering/Specifications/GraphicRendererPipelineSpecification.h b/ZEngine/include/ZEngine/Rendering/Specifications/GraphicRendererPipelineSpecification.h index ad213b51..c374964f 100644 --- a/ZEngine/include/ZEngine/Rendering/Specifications/GraphicRendererPipelineSpecification.h +++ b/ZEngine/include/ZEngine/Rendering/Specifications/GraphicRendererPipelineSpecification.h @@ -1,18 +1,37 @@ #pragma once -#include +#include #include #include -#include +#include namespace ZEngine::Rendering::Specifications { + struct VertexInputBindingSpecification + { + uint32_t Stride = 0; + uint32_t Rate = 0; + uint32_t Binding = 0; + }; + + struct VertexInputAttributeSpecification + { + uint32_t Location = 0; + uint32_t Binding = 0; + uint32_t Offset = 0; + ImageFormat Format = ImageFormat::UNDEFINED; + }; + struct GraphicRendererPipelineSpecification { - bool EnableBlending = false; - bool EnableDepthTest = true; - bool EnableStencilTest = false; - std::string DebugName; - ShaderSpecification ShaderSpecification; - Ref TargetFrameBuffer; + bool EnableBlending = false; + bool EnableDepthTest = true; + bool EnableStencilTest = false; + bool SwapchainAsRenderTarget = false; + std::string DebugName = {}; + ShaderSpecification ShaderSpecification = {}; + Ref TargetFrameBuffer = {}; + Ref SwapchainRenderTarget = {}; + std::vector VertexInputBindingSpecifications = {}; + std::vector VertexInputAttributeSpecifications = {}; }; -} \ No newline at end of file +} // namespace ZEngine::Rendering::Specifications \ No newline at end of file diff --git a/ZEngine/include/ZEngine/Rendering/Specifications/ImageMemoryBarrierSpecification.h b/ZEngine/include/ZEngine/Rendering/Specifications/ImageMemoryBarrierSpecification.h index aaae3eea..947cb384 100644 --- a/ZEngine/include/ZEngine/Rendering/Specifications/ImageMemoryBarrierSpecification.h +++ b/ZEngine/include/ZEngine/Rendering/Specifications/ImageMemoryBarrierSpecification.h @@ -14,5 +14,6 @@ namespace ZEngine::Rendering::Specifications VkImageAspectFlagBits ImageAspectMask; VkPipelineStageFlagBits SourceStageMask; VkPipelineStageFlagBits DestinationStageMask; + uint32_t LayerCount = 1; }; } \ No newline at end of file diff --git a/ZEngine/include/ZEngine/Rendering/Specifications/ShaderSpecification.h b/ZEngine/include/ZEngine/Rendering/Specifications/ShaderSpecification.h index 4533bcf8..6f3294a2 100644 --- a/ZEngine/include/ZEngine/Rendering/Specifications/ShaderSpecification.h +++ b/ZEngine/include/ZEngine/Rendering/Specifications/ShaderSpecification.h @@ -61,10 +61,19 @@ namespace ZEngine::Rendering::Specifications ShaderStageFlags Flags; }; + struct PushConstantSpecification + { + std::string Name; + uint32_t Size; + uint32_t Offset; + ShaderStageFlags Flags; + }; + struct ShaderSpecification { - std::string VertexFilename; - std::string FragmentFilename; + uint32_t OverloadMaxSet = 1; + std::string VertexFilename = {}; + std::string FragmentFilename = {}; }; } // ZEngine::Rendering::Specifications diff --git a/ZEngine/include/ZEngine/Rendering/Specifications/TextureSpecification.h b/ZEngine/include/ZEngine/Rendering/Specifications/TextureSpecification.h index 8b34e5d0..66319a4b 100644 --- a/ZEngine/include/ZEngine/Rendering/Specifications/TextureSpecification.h +++ b/ZEngine/include/ZEngine/Rendering/Specifications/TextureSpecification.h @@ -9,9 +9,11 @@ namespace ZEngine::Rendering::Specifications bool IsUsageSampled = true; bool IsUsageTransfert = true; bool PerformTransition = true; + bool IsCubemap = false; uint32_t Width = 0; uint32_t Height = 0; uint32_t BytePerPixel = 4; + uint32_t LayerCount = 1; ImageFormat Format = ImageFormat::UNDEFINED; const void* Data = nullptr; }; diff --git a/ZEngine/include/ZEngine/Rendering/Swapchain.h b/ZEngine/include/ZEngine/Rendering/Swapchain.h index cb6ad9c9..44395167 100644 --- a/ZEngine/include/ZEngine/Rendering/Swapchain.h +++ b/ZEngine/include/ZEngine/Rendering/Swapchain.h @@ -14,8 +14,6 @@ namespace ZEngine::Rendering ~Swapchain(); void Resize(); - - void AcquireNextImage(); void Present(); uint32_t GetMinImageCount() const; @@ -35,7 +33,6 @@ namespace ZEngine::Rendering VkSurfaceFormatKHR m_surface_format; bool m_is_surface_from_device; uint32_t m_current_frame_index{0}; - uint32_t m_current_frame_image_index{0}; uint32_t m_last_frame_image_index{0}; VkSwapchainKHR m_handle{VK_NULL_HANDLE}; uint32_t m_image_width{0}; @@ -49,6 +46,8 @@ namespace ZEngine::Rendering std::vector m_image_view_collection; std::vector m_framebuffer_collection; std::vector> m_acquired_semaphore_collection; + std::vector> m_render_complete_semaphore_collection; + std::vector> m_frame_signal_fence_collection; std::vector m_wait_semaphore_collection; std::mutex m_image_mutex; uint64_t m_identifier{0}; diff --git a/ZEngine/include/ZEngine/Rendering/Textures/Texture2D.h b/ZEngine/include/ZEngine/Rendering/Textures/Texture2D.h index 878d3ba4..3d575983 100644 --- a/ZEngine/include/ZEngine/Rendering/Textures/Texture2D.h +++ b/ZEngine/include/ZEngine/Rendering/Textures/Texture2D.h @@ -17,6 +17,7 @@ namespace ZEngine::Rendering::Textures static Ref Create(uint32_t width = 1, uint32_t height = 1); static Ref Create(uint32_t width, uint32_t height, float r, float g, float b, float a); static Ref Read(std::string_view filename); + static Ref ReadCubemap(std::string_view filename); static std::future> ReadAsync(std::string_view filename); virtual Hardwares::BufferImage& GetBuffer() override; diff --git a/ZEngine/src/CommandBuffer.cpp b/ZEngine/src/CommandBuffer.cpp index ce64e632..c60a9de1 100644 --- a/ZEngine/src/CommandBuffer.cpp +++ b/ZEngine/src/CommandBuffer.cpp @@ -3,35 +3,41 @@ #include #include #include +#include +#include #include +#include + namespace ZEngine::Rendering::Buffers { - CommandBuffer::CommandBuffer(VkCommandPool command_pool, Rendering::QueueType type, bool present_on_swapchain) + CommandBuffer::CommandBuffer(VkCommandPool command_pool, Rendering::QueueType type, bool one_time) { - m_queue_type = type; - if (present_on_swapchain) - { - m_signal_semaphore = CreateRef(); - } - m_signal_fence = CreateRef(); + m_queue_type = type; + m_command_pool = command_pool; + m_one_time_usage = one_time; - ZENGINE_VALIDATE_ASSERT(command_pool != VK_NULL_HANDLE, "Command Pool cannot be null") + ZENGINE_VALIDATE_ASSERT(m_command_pool != VK_NULL_HANDLE, "Command Pool cannot be null") auto device = Hardwares::VulkanDevice::GetNativeDeviceHandle(); VkCommandBufferAllocateInfo command_buffer_allocation_info = {}; command_buffer_allocation_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; command_buffer_allocation_info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; command_buffer_allocation_info.commandBufferCount = 1; - command_buffer_allocation_info.commandPool = command_pool; + command_buffer_allocation_info.commandPool = m_command_pool; ZENGINE_VALIDATE_ASSERT(vkAllocateCommandBuffers(device, &command_buffer_allocation_info, &m_command_buffer) == VK_SUCCESS, "Failed to allocate command buffer!") + m_command_buffer_state = CommanBufferState::Idle; } CommandBuffer::~CommandBuffer() { - m_signal_fence.reset(); - m_signal_semaphore.reset(); + if (m_command_pool && m_command_buffer) + { + VkCommandBuffer buffers[] = {m_command_buffer}; + auto device = Hardwares::VulkanDevice::GetNativeDeviceHandle(); + vkFreeCommandBuffers(device, m_command_pool, 1, buffers); + } } VkCommandBuffer CommandBuffer::GetHandle() const @@ -45,7 +51,7 @@ namespace ZEngine::Rendering::Buffers VkCommandBufferBeginInfo command_buffer_begin_info = {}; command_buffer_begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; - command_buffer_begin_info.flags |= VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; + command_buffer_begin_info.flags |= (m_one_time_usage) ? VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT : VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT; ZENGINE_VALIDATE_ASSERT(vkBeginCommandBuffer(m_command_buffer, &command_buffer_begin_info) == VK_SUCCESS, "Failed to begin the Command Buffer") m_command_buffer_state = CommanBufferState::Recording; @@ -56,44 +62,28 @@ namespace ZEngine::Rendering::Buffers ZENGINE_VALIDATE_ASSERT(m_command_buffer_state == CommanBufferState::Recording, "command buffer must be in Idle state") ZENGINE_VALIDATE_ASSERT(vkEndCommandBuffer(m_command_buffer) == VK_SUCCESS, "Failed to end recording command buffer!") - m_command_buffer_state = CommanBufferState::Ended; + m_command_buffer_state = CommanBufferState::Executable; } - void CommandBuffer::WaitForExecution() + bool CommandBuffer::Completed() { - if (m_command_buffer_state != CommanBufferState::Submitted) - { - ZENGINE_CORE_WARN("Command Buffer can't be waited because it's yet to be submitted") - } - - if (IsExecuting()) - { - if (!m_signal_fence->Wait()) - { - ZENGINE_CORE_WARN("Failed to wait for Command buffer's Fence, due to time out") - } - } - - if (m_signal_fence->GetState() == Primitives::FenceState::Submitted) - { - m_signal_fence->Reset(); - } - - m_command_buffer_state = CommanBufferState::Idle; + return m_signal_fence ? m_signal_fence->IsSignaled() : false; } - bool CommandBuffer::IsExecuting() + bool CommandBuffer::IsExecutable() { - return m_command_buffer_state == CommanBufferState::Submitted && !m_signal_fence->IsSignaled(); + return m_command_buffer_state == CommanBufferState::Executable; } - void CommandBuffer::Submit() + bool CommandBuffer::IsRecording() { - ZENGINE_VALIDATE_ASSERT(m_command_buffer_state == CommanBufferState::Ended, "command buffer must be in ended state") + return m_command_buffer_state == CommanBufferState::Recording; + } - Hardwares::VulkanDevice::QueueSubmit( - m_queue_type, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, m_command_buffer, nullptr, m_signal_semaphore.get(), m_signal_fence.get()); - m_command_buffer_state = CommanBufferState::Submitted; + void CommandBuffer::Submit(bool as_instant_command) + { + ZENGINE_VALIDATE_ASSERT(m_command_buffer_state == CommanBufferState::Executable, "command buffer must be in ended state") + Hardwares::VulkanDevice::QueueSubmit(m_queue_type, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, *this, as_instant_command); } CommanBufferState CommandBuffer::GetState() const @@ -101,48 +91,114 @@ namespace ZEngine::Rendering::Buffers return CommanBufferState{m_command_buffer_state.load()}; } + void CommandBuffer::ResetState() + { + if (!m_one_time_usage) + { + vkResetCommandBuffer(m_command_buffer, VK_COMMAND_BUFFER_RESET_RELEASE_RESOURCES_BIT); + m_command_buffer_state = CommanBufferState::Idle; + m_signal_fence = {}; + m_signal_semaphore = {}; + } + } + + void CommandBuffer::SetState(const CommanBufferState& state) + { + m_command_buffer_state = state; + } + Primitives::Semaphore* CommandBuffer::GetSignalSemaphore() const { return m_signal_semaphore.get(); } + void CommandBuffer::SetSignalFence(const Ref& semaphore) + { + m_signal_fence = semaphore; + } + + void CommandBuffer::SetSignalSemaphore(const Ref& semaphore) + { + m_signal_semaphore = semaphore; + } + + Primitives::Fence* CommandBuffer::GetSignalFence() + { + return m_signal_fence.get(); + } + void CommandBuffer::BeginRenderPass(const Ref& render_pass) { ZENGINE_VALIDATE_ASSERT(m_command_buffer != nullptr, "Command buffer can't be null") - auto render_pass_pipeline = render_pass->GetPipeline(); - auto framebuffer = render_pass_pipeline->GetTargetFrameBuffer(); + uint32_t extent_width = 0; + uint32_t extent_height = 0; + VkRenderPass render_pass_handle = VK_NULL_HANDLE; + VkFramebuffer framebuffer_handle = VK_NULL_HANDLE; + + auto render_pass_pipeline = render_pass->GetPipeline(); + const auto& pipeline_spec = render_pass_pipeline->GetSpecification(); + + if (pipeline_spec.SwapchainAsRenderTarget) + { + auto swapchain = render_pass_pipeline->GetTargetSwapchain(); + framebuffer_handle = swapchain->GetCurrentFramebuffer(); + render_pass_handle = render_pass_pipeline->GetRenderPassHandle(); + extent_width = Engine::GetWindow()->GetWidth(); + extent_height = Engine::GetWindow()->GetHeight(); + } + else + { + auto framebuffer = render_pass_pipeline->GetTargetFrameBuffer(); + extent_width = framebuffer->GetWidth(); + extent_height = framebuffer->GetHeight(); + framebuffer_handle = framebuffer->GetHandle(); + render_pass_handle = render_pass_pipeline->GetRenderPassHandle(); + } + VkRenderPassBeginInfo render_pass_begin_info = {}; render_pass_begin_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; render_pass_begin_info.renderPass = render_pass_pipeline->GetRenderPassHandle(); - render_pass_begin_info.framebuffer = framebuffer->GetHandle(); + render_pass_begin_info.framebuffer = framebuffer_handle; render_pass_begin_info.renderArea.offset = {0, 0}; - render_pass_begin_info.renderArea.extent = VkExtent2D{framebuffer->GetWidth(), framebuffer->GetHeight()}; + render_pass_begin_info.renderArea.extent = VkExtent2D{extent_width, extent_height}; + - auto& fb_spec = framebuffer->GetSpecification(); - std::array clear_values = {}; - clear_values[0].color = {fb_spec.ClearColorValue[0], fb_spec.ClearColorValue[1], fb_spec.ClearColorValue[2], fb_spec.ClearColorValue[3]}; - clear_values[1].depthStencil = {fb_spec.ClearDepthValue[0], (uint32_t) fb_spec.ClearDepthValue[1]}; - render_pass_begin_info.clearValueCount = clear_values.size(); - render_pass_begin_info.pClearValues = clear_values.data(); + if (pipeline_spec.SwapchainAsRenderTarget) + { + std::array clear_values = {}; + clear_values[0].color = {0.0f, 0.0f, 0.0f, 1.0f}; + render_pass_begin_info.clearValueCount = clear_values.size(); + render_pass_begin_info.pClearValues = clear_values.data(); + } + else + { + auto framebuffer = render_pass_pipeline->GetTargetFrameBuffer(); + auto& fb_spec = framebuffer->GetSpecification(); + std::array clear_values = {}; + clear_values[0].color = {fb_spec.ClearColorValue[0], fb_spec.ClearColorValue[1], fb_spec.ClearColorValue[2], fb_spec.ClearColorValue[3]}; + clear_values[1].depthStencil = {fb_spec.ClearDepthValue[0], (uint32_t) fb_spec.ClearDepthValue[1]}; + render_pass_begin_info.clearValueCount = clear_values.size(); + render_pass_begin_info.pClearValues = clear_values.data(); + } vkCmdBeginRenderPass(m_command_buffer, &render_pass_begin_info, VK_SUBPASS_CONTENTS_INLINE); VkViewport viewport = {}; viewport.x = 0.0f; viewport.y = 0.0f; - viewport.width = framebuffer->GetWidth(); - viewport.height = framebuffer->GetHeight(); + viewport.width = extent_width; + viewport.height = extent_height; viewport.minDepth = 0.0f; viewport.maxDepth = 1.0f; + vkCmdSetViewport(m_command_buffer, 0, 1, &viewport); /*Scissor definition*/ VkRect2D scissor = {}; scissor.offset = {0, 0}; - scissor.extent = {framebuffer->GetWidth(), framebuffer->GetHeight()}; - - vkCmdSetViewport(m_command_buffer, 0, 1, &viewport); + scissor.extent = {extent_width, extent_height}; vkCmdSetScissor(m_command_buffer, 0, 1, &scissor); + vkCmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, render_pass_pipeline->GetHandle()); m_active_render_pass = render_pass; @@ -176,6 +232,19 @@ namespace ZEngine::Rendering::Buffers } } + void CommandBuffer::BindDescriptorSet(const VkDescriptorSet& descriptor) + { + ZENGINE_VALIDATE_ASSERT(m_command_buffer != nullptr, "Command buffer can't be null") + ZENGINE_VALIDATE_ASSERT(descriptor != nullptr, "DescriptorSet can't be null") + if (auto render_pass = m_active_render_pass.lock()) + { + auto render_pass_pipeline = render_pass->GetPipeline(); + auto pipeline_layout = render_pass_pipeline->GetPipelineLayout(); + VkDescriptorSet desc_set[1] = {descriptor}; + vkCmdBindDescriptorSets(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline_layout, 0, 1, desc_set, 0, nullptr); + } + } + void CommandBuffer::DrawIndirect(const Ref& buffer) { ZENGINE_VALIDATE_ASSERT(m_command_buffer != nullptr, "Command buffer can't be null") @@ -194,4 +263,83 @@ namespace ZEngine::Rendering::Buffers vkCmdDrawIndexedIndirect(m_command_buffer, reinterpret_cast(buffer->GetNativeBufferHandle()), 0, count, sizeof(VkDrawIndexedIndirectCommand)); } } + + void CommandBuffer::DrawIndexed(uint32_t index_count, uint32_t instanceCount, uint32_t first_index, int32_t vertex_offset, uint32_t first_instance) + { + ZENGINE_VALIDATE_ASSERT(m_command_buffer != nullptr, "Command buffer can't be null") + + vkCmdDrawIndexed(m_command_buffer, index_count, instanceCount, first_index, vertex_offset, first_instance); + } + + void CommandBuffer::TransitionImageLayout(const Primitives::ImageMemoryBarrier& image_barrier) + { + ZENGINE_VALIDATE_ASSERT(m_command_buffer != nullptr, "Command buffer can't be null") + + const auto& barrier_handle = image_barrier.GetHandle(); + const auto& barrier_spec = image_barrier.GetSpecification(); + vkCmdPipelineBarrier(m_command_buffer, barrier_spec.SourceStageMask, barrier_spec.DestinationStageMask, 0, 0, nullptr, 0, nullptr, 1, &barrier_handle); + } + + void CommandBuffer::CopyBufferToImage( + const Hardwares::BufferView& source, + Hardwares::BufferImage& destination, + uint32_t width, + uint32_t height, + uint32_t layer_count, + VkImageLayout new_layout) + { + ZENGINE_VALIDATE_ASSERT(m_command_buffer != nullptr, "Command buffer can't be null") + + VkBufferImageCopy buffer_image_copy = {}; + buffer_image_copy.bufferOffset = 0; + buffer_image_copy.bufferRowLength = 0; + buffer_image_copy.bufferImageHeight = 0; + buffer_image_copy.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + buffer_image_copy.imageSubresource.mipLevel = 0; + buffer_image_copy.imageSubresource.baseArrayLayer = 0; + buffer_image_copy.imageSubresource.layerCount = layer_count; + buffer_image_copy.imageOffset = {0, 0, 0}; + buffer_image_copy.imageExtent = {width, height, 1}; + + vkCmdCopyBufferToImage(m_command_buffer, source.Handle, destination.Handle, new_layout, 1, &buffer_image_copy); + } + + void CommandBuffer::BindVertexBuffer(const Buffers::VertexBuffer& buffer) + { + ZENGINE_VALIDATE_ASSERT(m_command_buffer != nullptr, "Command buffer can't be null") + + if (buffer.GetNativeBufferHandle()) + { + VkDeviceSize vertex_offset[1] = {0}; + VkBuffer vertex_buffers[1] = {reinterpret_cast(buffer.GetNativeBufferHandle())}; + vkCmdBindVertexBuffers(m_command_buffer, 0, 1, vertex_buffers, vertex_offset); + } + } + + void CommandBuffer::BindIndexBuffer(const Buffers::IndexBuffer& buffer, VkIndexType type) + { + ZENGINE_VALIDATE_ASSERT(m_command_buffer != nullptr, "Command buffer can't be null") + if (buffer.GetNativeBufferHandle()) + { + vkCmdBindIndexBuffer(m_command_buffer, reinterpret_cast(buffer.GetNativeBufferHandle()), 0, type); + } + } + + void CommandBuffer::SetScissor(const VkRect2D& scissor) + { + ZENGINE_VALIDATE_ASSERT(m_command_buffer != nullptr, "Command buffer can't be null") + vkCmdSetScissor(m_command_buffer, 0, 1, &scissor); + } + + void CommandBuffer::PushConstants(VkShaderStageFlags stage_flags, uint32_t offset, uint32_t size, const void* data) + { + ZENGINE_VALIDATE_ASSERT(m_command_buffer != nullptr, "Command buffer can't be null") + + if (auto render_pass = m_active_render_pass.lock()) + { + auto render_pass_pipeline = render_pass->GetPipeline(); + auto pipeline_layout = render_pass_pipeline->GetPipelineLayout(); + vkCmdPushConstants(m_command_buffer, pipeline_layout, stage_flags, offset, size, data); + } + } } // namespace ZEngine::Rendering::Buffers diff --git a/ZEngine/src/CommandPool.cpp b/ZEngine/src/CommandPool.cpp index a48c2de4..231300d7 100644 --- a/ZEngine/src/CommandPool.cpp +++ b/ZEngine/src/CommandPool.cpp @@ -8,7 +8,6 @@ namespace ZEngine::Rendering::Pools CommandPool::CommandPool(Rendering::QueueType type, uint64_t swapchain_identifier, bool present_on_swapchain) { /* Create CommandPool */ - m_swapchain_identifier = swapchain_identifier; m_queue_type = type; auto device = Hardwares::VulkanDevice::GetNativeDeviceHandle(); Hardwares::QueueView queue_view = Hardwares::VulkanDevice::GetQueue(type); @@ -18,84 +17,61 @@ namespace ZEngine::Rendering::Pools command_pool_create_info.queueFamilyIndex = queue_view.FamilyIndex; ZENGINE_VALIDATE_ASSERT(vkCreateCommandPool(device, &command_pool_create_info, nullptr, &m_handle) == VK_SUCCESS, "Failed to create Command Pool") - /*Create CommandBuffer */ - m_current_command_buffer_index = 0; - for (int i = 0; i < m_command_buffer_collection.size(); ++i) - { - m_command_buffer_collection[i] = CreateRef(m_handle, m_queue_type, present_on_swapchain); - } + auto& properties = Hardwares::VulkanDevice::GetPhysicalDeviceProperties(); + m_max_command_buffer_count = properties.limits.maxDrawIndirectCount; } CommandPool::~CommandPool() { Hardwares::VulkanDevice::QueueWait(m_queue_type); - auto device = Hardwares::VulkanDevice::GetNativeDeviceHandle(); - - for (Ref command : m_command_buffer_collection) + for (auto it = m_allocated_command_buffers.begin(); it != m_allocated_command_buffers.end();) { - command->WaitForExecution(); + auto signal_fence = (*it)->GetSignalFence(); - auto command_buffer_handle = command->GetHandle(); - vkFreeCommandBuffers(device, m_handle, 1, &command_buffer_handle); + if (signal_fence && signal_fence->Wait()) + { + it = m_allocated_command_buffers.erase(it); + } + else + { + it = std::next(it); + } } - ZENGINE_DESTROY_VULKAN_HANDLE(device, vkDestroyCommandPool, m_handle, nullptr) + decltype(m_allocated_command_buffers) allocated_buffer; + std::swap(allocated_buffer, m_allocated_command_buffers); - m_command_buffer_collection.fill(nullptr); + auto device = Hardwares::VulkanDevice::GetNativeDeviceHandle(); + ZENGINE_DESTROY_VULKAN_HANDLE(device, vkDestroyCommandPool, m_handle, nullptr) } - void CommandPool::Tick() + Buffers::CommandBuffer* CommandPool::GetCommmandBuffer() { - if (first) - { - first = false; - return; - } - m_current_command_buffer_index++; + Buffers::CommandBuffer* m_available_command_buffer{nullptr}; - if (m_current_command_buffer_index == 10) + bool found = false; + for (int i = 0; i < m_allocated_command_buffers.size(); ++i) { - m_current_command_buffer_index = 0; - - auto device = Hardwares::VulkanDevice::GetNativeDeviceHandle(); - for (auto& command : m_command_buffer_collection) + if (m_allocated_command_buffers[i]->Completed()) { - ZENGINE_VALIDATE_ASSERT(command->GetState() != Buffers::CommanBufferState::Recording, "") - - if (command->GetState() == Buffers::CommanBufferState::Submitted) - { - command->WaitForExecution(); - } + m_allocated_command_buffers[i]->ResetState(); + m_available_command_buffer = m_allocated_command_buffers[i].get(); + found = true; + break; } - ZENGINE_VALIDATE_ASSERT(vkResetCommandPool(device, m_handle, 0) == VK_SUCCESS, "Failed to reset Command Pool") } - } - - Buffers::CommandBuffer* CommandPool::GetCurrentCommmandBuffer() - { - return m_command_buffer_collection[m_current_command_buffer_index].get(); - } - - std::vector CommandPool::GetAllWaitSemaphoreCollection() - { - std::vector wait_semaphore_collection; - for (auto command : m_command_buffer_collection) + if (!found) { - ZENGINE_VALIDATE_ASSERT(command->GetState() != Buffers::CommanBufferState::Recording, "") - - auto semaphore = command->GetSignalSemaphore(); - if (semaphore->GetState() == Primitives::SemaphoreState::Submitted) - { - wait_semaphore_collection.emplace_back(semaphore); - } + m_allocated_command_buffers.push_back(CreateRef(m_handle, m_queue_type, false)); + m_available_command_buffer = m_allocated_command_buffers.back().get(); } - return wait_semaphore_collection; + return m_available_command_buffer; } - uint64_t CommandPool::GetSwapchainParent() const + Ref CommandPool::GetOneTimeCommmandBuffer() { - return m_swapchain_identifier; + return CreateRef(m_handle, m_queue_type, true); } } // namespace ZEngine::Rendering::Pools \ No newline at end of file diff --git a/ZEngine/src/Engine.cpp b/ZEngine/src/Engine.cpp index 2f4cc8cd..60fee14e 100644 --- a/ZEngine/src/Engine.cpp +++ b/ZEngine/src/Engine.cpp @@ -79,6 +79,9 @@ namespace ZEngine void Engine::Render() { m_window->Render(); + + GraphicRenderer::Upload(); + m_window->GetSwapchain()->Present(); } bool Engine::OnEngineClosed(Event::EngineClosedEvent& event) diff --git a/ZEngine/src/Fence.cpp b/ZEngine/src/Fence.cpp index 0c2dbd57..33f35c93 100644 --- a/ZEngine/src/Fence.cpp +++ b/ZEngine/src/Fence.cpp @@ -4,10 +4,14 @@ namespace ZEngine::Rendering::Primitives { - Fence::Fence() + Fence::Fence(bool as_signaled) { VkFenceCreateInfo frame_fence_create_info = {}; frame_fence_create_info.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO; + if (as_signaled) + { + frame_fence_create_info.flags = VK_FENCE_CREATE_SIGNALED_BIT; + } auto device = Hardwares::VulkanDevice::GetNativeDeviceHandle(); ZENGINE_VALIDATE_ASSERT(vkCreateFence(device, &frame_fence_create_info, nullptr, &m_handle) == VK_SUCCESS, "Failed to create Fence") @@ -34,7 +38,8 @@ namespace ZEngine::Rendering::Primitives bool Fence::Wait(uint64_t timeout) { auto device = Hardwares::VulkanDevice::GetNativeDeviceHandle(); - return vkWaitForFences(device, 1, &m_handle, true, timeout) == VK_SUCCESS; + auto wait = vkWaitForFences(device, 1, &m_handle, VK_TRUE, timeout); + return wait == VK_SUCCESS; } void Fence::Reset() diff --git a/ZEngine/src/GlfwWindow/VulkanWindow.cpp b/ZEngine/src/GlfwWindow/VulkanWindow.cpp index 0b50c3b4..ad3d798e 100644 --- a/ZEngine/src/GlfwWindow/VulkanWindow.cpp +++ b/ZEngine/src/GlfwWindow/VulkanWindow.cpp @@ -339,8 +339,6 @@ namespace ZEngine::Window::GLFWWindow { layer->Render(); } - - m_swapchain->Present(); } Ref VulkanWindow::GetSwapchain() const diff --git a/ZEngine/src/GraphicRenderer.cpp b/ZEngine/src/GraphicRenderer.cpp index 0668f4a6..a786a30e 100644 --- a/ZEngine/src/GraphicRenderer.cpp +++ b/ZEngine/src/GraphicRenderer.cpp @@ -1,34 +1,57 @@ #include #include +#include #include using namespace ZEngine::Rendering::Specifications; +using namespace ZEngine::Rendering::Renderers::Contracts; namespace ZEngine::Rendering::Renderers { - uint32_t GraphicRenderer::s_viewport_width = 1; - uint32_t GraphicRenderer::s_viewport_height = 1; - RendererInformation GraphicRenderer::s_renderer_information = {}; - WeakRef GraphicRenderer::s_main_window_swapchain = {}; - std::array, RenderTarget::COUNT> GraphicRenderer::s_render_target_collection = {}; - Ref GraphicRenderer::s_scene_renderer = CreateRef(); + uint32_t GraphicRenderer::s_viewport_width = 1; + uint32_t GraphicRenderer::s_viewport_height = 1; + RendererInformation GraphicRenderer::s_renderer_information = {}; + WeakRef GraphicRenderer::s_main_window_swapchain = {}; + std::array, RenderTarget::COUNT> GraphicRenderer::s_render_target_collection = {}; + Ref GraphicRenderer::s_UBCamera = {}; + Pools::CommandPool* GraphicRenderer::s_command_pool = nullptr; + Buffers::CommandBuffer* GraphicRenderer::s_current_command_buffer = nullptr; + Buffers::CommandBuffer* GraphicRenderer::s_current_command_buffer_ui = nullptr; + Ref GraphicRenderer::s_scene_renderer = CreateRef(); + Ref GraphicRenderer::s_imgui_renderer = CreateRef(); void GraphicRenderer::Initialize() { - FrameBufferSpecificationVNext frame_ouput_spec = {}; - frame_ouput_spec.ClearColor = true; - frame_ouput_spec.ClearDepth = true; - frame_ouput_spec.AttachmentSpecifications = {ImageFormat::R8G8B8A8_UNORM, ImageFormat::DEPTH_STENCIL_FROM_DEVICE}; - s_render_target_collection[RenderTarget::FRAME_OUTPUT] = Buffers::FramebufferVNext::Create(frame_ouput_spec); + s_command_pool = Hardwares::VulkanDevice::GetCommandPool(QueueType::GRAPHIC_QUEUE); - s_scene_renderer->Initialize(); + FrameBufferSpecificationVNext render_target_ouput_spec = {}; + render_target_ouput_spec.ClearColor = true; + render_target_ouput_spec.ClearDepth = true; + render_target_ouput_spec.AttachmentSpecifications = {ImageFormat::R8G8B8A8_UNORM, ImageFormat::DEPTH_STENCIL_FROM_DEVICE}; + s_render_target_collection[RenderTarget::FRAME_OUTPUT] = Buffers::FramebufferVNext::Create(render_target_ouput_spec); + s_render_target_collection[RenderTarget::ENVIROMENT_CUBEMAP] = Buffers::FramebufferVNext::Create(render_target_ouput_spec); + + /* + * Shared Uniform Buffers + */ + s_UBCamera = CreateRef(s_renderer_information.FrameCount); + + /* + * Sub Renderer Initialization + */ + s_scene_renderer->Initialize(s_UBCamera); + s_imgui_renderer->Initialize(s_main_window_swapchain); } void GraphicRenderer::Deinitialize() { s_scene_renderer->Deinitialize(); + s_imgui_renderer->Deinitialize(); + s_render_target_collection.fill(nullptr); + s_UBCamera->Dispose(); + s_main_window_swapchain.reset(); } @@ -62,14 +85,50 @@ namespace ZEngine::Rendering::Renderers void GraphicRenderer::Update() { - s_scene_renderer->Tick(); + GetRendererInformation(); } void GraphicRenderer::DrawScene(const Ref& camera, const Ref& data) { - s_scene_renderer->StartScene(camera->GetPosition(), camera->GetViewMatrix(), camera->GetPerspectiveMatrix()); - s_scene_renderer->RenderScene(data); - s_scene_renderer->EndScene(); + s_current_command_buffer = s_command_pool->GetCommmandBuffer(); + + auto& scene_camera = *s_UBCamera; + auto ubo_camera_data = UBOCameraLayout{.View = camera->GetViewMatrix(), .Projection = camera->GetPerspectiveMatrix(), .Position = glm::vec4(camera->GetPosition(), 1.0f)}; + scene_camera[s_renderer_information.CurrentFrameIndex].SetData(&ubo_camera_data, sizeof(UBOCameraLayout)); + { + s_scene_renderer->StartScene(s_current_command_buffer); + s_scene_renderer->RenderScene(data, s_renderer_information.CurrentFrameIndex); + s_scene_renderer->EndScene(s_current_command_buffer, s_renderer_information.CurrentFrameIndex); + } + } + + void GraphicRenderer::BeginImguiFrame() + { + s_current_command_buffer_ui = s_command_pool->GetCommmandBuffer(); + s_imgui_renderer->BeginFrame(s_current_command_buffer_ui); + } + + void GraphicRenderer::DrawUIFrame() + { + s_imgui_renderer->Draw(s_current_command_buffer_ui, s_renderer_information.CurrentFrameIndex); + } + + void GraphicRenderer::EndImguiFrame() + { + s_imgui_renderer->EndFrame(s_current_command_buffer_ui, s_renderer_information.CurrentFrameIndex); + } + + VkDescriptorSet GraphicRenderer::GetImguiFrameOutput() + { + auto frame_output = GetFrameOutput(); + auto texture = frame_output->GetColorAttachmentCollection().at(0); + return s_imgui_renderer->UpdateFrameOutput(texture->GetImage2DBuffer()); + } + + void GraphicRenderer::Upload() + { + s_current_command_buffer->Submit(); + s_current_command_buffer_ui->Submit(); } const RendererInformation& GraphicRenderer::GetRendererInformation() diff --git a/ZEngine/src/ImGUIRenderer.cpp b/ZEngine/src/ImGUIRenderer.cpp index 4db78d96..118c4202 100644 --- a/ZEngine/src/ImGUIRenderer.cpp +++ b/ZEngine/src/ImGUIRenderer.cpp @@ -1,561 +1,359 @@ #include #include +#include #include #include #include #include -#include +#include using namespace ZEngine::Hardwares; using namespace ZEngine::Rendering; namespace ZEngine::Rendering::Renderers { - Pools::CommandPool* ImGUIRenderer::s_ui_command_pool = nullptr; - Rendering::Buffers::CommandBuffer* ImGUIRenderer::s_command_buffer = nullptr; - VkDescriptorPool ImGUIRenderer::s_descriptor_pool = VK_NULL_HANDLE; - - void ImGUIRenderer::Initialize(void* window, const Ref& swapchain) + void ImGUIRenderer::Initialize(const Ref& swapchain) { - s_ui_command_pool = VulkanDevice::CreateCommandPool(QueueType::GRAPHIC_QUEUE, swapchain->GetIdentifier(), true); - ImGui_ImplGlfw_InitForVulkan(reinterpret_cast(window), false); - - /*Create DescriptorPool*/ - auto device = Hardwares::VulkanDevice::GetNativeDeviceHandle(); - const auto& device_property = Hardwares::VulkanDevice::GetPhysicalDeviceProperties(); - std::vector pool_sizes = {{VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1}}; - VkDescriptorPoolCreateInfo pool_info = {}; - pool_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; - pool_info.flags = VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT; - pool_info.maxSets = 2000 * swapchain->GetImageCount(); - pool_info.poolSizeCount = pool_sizes.size(); - pool_info.pPoolSizes = pool_sizes.data(); - ZENGINE_VALIDATE_ASSERT(vkCreateDescriptorPool(device, &pool_info, nullptr, &s_descriptor_pool) == VK_SUCCESS, "Failed to create DescriptorPool -- ImGuiLayer") - - ImGui_ImplVulkan_InitInfo imgui_vulkan_init_info = {}; - imgui_vulkan_init_info.Instance = Hardwares::VulkanDevice::GetNativeInstanceHandle(); - imgui_vulkan_init_info.PhysicalDevice = Hardwares::VulkanDevice::GetNativePhysicalDeviceHandle(); - imgui_vulkan_init_info.Device = device; - auto queue_view = Hardwares::VulkanDevice::GetQueue(Rendering::QueueType::GRAPHIC_QUEUE); - imgui_vulkan_init_info.QueueFamily = queue_view.FamilyIndex; - imgui_vulkan_init_info.Queue = queue_view.Handle; - imgui_vulkan_init_info.PipelineCache = nullptr; - imgui_vulkan_init_info.DescriptorPool = s_descriptor_pool; - imgui_vulkan_init_info.Allocator = nullptr; - imgui_vulkan_init_info.MinImageCount = swapchain->GetMinImageCount(); - imgui_vulkan_init_info.ImageCount = swapchain->GetImageCount(); - imgui_vulkan_init_info.CheckVkResultFn = nullptr; - - ImGui_ImplVulkan_Init(&imgui_vulkan_init_info, swapchain->GetRenderPass()); - - // Upload Fonts - auto command_buffer = Hardwares::VulkanDevice::BeginInstantCommandBuffer(Rendering::QueueType::GRAPHIC_QUEUE); + auto current_window = Engine::GetWindow(); + + IMGUI_CHECKVERSION(); + ImGui::CreateContext(); + StyleDarkTheme(); + + ImGuiIO& io = ImGui::GetIO(); + io.ConfigViewportsNoTaskBarIcon = true; + io.ConfigViewportsNoDecoration = true; + io.BackendFlags |= ImGuiBackendFlags_RendererHasViewports; + io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset; + io.BackendFlags |= ImGuiBackendFlags_HasMouseHoveredViewport; + io.BackendRendererName = "ZEngine"; + + std::string_view default_layout_ini = "Settings/DefaultLayout.ini"; + const auto current_directoy = std::filesystem::current_path(); + auto layout_file_path = fmt::format("{0}/{1}", current_directoy.string(), default_layout_ini); + if (std::filesystem::exists(std::filesystem::path(layout_file_path))) { - ImGui_ImplVulkan_CreateFontsTexture(command_buffer->GetHandle()); + io.IniFilename = default_layout_ini.data(); } - Hardwares::VulkanDevice::EndInstantCommandBuffer(command_buffer); - __ImGUIDestroyFontUploadObjects(); + + // io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; + io.ConfigFlags |= ImGuiConfigFlags_DockingEnable; + io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable; + + auto& style = ImGui::GetStyle(); + style.WindowBorderSize = 0.f; + style.ChildBorderSize = 0.f; + style.FrameRounding = 7.0f; + + auto window_property = current_window->GetWindowProperty(); + io.Fonts->AddFontFromFileTTF("Settings/Fonts/OpenSans/OpenSans-Bold.ttf", 17.f * window_property.DpiScale); + io.FontDefault = io.Fonts->AddFontFromFileTTF("Settings/Fonts/OpenSans/OpenSans-Regular.ttf", 17.f * window_property.DpiScale); + io.FontGlobalScale = window_property.DpiScale; + + ImGui_ImplGlfw_InitForVulkan(reinterpret_cast(current_window->GetNativeWindow()), false); + + const auto& renderer_info = Renderers::GraphicRenderer::GetRendererInformation(); + + m_vertex_buffer = CreateRef(renderer_info.FrameCount); + m_index_buffer = CreateRef(renderer_info.FrameCount); + Specifications::GraphicRendererPipelineSpecification ui_pipeline_spec = {}; + ui_pipeline_spec.DebugName = "Imgui-pipeline"; + ui_pipeline_spec.SwapchainAsRenderTarget = true; + ui_pipeline_spec.SwapchainRenderTarget = swapchain; + ui_pipeline_spec.ShaderSpecification = {}; + ui_pipeline_spec.ShaderSpecification.VertexFilename = "Shaders/Cache/imgui_vertex.spv"; + ui_pipeline_spec.ShaderSpecification.FragmentFilename = "Shaders/Cache/imgui_fragment.spv"; + ui_pipeline_spec.ShaderSpecification.OverloadMaxSet = 2000; + + ui_pipeline_spec.VertexInputBindingSpecifications.resize(1); + ui_pipeline_spec.VertexInputBindingSpecifications[0].Stride = sizeof(ImDrawVert); + ui_pipeline_spec.VertexInputBindingSpecifications[0].Rate = VK_VERTEX_INPUT_RATE_VERTEX; + + ui_pipeline_spec.VertexInputAttributeSpecifications.resize(3); + ui_pipeline_spec.VertexInputAttributeSpecifications[0].Location = 0; + ui_pipeline_spec.VertexInputAttributeSpecifications[0].Binding = ui_pipeline_spec.VertexInputBindingSpecifications[0].Binding; + ui_pipeline_spec.VertexInputAttributeSpecifications[0].Format = Specifications::ImageFormat::R32G32_SFLOAT; + ui_pipeline_spec.VertexInputAttributeSpecifications[0].Offset = IM_OFFSETOF(ImDrawVert, pos); + ui_pipeline_spec.VertexInputAttributeSpecifications[1].Location = 1; + ui_pipeline_spec.VertexInputAttributeSpecifications[1].Binding = ui_pipeline_spec.VertexInputBindingSpecifications[0].Binding; + ui_pipeline_spec.VertexInputAttributeSpecifications[1].Format = Specifications::ImageFormat::R32G32_SFLOAT; + ui_pipeline_spec.VertexInputAttributeSpecifications[1].Offset = IM_OFFSETOF(ImDrawVert, uv); + ui_pipeline_spec.VertexInputAttributeSpecifications[2].Location = 2; + ui_pipeline_spec.VertexInputAttributeSpecifications[2].Binding = ui_pipeline_spec.VertexInputBindingSpecifications[0].Binding; + ui_pipeline_spec.VertexInputAttributeSpecifications[2].Format = Specifications::ImageFormat::R8G8B8A8_UNORM; + ui_pipeline_spec.VertexInputAttributeSpecifications[2].Offset = IM_OFFSETOF(ImDrawVert, col); + + RenderPasses::RenderPassSpecification ui_pass_spec = {}; + ui_pass_spec.Pipeline = Pipelines::GraphicPipeline::Create(ui_pipeline_spec); + m_ui_pass = RenderPasses::RenderPass::Create(ui_pass_spec); + m_ui_pass->Verify(); + m_ui_pass->Bake(); + + auto pipeline = m_ui_pass->GetPipeline(); + auto shader = pipeline->GetShader(); + auto descriptor_setlayout = shader->GetDescriptorSetLayout()[0]; + + auto device = Hardwares::VulkanDevice::GetNativeDeviceHandle(); + /* + * Font uploading + */ + unsigned char* pixels; + int width, height; + io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height); + size_t upload_size = width * height * 4 * sizeof(char); + + Specifications::TextureSpecification font_tex_spec = {}; + font_tex_spec.Width = width; + font_tex_spec.Height = height; + font_tex_spec.Data = pixels; + font_tex_spec.Format = Specifications::ImageFormat::R8G8B8A8_UNORM; + + Ref font_texture = Textures::Texture2D::Create(font_tex_spec); + + VkDescriptorSetAllocateInfo font_alloc_info = {}; + font_alloc_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO; + font_alloc_info.descriptorPool = shader->GetDescriptorPool(); + font_alloc_info.descriptorSetCount = 1; + font_alloc_info.pSetLayouts = &descriptor_setlayout; + ZENGINE_VALIDATE_ASSERT(vkAllocateDescriptorSets(device, &font_alloc_info, &m_font_descriptor_set) == VK_SUCCESS, "Failed to create descriptor set") + + auto& font_image_info = font_texture->GetDescriptorImageInfo(); + VkWriteDescriptorSet write_desc[1] = {}; + write_desc[0].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; + write_desc[0].dstSet = m_font_descriptor_set; + write_desc[0].descriptorCount = 1; + write_desc[0].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; + write_desc[0].pImageInfo = &font_image_info; + vkUpdateDescriptorSets(device, 1, write_desc, 0, nullptr); + + io.Fonts->SetTexID((ImTextureID) m_font_descriptor_set); + /* + * Creating another DescriptorSet from the SetLayout that will serve has Image/Frame output + */ + VkDescriptorSetAllocateInfo frame_alloc_info = {}; + frame_alloc_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO; + frame_alloc_info.descriptorPool = shader->GetDescriptorPool(); + frame_alloc_info.descriptorSetCount = 1; + frame_alloc_info.pSetLayouts = &descriptor_setlayout; + ZENGINE_VALIDATE_ASSERT(vkAllocateDescriptorSets(device, &frame_alloc_info, &m_frame_output) == VK_SUCCESS, "Failed to create descriptor set") } void ImGUIRenderer::Deinitialize() { - VulkanDevice::DisposeCommandPool(s_ui_command_pool); - ImGui_ImplVulkan_Shutdown(); + m_ui_pass->Dispose(); + m_vertex_buffer->Dispose(); + m_index_buffer->Dispose(); + ImGui_ImplGlfw_Shutdown(); ImGui::DestroyContext(); - - auto device = Hardwares::VulkanDevice::GetNativeDeviceHandle(); - ZENGINE_DESTROY_VULKAN_HANDLE(device, vkDestroyDescriptorPool, s_descriptor_pool, nullptr) } - void ImGUIRenderer::Tick() + void ImGUIRenderer::StyleDarkTheme() { - s_ui_command_pool->Tick(); + auto& colors = ImGui::GetStyle().Colors; + colors[ImGuiCol_WindowBg] = ImVec4{0.1f, 0.105f, 0.11f, 1.0f}; + + // Headers + colors[ImGuiCol_Header] = ImVec4{0.2f, 0.205f, 0.21f, 1.0f}; + colors[ImGuiCol_HeaderHovered] = ImVec4{0.3f, 0.305f, 0.31f, 1.0f}; + colors[ImGuiCol_HeaderActive] = ImVec4{0.15f, 0.1505f, 0.151f, 1.0f}; + + // Buttons + colors[ImGuiCol_Button] = ImVec4{0.2f, 0.205f, 0.21f, 1.0f}; + colors[ImGuiCol_ButtonHovered] = ImVec4{0.3f, 0.305f, 0.31f, 1.0f}; + colors[ImGuiCol_ButtonActive] = ImVec4{0.15f, 0.1505f, 0.151f, 1.0f}; + + // Frame BG + colors[ImGuiCol_FrameBg] = ImVec4{0.2f, 0.205f, 0.21f, 1.0f}; + colors[ImGuiCol_FrameBgHovered] = ImVec4{0.3f, 0.305f, 0.31f, 1.0f}; + colors[ImGuiCol_FrameBgActive] = ImVec4{0.15f, 0.1505f, 0.151f, 1.0f}; + + // Tabs + colors[ImGuiCol_Tab] = ImVec4{0.15f, 0.1505f, 0.151f, 1.0f}; + colors[ImGuiCol_TabHovered] = ImVec4{0.38f, 0.3805f, 0.381f, 1.0f}; + colors[ImGuiCol_TabActive] = ImVec4{0.28f, 0.2805f, 0.281f, 1.0f}; + colors[ImGuiCol_TabUnfocused] = ImVec4{0.15f, 0.1505f, 0.151f, 1.0f}; + colors[ImGuiCol_TabUnfocusedActive] = ImVec4{0.2f, 0.205f, 0.21f, 1.0f}; + + // Title + colors[ImGuiCol_TitleBg] = ImVec4{0.15f, 0.1505f, 0.151f, 1.0f}; + colors[ImGuiCol_TitleBgActive] = ImVec4{0.15f, 0.1505f, 0.151f, 1.0f}; + colors[ImGuiCol_TitleBgCollapsed] = ImVec4{0.15f, 0.1505f, 0.151f, 1.0f}; + + colors[ImGuiCol_DockingPreview] = ImVec4{0.2f, 0.205f, 0.21f, .5f}; + colors[ImGuiCol_SeparatorHovered] = ImVec4{1.f, 1.f, 1.0f, .5f}; + colors[ImGuiCol_SeparatorActive] = ImVec4{1.f, 1.f, 1.0f, .5f}; + colors[ImGuiCol_CheckMark] = ImVec4{1.0f, 1.f, 1.0f, 1.f}; } - void ImGUIRenderer::BeginFrame() + void ImGUIRenderer::BeginFrame(Rendering::Buffers::CommandBuffer* const command_buffer) { - ImGui_ImplVulkan_NewFrame(); ImGui_ImplGlfw_NewFrame(); ImGui::NewFrame(); ImGuizmo::BeginFrame(); - } - - void ImGUIRenderer::Draw(uint32_t window_width, uint32_t window_height, const Ref& swapchain, void** user_data, void* draw_data) - { - ZENGINE_VALIDATE_ASSERT(s_ui_command_pool != nullptr, "UI Command pool can't be null") - s_command_buffer = s_ui_command_pool->GetCurrentCommmandBuffer(); - s_command_buffer->Begin(); - { - // Begin RenderPass - VkRenderPassBeginInfo render_pass_begin_info = {}; - render_pass_begin_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; - render_pass_begin_info.renderPass = swapchain->GetRenderPass(); - render_pass_begin_info.framebuffer = swapchain->GetCurrentFramebuffer(); - render_pass_begin_info.renderArea.extent.width = window_width; - render_pass_begin_info.renderArea.extent.height = window_height; - - std::array clear_values = {}; - clear_values[0].color = {{0.0f, 0.0f, 0.0f, 1.0f}}; - render_pass_begin_info.clearValueCount = clear_values.size(); - render_pass_begin_info.pClearValues = clear_values.data(); - vkCmdBeginRenderPass(s_command_buffer->GetHandle(), &render_pass_begin_info, VK_SUBPASS_CONTENTS_INLINE); - - // Record dear imgui primitives into command buffer - if (user_data) - { - __ImGUIRenderDataChildViewport(draw_data, user_data, s_command_buffer->GetHandle(), nullptr); - } - else - { - __ImGUIRenderData(draw_data, s_command_buffer->GetHandle(), nullptr); - } - - vkCmdEndRenderPass(s_command_buffer->GetHandle()); - } - s_command_buffer->End(); - s_command_buffer->Submit(); - } - - void ImGUIRenderer::DrawChildWindow(uint32_t width, uint32_t height, ImguiViewPortWindowChild** window_child, void* draw_data) - { - ZENGINE_VALIDATE_ASSERT((*window_child)->CommandPool != nullptr, "UI Command pool can't be null") - - auto command_buffer = (*window_child)->CommandPool->GetCurrentCommmandBuffer(); command_buffer->Begin(); - { - // Begin RenderPass - VkRenderPassBeginInfo render_pass_begin_info = {}; - render_pass_begin_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; - render_pass_begin_info.renderPass = (*window_child)->Swapchain->GetRenderPass(); - render_pass_begin_info.framebuffer = (*window_child)->Swapchain->GetCurrentFramebuffer(); - render_pass_begin_info.renderArea.extent.width = width; - render_pass_begin_info.renderArea.extent.height = height; - - std::array clear_values = {}; - clear_values[0].color = {{0.0f, 0.0f, 0.0f, 1.0f}}; - render_pass_begin_info.clearValueCount = clear_values.size(); - render_pass_begin_info.pClearValues = clear_values.data(); - vkCmdBeginRenderPass(command_buffer->GetHandle(), &render_pass_begin_info, VK_SUBPASS_CONTENTS_INLINE); - - // Record dear imgui primitives into command buffer - __ImGUIRenderDataChildViewport(draw_data, &(*window_child)->RendererUserData, command_buffer->GetHandle(), nullptr); - - vkCmdEndRenderPass(command_buffer->GetHandle()); - } - command_buffer->End(); - command_buffer->Submit(); } - void ImGUIRenderer::EndFrame() + void ImGUIRenderer::Draw(Rendering::Buffers::CommandBuffer* const command_buffer, uint32_t frame_index) { - ImGuiIO& io = ImGui::GetIO(); - if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable) + ImGui::Render(); + auto draw_data = ImGui::GetDrawData(); + if (draw_data && draw_data->TotalVtxCount > 0) { - ImGui::UpdatePlatformWindows(); - ImGui::RenderPlatformWindowsDefault(); - } - } - - /* - * Note for Developers : - * Implementing this function has extracted and adapted from **imgui impl vulkan.cpp** to make it compliant with our strategy of enqueuing resources that need disposal. - * see : ImGui_ImplVulkan_DestroyFontUploadObjects(...) - */ - void ImGUIRenderer::__ImGUIDestroyFontUploadObjects() - { - ImGui_ImplVulkan_Data* bd = ImGui_ImplVulkan_GetBackendData(); - ImGui_ImplVulkan_InitInfo* v = &bd->VulkanInitInfo; - if (bd->UploadBuffer) - { - VulkanDevice::EnqueueForDeletion(DeviceResourceType::BUFFER, bd->UploadBuffer); - bd->UploadBuffer = VK_NULL_HANDLE; - } - if (bd->UploadBufferMemory) - { - VulkanDevice::EnqueueForDeletion(DeviceResourceType::BUFFERMEMORY, bd->UploadBufferMemory); - bd->UploadBufferMemory = VK_NULL_HANDLE; - } - } - - /* - * Note for Developers : - * Implementing this function has extracted and adapted from **imgui impl vulkan.cpp** to make it compliant with our strategy of enqueuing resources that need disposal. - * see : ImGui_ImplVulkan_RenderDrawData(...) - */ - void ImGUIRenderer::__ImGUIRenderData(void* data, VkCommandBuffer command_buffer, VkPipeline pipeline) - { - auto draw_data = reinterpret_cast(data); - - // Avoid rendering when minimized, scale coordinates for retina displays (screen coordinates != framebuffer coordinates) - int fb_width = (int) (draw_data->DisplaySize.x * draw_data->FramebufferScale.x); - int fb_height = (int) (draw_data->DisplaySize.y * draw_data->FramebufferScale.y); - if (fb_width <= 0 || fb_height <= 0) - return; - - ImGui_ImplVulkan_Data* bd = ImGui_ImplVulkan_GetBackendData(); - ImGui_ImplVulkan_InitInfo* v = &bd->VulkanInitInfo; - if (pipeline == VK_NULL_HANDLE) - pipeline = bd->Pipeline; - - // Allocate array to store enough vertex/index buffers. Each unique viewport gets its own storage. - ImGui_ImplVulkan_ViewportData* viewport_renderer_data = (ImGui_ImplVulkan_ViewportData*) draw_data->OwnerViewport->RendererUserData; - IM_ASSERT(viewport_renderer_data != nullptr); - ImGui_ImplVulkanH_WindowRenderBuffers* wrb = &viewport_renderer_data->RenderBuffers; - if (wrb->FrameRenderBuffers == nullptr) - { - wrb->Index = 0; - wrb->Count = v->ImageCount; - wrb->FrameRenderBuffers = (ImGui_ImplVulkanH_FrameRenderBuffers*) IM_ALLOC(sizeof(ImGui_ImplVulkanH_FrameRenderBuffers) * wrb->Count); - memset(wrb->FrameRenderBuffers, 0, sizeof(ImGui_ImplVulkanH_FrameRenderBuffers) * wrb->Count); - } - IM_ASSERT(wrb->Count == v->ImageCount); - wrb->Index = (wrb->Index + 1) % wrb->Count; - ImGui_ImplVulkanH_FrameRenderBuffers* rb = &wrb->FrameRenderBuffers[wrb->Index]; - - if (draw_data->TotalVtxCount > 0) - { - // Create or resize the vertex/index buffers - size_t vertex_size = draw_data->TotalVtxCount * sizeof(ImDrawVert); - size_t index_size = draw_data->TotalIdxCount * sizeof(ImDrawIdx); - if (rb->VertexBuffer == VK_NULL_HANDLE || rb->VertexBufferSize < vertex_size) - __ImGUICreateOrResizeBuffer(rb->VertexBuffer, rb->VertexBufferMemory, rb->VertexBufferSize, vertex_size, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT); - if (rb->IndexBuffer == VK_NULL_HANDLE || rb->IndexBufferSize < index_size) - __ImGUICreateOrResizeBuffer(rb->IndexBuffer, rb->IndexBufferMemory, rb->IndexBufferSize, index_size, VK_BUFFER_USAGE_INDEX_BUFFER_BIT); - - // Upload vertex/index data into a single contiguous GPU buffer - ImDrawVert* vtx_dst = nullptr; - ImDrawIdx* idx_dst = nullptr; - VkResult err = vkMapMemory(v->Device, rb->VertexBufferMemory, 0, rb->VertexBufferSize, 0, (void**) (&vtx_dst)); - check_vk_result(err); - err = vkMapMemory(v->Device, rb->IndexBufferMemory, 0, rb->IndexBufferSize, 0, (void**) (&idx_dst)); - check_vk_result(err); + // Avoid rendering when minimized, scale coordinates for retina displays (screen coordinates != framebuffer coordinates) + int fb_width = (int) (draw_data->DisplaySize.x * draw_data->FramebufferScale.x); + int fb_height = (int) (draw_data->DisplaySize.y * draw_data->FramebufferScale.y); + if (fb_width <= 0 || fb_height <= 0) + return; + + std::vector vertex_data_collection = {}; + std::vector index_data_collection = {}; for (int n = 0; n < draw_data->CmdListsCount; n++) { const ImDrawList* cmd_list = draw_data->CmdLists[n]; - memcpy(vtx_dst, cmd_list->VtxBuffer.Data, cmd_list->VtxBuffer.Size * sizeof(ImDrawVert)); - memcpy(idx_dst, cmd_list->IdxBuffer.Data, cmd_list->IdxBuffer.Size * sizeof(ImDrawIdx)); - vtx_dst += cmd_list->VtxBuffer.Size; - idx_dst += cmd_list->IdxBuffer.Size; + std::copy(std::begin(cmd_list->VtxBuffer), std::end(cmd_list->VtxBuffer), std::back_inserter(vertex_data_collection)); + std::copy(std::begin(cmd_list->IdxBuffer), std::end(cmd_list->IdxBuffer), std::back_inserter(index_data_collection)); } - VkMappedMemoryRange range[2] = {}; - range[0].sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE; - range[0].memory = rb->VertexBufferMemory; - range[0].size = VK_WHOLE_SIZE; - range[1].sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE; - range[1].memory = rb->IndexBufferMemory; - range[1].size = VK_WHOLE_SIZE; - err = vkFlushMappedMemoryRanges(v->Device, 2, range); - check_vk_result(err); - vkUnmapMemory(v->Device, rb->VertexBufferMemory); - vkUnmapMemory(v->Device, rb->IndexBufferMemory); - } + auto& vertex_buffer = *m_vertex_buffer; + auto& index_buffer = *m_index_buffer; - // Setup desired Vulkan state - ImGui_ImplVulkan_SetupRenderState(draw_data, pipeline, command_buffer, rb, fb_width, fb_height); - - // Will project scissor/clipping rectangles into framebuffer space - ImVec2 clip_off = draw_data->DisplayPos; // (0,0) unless using multi-viewports - ImVec2 clip_scale = draw_data->FramebufferScale; // (1,1) unless using retina display which are often (2,2) - - // Render command lists - // (Because we merged all buffers into a single one, we maintain our own offset into them) - int global_vtx_offset = 0; - int global_idx_offset = 0; - for (int n = 0; n < draw_data->CmdListsCount; n++) - { - const ImDrawList* cmd_list = draw_data->CmdLists[n]; - for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++) - { - const ImDrawCmd* pcmd = &cmd_list->CmdBuffer[cmd_i]; - if (pcmd->UserCallback != nullptr) - { - // User callback, registered via ImDrawList::AddCallback() - // (ImDrawCallback_ResetRenderState is a special callback value used by the user to request the renderer to reset render state.) - if (pcmd->UserCallback == ImDrawCallback_ResetRenderState) - ImGui_ImplVulkan_SetupRenderState(draw_data, pipeline, command_buffer, rb, fb_width, fb_height); - else - pcmd->UserCallback(cmd_list, pcmd); - } - else - { - // Project scissor/clipping rectangles into framebuffer space - ImVec2 clip_min((pcmd->ClipRect.x - clip_off.x) * clip_scale.x, (pcmd->ClipRect.y - clip_off.y) * clip_scale.y); - ImVec2 clip_max((pcmd->ClipRect.z - clip_off.x) * clip_scale.x, (pcmd->ClipRect.w - clip_off.y) * clip_scale.y); - - // Clamp to viewport as vkCmdSetScissor() won't accept values that are off bounds - if (clip_min.x < 0.0f) - { - clip_min.x = 0.0f; - } - if (clip_min.y < 0.0f) - { - clip_min.y = 0.0f; - } - if (clip_max.x > fb_width) - { - clip_max.x = (float) fb_width; - } - if (clip_max.y > fb_height) - { - clip_max.y = (float) fb_height; - } - if (clip_max.x <= clip_min.x || clip_max.y <= clip_min.y) - continue; - - // Apply scissor/clipping rectangle - VkRect2D scissor; - scissor.offset.x = (int32_t) (clip_min.x); - scissor.offset.y = (int32_t) (clip_min.y); - scissor.extent.width = (uint32_t) (clip_max.x - clip_min.x); - scissor.extent.height = (uint32_t) (clip_max.y - clip_min.y); - vkCmdSetScissor(command_buffer, 0, 1, &scissor); - - // Bind DescriptorSet with font or user texture - VkDescriptorSet desc_set[1] = {(VkDescriptorSet) pcmd->TextureId}; - if (sizeof(ImTextureID) < sizeof(ImU64)) - { - // We don't support texture switches if ImTextureID hasn't been redefined to be 64-bit. Do a flaky check that other textures haven't been used. - IM_ASSERT(pcmd->TextureId == (ImTextureID) bd->FontDescriptorSet); - desc_set[0] = bd->FontDescriptorSet; - } - vkCmdBindDescriptorSets(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, bd->PipelineLayout, 0, 1, desc_set, 0, nullptr); - - // Draw - vkCmdDrawIndexed(command_buffer, pcmd->ElemCount, 1, pcmd->IdxOffset + global_idx_offset, pcmd->VtxOffset + global_vtx_offset, 0); - } - } - global_idx_offset += cmd_list->IdxBuffer.Size; - global_vtx_offset += cmd_list->VtxBuffer.Size; + vertex_buffer[frame_index].SetData(vertex_data_collection); + index_buffer[frame_index].SetData(index_data_collection); } - - // Note: at this point both vkCmdSetViewport() and vkCmdSetScissor() have been called. - // Our last values will leak into user/application rendering IF: - // - Your app uses a pipeline with VK_DYNAMIC_STATE_VIEWPORT or VK_DYNAMIC_STATE_SCISSOR dynamic state - // - And you forgot to call vkCmdSetViewport() and vkCmdSetScissor() yourself to explicitly set that state. - // If you use VK_DYNAMIC_STATE_VIEWPORT or VK_DYNAMIC_STATE_SCISSOR you are responsible for setting the values before rendering. - // In theory we should aim to backup/restore those values but I am not sure this is possible. - // We perform a call to vkCmdSetScissor() to set back a full viewport which is likely to fix things for 99% users but technically this is not perfect. (See github #4644) - VkRect2D scissor = {{0, 0}, {(uint32_t) fb_width, (uint32_t) fb_height}}; - vkCmdSetScissor(command_buffer, 0, 1, &scissor); } - void ImGUIRenderer::__ImGUIRenderDataChildViewport(void* data, void** user_data, VkCommandBuffer command_buffer, VkPipeline pipeline) + void ImGUIRenderer::EndFrame(Rendering::Buffers::CommandBuffer* const command_buffer, uint32_t frame_index) { - auto draw_data = reinterpret_cast(data); - - // Avoid rendering when minimized, scale coordinates for retina displays (screen coordinates != framebuffer coordinates) - int fb_width = (int) (draw_data->DisplaySize.x * draw_data->FramebufferScale.x); - int fb_height = (int) (draw_data->DisplaySize.y * draw_data->FramebufferScale.y); - if (fb_width <= 0 || fb_height <= 0) - return; - - ImGui_ImplVulkan_Data* bd = ImGui_ImplVulkan_GetBackendData(); - ImGui_ImplVulkan_InitInfo* v = &bd->VulkanInitInfo; - if (pipeline == VK_NULL_HANDLE) - pipeline = bd->Pipeline; - - // Allocate array to store enough vertex/index buffers. Each unique viewport gets its own storage. - if ((*user_data) == nullptr) + command_buffer->BeginRenderPass(m_ui_pass); { - *user_data = IM_ALLOC(sizeof(ImGui_ImplVulkan_ViewportData)); - memset(*user_data, 0, sizeof(ImGui_ImplVulkan_ViewportData)); - } - - ImGui_ImplVulkan_ViewportData* viewport_renderer_data = (ImGui_ImplVulkan_ViewportData*) *user_data; - IM_ASSERT(viewport_renderer_data != nullptr); - ImGui_ImplVulkanH_WindowRenderBuffers* wrb = &viewport_renderer_data->RenderBuffers; - if (wrb->FrameRenderBuffers == nullptr) - { - wrb->Index = 0; - wrb->Count = v->ImageCount; - wrb->FrameRenderBuffers = (ImGui_ImplVulkanH_FrameRenderBuffers*) IM_ALLOC(sizeof(ImGui_ImplVulkanH_FrameRenderBuffers) * wrb->Count); - memset(wrb->FrameRenderBuffers, 0, sizeof(ImGui_ImplVulkanH_FrameRenderBuffers) * wrb->Count); - } - IM_ASSERT(wrb->Count == v->ImageCount); - wrb->Index = (wrb->Index + 1) % wrb->Count; - ImGui_ImplVulkanH_FrameRenderBuffers* rb = &wrb->FrameRenderBuffers[wrb->Index]; - - if (draw_data->TotalVtxCount > 0) - { - // Create or resize the vertex/index buffers - size_t vertex_size = draw_data->TotalVtxCount * sizeof(ImDrawVert); - size_t index_size = draw_data->TotalIdxCount * sizeof(ImDrawIdx); - if (rb->VertexBuffer == VK_NULL_HANDLE || rb->VertexBufferSize < vertex_size) - __ImGUICreateOrResizeBuffer(rb->VertexBuffer, rb->VertexBufferMemory, rb->VertexBufferSize, vertex_size, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT); - if (rb->IndexBuffer == VK_NULL_HANDLE || rb->IndexBufferSize < index_size) - __ImGUICreateOrResizeBuffer(rb->IndexBuffer, rb->IndexBufferMemory, rb->IndexBufferSize, index_size, VK_BUFFER_USAGE_INDEX_BUFFER_BIT); - - // Upload vertex/index data into a single contiguous GPU buffer - ImDrawVert* vtx_dst = nullptr; - ImDrawIdx* idx_dst = nullptr; - VkResult err = vkMapMemory(v->Device, rb->VertexBufferMemory, 0, rb->VertexBufferSize, 0, (void**) (&vtx_dst)); - check_vk_result(err); - err = vkMapMemory(v->Device, rb->IndexBufferMemory, 0, rb->IndexBufferSize, 0, (void**) (&idx_dst)); - check_vk_result(err); - for (int n = 0; n < draw_data->CmdListsCount; n++) - { - const ImDrawList* cmd_list = draw_data->CmdLists[n]; - memcpy(vtx_dst, cmd_list->VtxBuffer.Data, cmd_list->VtxBuffer.Size * sizeof(ImDrawVert)); - memcpy(idx_dst, cmd_list->IdxBuffer.Data, cmd_list->IdxBuffer.Size * sizeof(ImDrawIdx)); - vtx_dst += cmd_list->VtxBuffer.Size; - idx_dst += cmd_list->IdxBuffer.Size; - } - VkMappedMemoryRange range[2] = {}; - range[0].sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE; - range[0].memory = rb->VertexBufferMemory; - range[0].size = VK_WHOLE_SIZE; - range[1].sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE; - range[1].memory = rb->IndexBufferMemory; - range[1].size = VK_WHOLE_SIZE; - err = vkFlushMappedMemoryRanges(v->Device, 2, range); - check_vk_result(err); - vkUnmapMemory(v->Device, rb->VertexBufferMemory); - vkUnmapMemory(v->Device, rb->IndexBufferMemory); - } - - // Setup desired Vulkan state - ImGui_ImplVulkan_SetupRenderState(draw_data, pipeline, command_buffer, rb, fb_width, fb_height); + auto& vertex_buffer = *m_vertex_buffer; + auto& index_buffer = *m_index_buffer; + command_buffer->BindVertexBuffer(vertex_buffer[frame_index]); + command_buffer->BindIndexBuffer(index_buffer[frame_index], sizeof(ImDrawIdx) == 2 ? VK_INDEX_TYPE_UINT16 : VK_INDEX_TYPE_UINT32); - // Will project scissor/clipping rectangles into framebuffer space - ImVec2 clip_off = draw_data->DisplayPos; // (0,0) unless using multi-viewports - ImVec2 clip_scale = draw_data->FramebufferScale; // (1,1) unless using retina display which are often (2,2) + // Setup scale and translation: + // Our visible imgui space lies from draw_data->DisplayPps (top left) to draw_data->DisplayPos+data_data->DisplaySize (bottom right). DisplayPos is (0,0) for single + // viewport apps. + auto draw_data = ImGui::GetDrawData(); - // Render command lists - // (Because we merged all buffers into a single one, we maintain our own offset into them) - int global_vtx_offset = 0; - int global_idx_offset = 0; - for (int n = 0; n < draw_data->CmdListsCount; n++) - { - const ImDrawList* cmd_list = draw_data->CmdLists[n]; - for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++) + if (draw_data) { - const ImDrawCmd* pcmd = &cmd_list->CmdBuffer[cmd_i]; - if (pcmd->UserCallback != nullptr) + float scale[2]; + scale[0] = 2.0f / draw_data->DisplaySize.x; + scale[1] = 2.0f / draw_data->DisplaySize.y; + float translate[2]; + translate[0] = -1.0f - draw_data->DisplayPos.x * scale[0]; + translate[1] = -1.0f - draw_data->DisplayPos.y * scale[1]; + command_buffer->PushConstants(VK_SHADER_STAGE_VERTEX_BIT, sizeof(float) * 0, sizeof(float) * 2, scale); + command_buffer->PushConstants(VK_SHADER_STAGE_VERTEX_BIT, sizeof(float) * 2, sizeof(float) * 2, translate); + + // Will project scissor/clipping rectangles into framebuffer space + ImVec2 clip_off = draw_data->DisplayPos; // (0,0) unless using multi-viewports + ImVec2 clip_scale = draw_data->FramebufferScale; // (1,1) unless using retina display which are often (2,2) + + // Render command lists + // (Because we merged all buffers into a single one, we maintain our own offset into them) + int global_vtx_offset = 0; + int global_idx_offset = 0; + for (int n = 0; n < draw_data->CmdListsCount; n++) { - // User callback, registered via ImDrawList::AddCallback() - // (ImDrawCallback_ResetRenderState is a special callback value used by the user to request the renderer to reset render state.) - if (pcmd->UserCallback == ImDrawCallback_ResetRenderState) - ImGui_ImplVulkan_SetupRenderState(draw_data, pipeline, command_buffer, rb, fb_width, fb_height); - else - pcmd->UserCallback(cmd_list, pcmd); - } - else - { - // Project scissor/clipping rectangles into framebuffer space - ImVec2 clip_min((pcmd->ClipRect.x - clip_off.x) * clip_scale.x, (pcmd->ClipRect.y - clip_off.y) * clip_scale.y); - ImVec2 clip_max((pcmd->ClipRect.z - clip_off.x) * clip_scale.x, (pcmd->ClipRect.w - clip_off.y) * clip_scale.y); - - // Clamp to viewport as vkCmdSetScissor() won't accept values that are off bounds - if (clip_min.x < 0.0f) - { - clip_min.x = 0.0f; - } - if (clip_min.y < 0.0f) - { - clip_min.y = 0.0f; - } - if (clip_max.x > fb_width) - { - clip_max.x = (float) fb_width; - } - if (clip_max.y > fb_height) - { - clip_max.y = (float) fb_height; - } - if (clip_max.x <= clip_min.x || clip_max.y <= clip_min.y) - continue; - - // Apply scissor/clipping rectangle - VkRect2D scissor; - scissor.offset.x = (int32_t) (clip_min.x); - scissor.offset.y = (int32_t) (clip_min.y); - scissor.extent.width = (uint32_t) (clip_max.x - clip_min.x); - scissor.extent.height = (uint32_t) (clip_max.y - clip_min.y); - vkCmdSetScissor(command_buffer, 0, 1, &scissor); - - // Bind DescriptorSet with font or user texture - VkDescriptorSet desc_set[1] = {(VkDescriptorSet) pcmd->TextureId}; - if (sizeof(ImTextureID) < sizeof(ImU64)) + const ImDrawList* cmd_list = draw_data->CmdLists[n]; + for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++) { - // We don't support texture switches if ImTextureID hasn't been redefined to be 64-bit. Do a flaky check that other textures haven't been used. - IM_ASSERT(pcmd->TextureId == (ImTextureID) bd->FontDescriptorSet); - desc_set[0] = bd->FontDescriptorSet; + const ImDrawCmd* pcmd = &cmd_list->CmdBuffer[cmd_i]; + if (pcmd->UserCallback != nullptr) + { + // User callback, registered via ImDrawList::AddCallback() + // (ImDrawCallback_ResetRenderState is a special callback value used by the user to request the renderer to reset render state.) + if (pcmd->UserCallback == ImDrawCallback_ResetRenderState) + { + // ImGui_ImplVulkan_SetupRenderState(draw_data, pipeline, command_buffer, rb, fb_width, fb_height); + } + else + pcmd->UserCallback(cmd_list, pcmd); + } + else + { + auto current_window = Engine::GetWindow(); + // Project scissor/clipping rectangles into framebuffer space + ImVec2 clip_min((pcmd->ClipRect.x - clip_off.x) * clip_scale.x, (pcmd->ClipRect.y - clip_off.y) * clip_scale.y); + ImVec2 clip_max((pcmd->ClipRect.z - clip_off.x) * clip_scale.x, (pcmd->ClipRect.w - clip_off.y) * clip_scale.y); + + // Clamp to viewport as vkCmdSetScissor() won't accept values that are off bounds + if (clip_min.x < 0.0f) + { + clip_min.x = 0.0f; + } + if (clip_min.y < 0.0f) + { + clip_min.y = 0.0f; + } + if (clip_max.x > current_window->GetWidth()) + { + clip_max.x = (float) current_window->GetWidth(); + } + if (clip_max.y > current_window->GetHeight()) + { + clip_max.y = (float) current_window->GetHeight(); + } + if (clip_max.x <= clip_min.x || clip_max.y <= clip_min.y) + continue; + + // Apply scissor/clipping rectangle + VkRect2D scissor; + scissor.offset.x = (int32_t) (clip_min.x); + scissor.offset.y = (int32_t) (clip_min.y); + scissor.extent.width = (uint32_t) (clip_max.x - clip_min.x); + scissor.extent.height = (uint32_t) (clip_max.y - clip_min.y); + command_buffer->SetScissor(scissor); + + // Bind DescriptorSet with font or user texture + VkDescriptorSet desc_set[1] = {(VkDescriptorSet) pcmd->TextureId}; + if (sizeof(ImTextureID) < sizeof(ImU64)) + { + // We don't support texture switches if ImTextureID hasn't been redefined to be 64-bit. Do a flaky check that other textures haven't been used. + IM_ASSERT(pcmd->TextureId == (ImTextureID) m_font_descriptor_set); + desc_set[0] = m_font_descriptor_set; + } + + command_buffer->BindDescriptorSet(desc_set[0]); + command_buffer->DrawIndexed(pcmd->ElemCount, 1, pcmd->IdxOffset + global_idx_offset, pcmd->VtxOffset + global_vtx_offset, 0); + } } - vkCmdBindDescriptorSets(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, bd->PipelineLayout, 0, 1, desc_set, 0, nullptr); - - // Draw - vkCmdDrawIndexed(command_buffer, pcmd->ElemCount, 1, pcmd->IdxOffset + global_idx_offset, pcmd->VtxOffset + global_vtx_offset, 0); + global_idx_offset += cmd_list->IdxBuffer.Size; + global_vtx_offset += cmd_list->VtxBuffer.Size; } } - global_idx_offset += cmd_list->IdxBuffer.Size; - global_vtx_offset += cmd_list->VtxBuffer.Size; } + command_buffer->EndRenderPass(); + command_buffer->End(); - // Note: at this point both vkCmdSetViewport() and vkCmdSetScissor() have been called. - // Our last values will leak into user/application rendering IF: - // - Your app uses a pipeline with VK_DYNAMIC_STATE_VIEWPORT or VK_DYNAMIC_STATE_SCISSOR dynamic state - // - And you forgot to call vkCmdSetViewport() and vkCmdSetScissor() yourself to explicitly set that state. - // If you use VK_DYNAMIC_STATE_VIEWPORT or VK_DYNAMIC_STATE_SCISSOR you are responsible for setting the values before rendering. - // In theory we should aim to backup/restore those values but I am not sure this is possible. - // We perform a call to vkCmdSetScissor() to set back a full viewport which is likely to fix things for 99% users but technically this is not perfect. (See github #4644) - VkRect2D scissor = {{0, 0}, {(uint32_t) fb_width, (uint32_t) fb_height}}; - vkCmdSetScissor(command_buffer, 0, 1, &scissor); - } - - /* - * Note for Developers : - * Implementing this function has extracted and adapted from **imgui impl vulkan.cpp** to make it compliant with our strategy of enqueuing resources that need disposal. - * see : CreateOrResizeBuffer(...) - */ - void ImGUIRenderer::__ImGUICreateOrResizeBuffer(VkBuffer& buffer, VkDeviceMemory& buffer_memory, VkDeviceSize& p_buffer_size, size_t new_size, VkBufferUsageFlagBits usage) - { - ImGui_ImplVulkan_Data* bd = ImGui_ImplVulkan_GetBackendData(); - ImGui_ImplVulkan_InitInfo* v = &bd->VulkanInitInfo; - VkResult err; - if (buffer != VK_NULL_HANDLE) - { - // vkDestroyBuffer(v->Device, buffer, v->Allocator); - VulkanDevice::EnqueueForDeletion(DeviceResourceType::BUFFER, buffer); - buffer = VK_NULL_HANDLE; - } - if (buffer_memory != VK_NULL_HANDLE) + ImGuiIO& io = ImGui::GetIO(); + if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable) { - // vkFreeMemory(v->Device, buffer_memory, v->Allocator); - VulkanDevice::EnqueueForDeletion(DeviceResourceType::BUFFERMEMORY, buffer_memory); - buffer_memory = VK_NULL_HANDLE; + ImGui::UpdatePlatformWindows(); + ImGui::RenderPlatformWindowsDefault(); } - - VkDeviceSize vertex_buffer_size_aligned = ((new_size - 1) / bd->BufferMemoryAlignment + 1) * bd->BufferMemoryAlignment; - VkBufferCreateInfo buffer_info = {}; - buffer_info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; - buffer_info.size = vertex_buffer_size_aligned; - buffer_info.usage = usage; - buffer_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE; - err = vkCreateBuffer(v->Device, &buffer_info, v->Allocator, &buffer); - check_vk_result(err); - - VkMemoryRequirements req; - vkGetBufferMemoryRequirements(v->Device, buffer, &req); - bd->BufferMemoryAlignment = (bd->BufferMemoryAlignment > req.alignment) ? bd->BufferMemoryAlignment : req.alignment; - VkMemoryAllocateInfo alloc_info = {}; - alloc_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; - alloc_info.allocationSize = req.size; - alloc_info.memoryTypeIndex = ImGui_ImplVulkan_MemoryType(VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, req.memoryTypeBits); - err = vkAllocateMemory(v->Device, &alloc_info, v->Allocator, &buffer_memory); - check_vk_result(err); - - err = vkBindBufferMemory(v->Device, buffer, buffer_memory, 0); - check_vk_result(err); - p_buffer_size = req.size; } - ImguiViewPortWindowChild::ImguiViewPortWindowChild(void* viewport_handle) + VkDescriptorSet ImGUIRenderer::UpdateFrameOutput(const Ref& buffer) { - Swapchain = CreateRef(viewport_handle, false); - CommandPool = VulkanDevice::CreateCommandPool(QueueType::GRAPHIC_QUEUE, this->Swapchain->GetIdentifier(), true); + auto device = Hardwares::VulkanDevice::GetNativeDeviceHandle(); + VkDescriptorImageInfo desc_image[1] = {}; + desc_image[0].sampler = buffer->GetSampler(); + desc_image[0].imageView = buffer->GetImageViewHandle(); + desc_image[0].imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + VkWriteDescriptorSet write_desc[1] = {}; + write_desc[0].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; + write_desc[0].dstSet = m_frame_output; + write_desc[0].descriptorCount = 1; + write_desc[0].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; + write_desc[0].pImageInfo = desc_image; + vkUpdateDescriptorSets(device, 1, write_desc, 0, nullptr); + + return m_frame_output; } } // namespace ZEngine::Rendering::Renderers \ No newline at end of file diff --git a/ZEngine/src/Image2DBuffer.cpp b/ZEngine/src/Image2DBuffer.cpp index 4000a483..498baf12 100644 --- a/ZEngine/src/Image2DBuffer.cpp +++ b/ZEngine/src/Image2DBuffer.cpp @@ -3,7 +3,14 @@ namespace ZEngine::Rendering::Buffers { - Image2DBuffer::Image2DBuffer(uint32_t width, uint32_t height, VkFormat format, VkImageUsageFlags usage_flag_bit, VkImageAspectFlagBits image_aspect_flag_bit) + Image2DBuffer::Image2DBuffer( + uint32_t width, + uint32_t height, + VkFormat format, + VkImageUsageFlags usage_flag_bit, + VkImageAspectFlagBits image_aspect_flag_bit, + uint32_t layer_count, + VkImageCreateFlags image_create_flag_bit) : m_width(width), m_height(height) { ZENGINE_VALIDATE_ASSERT(m_width > 0, "Image width must be greater then zero") @@ -20,7 +27,7 @@ namespace ZEngine::Rendering::Buffers VK_SHARING_MODE_EXCLUSIVE, VK_SAMPLE_COUNT_1_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, - image_aspect_flag_bit); + image_aspect_flag_bit, layer_count, image_create_flag_bit); } Image2DBuffer::~Image2DBuffer() diff --git a/ZEngine/src/ImageMemoryBarrier.cpp b/ZEngine/src/ImageMemoryBarrier.cpp index f2800575..3a72cf54 100644 --- a/ZEngine/src/ImageMemoryBarrier.cpp +++ b/ZEngine/src/ImageMemoryBarrier.cpp @@ -12,7 +12,7 @@ namespace ZEngine::Rendering::Primitives m_handle.subresourceRange.aspectMask = specification.ImageAspectMask; m_handle.subresourceRange.baseMipLevel = 0; m_handle.subresourceRange.baseArrayLayer = 0; - m_handle.subresourceRange.layerCount = 1; + m_handle.subresourceRange.layerCount = m_specification.LayerCount; m_handle.subresourceRange.levelCount = 1; m_handle.image = specification.ImageHandle; m_handle.oldLayout = ImageLayoutMap[static_cast(specification.OldLayout)]; diff --git a/ZEngine/src/ImguiLayer.cpp b/ZEngine/src/ImguiLayer.cpp index 842dc21e..d227efeb 100644 --- a/ZEngine/src/ImguiLayer.cpp +++ b/ZEngine/src/ImguiLayer.cpp @@ -4,7 +4,7 @@ #include #include #include -#include +#include using namespace ZEngine::Rendering::Renderers; @@ -18,70 +18,12 @@ namespace ZEngine::Layers void ImguiLayer::Initialize() { - if (m_initialized) - { - ZENGINE_CORE_INFO("ImGUI layer already initialized") - return; - } - - if (auto current_window = m_window.lock()) - { - IMGUI_CHECKVERSION(); - ImGui::CreateContext(); - StyleDarkTheme(); - - ImGuiIO& io = ImGui::GetIO(); - io.ConfigViewportsNoTaskBarIcon = true; - io.ConfigViewportsNoDecoration = true; - io.BackendFlags |= ImGuiBackendFlags_RendererHasViewports; - io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset; - io.BackendFlags |= ImGuiBackendFlags_HasMouseHoveredViewport; - io.BackendRendererName = "ZEngine"; - - std::string_view default_layout_ini = "Settings/DefaultLayout.ini"; - const auto current_directoy = std::filesystem::current_path(); - auto layout_file_path = fmt::format("{0}/{1}", current_directoy.string(), default_layout_ini); - if (std::filesystem::exists(std::filesystem::path(layout_file_path))) - { - io.IniFilename = default_layout_ini.data(); - } - - // io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; - io.ConfigFlags |= ImGuiConfigFlags_DockingEnable; - io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable; - - auto& style = ImGui::GetStyle(); - style.WindowBorderSize = 0.f; - style.ChildBorderSize = 0.f; - style.FrameRounding = 7.0f; - - auto window_property = current_window->GetWindowProperty(); - io.Fonts->AddFontFromFileTTF("Settings/Fonts/OpenSans/OpenSans-Bold.ttf", 17.f * window_property.DpiScale); - io.FontDefault = io.Fonts->AddFontFromFileTTF("Settings/Fonts/OpenSans/OpenSans-Regular.ttf", 17.f * window_property.DpiScale); - io.FontGlobalScale = window_property.DpiScale; - - ImGUIRenderer::Initialize(current_window->GetNativeWindow(), current_window->GetSwapchain()); - auto& platform_io = ImGui::GetPlatformIO(); - platform_io.Renderer_CreateWindow = __ImGUIRendererCreateWindowCallback; - platform_io.Renderer_DestroyWindow = __ImGUIPlatformDestroyWindowCallback; - platform_io.Renderer_RenderWindow = __ImGUIPlatformRenderWindowCallback; - platform_io.Renderer_SetWindowSize = __ImGUIPlatformSetWindowSizeCallback; - platform_io.Renderer_SwapBuffers = __ImGUIPlatformSwapBuffersCallback; - - m_initialized = true; - } } void ImguiLayer::Deinitialize() { m_ui_components.clear(); m_ui_components.shrink_to_fit(); - - if (m_initialized) - { - ImGUIRenderer::Deinitialize(); - m_initialized = false; - } } bool ImguiLayer::OnEvent(Event::CoreEvent& event) @@ -104,8 +46,6 @@ namespace ZEngine::Layers void ImguiLayer::Update(Core::TimeStep dt) { - ImGUIRenderer::Tick(); - ImGuiIO& io = ImGui::GetIO(); if (dt > 0.0f) { @@ -246,90 +186,6 @@ namespace ZEngine::Layers return false; } - void ImguiLayer::StyleDarkTheme() - { - auto& colors = ImGui::GetStyle().Colors; - colors[ImGuiCol_WindowBg] = ImVec4{0.1f, 0.105f, 0.11f, 1.0f}; - - // Headers - colors[ImGuiCol_Header] = ImVec4{0.2f, 0.205f, 0.21f, 1.0f}; - colors[ImGuiCol_HeaderHovered] = ImVec4{0.3f, 0.305f, 0.31f, 1.0f}; - colors[ImGuiCol_HeaderActive] = ImVec4{0.15f, 0.1505f, 0.151f, 1.0f}; - - // Buttons - colors[ImGuiCol_Button] = ImVec4{0.2f, 0.205f, 0.21f, 1.0f}; - colors[ImGuiCol_ButtonHovered] = ImVec4{0.3f, 0.305f, 0.31f, 1.0f}; - colors[ImGuiCol_ButtonActive] = ImVec4{0.15f, 0.1505f, 0.151f, 1.0f}; - - // Frame BG - colors[ImGuiCol_FrameBg] = ImVec4{0.2f, 0.205f, 0.21f, 1.0f}; - colors[ImGuiCol_FrameBgHovered] = ImVec4{0.3f, 0.305f, 0.31f, 1.0f}; - colors[ImGuiCol_FrameBgActive] = ImVec4{0.15f, 0.1505f, 0.151f, 1.0f}; - - // Tabs - colors[ImGuiCol_Tab] = ImVec4{0.15f, 0.1505f, 0.151f, 1.0f}; - colors[ImGuiCol_TabHovered] = ImVec4{0.38f, 0.3805f, 0.381f, 1.0f}; - colors[ImGuiCol_TabActive] = ImVec4{0.28f, 0.2805f, 0.281f, 1.0f}; - colors[ImGuiCol_TabUnfocused] = ImVec4{0.15f, 0.1505f, 0.151f, 1.0f}; - colors[ImGuiCol_TabUnfocusedActive] = ImVec4{0.2f, 0.205f, 0.21f, 1.0f}; - - // Title - colors[ImGuiCol_TitleBg] = ImVec4{0.15f, 0.1505f, 0.151f, 1.0f}; - colors[ImGuiCol_TitleBgActive] = ImVec4{0.15f, 0.1505f, 0.151f, 1.0f}; - colors[ImGuiCol_TitleBgCollapsed] = ImVec4{0.15f, 0.1505f, 0.151f, 1.0f}; - - colors[ImGuiCol_DockingPreview] = ImVec4{0.2f, 0.205f, 0.21f, .5f}; - colors[ImGuiCol_SeparatorHovered] = ImVec4{1.f, 1.f, 1.0f, .5f}; - colors[ImGuiCol_SeparatorActive] = ImVec4{1.f, 1.f, 1.0f, .5f}; - colors[ImGuiCol_CheckMark] = ImVec4{1.0f, 1.f, 1.0f, 1.f}; - } - - void ImguiLayer::__ImGUIRendererCreateWindowCallback(ImGuiViewport* viewport) - { - ImguiViewPortWindowChild* viewport_window = new ImguiViewPortWindowChild{viewport->PlatformHandle}; - viewport->RendererUserData = viewport_window; - } - - void ImguiLayer::__ImGUIPlatformDestroyWindowCallback(ImGuiViewport* viewport) - { - if (viewport->RendererUserData) - { - auto window_child = reinterpret_cast(viewport->RendererUserData); - Hardwares::VulkanDevice::DisposeCommandPool(window_child->CommandPool); - window_child->Swapchain.reset(); - delete window_child; - } - viewport->RendererUserData = nullptr; - } - - void ImguiLayer::__ImGUIPlatformRenderWindowCallback(ImGuiViewport* viewport, void* args) - { - if (viewport->RendererUserData) - { - auto window_child = reinterpret_cast(viewport->RendererUserData); - window_child->CommandPool->Tick(); - ImGUIRenderer::DrawChildWindow(viewport->Size.x, viewport->Size.y, &window_child, viewport->DrawData); - } - } - - void ImguiLayer::__ImGUIPlatformSwapBuffersCallback(ImGuiViewport* viewport, void* args) - { - if (viewport->RendererUserData) - { - auto window_child = reinterpret_cast(viewport->RendererUserData); - window_child->Swapchain->Present(); - } - } - - void ImguiLayer::__ImGUIPlatformSetWindowSizeCallback(ImGuiViewport* viewport, ImVec2 size) - { - if (viewport->RendererUserData) - { - auto window_child = reinterpret_cast(viewport->RendererUserData); - window_child->Swapchain->Resize(); - } - } - void ImguiLayer::Render() { if (auto window_ptr = m_window.lock()) @@ -339,10 +195,7 @@ namespace ZEngine::Layers return; } - auto current_vulkan_window_ptr = reinterpret_cast(window_ptr.get()); - auto swapchain = current_vulkan_window_ptr->GetSwapchain(); - - ImGUIRenderer::BeginFrame(); + GraphicRenderer::BeginImguiFrame(); for (const auto& component : m_ui_components) { @@ -351,11 +204,8 @@ namespace ZEngine::Layers component->Render(); } } - ImGui::Render(); - /*Frame and CommandBuffer preparing*/ - ImGUIRenderer::Draw(window_ptr->GetWidth(), window_ptr->GetHeight(), swapchain, nullptr, ImGui::GetDrawData()); - - ImGUIRenderer::EndFrame(); + GraphicRenderer::DrawUIFrame(); + GraphicRenderer::EndImguiFrame(); } } } // namespace ZEngine::Layers diff --git a/ZEngine/src/PerspectiveCameraController.cpp b/ZEngine/src/PerspectiveCameraController.cpp index e020e7b3..2f9c6b3a 100644 --- a/ZEngine/src/PerspectiveCameraController.cpp +++ b/ZEngine/src/PerspectiveCameraController.cpp @@ -13,12 +13,18 @@ namespace ZEngine::Controllers void PerspectiveCameraController::Initialize() { + m_process_event = true; } void PerspectiveCameraController::Update(Core::TimeStep dt) { if (auto window = m_window.lock()) { + if (!m_process_event) + { + return; + } + const auto mouse_position = IDevice::As()->GetMousePosition(window); const auto mouse = glm::vec2(mouse_position[0], mouse_position[1]); bool mouse_pressed = false; @@ -82,6 +88,22 @@ namespace ZEngine::Controllers m_perspective_camera->SetTarget(target); } + void PerspectiveCameraController::ResumeEventProcessing() + { + { + std::lock_guard l(m_event_mutex); + m_process_event = true; + } + } + + void PerspectiveCameraController::PauseEventProcessing() + { + { + std::lock_guard l(m_event_mutex); + m_process_event = false; + } + } + const ZEngine::Ref PerspectiveCameraController::GetCamera() const { return m_perspective_camera; @@ -93,6 +115,11 @@ namespace ZEngine::Controllers bool PerspectiveCameraController::OnEvent(Event::CoreEvent& e) { + if (!m_process_event) + { + return false; + } + Event::EventDispatcher dispatcher(e); dispatcher.Dispatch(std::bind(&PerspectiveCameraController::OnMouseButtonWheelMoved, this, std::placeholders::_1)); return false; diff --git a/ZEngine/src/RenderPass.cpp b/ZEngine/src/RenderPass.cpp index 3feaaf12..71e89498 100644 --- a/ZEngine/src/RenderPass.cpp +++ b/ZEngine/src/RenderPass.cpp @@ -1,6 +1,7 @@ #include #include #include +#include using namespace ZEngine::Rendering::Buffers; @@ -38,6 +39,7 @@ namespace ZEngine::Rendering::Renderers::RenderPasses return; } + const uint32_t frame_count = Engine::GetWindow()->GetSwapchain()->GetImageCount(); const auto& shader = m_pipeline->GetShader(); const auto& descriptor_set_map = shader->GetDescriptorSetMap(); std::vector write_descriptor_set_collection = {}; @@ -111,8 +113,6 @@ namespace ZEngine::Rendering::Renderers::RenderPasses auto texture_array = reinterpret_cast(input.Input.Data); auto& texture_collection = texture_array->Data(); - uint32_t frame_count{3}; /*this should from the renderer*/ - for (uint32_t frame_index = 0; frame_index < frame_count; ++frame_index) { for (uint32_t index = 0; index < texture_collection.size(); ++index) @@ -133,6 +133,26 @@ namespace ZEngine::Rendering::Renderers::RenderPasses } } break; + case TEXTURE: + { + auto buffer = reinterpret_cast(input.Input.Data); + for (uint32_t frame_index = 0; frame_index < frame_count; ++frame_index) + { + const auto& image_info = buffer->GetDescriptorImageInfo(); + write_descriptor_set_collection.emplace_back(VkWriteDescriptorSet{ + .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, + .pNext = nullptr, + .dstSet = descriptor_set_map.at(input.Set)[frame_index], + .dstBinding = input.Binding, + .dstArrayElement = 0, + .descriptorCount = 1, + .descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, + .pImageInfo = &(image_info), + .pBufferInfo = nullptr, + .pTexelBufferView = nullptr}); + } + } + break; case UNIFORM_BUFFER: { auto buffer = reinterpret_cast(input.Input.Data); diff --git a/ZEngine/src/RendererPipeline.cpp b/ZEngine/src/RendererPipeline.cpp index c03f7418..b1003fc3 100644 --- a/ZEngine/src/RendererPipeline.cpp +++ b/ZEngine/src/RendererPipeline.cpp @@ -25,7 +25,6 @@ namespace ZEngine::Rendering::Renderers::Pipelines /* * Framebuffer Creation */ - m_target_framebuffer = m_pipeline_specification.TargetFrameBuffer; /*Pipeline fixed states*/ /* @@ -55,8 +54,31 @@ namespace ZEngine::Rendering::Renderers::Pipelines /* * Vertex Input */ + std::vector vertex_input_bindings = {}; + std::transform( + m_pipeline_specification.VertexInputBindingSpecifications.begin(), + m_pipeline_specification.VertexInputBindingSpecifications.end(), + std::back_inserter(vertex_input_bindings), + [](const Specifications::VertexInputBindingSpecification& input) { + return VkVertexInputBindingDescription{.binding = input.Binding, .stride = input.Stride, .inputRate = (VkVertexInputRate) input.Rate}; + }); + + std::vector vertex_input_attributes = {}; + std::transform( + m_pipeline_specification.VertexInputAttributeSpecifications.begin(), + m_pipeline_specification.VertexInputAttributeSpecifications.end(), + std::back_inserter(vertex_input_attributes), + [](const Specifications::VertexInputAttributeSpecification& input) { + return VkVertexInputAttributeDescription{ + .location = input.Location, .binding = input.Binding, .format = Specifications::ImageFormatMap[VALUE_FROM_SPEC_MAP(input.Format)], .offset = input.Offset}; + }); + VkPipelineVertexInputStateCreateInfo vertex_input_state_create_info = {}; vertex_input_state_create_info.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO; + vertex_input_state_create_info.vertexBindingDescriptionCount = vertex_input_bindings.size(); + vertex_input_state_create_info.pVertexBindingDescriptions = vertex_input_bindings.data(); + vertex_input_state_create_info.vertexAttributeDescriptionCount = vertex_input_attributes.size(); + vertex_input_state_create_info.pVertexAttributeDescriptions = vertex_input_attributes.data(); /* * Rasterizer */ @@ -123,12 +145,13 @@ namespace ZEngine::Rendering::Renderers::Pipelines * Pipeline layout */ const auto descriptor_set_layout_collection = m_shader->GetDescriptorSetLayout(); + const auto& push_constant_collection = m_shader->GetPushConstants(); VkPipelineLayoutCreateInfo pipeline_layout_create_info = {}; pipeline_layout_create_info.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; pipeline_layout_create_info.setLayoutCount = descriptor_set_layout_collection.size(); // Optional pipeline_layout_create_info.pSetLayouts = descriptor_set_layout_collection.data(); // Optional - pipeline_layout_create_info.pushConstantRangeCount = 0; // Optional - pipeline_layout_create_info.pPushConstantRanges = nullptr; // Optional + pipeline_layout_create_info.pushConstantRangeCount = push_constant_collection.size(); + pipeline_layout_create_info.pPushConstantRanges = push_constant_collection.data(); pipeline_layout_create_info.flags = 0; pipeline_layout_create_info.pNext = nullptr; ZENGINE_VALIDATE_ASSERT(vkCreatePipelineLayout(device, &(pipeline_layout_create_info), nullptr, &m_pipeline_layout) == VK_SUCCESS, "Failed to create pipeline layout") @@ -149,12 +172,26 @@ namespace ZEngine::Rendering::Renderers::Pipelines graphic_pipeline_create_info.pColorBlendState = &(color_blend_state_create_info); graphic_pipeline_create_info.pDynamicState = &(dynamic_state_create_info); graphic_pipeline_create_info.layout = m_pipeline_layout; - graphic_pipeline_create_info.renderPass = m_target_framebuffer->GetRenderPass(); - graphic_pipeline_create_info.subpass = 0; - graphic_pipeline_create_info.basePipelineHandle = VK_NULL_HANDLE; // Optional - graphic_pipeline_create_info.basePipelineIndex = -1; // Optional - graphic_pipeline_create_info.flags = 0; // Optional - graphic_pipeline_create_info.pNext = nullptr; // Optional + + if (!m_pipeline_specification.SwapchainAsRenderTarget) + { + ZENGINE_VALIDATE_ASSERT(m_pipeline_specification.TargetFrameBuffer, "Target framebuffer can't be null") + m_target_framebuffer = m_pipeline_specification.TargetFrameBuffer; + graphic_pipeline_create_info.renderPass = m_target_framebuffer->GetRenderPass(); + } + + if (m_pipeline_specification.SwapchainAsRenderTarget) + { + ZENGINE_VALIDATE_ASSERT(m_pipeline_specification.SwapchainRenderTarget, "Swapchain can't be null") + m_target_swapchain = m_pipeline_specification.SwapchainRenderTarget; + graphic_pipeline_create_info.renderPass = m_target_swapchain->GetRenderPass(); + } + + graphic_pipeline_create_info.subpass = 0; + graphic_pipeline_create_info.basePipelineHandle = VK_NULL_HANDLE; // Optional + graphic_pipeline_create_info.basePipelineIndex = -1; // Optional + graphic_pipeline_create_info.flags = 0; // Optional + graphic_pipeline_create_info.pNext = nullptr; // Optional ZENGINE_VALIDATE_ASSERT( vkCreateGraphicsPipelines(device, VK_NULL_HANDLE, 1, &graphic_pipeline_create_info, nullptr, &m_pipeline_handle) == VK_SUCCESS, "Failed to create Graphics Pipeline") } @@ -162,7 +199,16 @@ namespace ZEngine::Rendering::Renderers::Pipelines void GraphicPipeline::Dispose() { m_shader->Dispose(); - m_target_framebuffer->Dispose(); + + if (m_target_framebuffer) + { + m_target_framebuffer->Dispose(); + } + if (m_target_swapchain) + { + m_target_swapchain.~IntrusivePtr(); + m_target_swapchain = nullptr; + } Hardwares::VulkanDevice::EnqueueForDeletion(Rendering::DeviceResourceType::PIPELINE_LAYOUT, m_pipeline_layout); Hardwares::VulkanDevice::EnqueueForDeletion(Rendering::DeviceResourceType::PIPELINE, m_pipeline_handle); m_pipeline_layout = VK_NULL_HANDLE; @@ -181,11 +227,12 @@ namespace ZEngine::Rendering::Renderers::Pipelines VkRenderPass GraphicPipeline::GetRenderPassHandle() const { - if (!m_target_framebuffer) + if (!m_target_framebuffer && !m_target_swapchain) { return VK_NULL_HANDLE; } - return m_target_framebuffer->GetRenderPass(); + + return m_pipeline_specification.SwapchainAsRenderTarget ? m_target_swapchain->GetRenderPass() : m_target_framebuffer->GetRenderPass(); } Ref GraphicPipeline::GetTargetFrameBuffer() const @@ -193,6 +240,11 @@ namespace ZEngine::Rendering::Renderers::Pipelines return m_target_framebuffer; } + Ref GraphicPipeline::GetTargetSwapchain() const + { + return m_target_swapchain; + } + Ref GraphicPipeline::GetShader() const { return m_shader; diff --git a/ZEngine/src/SceneRenderer.cpp b/ZEngine/src/SceneRenderer.cpp index f3c2347e..27839b9d 100644 --- a/ZEngine/src/SceneRenderer.cpp +++ b/ZEngine/src/SceneRenderer.cpp @@ -8,41 +8,66 @@ using namespace ZEngine::Rendering::Specifications; namespace ZEngine::Rendering::Renderers { - void SceneRenderer::Initialize() + void SceneRenderer::Initialize(const Ref& camera) { const auto& renderer_info = Renderers::GraphicRenderer::GetRendererInformation(); - m_command_pool = Hardwares::VulkanDevice::CreateCommandPool(QueueType::GRAPHIC_QUEUE, renderer_info.SwapchainIdentifier, true); + m_upload_once_per_frame_count = renderer_info.FrameCount; m_last_drawn_vertices_count.resize(renderer_info.FrameCount, 0); m_last_drawn_index_count.resize(renderer_info.FrameCount, 0); - m_UB_Camera = CreateRef(renderer_info.FrameCount); - m_SBVertex = CreateRef(renderer_info.FrameCount); - m_SBIndex = CreateRef(renderer_info.FrameCount); - m_SBDrawData = CreateRef(renderer_info.FrameCount); - m_SBTransform = CreateRef(renderer_info.FrameCount); - m_SBMaterialData = CreateRef(renderer_info.FrameCount); - m_indirect_buffer.resize(renderer_info.FrameCount, CreateRef()); /* * Render Passes definition */ + /* + * Cubmap Pass + */ + cubemapSBVertex = CreateRef(renderer_info.FrameCount); + cubemapSBIndex = CreateRef(renderer_info.FrameCount); + cubemapSBDrawData = CreateRef(renderer_info.FrameCount); + for (uint32_t frame_index = 0; frame_index < renderer_info.FrameCount; ++frame_index) + { + s_cubemap_indirect_buffer.emplace_back(CreateRef()); + } + + s_environment_map = Textures::Texture2D::ReadCubemap("Settings/EnvironmentMaps/piazza_bologni_4k.hdr"); + Specifications::GraphicRendererPipelineSpecification cubemap_pipeline_spec = {}; + cubemap_pipeline_spec.DebugName = "Cubemap-Pipeline"; + // cubemap_pipeline_spec.TargetFrameBuffer = GraphicRenderer::GetRenderTarget(RenderTarget::ENVIROMENT_CUBEMAP); + cubemap_pipeline_spec.TargetFrameBuffer = GraphicRenderer::GetRenderTarget(RenderTarget::FRAME_OUTPUT); + cubemap_pipeline_spec.ShaderSpecification = {.VertexFilename = "Shaders/Cache/cubemap_vertex.spv", .FragmentFilename = "Shaders/Cache/cubemap_fragment.spv"}; + RenderPasses::RenderPassSpecification cubemap_pass_spec = {}; + cubemap_pass_spec.Pipeline = Pipelines::GraphicPipeline::Create(cubemap_pipeline_spec); + s_cubemap_pass = RenderPasses::RenderPass::Create(cubemap_pass_spec); + + s_cubemap_pass->SetInput("UBCamera", camera); + s_cubemap_pass->SetInput("VertexSB", cubemapSBVertex); + s_cubemap_pass->SetInput("IndexSB", cubemapSBIndex); + s_cubemap_pass->SetInput("DrawDataSB", cubemapSBDrawData); + s_cubemap_pass->SetInput("CubemapTexture", s_environment_map); + s_cubemap_pass->Verify(); + s_cubemap_pass->Bake(); + /* * Infinite Grid */ m_GridSBVertex = CreateRef(renderer_info.FrameCount); m_GridSBIndex = CreateRef(renderer_info.FrameCount); m_GridSBDrawData = CreateRef(renderer_info.FrameCount); - m_infinite_grid_indirect_buffer.resize(renderer_info.FrameCount, CreateRef()); + for (uint32_t frame_index = 0; frame_index < renderer_info.FrameCount; ++frame_index) + { + m_infinite_grid_indirect_buffer.emplace_back(CreateRef()); + } Specifications::GraphicRendererPipelineSpecification infinite_grid_spec = {}; infinite_grid_spec.DebugName = "Infinite-Grid-Pipeline"; - infinite_grid_spec.TargetFrameBuffer = GraphicRenderer::GetRenderTarget(RenderTarget::FRAME_OUTPUT); + infinite_grid_spec.TargetFrameBuffer = GraphicRenderer::GetRenderTarget(RenderTarget::FRAME_OUTPUT); infinite_grid_spec.ShaderSpecification = {.VertexFilename = "Shaders/Cache/infinite_grid_vertex.spv", .FragmentFilename = "Shaders/Cache/infinite_grid_fragment.spv"}; RenderPasses::RenderPassSpecification grid_color_pass = {}; grid_color_pass.Pipeline = Pipelines::GraphicPipeline::Create(infinite_grid_spec); m_infinite_grid_pass = RenderPasses::RenderPass::Create(grid_color_pass); - m_infinite_grid_pass->SetInput("UBCamera", m_UB_Camera); + m_infinite_grid_pass->SetInput("UBCamera", camera); m_infinite_grid_pass->SetInput("VertexSB", m_GridSBVertex); m_infinite_grid_pass->SetInput("IndexSB", m_GridSBIndex); m_infinite_grid_pass->SetInput("DrawDataSB", m_GridSBDrawData); @@ -51,7 +76,16 @@ namespace ZEngine::Rendering::Renderers /* * Final Color */ - Specifications::FrameBufferSpecificationVNext framebuffer_spec = {}; + m_SBVertex = CreateRef(renderer_info.FrameCount); + m_SBIndex = CreateRef(renderer_info.FrameCount); + m_SBDrawData = CreateRef(renderer_info.FrameCount); + m_SBTransform = CreateRef(renderer_info.FrameCount); + m_SBMaterialData = CreateRef(renderer_info.FrameCount); + for (uint32_t frame_index = 0; frame_index < renderer_info.FrameCount; ++frame_index) + { + m_indirect_buffer.emplace_back(CreateRef()); + } + Specifications::FrameBufferSpecificationVNext framebuffer_spec = {}; framebuffer_spec.ClearColor = false; framebuffer_spec.ClearDepth = false; framebuffer_spec.AttachmentSpecifications = {ImageFormat::R8G8B8A8_UNORM, ImageFormat::DEPTH_STENCIL_FROM_DEVICE}; @@ -66,19 +100,28 @@ namespace ZEngine::Rendering::Renderers color_pass.Pipeline = Pipelines::GraphicPipeline::Create(final_pipeline_spec); m_final_color_output_pass = RenderPasses::RenderPass::Create(color_pass); - m_final_color_output_pass->SetInput("UBCamera", m_UB_Camera); + m_final_color_output_pass->SetInput("UBCamera", camera); m_final_color_output_pass->SetInput("VertexSB", m_SBVertex); m_final_color_output_pass->SetInput("IndexSB", m_SBIndex); m_final_color_output_pass->SetInput("DrawDataSB", m_SBDrawData); m_final_color_output_pass->SetInput("TransformSB", m_SBTransform); m_final_color_output_pass->SetInput("MatSB", m_SBMaterialData); - m_final_color_output_pass->Verify(); m_final_color_output_pass->Bake(); } void SceneRenderer::Deinitialize() { + s_cubemap_pass->Dispose(); + s_environment_map->Dispose(); + cubemapSBVertex->Dispose(); + cubemapSBIndex->Dispose(); + cubemapSBDrawData->Dispose(); + for (auto& buffer : s_cubemap_indirect_buffer) + { + buffer->Dispose(); + } + m_infinite_grid_pass->Dispose(); m_GridSBVertex->Dispose(); m_GridSBIndex->Dispose(); @@ -89,7 +132,7 @@ namespace ZEngine::Rendering::Renderers } m_final_color_output_pass->Dispose(); - m_UB_Camera->Dispose(); + m_SBVertex->Dispose(); m_SBIndex->Dispose(); m_SBDrawData->Dispose(); @@ -102,8 +145,6 @@ namespace ZEngine::Rendering::Renderers m_global_texture_buffer_collection.clear(); m_global_texture_buffer_collection.shrink_to_fit(); - - Hardwares::VulkanDevice::DisposeCommandPool(m_command_pool); } void SceneRenderer::StartScene(const glm::vec4& camera_position, const glm::mat4& camera_view, const glm::mat4& camera_projection) @@ -113,38 +154,52 @@ namespace ZEngine::Rendering::Renderers m_camera_projection = camera_projection; } + void SceneRenderer::StartScene(Buffers::CommandBuffer* const command_buffer) + { + command_buffer->Begin(); + } + void SceneRenderer::StartScene(const glm::vec3& camera_position, const glm::mat4& camera_view, const glm::mat4& camera_projection) { this->StartScene(glm::vec4(camera_position, 1.0f), camera_view, camera_projection); } - void SceneRenderer::RenderScene(const Ref& scene_data) + void SceneRenderer::RenderScene(const Ref& scene_data, uint32_t current_frame_index) { - uint32_t current_frame_index = Renderers::GraphicRenderer::GetRendererInformation().CurrentFrameIndex; - /* - * Uploading Camera info - * Todo: Can be multithreaded - */ - auto& scene_camera = *m_UB_Camera; - auto ubo_camera_data = Contracts::UBOCameraLayout{.View = m_camera_view, .Projection = m_camera_projection, .Position = m_camera_position}; - scene_camera[current_frame_index].SetData(&ubo_camera_data, sizeof(Contracts::UBOCameraLayout)); - - /* - * Uploading Infinite Grid - */ + if (m_upload_once_per_frame_count > 0) { - auto& vertex_storage = *m_GridSBVertex; - vertex_storage[current_frame_index].SetData(m_grid_vertices); - - auto& index_storage = *m_GridSBIndex; - index_storage[current_frame_index].SetData(m_grid_indices); - - auto& draw_data_storage = *m_GridSBDrawData; - draw_data_storage[current_frame_index].SetData(m_grid_drawData); + /* + * Uploading Cubemap + */ + { + auto& vertex_buffer = *cubemapSBVertex; + auto& index_buffer = *cubemapSBIndex; + auto& draw_data_buffer = *cubemapSBDrawData; - m_infinite_grid_indirect_buffer[current_frame_index]->SetData(m_grid_indirect_commmand); + vertex_buffer[current_frame_index].SetData(m_cubemap_vertex_data); + index_buffer[current_frame_index].SetData(m_cubemap_index_data); + draw_data_buffer[current_frame_index].SetData(m_cubmap_draw_data); + s_cubemap_indirect_buffer[current_frame_index]->SetData(m_cubemap_indirect_commmand); + } + /* + * Uploading Infinite Grid + */ + { + auto& vertex_storage = *m_GridSBVertex; + auto& index_storage = *m_GridSBIndex; + auto& draw_data_storage = *m_GridSBDrawData; + + vertex_storage[current_frame_index].SetData(m_grid_vertices); + index_storage[current_frame_index].SetData(m_grid_indices); + draw_data_storage[current_frame_index].SetData(m_grid_drawData); + m_infinite_grid_indirect_buffer[current_frame_index]->SetData(m_grid_indirect_commmand); + } + + s_cubemap_pass->MarkDirty(); m_infinite_grid_pass->MarkDirty(); + + --m_upload_once_per_frame_count; } const auto& sceneNodeMeshMap = scene_data->SceneNodeMeshMap; @@ -247,38 +302,31 @@ namespace ZEngine::Rendering::Renderers m_final_color_output_pass->MarkDirty(); } - void SceneRenderer::EndScene() + void SceneRenderer::EndScene(Buffers::CommandBuffer* const command_buffer, uint32_t current_frame_index) { - uint32_t current_frame_index = Renderers::GraphicRenderer::GetRendererInformation().CurrentFrameIndex; + command_buffer->BeginRenderPass(s_cubemap_pass); + command_buffer->BindDescriptorSets(current_frame_index); + command_buffer->DrawIndirect(s_cubemap_indirect_buffer[current_frame_index]); + command_buffer->EndRenderPass(); + + // command_buffer->BeginRenderPass(m_infinite_grid_pass); + // command_buffer->BindDescriptorSets(current_frame_index); + // command_buffer->DrawIndirect(m_infinite_grid_indirect_buffer[current_frame_index]); + // command_buffer->EndRenderPass(); + + // command_buffer->BeginRenderPass(m_final_color_output_pass); + // command_buffer->BindDescriptorSets(current_frame_index); + // command_buffer->DrawIndirect(m_indirect_buffer[current_frame_index]); + // command_buffer->EndRenderPass(); - auto command_buffer = m_command_pool->GetCurrentCommmandBuffer(); - /* - * Drawing the scene... - */ - command_buffer->Begin(); - { - command_buffer->BeginRenderPass(m_infinite_grid_pass); - command_buffer->BindDescriptorSets(current_frame_index); - command_buffer->DrawIndirect(m_infinite_grid_indirect_buffer[current_frame_index]); - command_buffer->EndRenderPass(); - - command_buffer->BeginRenderPass(m_final_color_output_pass); - command_buffer->BindDescriptorSets(current_frame_index); - command_buffer->DrawIndirect(m_indirect_buffer[current_frame_index]); - command_buffer->EndRenderPass(); - } command_buffer->End(); - command_buffer->Submit(); } void SceneRenderer::SetViewportSize(uint32_t width, uint32_t height) { + s_cubemap_pass->ResizeRenderTarget(width, height); m_infinite_grid_pass->ResizeRenderTarget(width, height); m_final_color_output_pass->ResizeRenderTarget(width, height); } - void SceneRenderer::Tick() - { - m_command_pool->Tick(); - } } // namespace ZEngine::Rendering::Renderers diff --git a/ZEngine/src/Shader.cpp b/ZEngine/src/Shader.cpp index 689ec6c0..9baf09e6 100644 --- a/ZEngine/src/Shader.cpp +++ b/ZEngine/src/Shader.cpp @@ -29,6 +29,7 @@ namespace ZEngine::Rendering::Shaders CreateModule(); CreateDescriptorSetLayouts(); + CreatePushConstantRange(); } Shader::~Shader() @@ -85,6 +86,28 @@ namespace ZEngine::Rendering::Shaders m_layout_binding_specification_map[set].emplace_back(LayoutBindingSpecification{ .Set = set, .Binding = binding, .Name = SB_resource.name, .DescriptorType = DescriptorType::STORAGE_BUFFER, .Flags = ShaderStageFlags::VERTEX}); } + + for (const auto& pushConstant_resource : vertex_resources.push_constant_buffers) + { + const spirv_cross::SPIRType& type = spirv_compiler->get_type(pushConstant_resource.base_type_id); + uint32_t struct_offset = !m_push_constant_specification_collection.empty() ? m_push_constant_specification_collection.back().Offset : 0; + + if (type.basetype == spirv_cross::SPIRType::Struct) + { + uint32_t struct_total_size = 0; + for (uint32_t i = 0; i < type.member_types.size(); ++i) + { + uint32_t memberSize = spirv_compiler->get_declared_struct_member_size(type, i); + struct_total_size += memberSize; + } + m_push_constant_specification_collection.emplace_back( + PushConstantSpecification{.Name = pushConstant_resource.name, .Size = struct_total_size, .Offset = struct_offset, .Flags = ShaderStageFlags::VERTEX}); + /* + * We update the offset for next iteration + */ + struct_offset = struct_total_size; + } + } } /* * Fragment Shader processing @@ -126,6 +149,28 @@ namespace ZEngine::Rendering::Shaders .Set = set, .Binding = binding, .Name = SB_resource.name, .DescriptorType = DescriptorType::STORAGE_BUFFER, .Flags = ShaderStageFlags::FRAGMENT}); } + for (const auto& pushConstant_resource : fragment_resources.push_constant_buffers) + { + const spirv_cross::SPIRType& type = spirv_compiler->get_type(pushConstant_resource.base_type_id); + uint32_t struct_offset = !m_push_constant_specification_collection.empty() ? m_push_constant_specification_collection.back().Offset : 0; + + if (type.basetype == spirv_cross::SPIRType::Struct) + { + uint32_t struct_total_size = 0; + for (uint32_t i = 0; i < type.member_types.size(); ++i) + { + uint32_t memberSize = spirv_compiler->get_declared_struct_member_size(type, i); + struct_total_size += memberSize; + } + m_push_constant_specification_collection.emplace_back( + PushConstantSpecification{.Name = pushConstant_resource.name, .Size = struct_total_size, .Offset = struct_offset, .Flags = ShaderStageFlags::FRAGMENT}); + /* + * We update the offset for next iteration + */ + struct_offset = struct_total_size; + } + } + for (const auto& SI_resource : fragment_resources.sampled_images) { uint32_t set = spirv_compiler->get_decoration(SI_resource.id, spv::DecorationDescriptorSet); @@ -198,6 +243,21 @@ namespace ZEngine::Rendering::Shaders return m_descriptor_set_map; } + std::map>& Shader::GetDescriptorSetMap() + { + return m_descriptor_set_map; + } + + VkDescriptorPool Shader::GetDescriptorPool() const + { + return m_descriptor_pool; + } + + const std::vector& Shader::GetPushConstants() const + { + return m_push_constant_collection; + } + void Shader::Dispose() { auto device = Hardwares::VulkanDevice::GetNativeDeviceHandle(); @@ -302,7 +362,7 @@ namespace ZEngine::Rendering::Shaders VkDescriptorPoolCreateInfo pool_info = {}; pool_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; pool_info.flags = VK_DESCRIPTOR_POOL_CREATE_UPDATE_AFTER_BIND_BIT; - pool_info.maxSets = renderer_info.FrameCount * pool_size_collection.size(); + pool_info.maxSets = renderer_info.FrameCount * pool_size_collection.size() * m_specification.OverloadMaxSet; pool_info.poolSizeCount = pool_size_collection.size(); pool_info.pPoolSizes = pool_size_collection.data(); @@ -331,6 +391,17 @@ namespace ZEngine::Rendering::Shaders } } + void Shader::CreatePushConstantRange() + { + for (const auto& push_constant_spec : m_push_constant_specification_collection) + { + m_push_constant_collection.emplace_back(VkPushConstantRange{ + .stageFlags = ShaderStageFlagsMap[VALUE_FROM_SPEC_MAP(push_constant_spec.Flags)], .offset = push_constant_spec.Offset, .size = push_constant_spec.Size}); + } + m_push_constant_specification_collection.clear(); + m_push_constant_specification_collection.shrink_to_fit(); + } + Ref Shader::Create(Specifications::ShaderSpecification&& spec) { return CreateRef(std::move(spec)); diff --git a/ZEngine/src/Swapchain.cpp b/ZEngine/src/Swapchain.cpp index e85af25f..e49a0980 100644 --- a/ZEngine/src/Swapchain.cpp +++ b/ZEngine/src/Swapchain.cpp @@ -41,13 +41,22 @@ namespace ZEngine::Rendering m_attachment = Renderers::RenderPasses::Attachment::Create(attachment_specification); Create(); - AcquireNextImage(); } Swapchain::~Swapchain() { Dispose(); m_attachment->Dispose(); + + m_acquired_semaphore_collection.clear(); + m_acquired_semaphore_collection.shrink_to_fit(); + + m_render_complete_semaphore_collection.clear(); + m_render_complete_semaphore_collection.shrink_to_fit(); + + m_frame_signal_fence_collection.clear(); + m_frame_signal_fence_collection.shrink_to_fit(); + if (!m_is_surface_from_device) { auto instance = Hardwares::VulkanDevice::GetNativeInstanceHandle(); @@ -60,47 +69,38 @@ namespace ZEngine::Rendering { Dispose(); Create(); - AcquireNextImage(); } - void Swapchain::AcquireNextImage() + void Swapchain::Present() { - auto frame_count = (int32_t) m_image_collection.size(); - m_current_frame_index = (m_current_frame_index + 1) % frame_count; + Primitives::Fence* signal_fence = m_frame_signal_fence_collection[m_current_frame_index].get(); + signal_fence->Wait(UINT64_MAX); + signal_fence->Reset(); Primitives::Semaphore* signal_semaphore = m_acquired_semaphore_collection[m_current_frame_index].get(); - ZENGINE_VALIDATE_ASSERT(signal_semaphore->GetState() != Primitives::SemaphoreState::Submitted, "") - m_last_frame_image_index = m_current_frame_image_index; - - VkResult acquire_image_result = vkAcquireNextImageKHR( - Hardwares::VulkanDevice::GetNativeDeviceHandle(), m_handle, UINT64_MAX, signal_semaphore->GetHandle(), VK_NULL_HANDLE, &m_current_frame_image_index); - + uint32_t frame_index{UINT32_MAX}; + VkResult acquire_image_result = + vkAcquireNextImageKHR(Hardwares::VulkanDevice::GetNativeDeviceHandle(), m_handle, UINT64_MAX, signal_semaphore->GetHandle(), VK_NULL_HANDLE, &frame_index); signal_semaphore->SetState(Primitives::SemaphoreState::Submitted); - } - void Swapchain::Present() - { - m_wait_semaphore_collection.clear(); - m_wait_semaphore_collection.shrink_to_fit(); - - auto command_pool_collection = Hardwares::VulkanDevice::GetAllCommandPools(m_identifier); - for (auto& command_pool : command_pool_collection) + if (acquire_image_result == VK_SUBOPTIMAL_KHR || acquire_image_result == VK_ERROR_OUT_OF_DATE_KHR) { - auto semaphore_collection = command_pool->GetAllWaitSemaphoreCollection(); - std::copy(std::begin(semaphore_collection), std::end(semaphore_collection), std::back_inserter(m_wait_semaphore_collection)); + Resize(); + return; } - Primitives::Semaphore* signal_semaphore = m_acquired_semaphore_collection[m_current_frame_index].get(); - if (signal_semaphore->GetState() == Primitives::SemaphoreState::Submitted) + Primitives::Semaphore* render_complete_semaphore = m_render_complete_semaphore_collection[m_current_frame_index].get(); + if (!Hardwares::VulkanDevice::Present(m_handle, &frame_index, signal_semaphore, render_complete_semaphore, signal_fence)) { - m_wait_semaphore_collection.emplace_back(signal_semaphore); + Resize(); + return; } - Hardwares::VulkanDevice::Present(m_handle, &m_current_frame_image_index, m_wait_semaphore_collection); - - AcquireNextImage(); + auto frame_count = (int32_t) m_image_collection.size(); + m_current_frame_index = (m_current_frame_index + 1) % frame_count; + Hardwares::VulkanDevice::SetCurrentFrameIndex(m_current_frame_index); } uint32_t Swapchain::GetMinImageCount() const @@ -247,41 +247,32 @@ namespace ZEngine::Rendering m_image_collection.resize(image_count); m_image_view_collection.resize(image_count); m_framebuffer_collection.resize(image_count); - m_acquired_semaphore_collection.resize(image_count); + m_acquired_semaphore_collection.resize(image_count, nullptr); + m_render_complete_semaphore_collection.resize(image_count, nullptr); + m_frame_signal_fence_collection.resize(image_count, nullptr); ZENGINE_VALIDATE_ASSERT(vkGetSwapchainImagesKHR(native_device, m_handle, &image_count, m_image_collection.data()) == VK_SUCCESS, "Failed to get Images from Swapchain") /*Transition Image from Undefined to Present_src*/ - auto image_memory_barrier_collection = std::vector{m_image_collection.size()}; - - for (int i = 0; i < image_memory_barrier_collection.size(); ++i) + auto command_buffer = Hardwares::VulkanDevice::BeginInstantCommandBuffer(Rendering::QueueType::GRAPHIC_QUEUE); { - image_memory_barrier_collection[i].sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; - image_memory_barrier_collection[i].oldLayout = VK_IMAGE_LAYOUT_UNDEFINED; - image_memory_barrier_collection[i].newLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; - image_memory_barrier_collection[i].srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; - image_memory_barrier_collection[i].dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; - image_memory_barrier_collection[i].image = m_image_collection[i]; - image_memory_barrier_collection[i].subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - image_memory_barrier_collection[i].subresourceRange.baseMipLevel = 0; - image_memory_barrier_collection[i].subresourceRange.levelCount = 1; - image_memory_barrier_collection[i].subresourceRange.baseArrayLayer = 0; - image_memory_barrier_collection[i].subresourceRange.layerCount = 1; - image_memory_barrier_collection[i].srcAccessMask = 0; // No need for any source access - image_memory_barrier_collection[i].dstAccessMask = VK_ACCESS_MEMORY_READ_BIT; + for (int i = 0; i < m_image_collection.size(); ++i) + { + Specifications::ImageMemoryBarrierSpecification barrier_spec = {}; + barrier_spec.ImageHandle = m_image_collection[i]; + barrier_spec.OldLayout = Specifications::ImageLayout::UNDEFINED; + barrier_spec.NewLayout = Specifications::ImageLayout::PRESENT_SRC; + barrier_spec.ImageAspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + barrier_spec.SourceAccessMask = 0; + barrier_spec.DestinationAccessMask = VK_ACCESS_MEMORY_READ_BIT; + barrier_spec.SourceStageMask = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT; + barrier_spec.DestinationStageMask = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT; + barrier_spec.LayerCount = 1; + + Primitives::ImageMemoryBarrier barrier{barrier_spec}; + command_buffer->TransitionImageLayout(barrier); + } } - auto command_buffer = Hardwares::VulkanDevice::BeginInstantCommandBuffer(Rendering::QueueType::GRAPHIC_QUEUE); - vkCmdPipelineBarrier( - command_buffer->GetHandle(), - VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, - VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, - 0, - 0, - nullptr, - 0, - nullptr, - image_memory_barrier_collection.size(), - image_memory_barrier_collection.data()); Hardwares::VulkanDevice::EndInstantCommandBuffer(command_buffer); for (size_t i = 0; i < m_image_view_collection.size(); ++i) @@ -301,6 +292,16 @@ namespace ZEngine::Rendering { m_acquired_semaphore_collection[i] = CreateRef(); } + + for (size_t i = 0; i < m_render_complete_semaphore_collection.size(); i++) + { + m_render_complete_semaphore_collection[i] = CreateRef(); + } + + for (size_t i = 0; i < m_frame_signal_fence_collection.size(); i++) + { + m_frame_signal_fence_collection[i] = CreateRef(true); + } } void Swapchain::Dispose() @@ -324,14 +325,18 @@ namespace ZEngine::Rendering m_image_view_collection.clear(); m_image_collection.clear(); m_framebuffer_collection.clear(); - m_acquired_semaphore_collection.clear(); m_image_view_collection.shrink_to_fit(); m_image_collection.shrink_to_fit(); m_framebuffer_collection.shrink_to_fit(); - m_acquired_semaphore_collection.shrink_to_fit(); - Hardwares::VulkanDevice::QueueWaitAll(); + m_acquired_semaphore_collection.clear(); + m_render_complete_semaphore_collection.clear(); + m_frame_signal_fence_collection.clear(); + + m_acquired_semaphore_collection.shrink_to_fit(); + m_render_complete_semaphore_collection.shrink_to_fit(); + m_frame_signal_fence_collection.shrink_to_fit(); auto device = Hardwares::VulkanDevice::GetNativeDeviceHandle(); ZENGINE_DESTROY_VULKAN_HANDLE(device, vkDestroySwapchainKHR, m_handle, nullptr) diff --git a/ZEngine/src/Texture2D.cpp b/ZEngine/src/Texture2D.cpp index 4ac1cd35..40d39165 100644 --- a/ZEngine/src/Texture2D.cpp +++ b/ZEngine/src/Texture2D.cpp @@ -1,14 +1,17 @@ #include +#include #include #include #include -#include +#include #define STB_IMAGE_IMPLEMENTATION #ifdef __GNUC__ #define STBI_NO_SIMD #endif #include +#include +#include namespace ZEngine::Rendering::Textures { @@ -39,51 +42,58 @@ namespace ZEngine::Rendering::Textures if (!image_data) { - ZENGINE_CORE_ERROR("Failed to load texture file : %s", filename.data()) + ZENGINE_CORE_ERROR("Failed to load texture file : {0}", filename.data()) return Create(1, 1, 0, 0, 0, 0); } - /* * post processing to convert the image from RGB to RBGA */ - stbi_uc* image_data_rgba = nullptr; - if (channel == STBI_rgb) - { - image_data_rgba = (stbi_uc*) malloc(width * height * 4); - if (image_data_rgba) - { - // Copy RGB data and set alpha channel to 255 (fully opaque) - for (int i = 0; i < width * height; i++) - { - memcpy(image_data_rgba + i * 4, image_data + i * 3, 3); // Copy RGB channels - image_data_rgba[i * 4 + 3] = 255; // Alpha channel (fully opaque) - } - channel = STBI_rgb_alpha; - stbi_image_free(image_data); - } - else - { - ZENGINE_CORE_ERROR("Failed to load texture file : %s", filename.data()) - return CreateRef(); - } - } - else - { - image_data_rgba = image_data; - } + channel = (channel == STBI_rgb) ? STBI_rgb_alpha : channel; + std::vector output_buffer(width * height * channel); + stbir_resize_uint8(image_data, width, height, 0, output_buffer.data(), width, height, 0, channel); + stbi_image_free(image_data); Specifications::TextureSpecification spec = {}; spec.Width = width; spec.Height = height; - spec.BytePerPixel = channel; spec.Format = Specifications::ImageFormat::R8G8B8A8_SRGB; - spec.Data = image_data_rgba; + spec.BytePerPixel = Specifications::BytePerChannelMap[VALUE_FROM_SPEC_MAP(spec.Format)]; + spec.Data = output_buffer.data(); auto texture = Create(spec); - stbi_image_free(image_data_rgba); return texture; } + Ref Texture2D::ReadCubemap(std::string_view filename) + { + stbi_set_flip_vertically_on_load(1); + + int width = 0, height = 0, channel = 0; + const float* image_data = stbi_loadf(filename.data(), &width, &height, &channel, 4); + /* + * post processing to convert the image from RGB to RBGA + */ + channel = (channel == STBI_rgb) ? STBI_rgb_alpha : channel; + std::vector output_buffer(width * height * channel); + stbir_resize_float(image_data, width, height, 0, output_buffer.data(), width, height, 0, channel); + stbi_image_free((void*) image_data); + + Buffers::Bitmap in = {width, height, 4, Buffers::BitmapFormat::FLOAT, output_buffer.data()}; + Buffers::Bitmap vertical_cross = Buffers::Bitmap::EquirectangularMapToVerticalCross(in); + Buffers::Bitmap cubemap = Buffers::Bitmap::VerticalCrossToCubemap(vertical_cross); + + Specifications::TextureSpecification cubemap_texture_spec = {}; + cubemap_texture_spec.IsCubemap = true; + cubemap_texture_spec.Width = cubemap.Width; + cubemap_texture_spec.Height = cubemap.Height; + cubemap_texture_spec.Format = Specifications::ImageFormat::R32G32B32A32_SFLOAT; + cubemap_texture_spec.BytePerPixel = Specifications::BytePerChannelMap[VALUE_FROM_SPEC_MAP(cubemap_texture_spec.Format)]; + cubemap_texture_spec.Data = cubemap.Buffer.data(); + cubemap_texture_spec.LayerCount = 6; + + return Create(cubemap_texture_spec); + } + std::future> Texture2D::ReadAsync(std::string_view filename) { co_return Read(filename); @@ -114,6 +124,7 @@ namespace ZEngine::Rendering::Textures spec.Width = width; spec.Height = height; spec.Format = Specifications::ImageFormat::R8G8B8A8_SRGB; + spec.BytePerPixel = Specifications::BytePerChannelMap[VALUE_FROM_SPEC_MAP(spec.Format)]; spec.Data = image_data; return Create(spec); } @@ -129,6 +140,7 @@ namespace ZEngine::Rendering::Textures spec.Width = width; spec.Height = height; spec.Format = Specifications::ImageFormat::R8G8B8A8_SRGB; + spec.BytePerPixel = Specifications::BytePerChannelMap[VALUE_FROM_SPEC_MAP(spec.Format)]; spec.Data = image_data; return Create(spec); } @@ -146,15 +158,13 @@ namespace ZEngine::Rendering::Textures void Texture2D::FillAsVulkanImage(Ref& texture, const Specifications::TextureSpecification& spec) { texture->m_byte_per_pixel = spec.BytePerPixel; - texture->m_buffer_size = spec.Width * spec.Height * spec.BytePerPixel; + texture->m_buffer_size = spec.Width * spec.Height * spec.BytePerPixel * spec.LayerCount; texture->m_width = spec.Width; texture->m_height = spec.Height; - auto device = Hardwares::VulkanDevice::GetNativeDeviceHandle(); - Hardwares::BufferView staging_buffer = Hardwares::VulkanDevice::CreateBuffer( - texture->m_buffer_size, - VK_BUFFER_USAGE_TRANSFER_SRC_BIT, - VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT); + auto device = Hardwares::VulkanDevice::GetNativeDeviceHandle(); + Hardwares::BufferView staging_buffer = + Hardwares::VulkanDevice::CreateBuffer(texture->m_buffer_size, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT); Hardwares::VulkanDevice::MapAndCopyToMemory(staging_buffer, texture->m_buffer_size, spec.Data); @@ -165,17 +175,35 @@ namespace ZEngine::Rendering::Textures uint32_t image_usage_attachment = (spec.Format == Specifications::ImageFormat::DEPTH_STENCIL_FROM_DEVICE) ? VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT : VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; - auto image_format = (spec.Format == Specifications::ImageFormat::DEPTH_STENCIL_FROM_DEVICE) ? Hardwares::VulkanDevice::FindDepthFormat() - : Specifications::ImageFormatMap[static_cast(spec.Format)]; - texture->m_image_2d_buffer = CreateRef( - texture->m_width, - texture->m_height, image_format, - VkImageUsageFlagBits(image_usage_attachment | transfert_bit | sampled_bit), - VkImageAspectFlagBits(image_aspect)); + VkFormat image_format = (spec.Format == Specifications::ImageFormat::DEPTH_STENCIL_FROM_DEVICE) ? Hardwares::VulkanDevice::FindDepthFormat() + : Specifications::ImageFormatMap[static_cast(spec.Format)]; + + if (spec.IsCubemap) + { + texture->m_image_2d_buffer = CreateRef( + texture->m_width, + texture->m_height, + image_format, + VkImageUsageFlagBits(image_usage_attachment | transfert_bit | sampled_bit), + VkImageAspectFlagBits(image_aspect), + spec.LayerCount, + VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT); + } + else + { + texture->m_image_2d_buffer = CreateRef( + texture->m_width, + texture->m_height, + image_format, + VkImageUsageFlagBits(image_usage_attachment | transfert_bit | sampled_bit), + VkImageAspectFlagBits(image_aspect), + spec.LayerCount); + } if (spec.PerformTransition) { - /*Transition Image from VK_IMAGE_LAYOUT_UNDEFINED to VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL OR VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL and Copy buffer to image*/ + /*Transition Image from VK_IMAGE_LAYOUT_UNDEFINED to VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL OR VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL and Copy buffer to + * image*/ { auto image_handle = texture->m_image_2d_buffer->GetHandle(); auto& image_buffer = texture->m_image_2d_buffer->GetBuffer(); @@ -188,6 +216,7 @@ namespace ZEngine::Rendering::Textures barrier_spec_0.DestinationAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; barrier_spec_0.SourceStageMask = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT; barrier_spec_0.DestinationStageMask = VK_PIPELINE_STAGE_TRANSFER_BIT; + barrier_spec_0.LayerCount = spec.LayerCount; Primitives::ImageMemoryBarrier barrier_0{barrier_spec_0}; Specifications::ImageMemoryBarrierSpecification barrier_spec_1 = {}; @@ -200,16 +229,14 @@ namespace ZEngine::Rendering::Textures barrier_spec_1.DestinationAccessMask = VK_ACCESS_SHADER_READ_BIT; barrier_spec_1.SourceStageMask = VK_PIPELINE_STAGE_TRANSFER_BIT; barrier_spec_1.DestinationStageMask = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT; + barrier_spec_1.LayerCount = spec.LayerCount; Primitives::ImageMemoryBarrier barrier_1{barrier_spec_1}; - Hardwares::VulkanDevice::CopyBufferToImage( - Rendering::QueueType::GRAPHIC_QUEUE, - staging_buffer, - image_buffer, - texture->m_width, - texture->m_height, - 0, - std::vector{barrier_0, barrier_1}); + auto command_buffer = Hardwares::VulkanDevice::BeginInstantCommandBuffer(Rendering::QueueType::GRAPHIC_QUEUE); + command_buffer->TransitionImageLayout(barrier_0); + command_buffer->CopyBufferToImage(staging_buffer, image_buffer, texture->m_width, texture->m_height, spec.LayerCount, barrier_0.GetHandle().newLayout); + command_buffer->TransitionImageLayout(barrier_1); + Hardwares::VulkanDevice::EndInstantCommandBuffer(command_buffer); } } diff --git a/ZEngine/src/VulkanDevice.cpp b/ZEngine/src/VulkanDevice.cpp index f1cebdb1..8d13eaf3 100644 --- a/ZEngine/src/VulkanDevice.cpp +++ b/ZEngine/src/VulkanDevice.cpp @@ -9,6 +9,7 @@ #include #include +#include using namespace std::chrono_literals; @@ -22,6 +23,7 @@ namespace ZEngine::Hardwares VkSurfaceKHR VulkanDevice::m_surface = VK_NULL_HANDLE; uint32_t VulkanDevice::m_graphic_family_index = 0; uint32_t VulkanDevice::m_transfer_family_index = 0; + uint32_t VulkanDevice::s_current_frame_index = UINT32_MAX; std::map VulkanDevice::m_queue_map = {}; VkDevice VulkanDevice::m_logical_device = VK_NULL_HANDLE; VkPhysicalDevice VulkanDevice::m_physical_device = VK_NULL_HANDLE; @@ -29,8 +31,8 @@ namespace ZEngine::Hardwares VkPhysicalDeviceFeatures VulkanDevice::m_physical_device_feature = {}; VkPhysicalDeviceMemoryProperties VulkanDevice::m_physical_device_memory_properties = {}; VkDebugUtilsMessengerEXT VulkanDevice::m_debug_messenger = VK_NULL_HANDLE; - std::queue VulkanDevice::s_dirty_buffer_queue = {}; - std::queue VulkanDevice::s_dirty_buffer_image_queue = {}; + std::deque VulkanDevice::s_dirty_buffer_queue = {}; + std::deque VulkanDevice::s_dirty_buffer_image_queue = {}; std::vector> VulkanDevice::m_command_pool_collection = {}; PFN_vkCreateDebugUtilsMessengerEXT VulkanDevice::__createDebugMessengerPtr = nullptr; PFN_vkDestroyDebugUtilsMessengerEXT VulkanDevice::__destroyDebugMessengerPtr = nullptr; @@ -40,70 +42,19 @@ namespace ZEngine::Hardwares VkPresentModeKHR VulkanDevice::m_present_mode = {}; VkDescriptorPool VulkanDevice::m_descriptor_pool = VK_NULL_HANDLE; VmaAllocator VulkanDevice::s_vma_allocator = nullptr; - std::map> VulkanDevice::m_in_device_command_pool_map; - std::mutex VulkanDevice::m_queue_mutex; - std::mutex VulkanDevice::m_command_pool_mutex; - std::mutex VulkanDevice::m_deletion_queue_mutex; - std::condition_variable VulkanDevice::m_cond; - std::atomic_bool VulkanDevice::m_is_executing_instant_command = false; - std::mutex VulkanDevice::m_instant_command_mutex; - std::queue VulkanDevice::s_dirty_resource_collection; - std::jthread VulkanDevice::s_cleanup_thread; - std::condition_variable VulkanDevice::s_cleanup_cond; - std::chrono::seconds VulkanDevice::s_cleanup_timeout = 15s; - std::atomic_bool VulkanDevice::s_cleanup_thread_shutdown = false; + std::map> VulkanDevice::m_in_device_command_pool_map = {}; + std::mutex VulkanDevice::m_queue_mutex = {}; + std::mutex VulkanDevice::m_command_pool_mutex = {}; + std::mutex VulkanDevice::m_deletion_queue_mutex = {}; + std::mutex VulkanDevice::m_frame_value_mutex = {}; + std::condition_variable VulkanDevice::m_cond = {}; + std::atomic_bool VulkanDevice::m_is_executing_instant_command = false; + std::mutex VulkanDevice::m_instant_command_mutex = {}; + std::map>> VulkanDevice::s_queue_submit_info_pool = {}; + std::deque VulkanDevice::s_dirty_resource_collection = {}; void VulkanDevice::Initialize(GLFWwindow* const native_window, const std::vector& additional_extension_layer_name_collection) { - s_cleanup_thread = std::jthread([] { - while (true) - { - std::unique_lock lock(m_deletion_queue_mutex); - s_cleanup_cond.wait(lock, [] { - return (!s_dirty_resource_collection.empty()) || (!s_dirty_buffer_queue.empty()) || (!s_dirty_buffer_image_queue.empty()); - }); - - auto current_time = std::chrono::steady_clock::now(); - - if (!(s_cleanup_thread_shutdown.load())) - { - if (!s_dirty_resource_collection.empty()) - { - __cleanupDirtyResource(current_time); - } - - if (!s_dirty_buffer_queue.empty()) - { - __cleanupBufferDirtyResource(current_time); - } - - if (!s_dirty_buffer_image_queue.empty()) - { - __cleanupBufferImageDirtyResource(current_time); - } - - continue; - } - - while (!s_dirty_resource_collection.empty()) - { - __cleanupDirtyResource(current_time); - } - - while (!s_dirty_buffer_queue.empty()) - { - __cleanupBufferDirtyResource(current_time); - } - - while (!s_dirty_buffer_image_queue.empty()) - { - __cleanupBufferImageDirtyResource(current_time); - } - - break; - } - }); - /*Create Vulkan Instance*/ VkApplicationInfo app_info = {}; app_info.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO; @@ -403,37 +354,41 @@ namespace ZEngine::Hardwares { QueueWaitAll(); - m_command_pool_collection.clear(); - m_command_pool_collection.shrink_to_fit(); - m_in_device_command_pool_map.clear(); + while (!s_dirty_buffer_queue.empty()) + { + __cleanupBufferDirtyResource(); + } + + while (!s_dirty_buffer_image_queue.empty()) + { + __cleanupBufferImageDirtyResource(); + } + while (!s_dirty_resource_collection.empty()) + { + __cleanupDirtyResource(); + } + + m_in_device_command_pool_map.clear(); + s_queue_submit_info_pool.clear(); ZENGINE_DESTROY_VULKAN_HANDLE(m_vulkan_instance, vkDestroySurfaceKHR, m_surface, nullptr) } void VulkanDevice::Dispose() { - { - s_cleanup_thread_shutdown.exchange(true); - s_cleanup_timeout = -1s; - if (s_cleanup_thread.joinable()) - { - s_cleanup_thread.join(); - } - } - vmaDestroyAllocator(s_vma_allocator); if (__destroyDebugMessengerPtr) { ZENGINE_DESTROY_VULKAN_HANDLE(m_vulkan_instance, __destroyDebugMessengerPtr, m_debug_messenger, nullptr) + __destroyDebugMessengerPtr = nullptr; + __createDebugMessengerPtr = nullptr; } vkDestroyDevice(m_logical_device, nullptr); vkDestroyInstance(m_vulkan_instance, nullptr); m_logical_device = VK_NULL_HANDLE; m_vulkan_instance = VK_NULL_HANDLE; - __destroyDebugMessengerPtr = nullptr; - __createDebugMessengerPtr = nullptr; } VkDevice VulkanDevice::GetNativeDeviceHandle() @@ -446,68 +401,88 @@ namespace ZEngine::Hardwares return m_vulkan_instance; } - void VulkanDevice::QueueSubmit( + bool VulkanDevice::QueueSubmit( Rendering::QueueType queue_type, - const VkPipelineStageFlags wait_stage_flage, - VkCommandBuffer const buffer_handle, + const VkPipelineStageFlags wait_stage_flag, + Rendering::Buffers::CommandBuffer& command_buffer, + bool as_instant_submission, Rendering::Primitives::Semaphore* const wait_semaphore, - Rendering::Primitives::Semaphore* const signal_semaphore, - Rendering::Primitives::Fence* const signal_fence) + Rendering::Primitives::Semaphore* const, + Rendering::Primitives::Fence* const) { std::lock_guard lock(m_queue_mutex); - if (!buffer_handle) + if (!command_buffer.GetHandle()) { ZENGINE_CORE_ERROR("Command Buffer handle is null, Failed to submit to Queue") - return; + return false; } - if (wait_semaphore) + QueueSubmitInfo q = {.Buffer = command_buffer}; + q.DestinationStageMask = wait_stage_flag; + q.Type = queue_type; + q.IsImmediate = as_instant_submission; + + if (!q.IsImmediate) { - ZENGINE_VALIDATE_ASSERT(wait_semaphore->GetState() != Rendering::Primitives::SemaphoreState::Idle, "Wait semaphore is in an idle state and will never be signaled") + s_queue_submit_info_pool[queue_type][wait_stage_flag].push_back(std::move(q)); + return true; } - if (signal_semaphore) + Ref signal_semaphore = CreateRef(); + Ref signal_fence = CreateRef(); + + ZENGINE_VALIDATE_ASSERT(signal_semaphore->GetState() != Rendering::Primitives::SemaphoreState::Submitted, "Signal semaphore is already in a signaled state.") + ZENGINE_VALIDATE_ASSERT(signal_fence->GetState() != Rendering::Primitives::FenceState::Submitted, "Signal fence is already in a signaled state.") + + std::array signal_semaphore_collection = {signal_semaphore->GetHandle()}; + VkCommandBuffer buffer_handle = q.Buffer.GetHandle(); + VkSubmitInfo submit_info = {}; + submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; + submit_info.pNext = nullptr; + submit_info.waitSemaphoreCount = 0; + submit_info.pWaitSemaphores = nullptr; + submit_info.signalSemaphoreCount = 1; + submit_info.pSignalSemaphores = signal_semaphore_collection.data(); + submit_info.pWaitDstStageMask = &wait_stage_flag; + submit_info.commandBufferCount = 1; + submit_info.pCommandBuffers = &buffer_handle; + + ZENGINE_VALIDATE_ASSERT(vkQueueSubmit(GetQueue(queue_type).Handle, 1, &submit_info, signal_fence->GetHandle()) == VK_SUCCESS, "Failed to submit queue") + q.Buffer.SetSignalFence(signal_fence); + q.Buffer.SetSignalSemaphore(signal_semaphore); + q.Buffer.SetState(Rendering::Buffers::Pending); + + signal_fence->SetState(FenceState::Submitted); + signal_semaphore->SetState(SemaphoreState::Submitted); + + if (!signal_fence->Wait()) { - ZENGINE_VALIDATE_ASSERT(signal_semaphore->GetState() != Rendering::Primitives::SemaphoreState::Submitted, "Signal semaphore is already in a signaled state.") + ZENGINE_CORE_WARN("Failed to wait for Command buffer's Fence, due to timeout") } - if (signal_fence) + if (q.Buffer.Completed()) { - ZENGINE_VALIDATE_ASSERT(signal_fence->GetState() != Rendering::Primitives::FenceState::Submitted, "Signal fence is already in a signaled state.") + signal_fence->Reset(); } - std::array wait_semaphore_collection = {wait_semaphore ? wait_semaphore->GetHandle() : nullptr}; - std::array signal_semaphore_collection = {signal_semaphore ? signal_semaphore->GetHandle() : nullptr}; + q.Buffer.SetState(Rendering::Buffers::Invalid); - VkSubmitInfo submit_info = {}; - submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; - submit_info.pNext = nullptr; - submit_info.waitSemaphoreCount = wait_semaphore != nullptr ? 1 : 0; - submit_info.pWaitSemaphores = wait_semaphore != nullptr ? wait_semaphore_collection.data() : nullptr; - submit_info.signalSemaphoreCount = signal_semaphore != nullptr ? 1 : 0; - submit_info.pSignalSemaphores = signal_semaphore != nullptr ? signal_semaphore_collection.data() : nullptr; - submit_info.pWaitDstStageMask = &wait_stage_flage; - submit_info.commandBufferCount = 1; - submit_info.pCommandBuffers = &buffer_handle; - - auto fence_ptr = signal_fence ? signal_fence->GetHandle() : nullptr; - ZENGINE_VALIDATE_ASSERT(vkQueueSubmit(GetQueue(queue_type).Handle, 1, &submit_info, fence_ptr) == VK_SUCCESS, "Failed to submit queue") - - if (wait_semaphore) - { - wait_semaphore->SetState(SemaphoreState::Idle); - } + return true; + } - if (signal_semaphore) + void VulkanDevice::SetCurrentFrameIndex(uint32_t frame) + { { - signal_semaphore->SetState(SemaphoreState::Submitted); + std::unique_lock lock(m_frame_value_mutex); + s_current_frame_index = frame; } + } - if (signal_fence) - { - signal_fence->SetState(FenceState::Submitted); - } + uint32_t VulkanDevice::GetCurrentFrameIndex() + { + std::unique_lock lock(m_frame_value_mutex); + return s_current_frame_index; } void VulkanDevice::EnqueueForDeletion(Rendering::DeviceResourceType resource_type, void* const handle) @@ -516,8 +491,14 @@ namespace ZEngine::Hardwares std::lock_guard lock(m_deletion_queue_mutex); if (handle) { - s_dirty_resource_collection.emplace(DirtyResource{.Handle = handle, .MarkedAsDirtyTime = std::chrono::steady_clock::now(), .Type = resource_type}); - s_cleanup_cond.notify_one(); + auto find_it = std::find_if(s_dirty_resource_collection.begin(), s_dirty_resource_collection.end(), [handle](const DirtyResource& res) { + return res.Handle == handle; + }); + + if (find_it == std::end(s_dirty_resource_collection)) + { + s_dirty_resource_collection.push_back(DirtyResource{.FrameIndex = s_current_frame_index, .Handle = handle, .MarkedAsDirtyTime = std::chrono::steady_clock::now(), .Type = resource_type}); + } } } } @@ -528,10 +509,18 @@ namespace ZEngine::Hardwares std::lock_guard lock(m_deletion_queue_mutex); if (resource.Handle) { + resource.FrameIndex = s_current_frame_index; resource.Type = resource_type; resource.MarkedAsDirtyTime = std::chrono::steady_clock::now(); - s_dirty_resource_collection.emplace(resource); - s_cleanup_cond.notify_one(); + + auto find_it = std::find_if(s_dirty_resource_collection.begin(), s_dirty_resource_collection.end(), [&resource](const DirtyResource& res) { + return res.Handle == resource.Handle; + }); + + if (find_it == std::end(s_dirty_resource_collection)) + { + s_dirty_resource_collection.push_back(resource); + } } } } @@ -541,9 +530,9 @@ namespace ZEngine::Hardwares { std::lock_guard lock(m_deletion_queue_mutex); + buffer.FrameIndex = s_current_frame_index; buffer.MarkedAsDirtyTime = std::chrono::steady_clock::now(); - s_dirty_buffer_queue.push(buffer); - s_cleanup_cond.notify_one(); + s_dirty_buffer_queue.push_back(buffer); } } @@ -552,53 +541,182 @@ namespace ZEngine::Hardwares { std::lock_guard lock(m_deletion_queue_mutex); + buffer.FrameIndex = s_current_frame_index; buffer.MarkedAsDirtyTime = std::chrono::steady_clock::now(); - s_dirty_buffer_image_queue.push(buffer); - s_cleanup_cond.notify_one(); + s_dirty_buffer_image_queue.push_back(buffer); } } - void VulkanDevice::Present(VkSwapchainKHR swapchain, uint32_t* frame_image_index, const std::vector& wait_semaphore_collection) + bool VulkanDevice::Present( + VkSwapchainKHR swapchain, + uint32_t* frame_image_index, + Rendering::Primitives::Semaphore* const wait_semaphore, + Rendering::Primitives::Semaphore* const render_complete_semaphore, + Rendering::Primitives::Fence* const frame_fence) { - std::vector wait_semaphore_handle_collection(wait_semaphore_collection.size(), VK_NULL_HANDLE); - for (uint32_t i = 0; i < wait_semaphore_handle_collection.size(); ++i) + std::vector wait_semaphore_handle_collection = {wait_semaphore->GetHandle()}; + std::vector signal_semaphore_handle_collection = {render_complete_semaphore->GetHandle()}; + + /* + * Submitting pending Command Buffer + */ + std::vector queue_submission_collection = {}; + auto& pending_cmb_collection = s_queue_submit_info_pool[Rendering::QueueType::GRAPHIC_QUEUE][VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT]; + + std::vector buffers = {}; + std::transform(pending_cmb_collection.begin(), pending_cmb_collection.end(), std::back_inserter(buffers), [&](const QueueSubmitInfo& info) { + info.Buffer.SetSignalSemaphore(render_complete_semaphore); + info.Buffer.SetSignalFence(frame_fence); + return info.Buffer.GetHandle(); + }); + + ZENGINE_VALIDATE_ASSERT(render_complete_semaphore->GetState() != Rendering::Primitives::SemaphoreState::Submitted, "Signal semaphore is already in a signaled state.") + ZENGINE_VALIDATE_ASSERT(frame_fence->GetState() != Rendering::Primitives::FenceState::Submitted, "Signal fence is already in a signaled state.") + + VkPipelineStageFlags stage_flag = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; + VkSubmitInfo submit_info = {}; + submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; + submit_info.pNext = nullptr; + submit_info.waitSemaphoreCount = wait_semaphore_handle_collection.size(); + submit_info.pWaitSemaphores = wait_semaphore_handle_collection.data(); + submit_info.signalSemaphoreCount = signal_semaphore_handle_collection.size(); + submit_info.pSignalSemaphores = signal_semaphore_handle_collection.data(); + submit_info.pWaitDstStageMask = &(stage_flag); + submit_info.commandBufferCount = buffers.size(); + submit_info.pCommandBuffers = buffers.data(); + + ZENGINE_VALIDATE_ASSERT( + vkQueueSubmit(GetQueue(Rendering::QueueType::GRAPHIC_QUEUE).Handle, 1, &(submit_info), frame_fence->GetHandle()) == VK_SUCCESS, "Failed to submit queue") + + for (auto&& pending_cmb : pending_cmb_collection) { - wait_semaphore_handle_collection[i] = wait_semaphore_collection[i]->GetHandle(); + pending_cmb.Buffer.SetState(Rendering::Buffers::Pending); } + frame_fence->SetState(FenceState::Submitted); + render_complete_semaphore->SetState(SemaphoreState::Submitted); + VkPresentInfoKHR present_info = {}; present_info.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR; - present_info.waitSemaphoreCount = wait_semaphore_handle_collection.size(); - present_info.pWaitSemaphores = wait_semaphore_handle_collection.data(); + present_info.waitSemaphoreCount = signal_semaphore_handle_collection.size(); + present_info.pWaitSemaphores = signal_semaphore_handle_collection.data(); present_info.swapchainCount = 1; present_info.pSwapchains = &swapchain; present_info.pImageIndices = frame_image_index; VkResult present_result = vkQueuePresentKHR(m_queue_map[Rendering::QueueType::GRAPHIC_QUEUE], &present_info); + if (present_result == VK_ERROR_OUT_OF_DATE_KHR || present_result == VK_SUBOPTIMAL_KHR) + { + return false; + } + ZENGINE_VALIDATE_ASSERT(present_result == VK_SUCCESS, "Failed to present current frame on Window") - for (uint32_t i = 0; i < wait_semaphore_collection.size(); ++i) + wait_semaphore->SetState(Rendering::Primitives::SemaphoreState::Idle); + render_complete_semaphore->SetState(Rendering::Primitives::SemaphoreState::Idle); + + /* + * Cleanup current Frame allocated resource + */ + s_queue_submit_info_pool.clear(); + + for (auto it = s_dirty_resource_collection.begin(); it != s_dirty_resource_collection.end();) { - wait_semaphore_collection[i]->SetState(Rendering::Primitives::SemaphoreState::Idle); + if (it->FrameIndex == *frame_image_index) + { + switch (it->Type) + { + case Rendering::DeviceResourceType::SAMPLER: + vkDestroySampler(m_logical_device, reinterpret_cast(it->Handle), nullptr); + break; + case Rendering::DeviceResourceType::FRAMEBUFFER: + vkDestroyFramebuffer(m_logical_device, reinterpret_cast(it->Handle), nullptr); + break; + case Rendering::DeviceResourceType::IMAGEVIEW: + vkDestroyImageView(m_logical_device, reinterpret_cast(it->Handle), nullptr); + break; + case Rendering::DeviceResourceType::IMAGE: + vkDestroyImage(m_logical_device, reinterpret_cast(it->Handle), nullptr); + break; + case Rendering::DeviceResourceType::RENDERPASS: + vkDestroyRenderPass(m_logical_device, reinterpret_cast(it->Handle), nullptr); + break; + case Rendering::DeviceResourceType::BUFFERMEMORY: + vkFreeMemory(m_logical_device, reinterpret_cast(it->Handle), nullptr); + break; + case Rendering::DeviceResourceType::BUFFER: + vkDestroyBuffer(m_logical_device, reinterpret_cast(it->Handle), nullptr); + break; + case Rendering::DeviceResourceType::PIPELINE_LAYOUT: + vkDestroyPipelineLayout(m_logical_device, reinterpret_cast(it->Handle), nullptr); + break; + case Rendering::DeviceResourceType::PIPELINE: + vkDestroyPipeline(m_logical_device, reinterpret_cast(it->Handle), nullptr); + break; + case Rendering::DeviceResourceType::DESCRIPTORSETLAYOUT: + vkDestroyDescriptorSetLayout(m_logical_device, reinterpret_cast(it->Handle), nullptr); + break; + case Rendering::DeviceResourceType::DESCRIPTORPOOL: + vkDestroyDescriptorPool(m_logical_device, reinterpret_cast(it->Handle), nullptr); + break; + case Rendering::DeviceResourceType::SEMAPHORE: + vkDestroySemaphore(m_logical_device, reinterpret_cast(it->Handle), nullptr); + break; + case Rendering::DeviceResourceType::FENCE: + vkDestroyFence(m_logical_device, reinterpret_cast(it->Handle), nullptr); + break; + case Rendering::DeviceResourceType::DESCRIPTORSET: + { + auto ds = reinterpret_cast(it->Handle); + vkFreeDescriptorSets(m_logical_device, reinterpret_cast(it->Data1), 1, &ds); + break; + } + } + + it = s_dirty_resource_collection.erase(it); + } + else + { + it = std::next(it); + } } - } - Rendering::Pools::CommandPool* VulkanDevice::CreateCommandPool(Rendering::QueueType queue_type, uint64_t swapchain_id, bool present_on_swapchain) - { - return m_command_pool_collection.emplace_back(CreateRef(queue_type, swapchain_id, present_on_swapchain)).get(); - } + for (auto it = s_dirty_buffer_queue.begin(); it != s_dirty_buffer_queue.end();) + { + if (it->FrameIndex == *frame_image_index) + { + vmaDestroyBuffer(s_vma_allocator, it->Handle, it->Allocation); + it = s_dirty_buffer_queue.erase(it); + } + else + { + it = std::next(it); + } + } - std::vector> VulkanDevice::GetAllCommandPools(uint64_t swapchain_id) - { - std::vector> command_pool_collection; - for (auto& command_pool : m_command_pool_collection) + for (auto it = s_dirty_buffer_image_queue.begin(); it != s_dirty_buffer_image_queue.end();) { - if (command_pool->GetSwapchainParent() == swapchain_id) + if (it->FrameIndex == *frame_image_index) + { + vkDestroyImageView(m_logical_device, it->ViewHandle, nullptr); + vkDestroySampler(m_logical_device, it->Sampler, nullptr); + vmaDestroyImage(s_vma_allocator, it->Handle, it->Allocation); + it = s_dirty_buffer_image_queue.erase(it); + } + else { - command_pool_collection.push_back(command_pool); + it = std::next(it); } } - return command_pool_collection; + + return true; + } + + Rendering::Pools::CommandPool* VulkanDevice::CreateCommandPool(Rendering::QueueType queue_type, uint64_t swapchain_id, bool present_on_swapchain) + { + auto pool = CreateRef(queue_type, swapchain_id, present_on_swapchain); + m_command_pool_collection.push_back(std::move(pool)); + return m_command_pool_collection.back().get(); } void VulkanDevice::DisposeCommandPool(const Rendering::Pools::CommandPool* pool) @@ -639,6 +757,11 @@ namespace ZEngine::Hardwares return QueueView{.FamilyIndex = queue_family_index, .Handle = m_queue_map[type]}; } + Rendering::Pools::CommandPool* VulkanDevice::GetCommandPool(Rendering::QueueType queue_type) + { + return m_in_device_command_pool_map[queue_type].get(); + } + void VulkanDevice::QueueWaitAll() { QueueWait(Rendering::QueueType::TRANSFER_QUEUE); @@ -679,89 +802,76 @@ namespace ZEngine::Hardwares return VK_FALSE; } - void VulkanDevice::__cleanupDirtyResource(std::chrono::steady_clock::time_point time) + void VulkanDevice::__cleanupDirtyResource() { - auto& resource = s_dirty_resource_collection.front(); - auto elapsed_time = std::chrono::duration_cast(time - resource.MarkedAsDirtyTime); - if (elapsed_time >= s_cleanup_timeout) + auto& resource = s_dirty_resource_collection.front(); + switch (resource.Type) { - switch (resource.Type) + case Rendering::DeviceResourceType::SAMPLER: + vkDestroySampler(m_logical_device, reinterpret_cast(resource.Handle), nullptr); + break; + case Rendering::DeviceResourceType::FRAMEBUFFER: + vkDestroyFramebuffer(m_logical_device, reinterpret_cast(resource.Handle), nullptr); + break; + case Rendering::DeviceResourceType::IMAGEVIEW: + vkDestroyImageView(m_logical_device, reinterpret_cast(resource.Handle), nullptr); + break; + case Rendering::DeviceResourceType::IMAGE: + vkDestroyImage(m_logical_device, reinterpret_cast(resource.Handle), nullptr); + break; + case Rendering::DeviceResourceType::RENDERPASS: + vkDestroyRenderPass(m_logical_device, reinterpret_cast(resource.Handle), nullptr); + break; + case Rendering::DeviceResourceType::BUFFERMEMORY: + vkFreeMemory(m_logical_device, reinterpret_cast(resource.Handle), nullptr); + break; + case Rendering::DeviceResourceType::BUFFER: + vkDestroyBuffer(m_logical_device, reinterpret_cast(resource.Handle), nullptr); + break; + case Rendering::DeviceResourceType::PIPELINE_LAYOUT: + vkDestroyPipelineLayout(m_logical_device, reinterpret_cast(resource.Handle), nullptr); + break; + case Rendering::DeviceResourceType::PIPELINE: + vkDestroyPipeline(m_logical_device, reinterpret_cast(resource.Handle), nullptr); + break; + case Rendering::DeviceResourceType::DESCRIPTORSETLAYOUT: + vkDestroyDescriptorSetLayout(m_logical_device, reinterpret_cast(resource.Handle), nullptr); + break; + case Rendering::DeviceResourceType::DESCRIPTORPOOL: + vkDestroyDescriptorPool(m_logical_device, reinterpret_cast(resource.Handle), nullptr); + break; + case Rendering::DeviceResourceType::SEMAPHORE: + vkDestroySemaphore(m_logical_device, reinterpret_cast(resource.Handle), nullptr); + break; + case Rendering::DeviceResourceType::FENCE: + vkDestroyFence(m_logical_device, reinterpret_cast(resource.Handle), nullptr); + break; + case Rendering::DeviceResourceType::DESCRIPTORSET: { - case Rendering::DeviceResourceType::SAMPLER: - vkDestroySampler(m_logical_device, reinterpret_cast(resource.Handle), nullptr); - break; - case Rendering::DeviceResourceType::FRAMEBUFFER: - vkDestroyFramebuffer(m_logical_device, reinterpret_cast(resource.Handle), nullptr); - break; - case Rendering::DeviceResourceType::IMAGEVIEW: - vkDestroyImageView(m_logical_device, reinterpret_cast(resource.Handle), nullptr); - break; - case Rendering::DeviceResourceType::IMAGE: - vkDestroyImage(m_logical_device, reinterpret_cast(resource.Handle), nullptr); - break; - case Rendering::DeviceResourceType::RENDERPASS: - vkDestroyRenderPass(m_logical_device, reinterpret_cast(resource.Handle), nullptr); - break; - case Rendering::DeviceResourceType::BUFFERMEMORY: - vkFreeMemory(m_logical_device, reinterpret_cast(resource.Handle), nullptr); - break; - case Rendering::DeviceResourceType::BUFFER: - vkDestroyBuffer(m_logical_device, reinterpret_cast(resource.Handle), nullptr); - break; - case Rendering::DeviceResourceType::PIPELINE_LAYOUT: - vkDestroyPipelineLayout(m_logical_device, reinterpret_cast(resource.Handle), nullptr); - break; - case Rendering::DeviceResourceType::PIPELINE: - vkDestroyPipeline(m_logical_device, reinterpret_cast(resource.Handle), nullptr); - break; - case Rendering::DeviceResourceType::DESCRIPTORSETLAYOUT: - vkDestroyDescriptorSetLayout(m_logical_device, reinterpret_cast(resource.Handle), nullptr); - break; - case Rendering::DeviceResourceType::DESCRIPTORPOOL: - vkDestroyDescriptorPool(m_logical_device, reinterpret_cast(resource.Handle), nullptr); - break; - case Rendering::DeviceResourceType::SEMAPHORE: - vkDestroySemaphore(m_logical_device, reinterpret_cast(resource.Handle), nullptr); - break; - case Rendering::DeviceResourceType::FENCE: - vkDestroyFence(m_logical_device, reinterpret_cast(resource.Handle), nullptr); - break; - case Rendering::DeviceResourceType::DESCRIPTORSET: - { - auto ds = reinterpret_cast(resource.Handle); - vkFreeDescriptorSets(m_logical_device, reinterpret_cast(resource.Data1), 1, &ds); - break; - } + auto ds = reinterpret_cast(resource.Handle); + vkFreeDescriptorSets(m_logical_device, reinterpret_cast(resource.Data1), 1, &ds); + break; } - - s_dirty_resource_collection.pop(); } + + s_dirty_resource_collection.pop_front(); } - void VulkanDevice::__cleanupBufferDirtyResource(std::chrono::steady_clock::time_point time) + void VulkanDevice::__cleanupBufferDirtyResource() { - auto& resource = s_dirty_buffer_queue.front(); - auto elapsed_time = std::chrono::duration_cast(time - resource.MarkedAsDirtyTime); - if (elapsed_time >= s_cleanup_timeout) - { - vmaDestroyBuffer(s_vma_allocator, resource.Handle, resource.Allocation); - - s_dirty_buffer_queue.pop(); - } + auto& resource = s_dirty_buffer_queue.front(); + vmaDestroyBuffer(s_vma_allocator, resource.Handle, resource.Allocation); + s_dirty_buffer_queue.pop_front(); } - void VulkanDevice::__cleanupBufferImageDirtyResource(std::chrono::steady_clock::time_point time) + void VulkanDevice::__cleanupBufferImageDirtyResource() { - auto& resource = s_dirty_buffer_image_queue.front(); - auto elapsed_time = std::chrono::duration_cast(time - resource.MarkedAsDirtyTime); - if (elapsed_time >= s_cleanup_timeout) - { - vkDestroyImageView(m_logical_device, resource.ViewHandle, nullptr); - vkDestroySampler(m_logical_device, resource.Sampler, nullptr); - vmaDestroyImage(s_vma_allocator, resource.Handle, resource.Allocation); + auto& resource = s_dirty_buffer_image_queue.front(); + vkDestroyImageView(m_logical_device, resource.ViewHandle, nullptr); + vkDestroySampler(m_logical_device, resource.Sampler, nullptr); + vmaDestroyImage(s_vma_allocator, resource.Handle, resource.Allocation); - s_dirty_buffer_image_queue.pop(); - } + s_dirty_buffer_image_queue.pop_front(); } VkPhysicalDevice VulkanDevice::GetNativePhysicalDeviceHandle() @@ -785,7 +895,7 @@ namespace ZEngine::Hardwares if (data) { ZENGINE_VALIDATE_ASSERT(vmaMapMemory(s_vma_allocator, buffer.Allocation, &mapped_memory) == VK_SUCCESS, "Failed to map memory") - std::memcpy(mapped_memory, data, data_size); + ZENGINE_VALIDATE_ASSERT(Helpers::secure_memcpy(mapped_memory, data_size, data, data_size) == Helpers::MEMORY_OP_SUCCESS, "Failed to perform memory copy operation") vmaUnmapMemory(s_vma_allocator, buffer.Allocation); } } @@ -834,18 +944,20 @@ namespace ZEngine::Hardwares VkSharingMode image_sharing_mode, VkSampleCountFlagBits image_sample_count, VkMemoryPropertyFlags requested_properties, - VkImageAspectFlagBits image_aspect_flag) + VkImageAspectFlagBits image_aspect_flag, + uint32_t layer_count, + VkImageCreateFlags image_create_flag_bit) { BufferImage buffer_image = {}; VkImageCreateInfo image_create_info = {}; image_create_info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; - image_create_info.flags = 0; + image_create_info.flags = image_create_flag_bit; image_create_info.imageType = image_type; image_create_info.extent.width = width; image_create_info.extent.height = height; image_create_info.extent.depth = 1; image_create_info.mipLevels = 1; - image_create_info.arrayLayers = 1; + image_create_info.arrayLayers = layer_count; image_create_info.format = image_format; image_create_info.tiling = image_tiling; image_create_info.initialLayout = image_initial_layout; @@ -861,7 +973,7 @@ namespace ZEngine::Hardwares vmaCreateImage(s_vma_allocator, &image_create_info, &allocation_create_info, &(buffer_image.Handle), &(buffer_image.Allocation), nullptr) == VK_SUCCESS, "Failed to create buffer"); - buffer_image.ViewHandle = CreateImageView(buffer_image.Handle, image_format, image_aspect_flag); + buffer_image.ViewHandle = CreateImageView(buffer_image.Handle, image_format, image_aspect_flag, layer_count); buffer_image.Sampler = CreateImageSampler(); return buffer_image; } @@ -924,14 +1036,16 @@ namespace ZEngine::Hardwares {VK_FORMAT_D32_SFLOAT, VK_FORMAT_D32_SFLOAT_S8_UINT, VK_FORMAT_D24_UNORM_S8_UINT}, VK_IMAGE_TILING_OPTIMAL, VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT); } - VkImageView VulkanDevice::CreateImageView(VkImage image, VkFormat image_format, VkImageAspectFlagBits image_aspect_flag) + VkImageView VulkanDevice::CreateImageView(VkImage image, VkFormat image_format, VkImageAspectFlagBits image_aspect_flag, uint32_t layer_count) { VkImageView image_view{VK_NULL_HANDLE}; VkImageViewCreateInfo image_view_create_info = {}; image_view_create_info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; image_view_create_info.format = image_format; image_view_create_info.image = image; - image_view_create_info.viewType = VK_IMAGE_VIEW_TYPE_2D; + image_view_create_info.viewType = (image_format == VK_FORMAT_R32G32B32A32_SFLOAT) + ? VK_IMAGE_VIEW_TYPE_CUBE + : VK_IMAGE_VIEW_TYPE_2D; // ToDo : We should better abstract the creation of ImageView.. introduce Image2DBufferSpecification ? image_view_create_info.components.r = VK_COMPONENT_SWIZZLE_R; image_view_create_info.components.g = VK_COMPONENT_SWIZZLE_G; image_view_create_info.components.b = VK_COMPONENT_SWIZZLE_B; @@ -940,58 +1054,13 @@ namespace ZEngine::Hardwares image_view_create_info.subresourceRange.baseMipLevel = 0; image_view_create_info.subresourceRange.levelCount = 1; image_view_create_info.subresourceRange.baseArrayLayer = 0; - image_view_create_info.subresourceRange.layerCount = 1; + image_view_create_info.subresourceRange.layerCount = layer_count; ZENGINE_VALIDATE_ASSERT(vkCreateImageView(m_logical_device, &image_view_create_info, nullptr, &image_view) == VK_SUCCESS, "Failed to create image view") return image_view; } - void VulkanDevice::CopyBufferToImage( - const Rendering::QueueType& queue_type, - const BufferView& source, - BufferImage& destination, - uint32_t width, - uint32_t height, - uint32_t start_copy_after_barrier_index, - const std::vector& memory_barriers) - { - VkBufferImageCopy buffer_image_copy = {}; - buffer_image_copy.bufferOffset = 0; - buffer_image_copy.bufferRowLength = 0; - buffer_image_copy.bufferImageHeight = 0; - buffer_image_copy.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - buffer_image_copy.imageSubresource.mipLevel = 0; - buffer_image_copy.imageSubresource.baseArrayLayer = 0; - buffer_image_copy.imageSubresource.layerCount = 1; - buffer_image_copy.imageOffset = {0, 0, 0}; - buffer_image_copy.imageExtent = {width, height, 1}; - - auto command_buffer = BeginInstantCommandBuffer(queue_type); - { - if (!memory_barriers.empty()) - { - for (uint32_t i = 0; i < memory_barriers.size(); ++i) - { - const auto& barrier_handle = memory_barriers[i].GetHandle(); - const auto& barrier_spec = memory_barriers[i].GetSpecification(); - vkCmdPipelineBarrier( - command_buffer->GetHandle(), barrier_spec.SourceStageMask, barrier_spec.DestinationStageMask, 0, 0, nullptr, 0, nullptr, 1, &barrier_handle); - - if (i == start_copy_after_barrier_index) - { - vkCmdCopyBufferToImage(command_buffer->GetHandle(), source.Handle, destination.Handle, barrier_handle.newLayout, 1, &buffer_image_copy); - } - } - } - else - { - vkCmdCopyBufferToImage(command_buffer->GetHandle(), source.Handle, destination.Handle, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &buffer_image_copy); - } - } - EndInstantCommandBuffer(command_buffer); - } - VkFramebuffer VulkanDevice::CreateFramebuffer( const std::vector& attachments, const VkRenderPass& render_pass, @@ -1014,7 +1083,7 @@ namespace ZEngine::Hardwares return framebuffer; } - Rendering::Buffers::CommandBuffer* VulkanDevice::BeginInstantCommandBuffer(Rendering::QueueType type) + Ref VulkanDevice::BeginInstantCommandBuffer(Rendering::QueueType type) { std::unique_lock lock(m_instant_command_mutex); m_cond.wait(lock, [] { @@ -1022,18 +1091,17 @@ namespace ZEngine::Hardwares }); m_is_executing_instant_command = true; - auto command_buffer = m_in_device_command_pool_map[type]->GetCurrentCommmandBuffer(); + auto command_buffer = m_in_device_command_pool_map[type]->GetOneTimeCommmandBuffer(); command_buffer->Begin(); return command_buffer; } - void VulkanDevice::EndInstantCommandBuffer(Rendering::Buffers::CommandBuffer* const command) + void VulkanDevice::EndInstantCommandBuffer(Ref& command) { ZENGINE_VALIDATE_ASSERT(command != nullptr, "Command buffer can't be null") command->End(); - command->Submit(); - command->WaitForExecution(); + command->Submit(true); { std::unique_lock lock(m_instant_command_mutex); m_is_executing_instant_command = false; diff --git a/ZEngine/tests/bitmap_test.cpp b/ZEngine/tests/bitmap_test.cpp new file mode 100644 index 00000000..2a6f13b5 --- /dev/null +++ b/ZEngine/tests/bitmap_test.cpp @@ -0,0 +1,93 @@ +#include +#include +#include +#include + +#include +#include + +using namespace ZEngine::Rendering::Buffers; + + +constexpr float epsilon = 1e-2; + +static bool approximatelyEqual(float a, float b, float epsilon) +{ + return fabs(a - b) <= epsilon * fmax(1.0f, fmax(fabs(a), fabs(b))); +} + +TEST(BitmapTest, GetOrSetPixel) +{ + + glm::vec4 p(0.5, 0.5, 0.8, 0.0); + + Bitmap bitmap(100, 100, 3, BitmapFormat::UNSIGNED_BYTE); + bitmap.SetPixel(0, 0, p); + + auto pp = bitmap.GetPixel(0, 0); + + EXPECT_TRUE(approximatelyEqual(pp.x, p.x, epsilon)); + EXPECT_TRUE(approximatelyEqual(pp.y, p.y, epsilon)); + EXPECT_TRUE(approximatelyEqual(pp.z, p.z, epsilon)); +} + +TEST(BitmapTest, TestVerticalCross) +{ + int width = 0, height = 0, channel = 0; + const float* image_data = stbi_loadf("piazza_bologni_1k.hdr", &width, &height, &channel, 3); + + Bitmap in = {width, height, channel, BitmapFormat::FLOAT, image_data}; + Bitmap vertical_cross = Bitmap::EquirectangularMapToVerticalCross(in); + Bitmap cubemap = Bitmap::VerticalCrossToCubemap(vertical_cross); + stbi_image_free((void*) image_data); + + stbi_write_hdr("screenshot.hdr", vertical_cross.Width, vertical_cross.Height, vertical_cross.Channel, (const float*) vertical_cross.Buffer.data()); + stbi_write_hdr("screenshot2.hdr", cubemap.Width, cubemap.Height, cubemap.Channel, (const float*) cubemap.Buffer.data()); + + auto current_path = std::filesystem::current_path().string(); + + EXPECT_TRUE(std::filesystem::exists(current_path + "/screenshot.hdr")); + EXPECT_TRUE(std::filesystem::exists(current_path + "/screenshot2.hdr")); +} + + +TEST(BitmapTest, TestVerticalCross2) +{ + int width = 0, height = 0, channel = 0; + const float* image_data = stbi_loadf("piazza_bologni_1k.hdr", &width, &height, &channel, 3); + + std::vector image_buffer_32bit = {}; + + if (image_data) + { + const int total_pixel = width * height; + image_buffer_32bit.resize(total_pixel * 4); + + auto source_buffer_24 = image_data; + auto destination_buffer_32 = image_buffer_32bit.data(); + for (int i = 0; i != total_pixel; i++) + { + // Copy RGB channels from source to destination + *destination_buffer_32++ = *source_buffer_24++; + *destination_buffer_32++ = *source_buffer_24++; + *destination_buffer_32++ = *source_buffer_24++; + + // Set alpha channel to 1.0f + *destination_buffer_32++ = 1.0f; + } + } + stbi_image_free((void*) image_data); + + Bitmap in = {width, height, 4, BitmapFormat::FLOAT, image_buffer_32bit.data()}; + Bitmap vertical_cross = Bitmap::EquirectangularMapToVerticalCross(in); + Bitmap cubemap = Bitmap::VerticalCrossToCubemap(vertical_cross); + + stbi_write_hdr("screenshot3.hdr", vertical_cross.Width, vertical_cross.Height, vertical_cross.Channel, (const float*) vertical_cross.Buffer.data()); + stbi_write_hdr("screenshot4.hdr", cubemap.Width, cubemap.Height, cubemap.Channel, (const float*) cubemap.Buffer.data()); + stbi_write_png("screenshot5.png", cubemap.Width, cubemap.Height, cubemap.Channel, cubemap.Buffer.data(), 0); + + auto current_path = std::filesystem::current_path().string(); + + EXPECT_TRUE(std::filesystem::exists(current_path + "/screenshot3.hdr")); + EXPECT_TRUE(std::filesystem::exists(current_path + "/screenshot4.hdr")); +} \ No newline at end of file