From 96c7ab9f99acb4eda94dcf0039296c3935093881 Mon Sep 17 00:00:00 2001 From: Henrik Nyhammer Date: Fri, 19 Jan 2024 22:26:26 +0100 Subject: [PATCH 01/17] Renamed some stuff and improved the usage of transferring --- Demos/Demo1/Demo.cpp | 113 ++++-------------- .../Graphics/Vulkan/BufferUtilities.cpp | 24 +++- .../Graphics/Vulkan/GraphicsContext.cpp | 26 ++-- .../Graphics/Vulkan/GraphicsContext.hpp | 10 +- 4 files changed, 59 insertions(+), 114 deletions(-) diff --git a/Demos/Demo1/Demo.cpp b/Demos/Demo1/Demo.cpp index caa11a9..9a17af2 100644 --- a/Demos/Demo1/Demo.cpp +++ b/Demos/Demo1/Demo.cpp @@ -18,80 +18,6 @@ static void updateTitle() { ); } -class ProjectileBehavior : public BehaviorBase { -private: - Vector3 m_velocity; - -public: - ProjectileBehavior( - const EntityContext& context, - float movementSpeed - ) : BehaviorBase(context), - m_velocity(Vector3s::up * movementSpeed) - {} - - virtual void act() override { - auto& transform = m_context.getTransform(); - - transform.translate(m_velocity * DeltaTime::get()); - - if (transform.getTranslation().getLength() > 10.0f) { - m_context.destroyEntity(); - } - } -}; - -class PlayerBehavior : public BehaviorBase { -private: - float m_movementSpeed; - Degrees m_turnSpeed; - -public: - PlayerBehavior( - const EntityContext& context, - float movementSpeed, - Degrees turnSpeed - ) : BehaviorBase(context), - m_movementSpeed(movementSpeed), - m_turnSpeed(turnSpeed) - {} - - virtual void act() override { - auto velocity = Vector3{ - .x = static_cast(Keyboard::isKeyHeld(KeyboardKey::keyD) - Keyboard::isKeyHeld(KeyboardKey::keyA)), - .y = static_cast(Keyboard::isKeyHeld(KeyboardKey::keyW) - Keyboard::isKeyHeld(KeyboardKey::keyS)) - }; - - float rotation = Keyboard::isKeyHeld(KeyboardKey::keyQ) - Keyboard::isKeyHeld(KeyboardKey::keyE); - - auto& transform = m_context.getTransform(); - - transform.rotate(Quaternion::createRotation(Vector3s::forward, rotation * m_turnSpeed * DeltaTime::get())); - transform.translate(velocity.toNormalized() * m_movementSpeed * DeltaTime::get()); - - if (Keyboard::isKeyPressed(KeyboardKey::keySpace)) { - CurrentScene::createEntity( - EntityConfig{ - .transformConfig = TransformConfig{ - .translation = transform.getTranslation(), - .rotation = transform.getRotation(), - .scale = Vector3{ .x = 0.5f, .y = 0.5f, .z = 1.0f } - }, - .appearanceConfig = AppearanceConfig{ - .meshIndex = 1, - .color = ColorRgbs::magenta - }, - .behaviorFactory = BehaviorFactory::createFactoryFor(3.0f) - } - ); - } - - if (Keyboard::isKeyPressed(KeyboardKey::keyDelete)) { - m_context.destroyEntity(); - } - } -}; - class CameraBehavior : public BehaviorBase { private: float m_movementSpeed; @@ -129,7 +55,7 @@ int main() { AppConfig{ .windowConfig = WindowConfig{ .size = WindowSize{ - .width = 800, + .width = 800, .height = 600 }, .resizable = true @@ -138,24 +64,14 @@ int main() { .meshes = std::vector{ { .vertices = std::vector{ - Vertex{ .position = Vector3{ .x = -0.5f, .y = -0.5f, .z = 0.0f } }, - Vertex{ .position = Vector3{ .x = 0.5f, .y = -0.5f, .z = 0.0f } }, - Vertex{ .position = Vector3{ .x = 0.5f, .y = 0.5f, .z = 0.0f } }, - Vertex{ .position = Vector3{ .x = -0.5f, .y = 0.5f, .z = 0.0f } } - }, - .faces = std::vector{ - Face{ .indices = { 0, 1, 2 } }, - Face{ .indices = { 0, 2, 3 } } - } - }, - { - .vertices = std::vector{ - Vertex{ .position = Vector3{ .x = -0.5f, .y = -0.5f, .z = 0.0f } }, - Vertex{ .position = Vector3{ .x = 0.5f, .y = -0.5f, .z = 0.0f } }, - Vertex{ .position = Vector3{ .x = 0.0f, .y = 0.5f, .z = 0.0f } } + Vertex{.position = Vector3{.x = -0.5f, .y = -0.5f, .z = 0.0f } }, + Vertex{.position = Vector3{.x = 0.5f, .y = -0.5f, .z = 0.0f } }, + Vertex{.position = Vector3{.x = 0.5f, .y = 0.5f, .z = 0.0f } }, + Vertex{.position = Vector3{.x = -0.5f, .y = 0.5f, .z = 0.0f } } }, .faces = std::vector{ - Face{ .indices = { 0, 1, 2 } } + Face{.indices = { 0, 1, 2 } }, + Face{.indices = { 0, 2, 3 } } } } } @@ -172,9 +88,20 @@ int main() { { .appearanceConfig = AppearanceConfig{ .meshIndex = 0, - .color = ColorRgbs::green + .color = ColorRgb::createFromNonlinearSrgbColorCode(0xFF7700) + } + }, + { + .transformConfig = TransformConfig{ + .translation = Vector3{ + .x = -1.5f, + .z = 1.5f + } }, - .behaviorFactory = BehaviorFactory::createFactoryFor(10.0f, 270.0_deg) + .appearanceConfig = AppearanceConfig{ + .meshIndex = 0, + .color = ColorRgbs::magenta + } } }, .entityCreatedCallback = [](EntityId) { updateTitle(); }, diff --git a/Miracle/src/Miracle/Infrastructure/Graphics/Vulkan/BufferUtilities.cpp b/Miracle/src/Miracle/Infrastructure/Graphics/Vulkan/BufferUtilities.cpp index f393011..768e3d2 100644 --- a/Miracle/src/Miracle/Infrastructure/Graphics/Vulkan/BufferUtilities.cpp +++ b/Miracle/src/Miracle/Infrastructure/Graphics/Vulkan/BufferUtilities.cpp @@ -1,5 +1,7 @@ #include "BufferUtilities.hpp" +#include + namespace Miracle::Infrastructure::Graphics::Vulkan { std::pair BufferUtilities::createStagingBuffer( GraphicsContext& m_context, @@ -33,14 +35,30 @@ namespace Miracle::Infrastructure::Graphics::Vulkan { vk::BufferUsageFlags usage, vk::DeviceSize bufferSize ) { + auto& deviceInfo = m_context.getDeviceInfo(); + + bool useSharingMode = deviceInfo.queueFamilyIndices.graphicsFamilyIndex.value() + != deviceInfo.queueFamilyIndices.transferFamilyIndex.value(); + + auto queueFamilyIndexArray = std::array{ + deviceInfo.queueFamilyIndices.graphicsFamilyIndex.value(), + deviceInfo.queueFamilyIndices.transferFamilyIndex.value() + }; + return m_context.getAllocator().createBuffer( vk::BufferCreateInfo{ .flags = {}, .size = bufferSize, .usage = usage | vk::BufferUsageFlagBits::eTransferDst, - .sharingMode = vk::SharingMode::eExclusive, - .queueFamilyIndexCount = 0, - .pQueueFamilyIndices = nullptr + .sharingMode = useSharingMode + ? vk::SharingMode::eConcurrent + : vk::SharingMode::eExclusive, + .queueFamilyIndexCount = useSharingMode + ? static_cast(queueFamilyIndexArray.size()) + : 0, + .pQueueFamilyIndices = useSharingMode + ? queueFamilyIndexArray.data() + : nullptr }, vma::AllocationCreateInfo{ .flags = vma::AllocationCreateFlagBits::eDedicatedMemory, diff --git a/Miracle/src/Miracle/Infrastructure/Graphics/Vulkan/GraphicsContext.cpp b/Miracle/src/Miracle/Infrastructure/Graphics/Vulkan/GraphicsContext.cpp index 0db109e..839293c 100644 --- a/Miracle/src/Miracle/Infrastructure/Graphics/Vulkan/GraphicsContext.cpp +++ b/Miracle/src/Miracle/Infrastructure/Graphics/Vulkan/GraphicsContext.cpp @@ -51,14 +51,14 @@ namespace Miracle::Infrastructure::Graphics::Vulkan { .front() ); - m_graphicsCommandBufferSubmittedFences.reserve(m_graphicsCommandBuffers.size()); - m_graphicsCommandExecutionCompletedSemaphores.reserve(m_graphicsCommandBuffers.size()); - m_graphicsCommandPresentCompletedSemaphores.reserve(m_graphicsCommandBuffers.size()); + m_renderingCompletedFences.reserve(m_graphicsCommandBuffers.size()); + m_renderingCompletedSemaphores.reserve(m_graphicsCommandBuffers.size()); + m_presentCompletedSemaphores.reserve(m_graphicsCommandBuffers.size()); for (size_t i = 0; i < m_graphicsCommandBuffers.size(); i++) { - m_graphicsCommandBufferSubmittedFences.push_back(createFence(true)); - m_graphicsCommandExecutionCompletedSemaphores.push_back(createSemaphore()); - m_graphicsCommandPresentCompletedSemaphores.push_back(createSemaphore()); + m_renderingCompletedFences.push_back(createFence(true)); + m_renderingCompletedSemaphores.push_back(createSemaphore()); + m_presentCompletedSemaphores.push_back(createSemaphore()); } m_allocator = createAllocator(); @@ -122,7 +122,7 @@ namespace Miracle::Infrastructure::Graphics::Vulkan { void GraphicsContext::recordGraphicsCommands(const std::function& recording) { auto result = m_device.waitForFences( - *m_graphicsCommandBufferSubmittedFences[m_currentGraphicsCommandBufferIndex], + *m_renderingCompletedFences[m_currentGraphicsCommandBufferIndex], true, std::numeric_limits::max() ); @@ -160,19 +160,19 @@ namespace Miracle::Infrastructure::Graphics::Vulkan { void GraphicsContext::submitGraphicsRecording() { vk::PipelineStageFlags waitStage = vk::PipelineStageFlagBits::eColorAttachmentOutput; - m_device.resetFences(*m_graphicsCommandBufferSubmittedFences[m_currentGraphicsCommandBufferIndex]); + m_device.resetFences(*m_renderingCompletedFences[m_currentGraphicsCommandBufferIndex]); m_graphicsQueue.submit( vk::SubmitInfo{ .waitSemaphoreCount = 1, - .pWaitSemaphores = &*m_graphicsCommandPresentCompletedSemaphores[m_currentGraphicsCommandBufferIndex], + .pWaitSemaphores = &*m_presentCompletedSemaphores[m_currentGraphicsCommandBufferIndex], .pWaitDstStageMask = &waitStage, .commandBufferCount = 1, .pCommandBuffers = &*m_graphicsCommandBuffers[m_currentGraphicsCommandBufferIndex], .signalSemaphoreCount = 1, - .pSignalSemaphores = &*m_graphicsCommandExecutionCompletedSemaphores[m_currentGraphicsCommandBufferIndex] + .pSignalSemaphores = &*m_renderingCompletedSemaphores[m_currentGraphicsCommandBufferIndex] }, - * m_graphicsCommandBufferSubmittedFences[m_currentGraphicsCommandBufferIndex] + * m_renderingCompletedFences[m_currentGraphicsCommandBufferIndex] ); } @@ -210,10 +210,10 @@ namespace Miracle::Infrastructure::Graphics::Vulkan { } void GraphicsContext::recreatePresentCompletedSemaphores() { - m_graphicsCommandPresentCompletedSemaphores.clear(); + m_presentCompletedSemaphores.clear(); for (size_t i = 0; i < m_graphicsCommandBuffers.size(); i++) { - m_graphicsCommandPresentCompletedSemaphores.push_back(createSemaphore()); + m_presentCompletedSemaphores.push_back(createSemaphore()); } } diff --git a/Miracle/src/Miracle/Infrastructure/Graphics/Vulkan/GraphicsContext.hpp b/Miracle/src/Miracle/Infrastructure/Graphics/Vulkan/GraphicsContext.hpp index dcb4869..41ca637 100644 --- a/Miracle/src/Miracle/Infrastructure/Graphics/Vulkan/GraphicsContext.hpp +++ b/Miracle/src/Miracle/Infrastructure/Graphics/Vulkan/GraphicsContext.hpp @@ -41,9 +41,9 @@ namespace Miracle::Infrastructure::Graphics::Vulkan { vk::raii::CommandPool m_transferCommandPool = nullptr; std::vector m_graphicsCommandBuffers; vk::raii::CommandBuffer m_transferCommandBuffer = nullptr; - std::vector m_graphicsCommandBufferSubmittedFences; - std::vector m_graphicsCommandExecutionCompletedSemaphores; - std::vector m_graphicsCommandPresentCompletedSemaphores; + std::vector m_renderingCompletedFences; + std::vector m_renderingCompletedSemaphores; + std::vector m_presentCompletedSemaphores; size_t m_currentGraphicsCommandBufferIndex = 0; vma::Allocator m_allocator; @@ -107,11 +107,11 @@ namespace Miracle::Infrastructure::Graphics::Vulkan { } const vk::raii::Semaphore& getGraphicsCommandExecutionCompletedSemaphore() const { - return m_graphicsCommandExecutionCompletedSemaphores[m_currentGraphicsCommandBufferIndex]; + return m_renderingCompletedSemaphores[m_currentGraphicsCommandBufferIndex]; } const vk::raii::Semaphore& getGraphicsCommandPresentCompletedSemaphore() const { - return m_graphicsCommandPresentCompletedSemaphores[m_currentGraphicsCommandBufferIndex]; + return m_presentCompletedSemaphores[m_currentGraphicsCommandBufferIndex]; } const vma::Allocator& getAllocator() const { return m_allocator; } From 05c3ec98f5bf8591ba6bff2608055333c0b18baa Mon Sep 17 00:00:00 2001 From: Henrik Nyhammer Date: Sun, 28 Jan 2024 05:23:04 +0100 Subject: [PATCH 02/17] Small fix --- Demos/Demo1/Demo.cpp | 16 ++++++++-------- .../Graphics/Vulkan/BufferUtilities.cpp | 2 +- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/Demos/Demo1/Demo.cpp b/Demos/Demo1/Demo.cpp index 9a17af2..b1b7ad7 100644 --- a/Demos/Demo1/Demo.cpp +++ b/Demos/Demo1/Demo.cpp @@ -64,14 +64,14 @@ int main() { .meshes = std::vector{ { .vertices = std::vector{ - Vertex{.position = Vector3{.x = -0.5f, .y = -0.5f, .z = 0.0f } }, - Vertex{.position = Vector3{.x = 0.5f, .y = -0.5f, .z = 0.0f } }, - Vertex{.position = Vector3{.x = 0.5f, .y = 0.5f, .z = 0.0f } }, - Vertex{.position = Vector3{.x = -0.5f, .y = 0.5f, .z = 0.0f } } + Vertex{ .position = Vector3{ .x = -0.5f, .y = -0.5f, .z = 0.0f } }, + Vertex{ .position = Vector3{ .x = 0.5f, .y = -0.5f, .z = 0.0f } }, + Vertex{ .position = Vector3{ .x = 0.5f, .y = 0.5f, .z = 0.0f } }, + Vertex{ .position = Vector3{ .x = -0.5f, .y = 0.5f, .z = 0.0f } } }, .faces = std::vector{ - Face{.indices = { 0, 1, 2 } }, - Face{.indices = { 0, 2, 3 } } + Face{ .indices = { 0, 1, 2 } }, + Face{ .indices = { 0, 2, 3 } } } } } @@ -82,13 +82,13 @@ int main() { .transformConfig = TransformConfig{ .translation = Vector3{ 0.0f, 0.0f, -1.0f } }, - .cameraConfig = PerspectiveCameraConfig{}, + .cameraConfig = PerspectiveCameraConfig{}, .behaviorFactory = BehaviorFactory::createFactoryFor(1.0f, 120.0_deg) }, { .appearanceConfig = AppearanceConfig{ .meshIndex = 0, - .color = ColorRgb::createFromNonlinearSrgbColorCode(0xFF7700) + .color = ColorRgb::createFromNonlinearSrgbColorCode(0xFF7700) } }, { diff --git a/Miracle/src/Miracle/Infrastructure/Graphics/Vulkan/BufferUtilities.cpp b/Miracle/src/Miracle/Infrastructure/Graphics/Vulkan/BufferUtilities.cpp index 768e3d2..1aeb72d 100644 --- a/Miracle/src/Miracle/Infrastructure/Graphics/Vulkan/BufferUtilities.cpp +++ b/Miracle/src/Miracle/Infrastructure/Graphics/Vulkan/BufferUtilities.cpp @@ -61,7 +61,7 @@ namespace Miracle::Infrastructure::Graphics::Vulkan { : nullptr }, vma::AllocationCreateInfo{ - .flags = vma::AllocationCreateFlagBits::eDedicatedMemory, + .flags = {}, .usage = vma::MemoryUsage::eAuto, .requiredFlags = {}, .preferredFlags = {}, From 7e8f7b3d64fa32ab0617f91716797de50199b6d8 Mon Sep 17 00:00:00 2001 From: Henrik Date: Sat, 25 Oct 2025 01:09:19 +0200 Subject: [PATCH 03/17] Small fix --- CMakeLists.txt | 2 +- Demos/Demo1/Demo.cpp | 14 +++++++------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 79bf9d4..1eab5c6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.15 FATAL_ERROR) +cmake_minimum_required(VERSION 3.21) project("Miracle") diff --git a/Demos/Demo1/Demo.cpp b/Demos/Demo1/Demo.cpp index b1b7ad7..067e15b 100644 --- a/Demos/Demo1/Demo.cpp +++ b/Demos/Demo1/Demo.cpp @@ -61,8 +61,8 @@ int main() { .resizable = true }, .rendererConfig = RendererConfig{ - .meshes = std::vector{ - { + .meshes = std::vector{ + Mesh{ .vertices = std::vector{ Vertex{ .position = Vector3{ .x = -0.5f, .y = -0.5f, .z = 0.0f } }, Vertex{ .position = Vector3{ .x = 0.5f, .y = -0.5f, .z = 0.0f } }, @@ -77,21 +77,21 @@ int main() { } }, .sceneConfig = SceneConfig{ - .entityConfigs = std::vector{ - { + .entityConfigs = std::vector{ + EntityConfig{ .transformConfig = TransformConfig{ .translation = Vector3{ 0.0f, 0.0f, -1.0f } }, .cameraConfig = PerspectiveCameraConfig{}, .behaviorFactory = BehaviorFactory::createFactoryFor(1.0f, 120.0_deg) }, - { + EntityConfig{ .appearanceConfig = AppearanceConfig{ .meshIndex = 0, .color = ColorRgb::createFromNonlinearSrgbColorCode(0xFF7700) } }, - { + EntityConfig{ .transformConfig = TransformConfig{ .translation = Vector3{ .x = -1.5f, @@ -135,6 +135,6 @@ int main() { ); int exitCode = app.run(); - + return exitCode; } From b8893b35b01bf46ec622e9b6ff4ae1289dd21bc1 Mon Sep 17 00:00:00 2001 From: Henrik Date: Sat, 25 Oct 2025 22:54:14 +0200 Subject: [PATCH 04/17] Implemented depth testing --- Demos/Demo1/Demo.cpp | 2 +- .../Graphics/Vulkan/DeviceExplorer.cpp | 33 +++- .../Graphics/Vulkan/DeviceInfo.hpp | 1 + .../Graphics/Vulkan/GraphicsPipeline.cpp | 15 +- .../Graphics/Vulkan/Swapchain.cpp | 155 ++++++++++++++++-- .../Graphics/Vulkan/Swapchain.hpp | 11 ++ 6 files changed, 199 insertions(+), 18 deletions(-) diff --git a/Demos/Demo1/Demo.cpp b/Demos/Demo1/Demo.cpp index 067e15b..b61953f 100644 --- a/Demos/Demo1/Demo.cpp +++ b/Demos/Demo1/Demo.cpp @@ -83,7 +83,7 @@ int main() { .translation = Vector3{ 0.0f, 0.0f, -1.0f } }, .cameraConfig = PerspectiveCameraConfig{}, - .behaviorFactory = BehaviorFactory::createFactoryFor(1.0f, 120.0_deg) + .behaviorFactory = BehaviorFactory::createFactoryFor(2.0f, 120.0_deg) }, EntityConfig{ .appearanceConfig = AppearanceConfig{ diff --git a/Miracle/src/Miracle/Infrastructure/Graphics/Vulkan/DeviceExplorer.cpp b/Miracle/src/Miracle/Infrastructure/Graphics/Vulkan/DeviceExplorer.cpp index a913308..4f0b7ce 100644 --- a/Miracle/src/Miracle/Infrastructure/Graphics/Vulkan/DeviceExplorer.cpp +++ b/Miracle/src/Miracle/Infrastructure/Graphics/Vulkan/DeviceExplorer.cpp @@ -2,6 +2,8 @@ #include #include +#include +#include namespace Miracle::Infrastructure::Graphics::Vulkan { DeviceInfo DeviceExplorer::getDeviceInfo( @@ -20,18 +22,37 @@ namespace Miracle::Infrastructure::Graphics::Vulkan { memorySize += memoryProperties.memoryHeaps[memoryType.heapIndex].size; } } + + auto depthStencilImageFormats = std::vector{ + vk::Format::eD16Unorm, + vk::Format::eD16UnormS8Uint, + vk::Format::eD24UnormS8Uint, + vk::Format::eD32Sfloat, + vk::Format::eD32SfloatS8Uint + }; + + auto supportedDepthStencilImageFormatsWithOptimalTiling = std::vector(); + + for (auto& depthStencilImageFormat : depthStencilImageFormats) { + auto formatProperties = device.getFormatProperties(depthStencilImageFormat); + + if (formatProperties.optimalTilingFeatures & vk::FormatFeatureFlagBits::eDepthStencilAttachment) + supportedDepthStencilImageFormatsWithOptimalTiling.push_back(depthStencilImageFormat); + } return DeviceInfo{ - .name = properties.deviceName, - .type = properties.deviceType, - .deviceLocalMemorySize = memorySize, - .queueFamilyIndices = queryQueueFamilyIndices(device, surface), - .extensionSupport = queryExtensionSupport(device, surface) + .name = properties.deviceName, + .type = properties.deviceType, + .deviceLocalMemorySize = memorySize, + .depthStencilOptimalTilingImageFormatsSupported = std::move(supportedDepthStencilImageFormatsWithOptimalTiling), + .queueFamilyIndices = queryQueueFamilyIndices(device, surface), + .extensionSupport = queryExtensionSupport(device, surface) }; } bool DeviceExplorer::isDeviceSupported(const DeviceInfo& deviceInfo) { - return deviceInfo.queueFamilyIndices.graphicsFamilyIndex.has_value() + return !deviceInfo.depthStencilOptimalTilingImageFormatsSupported.empty() + && deviceInfo.queueFamilyIndices.graphicsFamilyIndex.has_value() && deviceInfo.queueFamilyIndices.presentFamilyIndex.has_value() && deviceInfo.queueFamilyIndices.transferFamilyIndex.has_value() && deviceInfo.extensionSupport.swapchainSupport.has_value() diff --git a/Miracle/src/Miracle/Infrastructure/Graphics/Vulkan/DeviceInfo.hpp b/Miracle/src/Miracle/Infrastructure/Graphics/Vulkan/DeviceInfo.hpp index 0fd0fba..315780f 100644 --- a/Miracle/src/Miracle/Infrastructure/Graphics/Vulkan/DeviceInfo.hpp +++ b/Miracle/src/Miracle/Infrastructure/Graphics/Vulkan/DeviceInfo.hpp @@ -54,6 +54,7 @@ namespace Miracle::Infrastructure::Graphics::Vulkan { std::string name = {}; vk::PhysicalDeviceType type = {}; vk::DeviceSize deviceLocalMemorySize = {}; + std::vector depthStencilOptimalTilingImageFormatsSupported = {}; QueueFamilyIndices queueFamilyIndices = {}; DeviceExtensionSupport extensionSupport = {}; }; diff --git a/Miracle/src/Miracle/Infrastructure/Graphics/Vulkan/GraphicsPipeline.cpp b/Miracle/src/Miracle/Infrastructure/Graphics/Vulkan/GraphicsPipeline.cpp index 6052998..802c9fc 100644 --- a/Miracle/src/Miracle/Infrastructure/Graphics/Vulkan/GraphicsPipeline.cpp +++ b/Miracle/src/Miracle/Infrastructure/Graphics/Vulkan/GraphicsPipeline.cpp @@ -105,6 +105,19 @@ namespace Miracle::Infrastructure::Graphics::Vulkan { .alphaToOneEnable = {} }; + auto depthStencilStateCreateInfo = vk::PipelineDepthStencilStateCreateInfo{ + .flags = {}, + .depthTestEnable = true, + .depthWriteEnable = true, + .depthCompareOp = vk::CompareOp::eLess, + .depthBoundsTestEnable = false, + .stencilTestEnable = false, + .front = {}, + .back = {}, + .minDepthBounds = {}, + .maxDepthBounds = {} + }; + auto colorBlendAttachmentState = vk::PipelineColorBlendAttachmentState{ .blendEnable = false, .srcColorBlendFactor = {}, @@ -181,7 +194,7 @@ namespace Miracle::Infrastructure::Graphics::Vulkan { .pViewportState = &viewportStateCreateInfo, .pRasterizationState = &rasterizationStateCreateInfo, .pMultisampleState = &multisampleStateCreateInfo, - .pDepthStencilState = nullptr, + .pDepthStencilState = &depthStencilStateCreateInfo, .pColorBlendState = &colorBlendStateCreateInfo, .pDynamicState = &dynamicStateCreateInfo, .layout = *m_layout, diff --git a/Miracle/src/Miracle/Infrastructure/Graphics/Vulkan/Swapchain.cpp b/Miracle/src/Miracle/Infrastructure/Graphics/Vulkan/Swapchain.cpp index 24c46f5..fbb2fe9 100644 --- a/Miracle/src/Miracle/Infrastructure/Graphics/Vulkan/Swapchain.cpp +++ b/Miracle/src/Miracle/Infrastructure/Graphics/Vulkan/Swapchain.cpp @@ -28,6 +28,15 @@ namespace Miracle::Infrastructure::Graphics::Vulkan { m_images.emplace_back(image, createImageView(image)); } + m_depthImageFormat = selectOptimalTilingDepthImageFormat(); + + auto [depthImage, depthImageAllocation] = createDepthImage(); + + m_depthImage = depthImage; + m_depthImageAllocation = depthImageAllocation; + + m_depthImageView = createDepthImageView(m_depthImage); + m_renderPass = createRenderPass(); m_frameBuffers.reserve(m_images.size()); @@ -49,6 +58,8 @@ namespace Miracle::Infrastructure::Graphics::Vulkan { Swapchain::~Swapchain() { m_logger.info("Destroying Vulkan swapchain..."); + + m_context.getAllocator().destroyImage(m_depthImage, m_depthImageAllocation); } Application::SwapchainImageSize Swapchain::getImageSize() const { @@ -69,6 +80,12 @@ namespace Miracle::Infrastructure::Graphics::Vulkan { 1.0f } ) + ), + vk::ClearValue( + vk::ClearDepthStencilValue{ + .depth = 1.0f, + .stencil = 0 + } ) }; @@ -117,6 +134,10 @@ namespace Miracle::Infrastructure::Graphics::Vulkan { void Swapchain::recreate() { m_frameBuffers.clear(); + + m_depthImageView.clear(); + m_context.getAllocator().destroyImage(m_depthImage, m_depthImageAllocation); + m_images.clear(); m_swapchain.clear(); @@ -129,6 +150,12 @@ namespace Miracle::Infrastructure::Graphics::Vulkan { m_images.emplace_back(image, createImageView(image)); } + auto [depthImage, depthImageAllocation] = createDepthImage(); + + m_depthImage = depthImage; + m_depthImageAllocation = depthImageAllocation; + m_depthImageView = createDepthImageView(m_depthImage); + for (auto& [image, imageView] : m_images) { m_frameBuffers.push_back(createFrameBuffer(imageView)); } @@ -318,26 +345,42 @@ namespace Miracle::Infrastructure::Graphics::Vulkan { .stencilStoreOp = vk::AttachmentStoreOp::eDontCare, .initialLayout = vk::ImageLayout::eUndefined, .finalLayout = vk::ImageLayout::ePresentSrcKHR + }, + vk::AttachmentDescription{ + .flags = {}, + .format = m_depthImageFormat, + .samples = vk::SampleCountFlagBits::e1, + .loadOp = vk::AttachmentLoadOp::eClear, + .storeOp = vk::AttachmentStoreOp::eDontCare, + .stencilLoadOp = vk::AttachmentLoadOp::eDontCare, + .stencilStoreOp = vk::AttachmentStoreOp::eDontCare, + .initialLayout = vk::ImageLayout::eUndefined, + .finalLayout = vk::ImageLayout::eDepthStencilAttachmentOptimal } }; - auto attachmentReferences = std::array{ + auto colorAttachmentReferences = std::array{ vk::AttachmentReference{ .attachment = 0, .layout = vk::ImageLayout::eColorAttachmentOptimal } }; + auto depthStencilAttachmentReference = vk::AttachmentReference{ + .attachment = 1, + .layout = vk::ImageLayout::eDepthStencilAttachmentOptimal + }; + auto subpasses = std::array{ vk::SubpassDescription{ .flags = {}, .pipelineBindPoint = vk::PipelineBindPoint::eGraphics, .inputAttachmentCount = 0, .pInputAttachments = nullptr, - .colorAttachmentCount = static_cast(attachmentReferences.size()), - .pColorAttachments = attachmentReferences.data(), + .colorAttachmentCount = static_cast(colorAttachmentReferences.size()), + .pColorAttachments = colorAttachmentReferences.data(), .pResolveAttachments = nullptr, - .pDepthStencilAttachment = nullptr, + .pDepthStencilAttachment = &depthStencilAttachmentReference, .preserveAttachmentCount = 0, .pPreserveAttachments = nullptr } @@ -347,10 +390,10 @@ namespace Miracle::Infrastructure::Graphics::Vulkan { vk::SubpassDependency{ .srcSubpass = VK_SUBPASS_EXTERNAL, .dstSubpass = 0, - .srcStageMask = vk::PipelineStageFlagBits::eColorAttachmentOutput, - .dstStageMask = vk::PipelineStageFlagBits::eColorAttachmentOutput, - .srcAccessMask = vk::AccessFlags(), - .dstAccessMask = vk::AccessFlagBits::eColorAttachmentWrite, + .srcStageMask = vk::PipelineStageFlagBits::eColorAttachmentOutput | vk::PipelineStageFlagBits::eLateFragmentTests, + .dstStageMask = vk::PipelineStageFlagBits::eColorAttachmentOutput | vk::PipelineStageFlagBits::eEarlyFragmentTests, + .srcAccessMask = vk::AccessFlagBits::eDepthStencilAttachmentWrite, + .dstAccessMask = vk::AccessFlagBits::eColorAttachmentWrite | vk::AccessFlagBits::eDepthStencilAttachmentWrite, .dependencyFlags = {} } }; @@ -378,13 +421,18 @@ namespace Miracle::Infrastructure::Graphics::Vulkan { } vk::raii::Framebuffer Swapchain::createFrameBuffer(const vk::raii::ImageView& imageView) const { + auto attachments = std::array{ + *imageView, + *m_depthImageView + }; + try { return m_context.getDevice().createFramebuffer( vk::FramebufferCreateInfo{ .flags = {}, .renderPass = *m_renderPass, - .attachmentCount = 1, - .pAttachments = &*imageView, + .attachmentCount = static_cast(attachments.size()), + .pAttachments = attachments.data(), .width = m_imageExtent.width, .height = m_imageExtent.height, .layers = 1 @@ -400,6 +448,93 @@ namespace Miracle::Infrastructure::Graphics::Vulkan { } } + vk::Format Swapchain::selectOptimalTilingDepthImageFormat() const { + for (auto& format : m_context.getDeviceInfo().depthStencilOptimalTilingImageFormatsSupported) { + if (format == vk::Format::eD32Sfloat) return format; + } + + return m_context.getDeviceInfo().depthStencilOptimalTilingImageFormatsSupported.back(); + } + + std::pair Swapchain::createDepthImage() const { + try { + return m_context.getAllocator().createImage( + vk::ImageCreateInfo{ + .flags = {}, + .imageType = vk::ImageType::e2D, + .format = m_depthImageFormat, + .extent = vk::Extent3D{ + .width = m_imageExtent.width, + .height = m_imageExtent.height, + .depth = 1 + }, + .mipLevels = 1, + .arrayLayers = 1, + .samples = vk::SampleCountFlagBits::e1, + .tiling = vk::ImageTiling::eOptimal, + .usage = vk::ImageUsageFlagBits::eDepthStencilAttachment, + .sharingMode = vk::SharingMode::eExclusive, + .queueFamilyIndexCount = 0, + .pQueueFamilyIndices = nullptr, + .initialLayout = vk::ImageLayout::eUndefined + }, + vma::AllocationCreateInfo{ + .flags = {}, + .usage = vma::MemoryUsage::eAuto, + .requiredFlags = {}, + .preferredFlags = {}, + .memoryTypeBits = {}, + .pool = nullptr, + .pUserData = nullptr, + .priority = 1.0 + } + ); + } + catch (const std::exception& e) { + m_logger.error( + std::format("Failed to create Vulkan depth image for swapchain.\n{}", e.what()) + ); + + throw Application::SwapchainErrors::CreationError(); + } + } + + vk::raii::ImageView Swapchain::createDepthImageView(const vk::Image& depthImage) const { + try { + return m_context.getDevice().createImageView( + vk::ImageViewCreateInfo{ + .flags = {}, + .image = depthImage, + .viewType = vk::ImageViewType::e2D, + .format = m_depthImageFormat, + .components = vk::ComponentMapping{ + .r = vk::ComponentSwizzle::eIdentity, + .g = vk::ComponentSwizzle::eIdentity, + .b = vk::ComponentSwizzle::eIdentity, + .a = vk::ComponentSwizzle::eIdentity + }, + .subresourceRange = vk::ImageSubresourceRange{ + .aspectMask = vk::ImageAspectFlagBits::eDepth, + .baseMipLevel = 0, + .levelCount = 1, + .baseArrayLayer = 0, + .layerCount = 1 + } + } + ); + } + catch (const std::exception& e) { + m_logger.error( + std::format( + "Failed to create Vulkan depth image view for depth image for swapchain.\n{}", + e.what() + ) + ); + + throw Application::SwapchainErrors::CreationError(); + } + } + uint32_t Swapchain::getNextImageIndex() { auto [result, imageIndex] = m_swapchain.acquireNextImage( std::numeric_limits().max(), diff --git a/Miracle/src/Miracle/Infrastructure/Graphics/Vulkan/Swapchain.hpp b/Miracle/src/Miracle/Infrastructure/Graphics/Vulkan/Swapchain.hpp index 30d391a..c746779 100644 --- a/Miracle/src/Miracle/Infrastructure/Graphics/Vulkan/Swapchain.hpp +++ b/Miracle/src/Miracle/Infrastructure/Graphics/Vulkan/Swapchain.hpp @@ -6,6 +6,7 @@ #include #include #include "Vulkan.hpp" +#include "Vma.hpp" #include "GraphicsContext.hpp" namespace Miracle::Infrastructure::Graphics::Vulkan { @@ -20,6 +21,10 @@ namespace Miracle::Infrastructure::Graphics::Vulkan { vk::PresentModeKHR m_presentMode; vk::raii::SwapchainKHR m_swapchain; std::vector> m_images; + vk::Format m_depthImageFormat; + vk::Image m_depthImage; + vma::Allocation m_depthImageAllocation; + vk::raii::ImageView m_depthImageView = nullptr; vk::raii::RenderPass m_renderPass = nullptr; std::vector m_frameBuffers; uint32_t m_imageIndex = 0; @@ -74,6 +79,12 @@ namespace Miracle::Infrastructure::Graphics::Vulkan { vk::raii::Framebuffer createFrameBuffer(const vk::raii::ImageView& imageView) const; + vk::Format selectOptimalTilingDepthImageFormat() const; + + std::pair createDepthImage() const; + + vk::raii::ImageView createDepthImageView(const vk::Image& depthImage) const; + uint32_t getNextImageIndex(); }; } From 5e0204ea7dff2db4e195b18d0a1966be0a27e075 Mon Sep 17 00:00:00 2001 From: Henrik Date: Sat, 25 Oct 2025 22:57:23 +0200 Subject: [PATCH 05/17] Fix to avoid potential bug --- .../src/Miracle/Infrastructure/Graphics/Vulkan/Swapchain.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Miracle/src/Miracle/Infrastructure/Graphics/Vulkan/Swapchain.cpp b/Miracle/src/Miracle/Infrastructure/Graphics/Vulkan/Swapchain.cpp index fbb2fe9..7a83de3 100644 --- a/Miracle/src/Miracle/Infrastructure/Graphics/Vulkan/Swapchain.cpp +++ b/Miracle/src/Miracle/Infrastructure/Graphics/Vulkan/Swapchain.cpp @@ -59,6 +59,8 @@ namespace Miracle::Infrastructure::Graphics::Vulkan { Swapchain::~Swapchain() { m_logger.info("Destroying Vulkan swapchain..."); + m_frameBuffers.clear(); + m_depthImageView.clear(); m_context.getAllocator().destroyImage(m_depthImage, m_depthImageAllocation); } From c64ebfa121fd0719a48494c2031a44637ed585e7 Mon Sep 17 00:00:00 2001 From: Henrik Date: Sun, 26 Oct 2025 07:12:45 +0100 Subject: [PATCH 06/17] Added depth testing to dynamic state and made depth testing controllable from user application --- Demos/Demo1/Demo.cpp | 8 +++----- .../Application/Graphics/IGraphicsContext.hpp | 6 ++++++ .../Miracle/Application/Graphics/Renderer.hpp | 8 ++++++++ .../include/Miracle/Application/Mappings.hpp | 3 ++- .../Miracle/Common/Models/RendererConfig.hpp | 1 + Miracle/include/Miracle/Interface/Renderer.hpp | 12 ++++++++++++ .../Miracle/Application/Graphics/Renderer.cpp | 5 ++++- .../Graphics/Vulkan/DeviceExplorer.cpp | 7 +++++-- .../Graphics/Vulkan/DeviceInfo.hpp | 1 + .../Graphics/Vulkan/GraphicsContext.cpp | 18 +++++++++++++++++- .../Graphics/Vulkan/GraphicsContext.hpp | 4 ++++ .../Graphics/Vulkan/GraphicsPipeline.cpp | 8 +++++--- .../Graphics/Vulkan/Swapchain.cpp | 1 - 13 files changed, 68 insertions(+), 14 deletions(-) diff --git a/Demos/Demo1/Demo.cpp b/Demos/Demo1/Demo.cpp index b61953f..a70ed55 100644 --- a/Demos/Demo1/Demo.cpp +++ b/Demos/Demo1/Demo.cpp @@ -61,7 +61,8 @@ int main() { .resizable = true }, .rendererConfig = RendererConfig{ - .meshes = std::vector{ + .useDepthTesting = true, + .meshes = std::vector{ Mesh{ .vertices = std::vector{ Vertex{ .position = Vector3{ .x = -0.5f, .y = -0.5f, .z = 0.0f } }, @@ -125,10 +126,7 @@ int main() { } if (Keyboard::isKeyPressed(KeyboardKey::keyF3)) { - Renderer::setVsyncAndTripleBuffering( - !Renderer::isUsingVsync(), - !Renderer::isUsingTripleBuffering() - ); + Renderer::setDepthTesting(!Renderer::isUsingDepthTesting()); } } } diff --git a/Miracle/include/Miracle/Application/Graphics/IGraphicsContext.hpp b/Miracle/include/Miracle/Application/Graphics/IGraphicsContext.hpp index bb84df3..7e588e3 100644 --- a/Miracle/include/Miracle/Application/Graphics/IGraphicsContext.hpp +++ b/Miracle/include/Miracle/Application/Graphics/IGraphicsContext.hpp @@ -27,6 +27,12 @@ namespace Miracle::Application { unsigned int height ) = 0; + // Graphics command + virtual void setDepthTestEnabled(bool enabled) = 0; + + // Graphics command + virtual void setDepthWriteEnabled(bool enabled) = 0; + // Graphics command virtual void draw(uint32_t vertexCount) = 0; diff --git a/Miracle/include/Miracle/Application/Graphics/Renderer.hpp b/Miracle/include/Miracle/Application/Graphics/Renderer.hpp index 1d92452..9d15b24 100644 --- a/Miracle/include/Miracle/Application/Graphics/Renderer.hpp +++ b/Miracle/include/Miracle/Application/Graphics/Renderer.hpp @@ -18,6 +18,7 @@ namespace Miracle::Application { struct RendererInitProps{ SwapchainInitProps swapchainInitProps = {}; + bool useDepthTesting; const std::vector& meshes = {}; }; @@ -31,6 +32,7 @@ namespace Miracle::Application { std::unique_ptr m_swapchain; std::unique_ptr m_pipeline; std::vector m_meshBuffersList; + bool m_useDepthTesting; public: Renderer( @@ -66,6 +68,12 @@ namespace Miracle::Application { m_swapchain->recreate(); } + bool isUsingDepthTesting() const { return m_useDepthTesting; } + + void setDepthTesting(bool useDepthTesting) { + m_useDepthTesting = useDepthTesting; + } + bool render(const Scene& scene); private: diff --git a/Miracle/include/Miracle/Application/Mappings.hpp b/Miracle/include/Miracle/Application/Mappings.hpp index e40e8a0..c8e93f7 100644 --- a/Miracle/include/Miracle/Application/Mappings.hpp +++ b/Miracle/include/Miracle/Application/Mappings.hpp @@ -34,7 +34,8 @@ namespace Miracle::Application { .useVsync = rendererConfig.swapchainConfig.useVsync, .useTripleBuffering = rendererConfig.swapchainConfig.useTripleBuffering }, - .meshes = rendererConfig.meshes + .useDepthTesting = rendererConfig.useDepthTesting, + .meshes = rendererConfig.meshes }; } diff --git a/Miracle/include/Miracle/Common/Models/RendererConfig.hpp b/Miracle/include/Miracle/Common/Models/RendererConfig.hpp index de7c3ec..4ae88a0 100644 --- a/Miracle/include/Miracle/Common/Models/RendererConfig.hpp +++ b/Miracle/include/Miracle/Common/Models/RendererConfig.hpp @@ -8,6 +8,7 @@ namespace Miracle { struct RendererConfig { SwapchainConfig swapchainConfig = {}; + bool useDepthTesting = false; std::vector meshes = {}; }; } diff --git a/Miracle/include/Miracle/Interface/Renderer.hpp b/Miracle/include/Miracle/Interface/Renderer.hpp index b6d8187..f6734e4 100644 --- a/Miracle/include/Miracle/Interface/Renderer.hpp +++ b/Miracle/include/Miracle/Interface/Renderer.hpp @@ -37,5 +37,17 @@ namespace Miracle { App::s_currentApp->m_dependencies->getRenderer() .setVsyncAndTripleBuffering(useVsync, useTripleBuffering); } + + static bool isUsingDepthTesting() { + if (App::s_currentApp == nullptr) [[unlikely]] throw NoAppRunningError(); + + return App::s_currentApp->m_dependencies->getRenderer().isUsingDepthTesting(); + } + + static void setDepthTesting(bool useDepthTesting) { + if (App::s_currentApp == nullptr) [[unlikely]] throw NoAppRunningError(); + + App::s_currentApp->m_dependencies->getRenderer().setDepthTesting(useDepthTesting); + } }; } diff --git a/Miracle/src/Miracle/Application/Graphics/Renderer.cpp b/Miracle/src/Miracle/Application/Graphics/Renderer.cpp index b8bdd70..4e2cad1 100644 --- a/Miracle/src/Miracle/Application/Graphics/Renderer.cpp +++ b/Miracle/src/Miracle/Application/Graphics/Renderer.cpp @@ -16,7 +16,8 @@ namespace Miracle::Application { m_context(context), m_swapchain(m_api.createSwapchain(m_context, initProps.swapchainInitProps)), m_pipeline(m_api.createGraphicsPipeline(m_fileAccess, m_context, *m_swapchain.get())), - m_meshBuffersList(createMeshBuffersList(initProps.meshes)) + m_meshBuffersList(createMeshBuffersList(initProps.meshes)), + m_useDepthTesting(initProps.useDepthTesting) { m_logger.info("Renderer created"); } @@ -82,6 +83,8 @@ namespace Miracle::Application { m_swapchain->beginRenderPass(scene.getBackgroundColor()); m_context.setViewport(0.0f, 0.0f, swapchainImageSize.width, swapchainImageSize.height); m_context.setScissor(0, 0, swapchainImageSize.width, swapchainImageSize.height); + m_context.setDepthTestEnabled(m_useDepthTesting); + m_context.setDepthWriteEnabled(m_useDepthTesting); if (!m_meshBuffersList.empty()) { scene.forEachEntityAppearance( diff --git a/Miracle/src/Miracle/Infrastructure/Graphics/Vulkan/DeviceExplorer.cpp b/Miracle/src/Miracle/Infrastructure/Graphics/Vulkan/DeviceExplorer.cpp index 4f0b7ce..419421c 100644 --- a/Miracle/src/Miracle/Infrastructure/Graphics/Vulkan/DeviceExplorer.cpp +++ b/Miracle/src/Miracle/Infrastructure/Graphics/Vulkan/DeviceExplorer.cpp @@ -58,7 +58,8 @@ namespace Miracle::Infrastructure::Graphics::Vulkan { && deviceInfo.extensionSupport.swapchainSupport.has_value() && deviceInfo.extensionSupport.swapchainSupport.value().hasDoubleBufferingSupport && !deviceInfo.extensionSupport.swapchainSupport.value().surfaceFormats.empty() - && deviceInfo.extensionSupport.swapchainSupport.value().hasImmediateModePresentationSupport; + && deviceInfo.extensionSupport.swapchainSupport.value().hasImmediateModePresentationSupport + && deviceInfo.extensionSupport.hasExtendedDynamicStateSupport; } QueueFamilyIndices DeviceExplorer::queryQueueFamilyIndices( @@ -112,7 +113,9 @@ namespace Miracle::Infrastructure::Graphics::Vulkan { for (auto& extensionProperties : device.enumerateDeviceExtensionProperties()) { if (std::strcmp(extensionProperties.extensionName, VK_KHR_SWAPCHAIN_EXTENSION_NAME) == 0) { extensionSupport.swapchainSupport = querySwapchainSupport(device, surface); - break; + } + else if (std::strcmp(extensionProperties.extensionName, VK_EXT_EXTENDED_DYNAMIC_STATE_EXTENSION_NAME) == 0) { + extensionSupport.hasExtendedDynamicStateSupport = true; } } diff --git a/Miracle/src/Miracle/Infrastructure/Graphics/Vulkan/DeviceInfo.hpp b/Miracle/src/Miracle/Infrastructure/Graphics/Vulkan/DeviceInfo.hpp index 315780f..7de6758 100644 --- a/Miracle/src/Miracle/Infrastructure/Graphics/Vulkan/DeviceInfo.hpp +++ b/Miracle/src/Miracle/Infrastructure/Graphics/Vulkan/DeviceInfo.hpp @@ -48,6 +48,7 @@ namespace Miracle::Infrastructure::Graphics::Vulkan { struct DeviceExtensionSupport { std::optional swapchainSupport = {}; + bool hasExtendedDynamicStateSupport = {}; }; struct DeviceInfo { diff --git a/Miracle/src/Miracle/Infrastructure/Graphics/Vulkan/GraphicsContext.cpp b/Miracle/src/Miracle/Infrastructure/Graphics/Vulkan/GraphicsContext.cpp index 839293c..9dda762 100644 --- a/Miracle/src/Miracle/Infrastructure/Graphics/Vulkan/GraphicsContext.cpp +++ b/Miracle/src/Miracle/Infrastructure/Graphics/Vulkan/GraphicsContext.cpp @@ -112,6 +112,14 @@ namespace Miracle::Infrastructure::Graphics::Vulkan { ); } + void GraphicsContext::setDepthTestEnabled(bool enabled) { + getGraphicsCommandBuffer().setDepthTestEnable(enabled); + } + + void GraphicsContext::setDepthWriteEnabled(bool enabled) { + getGraphicsCommandBuffer().setDepthWriteEnable(enabled); + } + void GraphicsContext::draw(uint32_t vertexCount) { getGraphicsCommandBuffer().draw(vertexCount, 1, 0, 0); } @@ -469,11 +477,19 @@ namespace Miracle::Infrastructure::Graphics::Vulkan { ); } - auto extensionNames = std::array{ VK_KHR_SWAPCHAIN_EXTENSION_NAME }; + auto extensionNames = std::array{ + VK_KHR_SWAPCHAIN_EXTENSION_NAME, + VK_EXT_EXTENDED_DYNAMIC_STATE_EXTENSION_NAME + }; + + auto extendedDynamicStateFeatures = vk::PhysicalDeviceExtendedDynamicStateFeaturesEXT{ + .extendedDynamicState = true + }; try { return m_physicalDevice.createDevice( vk::DeviceCreateInfo{ + .pNext = &extendedDynamicStateFeatures, .flags = {}, .queueCreateInfoCount = static_cast(deviceQueueCreateInfos.size()), .pQueueCreateInfos = deviceQueueCreateInfos.data(), diff --git a/Miracle/src/Miracle/Infrastructure/Graphics/Vulkan/GraphicsContext.hpp b/Miracle/src/Miracle/Infrastructure/Graphics/Vulkan/GraphicsContext.hpp index 41ca637..2d5fca7 100644 --- a/Miracle/src/Miracle/Infrastructure/Graphics/Vulkan/GraphicsContext.hpp +++ b/Miracle/src/Miracle/Infrastructure/Graphics/Vulkan/GraphicsContext.hpp @@ -70,6 +70,10 @@ namespace Miracle::Infrastructure::Graphics::Vulkan { unsigned int height ) override; + virtual void setDepthTestEnabled(bool enabled) override; + + virtual void setDepthWriteEnabled(bool enabled) override; + virtual void draw(uint32_t vertexCount) override; virtual void drawIndexed(uint32_t indexCount) override; diff --git a/Miracle/src/Miracle/Infrastructure/Graphics/Vulkan/GraphicsPipeline.cpp b/Miracle/src/Miracle/Infrastructure/Graphics/Vulkan/GraphicsPipeline.cpp index 802c9fc..42f917c 100644 --- a/Miracle/src/Miracle/Infrastructure/Graphics/Vulkan/GraphicsPipeline.cpp +++ b/Miracle/src/Miracle/Infrastructure/Graphics/Vulkan/GraphicsPipeline.cpp @@ -107,8 +107,8 @@ namespace Miracle::Infrastructure::Graphics::Vulkan { auto depthStencilStateCreateInfo = vk::PipelineDepthStencilStateCreateInfo{ .flags = {}, - .depthTestEnable = true, - .depthWriteEnable = true, + .depthTestEnable = {}, + .depthWriteEnable = {}, .depthCompareOp = vk::CompareOp::eLess, .depthBoundsTestEnable = false, .stencilTestEnable = false, @@ -143,7 +143,9 @@ namespace Miracle::Infrastructure::Graphics::Vulkan { auto dynamicStates = std::array{ vk::DynamicState::eViewport, - vk::DynamicState::eScissor + vk::DynamicState::eScissor, + vk::DynamicState::eDepthTestEnable, + vk::DynamicState::eDepthWriteEnable }; auto dynamicStateCreateInfo = vk::PipelineDynamicStateCreateInfo{ diff --git a/Miracle/src/Miracle/Infrastructure/Graphics/Vulkan/Swapchain.cpp b/Miracle/src/Miracle/Infrastructure/Graphics/Vulkan/Swapchain.cpp index 7a83de3..7eaf9de 100644 --- a/Miracle/src/Miracle/Infrastructure/Graphics/Vulkan/Swapchain.cpp +++ b/Miracle/src/Miracle/Infrastructure/Graphics/Vulkan/Swapchain.cpp @@ -34,7 +34,6 @@ namespace Miracle::Infrastructure::Graphics::Vulkan { m_depthImage = depthImage; m_depthImageAllocation = depthImageAllocation; - m_depthImageView = createDepthImageView(m_depthImage); m_renderPass = createRenderPass(); From 6586f8bce17b65585da094289da1f1c671f214af Mon Sep 17 00:00:00 2001 From: Henrik Date: Mon, 27 Oct 2025 03:01:20 +0100 Subject: [PATCH 07/17] Demo work --- CMakeLists.txt | 1 + Demos/Demo1/Demo.cpp | 30 +++++- Demos/Demo2/CMakeLists.txt | 14 +++ Demos/Demo2/Demo.cpp | 190 +++++++++++++++++++++++++++++++++++++ 4 files changed, 231 insertions(+), 4 deletions(-) create mode 100644 Demos/Demo2/CMakeLists.txt create mode 100644 Demos/Demo2/Demo.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 1eab5c6..fd5d9e3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -19,4 +19,5 @@ add_subdirectory("Miracle") # Demo targets if(MIRACLE_BUILD_DEMO_TARGETS) add_subdirectory("Demos/Demo1") + add_subdirectory("Demos/Demo2") endif() diff --git a/Demos/Demo1/Demo.cpp b/Demos/Demo1/Demo.cpp index a70ed55..d937def 100644 --- a/Demos/Demo1/Demo.cpp +++ b/Demos/Demo1/Demo.cpp @@ -8,8 +8,9 @@ static void updateTitle() { Window::setTitle( UnicodeConverter::toUtf8( std::format( - "{} - FPS: {} - UPS: {} - Entity count: {}", + "{} - Depth test: {} - FPS: {} - UPS: {} - Entity count: {}", CurrentApp::getName(), + Renderer::isUsingDepthTesting() ? "enabled" : "disabled", PerformanceCounters::getFps(), PerformanceCounters::getUps(), CurrentScene::getEntityCount() @@ -61,6 +62,9 @@ int main() { .resizable = true }, .rendererConfig = RendererConfig{ + .swapchainConfig = SwapchainConfig{ + .useVsync = true + }, .useDepthTesting = true, .meshes = std::vector{ Mesh{ @@ -83,7 +87,9 @@ int main() { .transformConfig = TransformConfig{ .translation = Vector3{ 0.0f, 0.0f, -1.0f } }, - .cameraConfig = PerspectiveCameraConfig{}, + .cameraConfig = PerspectiveCameraConfig{ + .fieldOfView = 80.0_deg + }, .behaviorFactory = BehaviorFactory::createFactoryFor(2.0f, 120.0_deg) }, EntityConfig{ @@ -95,14 +101,29 @@ int main() { EntityConfig{ .transformConfig = TransformConfig{ .translation = Vector3{ - .x = -1.5f, - .z = 1.5f + .x = -1.0f, + .z = 1.0f } }, .appearanceConfig = AppearanceConfig{ .meshIndex = 0, .color = ColorRgbs::magenta } + }, + EntityConfig{ + .transformConfig = TransformConfig{ + .translation = Vector3{ + .x = -0.5f, + .y = -0.5f, + .z = 0.5f + }, + .rotation = Quaternion::createRotation(Vector3s::right, 90.0_deg), + .scale = Vector3{ .x = 1.0f, .y = 1.0f, .z = 1.0f } * 6.0f + }, + .appearanceConfig = AppearanceConfig{ + .meshIndex = 0, + .color = ColorRgbs::green + } } }, .entityCreatedCallback = [](EntityId) { updateTitle(); }, @@ -127,6 +148,7 @@ int main() { if (Keyboard::isKeyPressed(KeyboardKey::keyF3)) { Renderer::setDepthTesting(!Renderer::isUsingDepthTesting()); + updateTitle(); } } } diff --git a/Demos/Demo2/CMakeLists.txt b/Demos/Demo2/CMakeLists.txt new file mode 100644 index 0000000..e78b99c --- /dev/null +++ b/Demos/Demo2/CMakeLists.txt @@ -0,0 +1,14 @@ +# Target definition +add_executable(Demo2 "Demo.cpp") + +# Target properties +set_target_properties( + Demo2 + PROPERTIES + CXX_STANDARD 20 + CXX_STANDARD_REQUIRED true + MSVC_RUNTIME_LIBRARY "MultiThreaded$<$:Debug>" +) + +# Linking +target_link_libraries(Demo2 PRIVATE Miracle) diff --git a/Demos/Demo2/Demo.cpp b/Demos/Demo2/Demo.cpp new file mode 100644 index 0000000..15c5f6d --- /dev/null +++ b/Demos/Demo2/Demo.cpp @@ -0,0 +1,190 @@ +#include + +#include + +using namespace Miracle; + +static void updateTitle() { + Window::setTitle( + UnicodeConverter::toUtf8( + std::format( + "{} - FPS: {} - UPS: {} - Entity count: {}", + CurrentApp::getName(), + PerformanceCounters::getFps(), + PerformanceCounters::getUps(), + CurrentScene::getEntityCount() + ) + ) + ); +} + +class CameraBehavior : public BehaviorBase { +private: + float m_movementSpeed; + +public: + CameraBehavior( + const EntityContext& context, + float movementSpeed + ) : BehaviorBase(context), + m_movementSpeed(movementSpeed) + {} + + virtual void act() { + auto velocity = Vector3{ + .x = static_cast(Keyboard::isKeyHeld(KeyboardKey::keyRight) - Keyboard::isKeyHeld(KeyboardKey::keyLeft)), + .y = static_cast(Keyboard::isKeyHeld(KeyboardKey::keyUp) - Keyboard::isKeyHeld(KeyboardKey::keyDown)), + }; + + m_context.getTransform().translate(velocity.toNormalized() * m_movementSpeed * DeltaTime::get()); + } +}; + +class BulletBehavior : public BehaviorBase { +private: + Vector3 m_velocity; + +public: + BulletBehavior( + const EntityContext& context, + float movementSpeed + ) : BehaviorBase(context), + m_velocity(Vector3s::up * movementSpeed) + {} + + virtual void act() { + auto& transform = m_context.getTransform(); + transform.translate(m_velocity * DeltaTime::get()); + + if (transform.getTranslation().distanceTo(Vector3s::zero) > 10.0f) + m_context.destroyEntity(); + } +}; + +class PlayerBehavior : public BehaviorBase { +private: + float m_movementSpeed; + Degrees m_turnSpeed; + +public: + PlayerBehavior( + const EntityContext& context, + float movementSpeed, + Degrees turnSpeed + ) : BehaviorBase(context), + m_movementSpeed(movementSpeed), + m_turnSpeed(turnSpeed) + {} + + virtual void act() { + auto velocity = (Vector3s::up * (static_cast(Keyboard::isKeyHeld(KeyboardKey::keyW) - Keyboard::isKeyHeld(KeyboardKey::keyS)))) + .toNormalized() * m_movementSpeed; + + auto deltaRotation = m_turnSpeed + * static_cast(Keyboard::isKeyHeld(KeyboardKey::keyA) - Keyboard::isKeyHeld(KeyboardKey::keyD)); + + auto& transform = m_context.getTransform(); + + transform.rotate(Quaternion::createRotation(Vector3s::forward, deltaRotation * DeltaTime::get())); + transform.translate(velocity * DeltaTime::get()); + + if (Keyboard::isKeyPressed(KeyboardKey::keySpace)) + CurrentScene::createEntity( + EntityConfig{ + .transformConfig = TransformConfig{ + .translation = transform.getTranslation(), + .rotation = transform.getRotation(), + .scale = Vector3{ .x = 1.0f, .y = 1.0f } * 0.25f + }, + .appearanceConfig = AppearanceConfig{ + .meshIndex = 0, + .color = ColorRgbs::cyan + }, + .behaviorFactory = BehaviorFactory::createFactoryFor(5.0f) + } + ); + } +}; + +int main() { + auto app = App( + "Demo 1", + AppConfig{ + .windowConfig = WindowConfig{ + .size = WindowSize{ + .width = 800, + .height = 600 + }, + .resizable = true + }, + .rendererConfig = RendererConfig{ + .swapchainConfig = SwapchainConfig{ + .useVsync = true + }, + .meshes = std::vector{ + Mesh{ + .vertices = std::vector{ + Vertex{ .position = Vector3{ .x = -0.5f, .y = -0.5f } }, + Vertex{ .position = Vector3{ .x = 0.5f, .y = -0.5f } }, + Vertex{ .position = Vector3{ .x = 0.0f, .y = 0.5f } } + }, + .faces = std::vector{ + Face{ .indices = { 0, 1, 2 } } + } + }, + Mesh{ + .vertices = std::vector{ + Vertex{ .position = Vector3{ .x = -0.5f, .y = -0.5f } }, + Vertex{ .position = Vector3{ .x = 0.5f, .y = -0.5f } }, + Vertex{ .position = Vector3{ .x = 0.5f, .y = 0.5f } }, + Vertex{ .position = Vector3{ .x = -0.5f, .y = 0.5f } } + }, + .faces = std::vector{ + Face{ .indices = { 0, 1, 2 } }, + Face{ .indices = { 0, 2, 3 } } + } + } + } + }, + .sceneConfig = SceneConfig{ + .entityConfigs = std::vector{ + EntityConfig{ + .transformConfig = TransformConfig{}, + .cameraConfig = OrthographicCameraConfig{}, + .behaviorFactory = BehaviorFactory::createFactoryFor(2.0f) + }, + EntityConfig{ + .appearanceConfig = AppearanceConfig{ + .meshIndex = 1, + .color = ColorRgbs::magenta + }, + .behaviorFactory = BehaviorFactory::createFactoryFor(8.0f, 225.0_deg) + } + }, + .entityCreatedCallback = [](EntityId) { updateTitle(); }, + .entityDestroyedCallback = [](EntityId) { updateTitle(); } + }, + .startScript = []() { + PerformanceCounters::setCountersUpdatedCallback(updateTitle); + updateTitle(); + }, + .updateScript = []() { + if (Keyboard::isKeyPressed(KeyboardKey::keyEscape)) { + CurrentApp::close(); + } + + if (Keyboard::isKeyPressed(KeyboardKey::keyF1)) { + Renderer::setVsync(!Renderer::isUsingVsync()); + } + + if (Keyboard::isKeyPressed(KeyboardKey::keyF2)) { + Renderer::setTripleBuffering(!Renderer::isUsingTripleBuffering()); + } + } + } + ); + + int exitCode = app.run(); + + return exitCode; +} From ab445717af4d2139dbc65c4b23b0fca8041cd5a3 Mon Sep 17 00:00:00 2001 From: Henrik Date: Mon, 27 Oct 2025 10:04:16 +0100 Subject: [PATCH 08/17] Small update to demo 2 --- Demos/Demo2/Demo.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Demos/Demo2/Demo.cpp b/Demos/Demo2/Demo.cpp index 15c5f6d..1ff2fa1 100644 --- a/Demos/Demo2/Demo.cpp +++ b/Demos/Demo2/Demo.cpp @@ -56,7 +56,7 @@ class BulletBehavior : public BehaviorBase { auto& transform = m_context.getTransform(); transform.translate(m_velocity * DeltaTime::get()); - if (transform.getTranslation().distanceTo(Vector3s::zero) > 10.0f) + if (transform.getTranslation().distanceTo(Vector3s::zero) > 15.0f) m_context.destroyEntity(); } }; From 1db908a627b3bfd4a6d2871b1f60685af93d8519 Mon Sep 17 00:00:00 2001 From: Henrik Date: Mon, 27 Oct 2025 22:46:16 +0100 Subject: [PATCH 09/17] Update to github workflow --- .github/workflows/build-and-test.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index f854017..c34b61c 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -13,7 +13,7 @@ jobs: steps: - name: Checkout code - uses: actions/checkout@v2 + uses: actions/checkout@v4 - name: Setup MSVC dev environment uses: ilammy/msvc-dev-cmd@v1 @@ -43,7 +43,7 @@ jobs: steps: - name: Checkout code - uses: actions/checkout@v2 + uses: actions/checkout@v4 - name: Install ninja-build tool uses: seanmiddleditch/gha-setup-ninja@v3 @@ -72,7 +72,7 @@ jobs: steps: - name: Checkout code - uses: actions/checkout@v2 + uses: actions/checkout@v4 - name: Install ninja-build tool uses: seanmiddleditch/gha-setup-ninja@v3 From aa492e6cb758563eee87f88c050309633a7fcc97 Mon Sep 17 00:00:00 2001 From: Henrik Date: Mon, 27 Oct 2025 23:31:35 +0100 Subject: [PATCH 10/17] 2nd attempt --- .github/workflows/build-and-test.yml | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index c34b61c..0a2b90a 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -18,11 +18,8 @@ jobs: - name: Setup MSVC dev environment uses: ilammy/msvc-dev-cmd@v1 - - name: Install ninja-build tool - uses: seanmiddleditch/gha-setup-ninja@v3 - - name: Install Vulkan SDK - uses: humbletim/install-vulkan-sdk@81f46b36426f4ccdc1c0e7ab48109f3c98cfdc81 + uses: humbletim/install-vulkan-sdk@v1.2 with: version: 1.3.243.0 @@ -45,11 +42,8 @@ jobs: - name: Checkout code uses: actions/checkout@v4 - - name: Install ninja-build tool - uses: seanmiddleditch/gha-setup-ninja@v3 - - name: Install Vulkan SDK - uses: humbletim/install-vulkan-sdk@81f46b36426f4ccdc1c0e7ab48109f3c98cfdc81 + uses: humbletim/install-vulkan-sdk@v1.2 with: version: 1.3.243.0 @@ -74,16 +68,13 @@ jobs: - name: Checkout code uses: actions/checkout@v4 - - name: Install ninja-build tool - uses: seanmiddleditch/gha-setup-ninja@v3 - - name: Install platform-specific dependencies run: | sudo apt update sudo apt install libxinerama-dev libxcursor-dev xorg-dev libglu1-mesa-dev - name: Install Vulkan SDK - uses: humbletim/install-vulkan-sdk@81f46b36426f4ccdc1c0e7ab48109f3c98cfdc81 + uses: humbletim/install-vulkan-sdk@v1.2 with: version: 1.3.243.0 From c837f30907fa45055205d71dfde3a25af857dd69 Mon Sep 17 00:00:00 2001 From: Henrik Date: Wed, 29 Oct 2025 16:53:15 +0100 Subject: [PATCH 11/17] Updated Vulkan version, project dependencies and fixed breaking changes --- .github/workflows/build-and-test.yml | 6 +- Miracle/CMakeLists.txt | 4 +- .../Infrastructure/Ecs/Entt/EcsContainer.hpp | 4 +- .../Graphics/Vulkan/BufferUtilities.cpp | 133 +++++++++++------- .../Graphics/Vulkan/BufferUtilities.hpp | 6 +- .../Graphics/Vulkan/GraphicsContext.cpp | 57 ++++---- .../Graphics/Vulkan/GraphicsContext.hpp | 14 +- .../Graphics/Vulkan/IndexBuffer.cpp | 16 ++- .../Graphics/Vulkan/IndexBuffer.hpp | 2 +- .../Graphics/Vulkan/Swapchain.cpp | 91 +++++++----- .../Graphics/Vulkan/Swapchain.hpp | 4 +- .../Graphics/Vulkan/VertexBuffer.cpp | 16 ++- .../Graphics/Vulkan/VertexBuffer.hpp | 2 +- .../Infrastructure/Graphics/Vulkan/Vma.hpp | 2 +- vcpkg.json | 4 +- 15 files changed, 212 insertions(+), 149 deletions(-) diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index 0a2b90a..ec50ff0 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -21,7 +21,7 @@ jobs: - name: Install Vulkan SDK uses: humbletim/install-vulkan-sdk@v1.2 with: - version: 1.3.243.0 + version: 1.4.328.1 - name: Configure CMake run: | @@ -45,7 +45,7 @@ jobs: - name: Install Vulkan SDK uses: humbletim/install-vulkan-sdk@v1.2 with: - version: 1.3.243.0 + version: 1.4.328.1 - name: Configure CMake run: | @@ -76,7 +76,7 @@ jobs: - name: Install Vulkan SDK uses: humbletim/install-vulkan-sdk@v1.2 with: - version: 1.3.243.0 + version: 1.4.328.1 - name: Configure CMake run: | diff --git a/Miracle/CMakeLists.txt b/Miracle/CMakeLists.txt index 780ac24..c58d25b 100644 --- a/Miracle/CMakeLists.txt +++ b/Miracle/CMakeLists.txt @@ -15,7 +15,7 @@ find_package(spdlog CONFIG REQUIRED) find_package(glfw3 CONFIG REQUIRED) find_package(tinyfiledialogs CONFIG REQUIRED) find_package(Vulkan REQUIRED) -find_package(unofficial-vulkan-memory-allocator-hpp CONFIG REQUIRED) +find_package(VulkanMemoryAllocator CONFIG REQUIRED) find_package(EnTT CONFIG REQUIRED) # Link 3rd-party libraries @@ -25,7 +25,7 @@ target_link_libraries( PRIVATE glfw PRIVATE tinyfiledialogs::tinyfiledialogs PRIVATE Vulkan::Vulkan - PRIVATE unofficial::VulkanMemoryAllocator-Hpp::VulkanMemoryAllocator-Hpp + PRIVATE GPUOpen::VulkanMemoryAllocator PRIVATE EnTT::EnTT ) diff --git a/Miracle/src/Miracle/Infrastructure/Ecs/Entt/EcsContainer.hpp b/Miracle/src/Miracle/Infrastructure/Ecs/Entt/EcsContainer.hpp index af23d95..1102ca1 100644 --- a/Miracle/src/Miracle/Infrastructure/Ecs/Entt/EcsContainer.hpp +++ b/Miracle/src/Miracle/Infrastructure/Ecs/Entt/EcsContainer.hpp @@ -18,7 +18,9 @@ namespace Miracle::Infrastructure::Ecs::Entt { public: virtual size_t getEntityCount() const override { - return m_registry.storage()->in_use(); + auto test = m_registry.storage()->each(); + + return test.cend().base() - test.cbegin().base(); } virtual EntityId createEntity(const EntityConfig& config) override; diff --git a/Miracle/src/Miracle/Infrastructure/Graphics/Vulkan/BufferUtilities.cpp b/Miracle/src/Miracle/Infrastructure/Graphics/Vulkan/BufferUtilities.cpp index 1aeb72d..a259129 100644 --- a/Miracle/src/Miracle/Infrastructure/Graphics/Vulkan/BufferUtilities.cpp +++ b/Miracle/src/Miracle/Infrastructure/Graphics/Vulkan/BufferUtilities.cpp @@ -1,36 +1,56 @@ #include "BufferUtilities.hpp" #include +#include namespace Miracle::Infrastructure::Graphics::Vulkan { - std::pair BufferUtilities::createStagingBuffer( + std::tuple BufferUtilities::createStagingBuffer( GraphicsContext& m_context, vk::DeviceSize bufferSize ) { - return m_context.getAllocator().createBuffer( - vk::BufferCreateInfo{ - .flags = {}, - .size = bufferSize, - .usage = vk::BufferUsageFlagBits::eTransferSrc, - .sharingMode = vk::SharingMode::eExclusive, - .queueFamilyIndexCount = 0, - .pQueueFamilyIndices = nullptr - }, - vma::AllocationCreateInfo{ - .flags = vma::AllocationCreateFlagBits::eHostAccessSequentialWrite - | vma::AllocationCreateFlagBits::eMapped, - .usage = vma::MemoryUsage::eAuto, - .requiredFlags = {}, - .preferredFlags = {}, - .memoryTypeBits = {}, - .pool = nullptr, - .pUserData = nullptr, - .priority = 1.0f - } + auto createInfo = VkBufferCreateInfo{ + .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, + .pNext = {}, + .flags = {}, + .size = bufferSize, + .usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT, + .sharingMode = VK_SHARING_MODE_EXCLUSIVE, + .queueFamilyIndexCount = 0, + .pQueueFamilyIndices = nullptr + }; + + auto allocationCreateInfo = VmaAllocationCreateInfo{ + .flags = VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT + | VMA_ALLOCATION_CREATE_MAPPED_BIT, + .usage = VMA_MEMORY_USAGE_AUTO, + .requiredFlags = {}, + .preferredFlags = {}, + .memoryTypeBits = {}, + .pool = nullptr, + .pUserData = nullptr, + .priority = 1.0f + }; + + VkBuffer buffer; + VmaAllocation allocation; + VmaAllocationInfo allocationInfo; + + auto result = vmaCreateBuffer( + m_context.getAllocator(), + &createInfo, + &allocationCreateInfo, + &buffer, + &allocation, + &allocationInfo ); + + if (result != VK_SUCCESS) + throw std::runtime_error("vmaCreateBuffer"); + + return { buffer, allocation, allocationInfo }; } - std::pair BufferUtilities::createBuffer( + std::tuple BufferUtilities::createBuffer( GraphicsContext& m_context, vk::BufferUsageFlags usage, vk::DeviceSize bufferSize @@ -45,32 +65,51 @@ namespace Miracle::Infrastructure::Graphics::Vulkan { deviceInfo.queueFamilyIndices.transferFamilyIndex.value() }; - return m_context.getAllocator().createBuffer( - vk::BufferCreateInfo{ - .flags = {}, - .size = bufferSize, - .usage = usage | vk::BufferUsageFlagBits::eTransferDst, - .sharingMode = useSharingMode - ? vk::SharingMode::eConcurrent - : vk::SharingMode::eExclusive, - .queueFamilyIndexCount = useSharingMode - ? static_cast(queueFamilyIndexArray.size()) - : 0, - .pQueueFamilyIndices = useSharingMode - ? queueFamilyIndexArray.data() - : nullptr - }, - vma::AllocationCreateInfo{ - .flags = {}, - .usage = vma::MemoryUsage::eAuto, - .requiredFlags = {}, - .preferredFlags = {}, - .memoryTypeBits = {}, - .pool = nullptr, - .pUserData = nullptr, - .priority = 1.0f - } + auto createInfo = VkBufferCreateInfo{ + .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, + .pNext = {}, + .flags = {}, + .size = bufferSize, + .usage = static_cast(usage) | VK_BUFFER_USAGE_TRANSFER_DST_BIT, + .sharingMode = useSharingMode + ? VK_SHARING_MODE_CONCURRENT + : VK_SHARING_MODE_EXCLUSIVE, + .queueFamilyIndexCount = useSharingMode + ? static_cast(queueFamilyIndexArray.size()) + : 0, + .pQueueFamilyIndices = useSharingMode + ? queueFamilyIndexArray.data() + : nullptr + }; + + auto allocationCreateInfo = VmaAllocationCreateInfo{ + .flags = {}, + .usage = VMA_MEMORY_USAGE_AUTO, + .requiredFlags = {}, + .preferredFlags = {}, + .memoryTypeBits = {}, + .pool = nullptr, + .pUserData = nullptr, + .priority = 1.0f + }; + + VkBuffer buffer; + VmaAllocation allocation; + VmaAllocationInfo allocationInfo; + + auto result = vmaCreateBuffer( + m_context.getAllocator(), + &createInfo, + &allocationCreateInfo, + &buffer, + &allocation, + &allocationInfo ); + + if (result != VK_SUCCESS) + throw std::runtime_error("vmaCreateBuffer"); + + return { buffer, allocation, allocationInfo }; } void BufferUtilities::copyBuffer( diff --git a/Miracle/src/Miracle/Infrastructure/Graphics/Vulkan/BufferUtilities.hpp b/Miracle/src/Miracle/Infrastructure/Graphics/Vulkan/BufferUtilities.hpp index ab7c81d..be62f49 100644 --- a/Miracle/src/Miracle/Infrastructure/Graphics/Vulkan/BufferUtilities.hpp +++ b/Miracle/src/Miracle/Infrastructure/Graphics/Vulkan/BufferUtilities.hpp @@ -1,6 +1,6 @@ #pragma once -#include +#include #include "Vulkan.hpp" #include "Vma.hpp" @@ -11,12 +11,12 @@ namespace Miracle::Infrastructure::Graphics::Vulkan { public: BufferUtilities() = delete; - static std::pair createStagingBuffer( + static std::tuple createStagingBuffer( GraphicsContext& m_context, vk::DeviceSize bufferSize ); - static std::pair createBuffer( + static std::tuple createBuffer( GraphicsContext& m_context, vk::BufferUsageFlags usage, vk::DeviceSize bufferSize diff --git a/Miracle/src/Miracle/Infrastructure/Graphics/Vulkan/GraphicsContext.cpp b/Miracle/src/Miracle/Infrastructure/Graphics/Vulkan/GraphicsContext.cpp index 9dda762..02a20c5 100644 --- a/Miracle/src/Miracle/Infrastructure/Graphics/Vulkan/GraphicsContext.cpp +++ b/Miracle/src/Miracle/Infrastructure/Graphics/Vulkan/GraphicsContext.cpp @@ -69,7 +69,7 @@ namespace Miracle::Infrastructure::Graphics::Vulkan { GraphicsContext::~GraphicsContext() { m_logger.info("Destroying Vulkan graphics context..."); - m_allocator.destroy(); + vmaDestroyAllocator(m_allocator); } void GraphicsContext::setViewport( @@ -367,19 +367,19 @@ namespace Miracle::Infrastructure::Graphics::Vulkan { }; } - VKAPI_ATTR VkBool32 VKAPI_CALL GraphicsContext::logDebugMessage( - VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity, - VkDebugUtilsMessageTypeFlagsEXT messageType, - const VkDebugUtilsMessengerCallbackDataEXT* callbackData, + vk::Bool32 VKAPI_PTR GraphicsContext::logDebugMessage( + vk::DebugUtilsMessageSeverityFlagBitsEXT messageSeverity, + vk::DebugUtilsMessageTypeFlagsEXT messageType, + const vk::DebugUtilsMessengerCallbackDataEXT* callbackData, void* userData ) { switch (messageSeverity) { - case VkDebugUtilsMessageSeverityFlagBitsEXT::VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT: + case vk::DebugUtilsMessageSeverityFlagBitsEXT::eError: reinterpret_cast(userData) ->m_logger.error(callbackData->pMessage); break; - case VkDebugUtilsMessageSeverityFlagBitsEXT::VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT: + case vk::DebugUtilsMessageSeverityFlagBitsEXT::eWarning: reinterpret_cast(userData) ->m_logger.warning(callbackData->pMessage); break; @@ -582,27 +582,30 @@ namespace Miracle::Infrastructure::Graphics::Vulkan { } } - vma::Allocator GraphicsContext::createAllocator() const { - try { - return vma::createAllocator( - vma::AllocatorCreateInfo{ - .flags = {}, - .physicalDevice = *m_physicalDevice, - .device = *m_device, - .preferredLargeHeapBlockSize = {}, - .pAllocationCallbacks = {}, - .pDeviceMemoryCallbacks = {}, - .pHeapSizeLimit = {}, - .pVulkanFunctions = {}, - .instance = *m_instance, - .vulkanApiVersion = s_vulkanApiVersion, - .pTypeExternalMemoryHandleTypes = {} - } - ); - } - catch (const std::exception& e) { - m_logger.error(std::format("Failed to create Vulkan memory allocator for context.\n{}", e.what())); + VmaAllocator GraphicsContext::createAllocator() const { + auto createInfo = VmaAllocatorCreateInfo{ + .flags = {}, + .physicalDevice = *m_physicalDevice, + .device = *m_device, + .preferredLargeHeapBlockSize = {}, + .pAllocationCallbacks = {}, + .pDeviceMemoryCallbacks = {}, + .pHeapSizeLimit = {}, + .pVulkanFunctions = {}, + .instance = *m_instance, + .vulkanApiVersion = s_vulkanApiVersion, + .pTypeExternalMemoryHandleTypes = {} + }; + + VmaAllocator allocator; + + auto result = vmaCreateAllocator(&createInfo, &allocator); + + if (result != VK_SUCCESS) { + m_logger.error(std::format("Failed to create Vulkan memory allocator for context.\n{}", "vmaCreateAllocator")); throw Application::GraphicsContextErrors::CreationError(); } + + return allocator; } } diff --git a/Miracle/src/Miracle/Infrastructure/Graphics/Vulkan/GraphicsContext.hpp b/Miracle/src/Miracle/Infrastructure/Graphics/Vulkan/GraphicsContext.hpp index 2d5fca7..8e7aa86 100644 --- a/Miracle/src/Miracle/Infrastructure/Graphics/Vulkan/GraphicsContext.hpp +++ b/Miracle/src/Miracle/Infrastructure/Graphics/Vulkan/GraphicsContext.hpp @@ -45,7 +45,7 @@ namespace Miracle::Infrastructure::Graphics::Vulkan { std::vector m_renderingCompletedSemaphores; std::vector m_presentCompletedSemaphores; size_t m_currentGraphicsCommandBufferIndex = 0; - vma::Allocator m_allocator; + VmaAllocator m_allocator; public: GraphicsContext( @@ -118,7 +118,7 @@ namespace Miracle::Infrastructure::Graphics::Vulkan { return m_presentCompletedSemaphores[m_currentGraphicsCommandBufferIndex]; } - const vma::Allocator& getAllocator() const { return m_allocator; } + VmaAllocator getAllocator() const { return m_allocator; } SurfaceExtent getCurrentSurfaceExtent() const; @@ -144,10 +144,10 @@ namespace Miracle::Infrastructure::Graphics::Vulkan { vk::DebugUtilsMessengerCreateInfoEXT getDebugMessengerCreateInfo(); - static VKAPI_ATTR VkBool32 VKAPI_CALL logDebugMessage( - VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity, - VkDebugUtilsMessageTypeFlagsEXT messageType, - const VkDebugUtilsMessengerCallbackDataEXT* callbackData, + static vk::Bool32 VKAPI_PTR logDebugMessage( + vk::DebugUtilsMessageSeverityFlagBitsEXT messageSeverity, + vk::DebugUtilsMessageTypeFlagsEXT messageType, + const vk::DebugUtilsMessengerCallbackDataEXT* callbackData, void* userData ); #endif @@ -167,6 +167,6 @@ namespace Miracle::Infrastructure::Graphics::Vulkan { vk::raii::Semaphore createSemaphore() const; - vma::Allocator createAllocator() const; + VmaAllocator createAllocator() const; }; } diff --git a/Miracle/src/Miracle/Infrastructure/Graphics/Vulkan/IndexBuffer.cpp b/Miracle/src/Miracle/Infrastructure/Graphics/Vulkan/IndexBuffer.cpp index 0de26f8..9c0a611 100644 --- a/Miracle/src/Miracle/Infrastructure/Graphics/Vulkan/IndexBuffer.cpp +++ b/Miracle/src/Miracle/Infrastructure/Graphics/Vulkan/IndexBuffer.cpp @@ -21,16 +21,18 @@ namespace Miracle::Infrastructure::Graphics::Vulkan { auto requiredBufferSize = static_cast(sizeof(faces.front()) * faces.size()); - auto [stagingBuffer, stagingAllocation] = std::pair(); + auto [stagingBuffer, stagingAllocation, stagingAllocationInfo] = + std::tuple(); try { - auto [buffer, allocation] = BufferUtilities::createStagingBuffer( + auto [buffer, allocation, allocationInfo] = BufferUtilities::createStagingBuffer( m_context, requiredBufferSize ); stagingBuffer = buffer; stagingAllocation = allocation; + stagingAllocationInfo = allocationInfo; } catch (const std::exception& e) { m_logger.error( @@ -40,11 +42,11 @@ namespace Miracle::Infrastructure::Graphics::Vulkan { throw Application::IndexBufferErrors::CreationError(); } - auto stagingBufferData = m_context.getAllocator().getAllocationInfo(stagingAllocation).pMappedData; + auto stagingBufferData = stagingAllocationInfo.pMappedData; std::memcpy(stagingBufferData, faces.data(), requiredBufferSize); try { - auto [buffer, allocation] = BufferUtilities::createBuffer( + auto [buffer, allocation, allocationInfo] = BufferUtilities::createBuffer( m_context, vk::BufferUsageFlagBits::eIndexBuffer, requiredBufferSize @@ -58,13 +60,13 @@ namespace Miracle::Infrastructure::Graphics::Vulkan { std::format("Failed to create Vulkan index buffer.\n{}", e.what()) ); - m_context.getAllocator().destroyBuffer(stagingBuffer, stagingAllocation); + vmaDestroyBuffer(m_context.getAllocator(), stagingBuffer, stagingAllocation); throw Application::IndexBufferErrors::CreationError(); } BufferUtilities::copyBuffer(m_context, m_buffer, stagingBuffer, requiredBufferSize); - m_context.getAllocator().destroyBuffer(stagingBuffer, stagingAllocation); + vmaDestroyBuffer(m_context.getAllocator(), stagingBuffer, stagingAllocation); m_indexCount = faces.front().indices.size() * faces.size(); @@ -74,7 +76,7 @@ namespace Miracle::Infrastructure::Graphics::Vulkan { IndexBuffer::~IndexBuffer() { m_logger.info("Destroying Vulkan index buffer..."); - m_context.getAllocator().destroyBuffer(m_buffer, m_allocation); + vmaDestroyBuffer(m_context.getAllocator(), m_buffer, m_allocation); } void IndexBuffer::bind() { diff --git a/Miracle/src/Miracle/Infrastructure/Graphics/Vulkan/IndexBuffer.hpp b/Miracle/src/Miracle/Infrastructure/Graphics/Vulkan/IndexBuffer.hpp index 3ca9b02..7eb51e3 100644 --- a/Miracle/src/Miracle/Infrastructure/Graphics/Vulkan/IndexBuffer.hpp +++ b/Miracle/src/Miracle/Infrastructure/Graphics/Vulkan/IndexBuffer.hpp @@ -16,7 +16,7 @@ namespace Miracle::Infrastructure::Graphics::Vulkan { GraphicsContext& m_context; vk::Buffer m_buffer = nullptr; - vma::Allocation m_allocation = nullptr; + VmaAllocation m_allocation = nullptr; uint32_t m_indexCount = 0; public: diff --git a/Miracle/src/Miracle/Infrastructure/Graphics/Vulkan/Swapchain.cpp b/Miracle/src/Miracle/Infrastructure/Graphics/Vulkan/Swapchain.cpp index 7eaf9de..8d1dfdc 100644 --- a/Miracle/src/Miracle/Infrastructure/Graphics/Vulkan/Swapchain.cpp +++ b/Miracle/src/Miracle/Infrastructure/Graphics/Vulkan/Swapchain.cpp @@ -60,7 +60,7 @@ namespace Miracle::Infrastructure::Graphics::Vulkan { m_frameBuffers.clear(); m_depthImageView.clear(); - m_context.getAllocator().destroyImage(m_depthImage, m_depthImageAllocation); + vmaDestroyImage(m_context.getAllocator(), m_depthImage, m_depthImageAllocation); } Application::SwapchainImageSize Swapchain::getImageSize() const { @@ -137,7 +137,7 @@ namespace Miracle::Infrastructure::Graphics::Vulkan { m_frameBuffers.clear(); m_depthImageView.clear(); - m_context.getAllocator().destroyImage(m_depthImage, m_depthImageAllocation); + vmaDestroyImage(m_context.getAllocator(), m_depthImage, m_depthImageAllocation); m_images.clear(); m_swapchain.clear(); @@ -457,47 +457,62 @@ namespace Miracle::Infrastructure::Graphics::Vulkan { return m_context.getDeviceInfo().depthStencilOptimalTilingImageFormatsSupported.back(); } - std::pair Swapchain::createDepthImage() const { - try { - return m_context.getAllocator().createImage( - vk::ImageCreateInfo{ - .flags = {}, - .imageType = vk::ImageType::e2D, - .format = m_depthImageFormat, - .extent = vk::Extent3D{ - .width = m_imageExtent.width, - .height = m_imageExtent.height, - .depth = 1 - }, - .mipLevels = 1, - .arrayLayers = 1, - .samples = vk::SampleCountFlagBits::e1, - .tiling = vk::ImageTiling::eOptimal, - .usage = vk::ImageUsageFlagBits::eDepthStencilAttachment, - .sharingMode = vk::SharingMode::eExclusive, - .queueFamilyIndexCount = 0, - .pQueueFamilyIndices = nullptr, - .initialLayout = vk::ImageLayout::eUndefined - }, - vma::AllocationCreateInfo{ - .flags = {}, - .usage = vma::MemoryUsage::eAuto, - .requiredFlags = {}, - .preferredFlags = {}, - .memoryTypeBits = {}, - .pool = nullptr, - .pUserData = nullptr, - .priority = 1.0 - } - ); - } - catch (const std::exception& e) { + std::pair Swapchain::createDepthImage() const { + auto createInfo = VkImageCreateInfo{ + .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, + .pNext = {}, + .flags = {}, + .imageType = VK_IMAGE_TYPE_2D, + .format = static_cast(m_depthImageFormat), + .extent = VkExtent3D{ + .width = m_imageExtent.width, + .height = m_imageExtent.height, + .depth = 1 + }, + .mipLevels = 1, + .arrayLayers = 1, + .samples = VK_SAMPLE_COUNT_1_BIT, + .tiling = VK_IMAGE_TILING_OPTIMAL, + .usage = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT, + .sharingMode = VK_SHARING_MODE_EXCLUSIVE, + .queueFamilyIndexCount = 0, + .pQueueFamilyIndices = nullptr, + .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED + }; + + auto allocationCreateInfo = VmaAllocationCreateInfo{ + .flags = {}, + .usage = VMA_MEMORY_USAGE_AUTO, + .requiredFlags = {}, + .preferredFlags = {}, + .memoryTypeBits = {}, + .pool = nullptr, + .pUserData = nullptr, + .priority = 1.0 + }; + + VkImage image; + VmaAllocation allocation; + VmaAllocationInfo allocationInfo; + + auto result = vmaCreateImage( + m_context.getAllocator(), + &createInfo, + &allocationCreateInfo, + &image, + &allocation, + &allocationInfo + ); + + if (result != VK_SUCCESS) { m_logger.error( - std::format("Failed to create Vulkan depth image for swapchain.\n{}", e.what()) + std::format("Failed to create Vulkan depth image for swapchain.\n{}", "vmaCreateImage") ); throw Application::SwapchainErrors::CreationError(); } + + return { image, allocation }; } vk::raii::ImageView Swapchain::createDepthImageView(const vk::Image& depthImage) const { diff --git a/Miracle/src/Miracle/Infrastructure/Graphics/Vulkan/Swapchain.hpp b/Miracle/src/Miracle/Infrastructure/Graphics/Vulkan/Swapchain.hpp index c746779..a9823eb 100644 --- a/Miracle/src/Miracle/Infrastructure/Graphics/Vulkan/Swapchain.hpp +++ b/Miracle/src/Miracle/Infrastructure/Graphics/Vulkan/Swapchain.hpp @@ -23,7 +23,7 @@ namespace Miracle::Infrastructure::Graphics::Vulkan { std::vector> m_images; vk::Format m_depthImageFormat; vk::Image m_depthImage; - vma::Allocation m_depthImageAllocation; + VmaAllocation m_depthImageAllocation; vk::raii::ImageView m_depthImageView = nullptr; vk::raii::RenderPass m_renderPass = nullptr; std::vector m_frameBuffers; @@ -81,7 +81,7 @@ namespace Miracle::Infrastructure::Graphics::Vulkan { vk::Format selectOptimalTilingDepthImageFormat() const; - std::pair createDepthImage() const; + std::pair createDepthImage() const; vk::raii::ImageView createDepthImageView(const vk::Image& depthImage) const; diff --git a/Miracle/src/Miracle/Infrastructure/Graphics/Vulkan/VertexBuffer.cpp b/Miracle/src/Miracle/Infrastructure/Graphics/Vulkan/VertexBuffer.cpp index 8dc3b19..1abe266 100644 --- a/Miracle/src/Miracle/Infrastructure/Graphics/Vulkan/VertexBuffer.cpp +++ b/Miracle/src/Miracle/Infrastructure/Graphics/Vulkan/VertexBuffer.cpp @@ -21,16 +21,18 @@ namespace Miracle::Infrastructure::Graphics::Vulkan { auto requiredBufferSize = static_cast(sizeof(vertices.front()) * vertices.size()); - auto [stagingBuffer, stagingAllocation] = std::pair(); + auto [stagingBuffer, stagingAllocation, stagingAllocationInfo] = + std::tuple(); try { - auto [buffer, allocation] = BufferUtilities::createStagingBuffer( + auto [buffer, allocation, allocationInfo] = BufferUtilities::createStagingBuffer( m_context, requiredBufferSize ); stagingBuffer = buffer; stagingAllocation = allocation; + stagingAllocationInfo = allocationInfo; } catch (const std::exception& e) { m_logger.error( @@ -40,11 +42,11 @@ namespace Miracle::Infrastructure::Graphics::Vulkan { throw Application::VertexBufferErrors::CreationError(); } - auto stagingBufferData = m_context.getAllocator().getAllocationInfo(stagingAllocation).pMappedData; + auto stagingBufferData = stagingAllocationInfo.pMappedData; std::memcpy(stagingBufferData, vertices.data(), requiredBufferSize); try { - auto [buffer, allocation] = BufferUtilities::createBuffer( + auto [buffer, allocation, allocationInfo] = BufferUtilities::createBuffer( m_context, vk::BufferUsageFlagBits::eVertexBuffer, requiredBufferSize @@ -58,13 +60,13 @@ namespace Miracle::Infrastructure::Graphics::Vulkan { std::format("Failed to create Vulkan vertex buffer.\n{}", e.what()) ); - m_context.getAllocator().destroyBuffer(stagingBuffer, stagingAllocation); + vmaDestroyBuffer(m_context.getAllocator(), stagingBuffer, stagingAllocation); throw Application::VertexBufferErrors::CreationError(); } BufferUtilities::copyBuffer(m_context, m_buffer, stagingBuffer, requiredBufferSize); - m_context.getAllocator().destroyBuffer(stagingBuffer, stagingAllocation); + vmaDestroyBuffer(m_context.getAllocator(), stagingBuffer, stagingAllocation); m_vertexCount = vertices.size(); @@ -74,7 +76,7 @@ namespace Miracle::Infrastructure::Graphics::Vulkan { VertexBuffer::~VertexBuffer() { m_logger.info("Destroying Vulkan vertex buffer..."); - m_context.getAllocator().destroyBuffer(m_buffer, m_allocation); + vmaDestroyBuffer(m_context.getAllocator(), m_buffer, m_allocation); } void VertexBuffer::bind() { diff --git a/Miracle/src/Miracle/Infrastructure/Graphics/Vulkan/VertexBuffer.hpp b/Miracle/src/Miracle/Infrastructure/Graphics/Vulkan/VertexBuffer.hpp index 1dcd34f..594d68a 100644 --- a/Miracle/src/Miracle/Infrastructure/Graphics/Vulkan/VertexBuffer.hpp +++ b/Miracle/src/Miracle/Infrastructure/Graphics/Vulkan/VertexBuffer.hpp @@ -16,7 +16,7 @@ namespace Miracle::Infrastructure::Graphics::Vulkan { GraphicsContext& m_context; vk::Buffer m_buffer = nullptr; - vma::Allocation m_allocation = nullptr; + VmaAllocation m_allocation = nullptr; uint32_t m_vertexCount = 0; public: diff --git a/Miracle/src/Miracle/Infrastructure/Graphics/Vulkan/Vma.hpp b/Miracle/src/Miracle/Infrastructure/Graphics/Vulkan/Vma.hpp index d2931d2..6638988 100644 --- a/Miracle/src/Miracle/Infrastructure/Graphics/Vulkan/Vma.hpp +++ b/Miracle/src/Miracle/Infrastructure/Graphics/Vulkan/Vma.hpp @@ -1,4 +1,4 @@ #pragma once #include "Vulkan.hpp" -#include +#include diff --git a/vcpkg.json b/vcpkg.json index 7215df8..5d3485a 100644 --- a/vcpkg.json +++ b/vcpkg.json @@ -1,12 +1,12 @@ { "$schema": "https://raw.githubusercontent.com/microsoft/vcpkg-tool/main/docs/vcpkg.schema.json", - "builtin-baseline": "c6d6efed3e9b4242765bfe1b5c5befffd85f7b92", + "builtin-baseline": "46f0f5e38a1127e1fd0d4106024889958d746178", "dependencies": [ "spdlog", "glfw3", "tinyfiledialogs", "vulkan", - "vulkan-memory-allocator-hpp", + "vulkan-memory-allocator", "entt" ] } From eccca77486fce769bb6458bc69326c2863f689c3 Mon Sep 17 00:00:00 2001 From: Henrik Date: Sun, 9 Nov 2025 06:24:30 +0100 Subject: [PATCH 12/17] Finally fixed Vulkan sync issues --- .../Application/Graphics/ISwapchain.hpp | 2 + .../Miracle/Common/Models/SwapchainConfig.hpp | 2 +- Miracle/src/Miracle/App.cpp | 2 +- .../Miracle/Application/Graphics/Renderer.cpp | 2 + .../Infrastructure/Ecs/Entt/EcsContainer.hpp | 4 +- .../Graphics/Vulkan/GraphicsContext.cpp | 39 +++++++++---------- .../Graphics/Vulkan/GraphicsContext.hpp | 30 +++++++++----- .../Graphics/Vulkan/Swapchain.cpp | 27 +++++++++---- .../Graphics/Vulkan/Swapchain.hpp | 2 + 9 files changed, 68 insertions(+), 42 deletions(-) diff --git a/Miracle/include/Miracle/Application/Graphics/ISwapchain.hpp b/Miracle/include/Miracle/Application/Graphics/ISwapchain.hpp index d95c44a..eee3a83 100644 --- a/Miracle/include/Miracle/Application/Graphics/ISwapchain.hpp +++ b/Miracle/include/Miracle/Application/Graphics/ISwapchain.hpp @@ -21,6 +21,8 @@ namespace Miracle::Application { // Graphics command virtual void endRenderPass() = 0; + virtual void prepareNextImage() = 0; + virtual void swap() = 0; virtual void recreate() = 0; diff --git a/Miracle/include/Miracle/Common/Models/SwapchainConfig.hpp b/Miracle/include/Miracle/Common/Models/SwapchainConfig.hpp index c919c12..3d0cca3 100644 --- a/Miracle/include/Miracle/Common/Models/SwapchainConfig.hpp +++ b/Miracle/include/Miracle/Common/Models/SwapchainConfig.hpp @@ -2,7 +2,7 @@ namespace Miracle { struct SwapchainConfig { - bool useVsync = false; + bool useVsync = false; bool useTripleBuffering = false; }; } diff --git a/Miracle/src/Miracle/App.cpp b/Miracle/src/Miracle/App.cpp index d158547..5aeb487 100644 --- a/Miracle/src/Miracle/App.cpp +++ b/Miracle/src/Miracle/App.cpp @@ -105,7 +105,7 @@ namespace Miracle { currentScene.update(); performanceCountingService.incrementUpdateCounter(); - bool frameRendered = renderer.render(sceneManager.getCurrentScene()); + bool frameRendered = renderer.render(currentScene); if (frameRendered) { performanceCountingService.incrementFrameCounter(); diff --git a/Miracle/src/Miracle/Application/Graphics/Renderer.cpp b/Miracle/src/Miracle/Application/Graphics/Renderer.cpp index 4e2cad1..a7d0ad6 100644 --- a/Miracle/src/Miracle/Application/Graphics/Renderer.cpp +++ b/Miracle/src/Miracle/Application/Graphics/Renderer.cpp @@ -78,6 +78,8 @@ namespace Miracle::Application { auto viewProjection = view * projection; + m_swapchain->prepareNextImage(); + m_context.recordGraphicsCommands( [&]() { m_swapchain->beginRenderPass(scene.getBackgroundColor()); diff --git a/Miracle/src/Miracle/Infrastructure/Ecs/Entt/EcsContainer.hpp b/Miracle/src/Miracle/Infrastructure/Ecs/Entt/EcsContainer.hpp index 1102ca1..72545b4 100644 --- a/Miracle/src/Miracle/Infrastructure/Ecs/Entt/EcsContainer.hpp +++ b/Miracle/src/Miracle/Infrastructure/Ecs/Entt/EcsContainer.hpp @@ -18,9 +18,9 @@ namespace Miracle::Infrastructure::Ecs::Entt { public: virtual size_t getEntityCount() const override { - auto test = m_registry.storage()->each(); + auto entityIteratorAdaptor = m_registry.storage()->each(); - return test.cend().base() - test.cbegin().base(); + return entityIteratorAdaptor.cend().base() - entityIteratorAdaptor.cbegin().base(); } virtual EntityId createEntity(const EntityConfig& config) override; diff --git a/Miracle/src/Miracle/Infrastructure/Graphics/Vulkan/GraphicsContext.cpp b/Miracle/src/Miracle/Infrastructure/Graphics/Vulkan/GraphicsContext.cpp index 02a20c5..f2ee63d 100644 --- a/Miracle/src/Miracle/Infrastructure/Graphics/Vulkan/GraphicsContext.cpp +++ b/Miracle/src/Miracle/Infrastructure/Graphics/Vulkan/GraphicsContext.cpp @@ -51,14 +51,12 @@ namespace Miracle::Infrastructure::Graphics::Vulkan { .front() ); + m_imageAcquiredSemaphores.reserve(m_graphicsCommandBuffers.size()); m_renderingCompletedFences.reserve(m_graphicsCommandBuffers.size()); - m_renderingCompletedSemaphores.reserve(m_graphicsCommandBuffers.size()); - m_presentCompletedSemaphores.reserve(m_graphicsCommandBuffers.size()); for (size_t i = 0; i < m_graphicsCommandBuffers.size(); i++) { + m_imageAcquiredSemaphores.push_back(createSemaphore()); m_renderingCompletedFences.push_back(createFence(true)); - m_renderingCompletedSemaphores.push_back(createSemaphore()); - m_presentCompletedSemaphores.push_back(createSemaphore()); } m_allocator = createAllocator(); @@ -129,16 +127,6 @@ namespace Miracle::Infrastructure::Graphics::Vulkan { } void GraphicsContext::recordGraphicsCommands(const std::function& recording) { - auto result = m_device.waitForFences( - *m_renderingCompletedFences[m_currentGraphicsCommandBufferIndex], - true, - std::numeric_limits::max() - ); - - if (result == vk::Result::eTimeout) [[unlikely]] { - m_logger.warning("Timed out on waiting for Vulkan fence"); - } - m_graphicsCommandBuffers[m_currentGraphicsCommandBufferIndex].begin( vk::CommandBufferBeginInfo{ .flags = {}, @@ -173,12 +161,12 @@ namespace Miracle::Infrastructure::Graphics::Vulkan { m_graphicsQueue.submit( vk::SubmitInfo{ .waitSemaphoreCount = 1, - .pWaitSemaphores = &*m_presentCompletedSemaphores[m_currentGraphicsCommandBufferIndex], + .pWaitSemaphores = &*m_imageAcquiredSemaphores[m_currentGraphicsCommandBufferIndex], .pWaitDstStageMask = &waitStage, .commandBufferCount = 1, .pCommandBuffers = &*m_graphicsCommandBuffers[m_currentGraphicsCommandBufferIndex], .signalSemaphoreCount = 1, - .pSignalSemaphores = &*m_renderingCompletedSemaphores[m_currentGraphicsCommandBufferIndex] + .pSignalSemaphores = &*getGraphicsCommandsExecutedSemaphore() }, * m_renderingCompletedFences[m_currentGraphicsCommandBufferIndex] ); @@ -217,11 +205,20 @@ namespace Miracle::Infrastructure::Graphics::Vulkan { }; } - void GraphicsContext::recreatePresentCompletedSemaphores() { - m_presentCompletedSemaphores.clear(); - - for (size_t i = 0; i < m_graphicsCommandBuffers.size(); i++) { - m_presentCompletedSemaphores.push_back(createSemaphore()); + void GraphicsContext::allocateGraphicsCommandsExecutedSemaphores(size_t count) { + m_graphicsCommandsExecutedSemaphores.clear(); + m_graphicsCommandsExecutedSemaphores.reserve(count); + + for (size_t i = 0; i < count; i++) { + m_graphicsCommandsExecutedSemaphores.push_back( + std::make_pair, size_t>( + std::array{ + createSemaphore(), + createSemaphore() + }, + 0 + ) + ); } } diff --git a/Miracle/src/Miracle/Infrastructure/Graphics/Vulkan/GraphicsContext.hpp b/Miracle/src/Miracle/Infrastructure/Graphics/Vulkan/GraphicsContext.hpp index 8e7aa86..506552a 100644 --- a/Miracle/src/Miracle/Infrastructure/Graphics/Vulkan/GraphicsContext.hpp +++ b/Miracle/src/Miracle/Infrastructure/Graphics/Vulkan/GraphicsContext.hpp @@ -6,6 +6,7 @@ #include #include #include +#include #include #include @@ -19,7 +20,7 @@ namespace Miracle::Infrastructure::Graphics::Vulkan { class GraphicsContext : public Application::IGraphicsContext { private: - static constexpr uint32_t s_vulkanApiVersion = VK_API_VERSION_1_1; + static constexpr uint32_t s_vulkanApiVersion = vk::ApiVersion11; static constexpr auto s_validationLayerNames = std::array{ "VK_LAYER_KHRONOS_validation" }; Application::ILogger& m_logger; @@ -41,10 +42,11 @@ namespace Miracle::Infrastructure::Graphics::Vulkan { vk::raii::CommandPool m_transferCommandPool = nullptr; std::vector m_graphicsCommandBuffers; vk::raii::CommandBuffer m_transferCommandBuffer = nullptr; + std::vector m_imageAcquiredSemaphores; + std::vector, size_t>> m_graphicsCommandsExecutedSemaphores; std::vector m_renderingCompletedFences; - std::vector m_renderingCompletedSemaphores; - std::vector m_presentCompletedSemaphores; size_t m_currentGraphicsCommandBufferIndex = 0; + size_t m_graphicsCommandsExecutedSemaphoreIndex = 0; VmaAllocator m_allocator; public: @@ -110,12 +112,22 @@ namespace Miracle::Infrastructure::Graphics::Vulkan { return m_transferCommandBuffer; } - const vk::raii::Semaphore& getGraphicsCommandExecutionCompletedSemaphore() const { - return m_renderingCompletedSemaphores[m_currentGraphicsCommandBufferIndex]; + const vk::raii::Semaphore& getImageAcquiredSemaphore() const { + return m_imageAcquiredSemaphores[m_currentGraphicsCommandBufferIndex]; } - const vk::raii::Semaphore& getGraphicsCommandPresentCompletedSemaphore() const { - return m_presentCompletedSemaphores[m_currentGraphicsCommandBufferIndex]; + const vk::raii::Semaphore& getGraphicsCommandsExecutedSemaphore() const { + auto& [semaphores, index] = m_graphicsCommandsExecutedSemaphores[m_graphicsCommandsExecutedSemaphoreIndex]; + return semaphores[index]; + } + + void setGraphicsCommandsExecutedSemaphoreIndex(size_t index) { + m_graphicsCommandsExecutedSemaphoreIndex = index; + ++m_graphicsCommandsExecutedSemaphores[m_graphicsCommandsExecutedSemaphoreIndex].second %= 2; + } + + const vk::raii::Fence& getRenderingCompletedFence() const { + return m_renderingCompletedFences[m_currentGraphicsCommandBufferIndex]; } VmaAllocator getAllocator() const { return m_allocator; } @@ -126,12 +138,12 @@ namespace Miracle::Infrastructure::Graphics::Vulkan { return m_physicalDevice.getSurfaceCapabilitiesKHR(*m_surface).currentTransform; } + void allocateGraphicsCommandsExecutedSemaphores(size_t count); + void nextGraphicsCommandBuffer() { ++m_currentGraphicsCommandBufferIndex %= m_graphicsCommandBuffers.size(); } - void recreatePresentCompletedSemaphores(); - private: vk::raii::Instance createInstance(const std::string_view& appName); diff --git a/Miracle/src/Miracle/Infrastructure/Graphics/Vulkan/Swapchain.cpp b/Miracle/src/Miracle/Infrastructure/Graphics/Vulkan/Swapchain.cpp index 8d1dfdc..51305b6 100644 --- a/Miracle/src/Miracle/Infrastructure/Graphics/Vulkan/Swapchain.cpp +++ b/Miracle/src/Miracle/Infrastructure/Graphics/Vulkan/Swapchain.cpp @@ -44,7 +44,7 @@ namespace Miracle::Infrastructure::Graphics::Vulkan { m_frameBuffers.push_back(createFrameBuffer(imageView)); } - m_imageIndex = getNextImageIndex(); + m_context.allocateGraphicsCommandsExecutedSemaphores(m_images.size()); m_logger.info( std::format( @@ -112,11 +112,26 @@ namespace Miracle::Infrastructure::Graphics::Vulkan { m_context.getGraphicsCommandBuffer().endRenderPass(); } + void Swapchain::prepareNextImage() { + auto result = m_context.getDevice().waitForFences( + *m_context.getRenderingCompletedFence(), + true, + std::numeric_limits::max() + ); + + if (result == vk::Result::eTimeout) [[unlikely]] { + m_logger.warning("Timed out on waiting for Vulkan fence"); + } + + m_imageIndex = getNextImageIndex(); + m_context.setGraphicsCommandsExecutedSemaphoreIndex(m_imageIndex); + } + void Swapchain::swap() { auto result = m_context.getPresentQueue().presentKHR( vk::PresentInfoKHR{ .waitSemaphoreCount = 1, - .pWaitSemaphores = &*m_context.getGraphicsCommandExecutionCompletedSemaphore(), + .pWaitSemaphores = &*m_context.getGraphicsCommandsExecutedSemaphore(), .swapchainCount = 1, .pSwapchains = &*m_swapchain, .pImageIndices = &m_imageIndex, @@ -129,8 +144,6 @@ namespace Miracle::Infrastructure::Graphics::Vulkan { } m_context.nextGraphicsCommandBuffer(); - - m_imageIndex = getNextImageIndex(); } void Swapchain::recreate() { @@ -161,9 +174,7 @@ namespace Miracle::Infrastructure::Graphics::Vulkan { m_frameBuffers.push_back(createFrameBuffer(imageView)); } - m_context.recreatePresentCompletedSemaphores(); - - m_imageIndex = getNextImageIndex(); + m_context.allocateGraphicsCommandsExecutedSemaphores(m_images.size()); m_logger.info( std::format( @@ -554,7 +565,7 @@ namespace Miracle::Infrastructure::Graphics::Vulkan { uint32_t Swapchain::getNextImageIndex() { auto [result, imageIndex] = m_swapchain.acquireNextImage( std::numeric_limits().max(), - *m_context.getGraphicsCommandPresentCompletedSemaphore() + *m_context.getImageAcquiredSemaphore() ); switch (result) { diff --git a/Miracle/src/Miracle/Infrastructure/Graphics/Vulkan/Swapchain.hpp b/Miracle/src/Miracle/Infrastructure/Graphics/Vulkan/Swapchain.hpp index a9823eb..9431b8e 100644 --- a/Miracle/src/Miracle/Infrastructure/Graphics/Vulkan/Swapchain.hpp +++ b/Miracle/src/Miracle/Infrastructure/Graphics/Vulkan/Swapchain.hpp @@ -44,6 +44,8 @@ namespace Miracle::Infrastructure::Graphics::Vulkan { virtual void endRenderPass() override; + virtual void prepareNextImage() override; + virtual void swap() override; virtual void recreate() override; From cd120f5b10d52392a2fe52f5c46455a59e20185c Mon Sep 17 00:00:00 2001 From: Henrik Date: Sun, 9 Nov 2025 06:28:26 +0100 Subject: [PATCH 13/17] Changed Vulkan version in workflow --- .github/workflows/build-and-test.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index ec50ff0..62d7ae2 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -21,7 +21,7 @@ jobs: - name: Install Vulkan SDK uses: humbletim/install-vulkan-sdk@v1.2 with: - version: 1.4.328.1 + version: 1.4.309.0 - name: Configure CMake run: | @@ -45,7 +45,7 @@ jobs: - name: Install Vulkan SDK uses: humbletim/install-vulkan-sdk@v1.2 with: - version: 1.4.328.1 + version: 1.4.309.0 - name: Configure CMake run: | @@ -76,7 +76,7 @@ jobs: - name: Install Vulkan SDK uses: humbletim/install-vulkan-sdk@v1.2 with: - version: 1.4.328.1 + version: 1.4.309.0 - name: Configure CMake run: | From e0bd665f6ba72f4b471d0af8703aff12cad1d26d Mon Sep 17 00:00:00 2001 From: Henrik Date: Sun, 9 Nov 2025 06:33:28 +0100 Subject: [PATCH 14/17] Attempt at fixing macOS workflow --- .github/workflows/build-and-test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index 62d7ae2..2190ad0 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -52,7 +52,7 @@ jobs: export VCPKG_ROOT=$VCPKG_INSTALLATION_ROOT cmake --preset macos-release env: - CXX: g++-13 + CXX: gcc-13 - name: Build run: cmake --build --preset macos-release-build From a716bfb938a60faa5830a655e95de962e619be44 Mon Sep 17 00:00:00 2001 From: Henrik Date: Sun, 9 Nov 2025 23:53:48 +0100 Subject: [PATCH 15/17] Switch macOS preset to use ARM triplet for vcpkg --- .github/workflows/build-and-test.yml | 2 +- CMakePresets.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index 2190ad0..62d7ae2 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -52,7 +52,7 @@ jobs: export VCPKG_ROOT=$VCPKG_INSTALLATION_ROOT cmake --preset macos-release env: - CXX: gcc-13 + CXX: g++-13 - name: Build run: cmake --build --preset macos-release-build diff --git a/CMakePresets.json b/CMakePresets.json index 75f0934..01c829d 100644 --- a/CMakePresets.json +++ b/CMakePresets.json @@ -46,7 +46,7 @@ "inherits": "base", "cacheVariables": { "CMAKE_BUILD_TYPE": "Debug", - "VCPKG_TARGET_TRIPLET": "x64-osx" + "VCPKG_TARGET_TRIPLET": "arm64-osx" }, "condition": { "type": "equals", From 72f4b941ea0cdad81fbdb051d1275ba7b028b532 Mon Sep 17 00:00:00 2001 From: Henrik Date: Mon, 10 Nov 2025 04:07:35 +0100 Subject: [PATCH 16/17] Test --- .github/workflows/build-and-test.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index 62d7ae2..99b449b 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -18,6 +18,9 @@ jobs: - name: Setup MSVC dev environment uses: ilammy/msvc-dev-cmd@v1 + - name: Test + run: curl https://sourceforge.net/p/tinyfiledialogs/code/ci/b071fb40ad9b321408d480a6d1433bf21be01578/tree/tinyfiledialogs.c?format=raw --output test.c + - name: Install Vulkan SDK uses: humbletim/install-vulkan-sdk@v1.2 with: From 73b76c78a1e781e80cd39bec9dbb6befdec2c1f3 Mon Sep 17 00:00:00 2001 From: Henrik Date: Tue, 11 Nov 2025 04:08:37 +0100 Subject: [PATCH 17/17] Remove test step --- .github/workflows/build-and-test.yml | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index 99b449b..933f2b5 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -18,9 +18,6 @@ jobs: - name: Setup MSVC dev environment uses: ilammy/msvc-dev-cmd@v1 - - name: Test - run: curl https://sourceforge.net/p/tinyfiledialogs/code/ci/b071fb40ad9b321408d480a6d1433bf21be01578/tree/tinyfiledialogs.c?format=raw --output test.c - - name: Install Vulkan SDK uses: humbletim/install-vulkan-sdk@v1.2 with: @@ -37,7 +34,7 @@ jobs: - name: Test run: ctest --preset x64-release-tests - # Mac OS + # macOS macos-build-and-test: runs-on: macos-latest