diff --git a/examples/VulkanTest/main.cpp b/examples/VulkanTest/main.cpp index d4e2ba25d..9612cacd9 100644 --- a/examples/VulkanTest/main.cpp +++ b/examples/VulkanTest/main.cpp @@ -114,18 +114,6 @@ int main() // Vertex buffer std::cout << "Vertex count: " << drfreakVB->GetVertexCount() << std::endl; - Nz::VkRenderWindow& vulkanWindow = *static_cast(window.GetImpl()); - Nz::VulkanDevice& vulkanDevice = vulkanWindow.GetDevice(); - - Nz::Vk::CommandPool cmdPool; - if (!cmdPool.Create(vulkanDevice, 0, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT)) - { - NazaraError("Failed to create rendering cmd pool"); - return __LINE__; - } - - Nz::Vk::QueueHandle graphicsQueue = vulkanDevice.GetQueue(0, 0); - // Texture Nz::ImageRef drfreakImage = Nz::Image::LoadFromFile("resources/Spaceship/Texture/diffuse.png"); if (!drfreakImage || !drfreakImage->Convert(Nz::PixelFormatType_RGBA8)) @@ -219,8 +207,11 @@ int main() clearValues[0].color = {0.0f, 0.0f, 0.0f, 0.0f}; clearValues[1].depthStencil = {1.f, 0}; + Nz::VkRenderWindow& vulkanWindow = *static_cast(window.GetImpl()); + Nz::VulkanDevice& vulkanDevice = vulkanWindow.GetDevice(); + Nz::UInt32 imageCount = vulkanWindow.GetFramebufferCount(); - std::vector renderCmds = cmdPool.AllocateCommandBuffers(imageCount, VK_COMMAND_BUFFER_LEVEL_PRIMARY); + std::vector> renderCmds(imageCount); Nz::RenderBuffer* renderBufferIB = static_cast(drfreakIB->GetBuffer()->GetImpl()); Nz::RenderBuffer* renderBufferVB = static_cast(drfreakVB->GetBuffer()->GetImpl()); @@ -237,18 +228,14 @@ int main() return __LINE__; } - Nz::VulkanBuffer* indexBufferImpl = static_cast(renderBufferIB->GetHardwareBuffer(&vulkanDevice)); - Nz::VulkanBuffer* vertexBufferImpl = static_cast(renderBufferVB->GetHardwareBuffer(&vulkanDevice)); + Nz::AbstractBuffer* indexBufferImpl = renderBufferIB->GetHardwareBuffer(&vulkanDevice); + Nz::AbstractBuffer* vertexBufferImpl = renderBufferVB->GetHardwareBuffer(&vulkanDevice); Nz::VulkanRenderPipeline* vkPipeline = static_cast(pipeline.get()); - Nz::VulkanRenderPipelineLayout* vkPipelineLayout = static_cast(renderPipelineLayout.get()); - - Nz::VulkanShaderBinding& vkShaderBinding = static_cast(shaderBinding); - for (Nz::UInt32 i = 0; i < imageCount; ++i) { - Nz::Vk::CommandBuffer& renderCmd = renderCmds[i]; + auto& commandBufferPtr = renderCmds[i]; VkRect2D renderArea = { { // VkOffset2D offset @@ -271,24 +258,29 @@ int main() clearValues.data() // const VkClearValue *pClearValues }; - renderCmd.Begin(); - renderCmd.BeginDebugRegion("Main window rendering", Nz::Color::Green); - renderCmd.BeginRenderPass(render_pass_begin_info); - renderCmd.BindIndexBuffer(indexBufferImpl->GetBuffer(), 0, VK_INDEX_TYPE_UINT16); - renderCmd.BindVertexBuffer(0, vertexBufferImpl->GetBuffer(), 0); - renderCmd.BindDescriptorSet(VK_PIPELINE_BIND_POINT_GRAPHICS, vkPipelineLayout->GetPipelineLayout(), 0, vkShaderBinding.GetDescriptorSet()); - renderCmd.BindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, vkPipeline->Get(vulkanWindow.GetRenderPass())); - renderCmd.SetScissor(Nz::Recti{0, 0, int(windowSize.x), int(windowSize.y)}); - renderCmd.SetViewport({0.f, 0.f, float(windowSize.x), float(windowSize.y)}, 0.f, 1.f); - renderCmd.DrawIndexed(drfreakIB->GetIndexCount()); - renderCmd.EndRenderPass(); - renderCmd.EndDebugRegion(); - - if (!renderCmd.End()) + commandBufferPtr = vulkanWindow.BuildCommandBuffer([&](Nz::CommandBufferBuilder& builder) { - NazaraError("Failed to specify render cmd"); - return __LINE__; - } + Nz::Vk::CommandBuffer& vkCommandBuffer = static_cast(builder).GetCommandBuffer(); + + builder.BeginDebugRegion("Main window rendering", Nz::Color::Green); + { + vkCommandBuffer.BeginRenderPass(render_pass_begin_info); + { + builder.BindIndexBuffer(indexBufferImpl); + builder.BindVertexBuffer(0, vertexBufferImpl); + builder.BindShaderBinding(shaderBinding); + + builder.SetScissor(Nz::Recti{ 0, 0, int(windowSize.x), int(windowSize.y) }); + builder.SetViewport(Nz::Recti{ 0, 0, int(windowSize.x), int(windowSize.y) }); + + vkCommandBuffer.BindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, vkPipeline->Get(vulkanWindow.GetRenderPass())); //< TODO + + builder.DrawIndexed(drfreakIB->GetIndexCount()); + } + vkCommandBuffer.EndRenderPass(); + } + builder.EndDebugRegion(); + }); } Nz::Vector3f viewerPos = Nz::Vector3f::Zero(); @@ -298,38 +290,6 @@ int main() window.EnableEventPolling(true); - struct ImageData - { - Nz::Vk::Fence inflightFence; - Nz::Vk::Semaphore imageAvailableSemaphore; - Nz::Vk::Semaphore renderFinishedSemaphore; - Nz::Vk::AutoCommandBuffer commandBuffer; - std::optional uploadPool; - }; - - const std::size_t MaxConcurrentImage = imageCount; - - Nz::Vk::CommandPool transientPool; - transientPool.Create(vulkanDevice, 0, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT); - transientPool.SetDebugName("Transient command pool"); - - std::vector frameSync(MaxConcurrentImage); - for (ImageData& syncData : frameSync) - { - syncData.imageAvailableSemaphore.Create(vulkanDevice); - syncData.renderFinishedSemaphore.Create(vulkanDevice); - - syncData.inflightFence.Create(vulkanDevice, VK_FENCE_CREATE_SIGNALED_BIT); - - syncData.uploadPool.emplace(vulkanDevice, 8 * 1024 * 1024); - - syncData.commandBuffer = transientPool.AllocateCommandBuffer(VK_COMMAND_BUFFER_LEVEL_PRIMARY); - } - - std::vector inflightFences(imageCount, nullptr); - - std::size_t currentFrame = 0; - Nz::Clock updateClock; Nz::Clock secondClock; unsigned int fps = 0; @@ -395,47 +355,30 @@ int main() viewerPos += Nz::Vector3f::Down() * cameraSpeed; } - ImageData& frame = frameSync[currentFrame]; - frame.inflightFence.Wait(); - - Nz::UInt32 imageIndex; - if (!vulkanWindow.Acquire(&imageIndex, frame.imageAvailableSemaphore)) - { - std::cout << "Failed to acquire next image" << std::endl; - return EXIT_FAILURE; - } - - if (inflightFences[imageIndex]) - inflightFences[imageIndex]->Wait(); - - inflightFences[imageIndex] = &frame.inflightFence; - inflightFences[imageIndex]->Reset(); - - // Update UBO - frame.uploadPool->Reset(); + Nz::VulkanRenderImage& renderImage = vulkanWindow.Acquire(); ubo.viewMatrix = Nz::Matrix4f::ViewMatrix(viewerPos, camAngles); - auto allocData = frame.uploadPool->Allocate(uniformSize); - assert(allocData); + auto& allocation = renderImage.GetUploadPool().Allocate(uniformSize); - std::memcpy(allocData->mappedPtr, &ubo, sizeof(ubo)); + std::memcpy(allocation.mappedPtr, &ubo, sizeof(ubo)); - frame.commandBuffer->Begin(VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT); - frame.commandBuffer->BeginDebugRegion("UBO Update", Nz::Color::Yellow); - frame.commandBuffer->MemoryBarrier(VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0U, VK_ACCESS_TRANSFER_READ_BIT); - frame.commandBuffer->CopyBuffer(allocData->buffer, static_cast(uniformBuffer.get())->GetBuffer(), allocData->size, allocData->offset); - frame.commandBuffer->MemoryBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_VERTEX_SHADER_BIT, VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_UNIFORM_READ_BIT); - frame.commandBuffer->EndDebugRegion(); - frame.commandBuffer->End(); + renderImage.Execute([&](Nz::CommandBufferBuilder& builder) + { + builder.BeginDebugRegion("UBO Update", Nz::Color::Yellow); + { + builder.PreTransferBarrier(); + builder.CopyBuffer(allocation, uniformBuffer.get()); + builder.PostTransferBarrier(); + } + builder.EndDebugRegion(); + }, false); - if (!graphicsQueue.Submit(frame.commandBuffer)) - return false; + Nz::UInt32 imageIndex = renderImage.GetImageIndex(); - if (!graphicsQueue.Submit(renderCmds[imageIndex], frame.imageAvailableSemaphore, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, frame.renderFinishedSemaphore, frame.inflightFence)) - return false; + renderImage.SubmitCommandBuffer(renderCmds[imageIndex].get(), true); - vulkanWindow.Present(imageIndex, frame.renderFinishedSemaphore); + renderImage.Present(); // On incrémente le compteur de FPS improvisé fps++; @@ -458,8 +401,6 @@ int main() // Et on relance l'horloge pour refaire ça dans une seconde secondClock.Restart(); } - - currentFrame = (currentFrame + 1) % imageCount; } instance.vkDestroyDebugUtilsMessengerEXT(instance, callback, nullptr); diff --git a/include/Nazara/Renderer.hpp b/include/Nazara/Renderer.hpp index 6ce0da6dc..df330e594 100644 --- a/include/Nazara/Renderer.hpp +++ b/include/Nazara/Renderer.hpp @@ -29,15 +29,19 @@ #ifndef NAZARA_GLOBAL_RENDERER_HPP #define NAZARA_GLOBAL_RENDERER_HPP +#include +#include #include #include #include #include #include +#include #include #include #include #include +#include #include #include #include @@ -52,5 +56,6 @@ #include #include #include +#include #endif // NAZARA_GLOBAL_RENDERER_HPP diff --git a/include/Nazara/Renderer/CommandBuffer.hpp b/include/Nazara/Renderer/CommandBuffer.hpp new file mode 100644 index 000000000..547d0a3f2 --- /dev/null +++ b/include/Nazara/Renderer/CommandBuffer.hpp @@ -0,0 +1,30 @@ +// Copyright (C) 2020 Jérôme Leclercq +// This file is part of the "Nazara Engine - Utility module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#pragma once + +#ifndef NAZARA_COMMANDBUFFER_HPP +#define NAZARA_COMMANDBUFFER_HPP + +#include +#include + +namespace Nz +{ + class NAZARA_RENDERER_API CommandBuffer + { + public: + CommandBuffer() = default; + CommandBuffer(const CommandBuffer&) = delete; + CommandBuffer(CommandBuffer&&) = default; + virtual ~CommandBuffer(); + + CommandBuffer& operator=(const CommandBuffer&) = delete; + CommandBuffer& operator=(CommandBuffer&&) = default; + }; +} + +#include + +#endif // NAZARA_COMMANDBUFFER_HPP diff --git a/include/Nazara/Renderer/CommandBuffer.inl b/include/Nazara/Renderer/CommandBuffer.inl new file mode 100644 index 000000000..be4849bd3 --- /dev/null +++ b/include/Nazara/Renderer/CommandBuffer.inl @@ -0,0 +1,12 @@ +// Copyright (C) 2020 Jérôme Leclercq +// This file is part of the "Nazara Engine - Utility module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#include + +namespace Nz +{ +} + +#include diff --git a/include/Nazara/Renderer/CommandBufferBuilder.hpp b/include/Nazara/Renderer/CommandBufferBuilder.hpp new file mode 100644 index 000000000..5d30a5205 --- /dev/null +++ b/include/Nazara/Renderer/CommandBufferBuilder.hpp @@ -0,0 +1,59 @@ +// Copyright (C) 2020 Jérôme Leclercq +// This file is part of the "Nazara Engine - Utility module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#pragma once + +#ifndef NAZARA_COMMANDBUFFERBUILDER_HPP +#define NAZARA_COMMANDBUFFERBUILDER_HPP + +#include +#include +#include +#include +#include +#include +#include + +namespace Nz +{ + class ShaderBinding; + + class NAZARA_RENDERER_API CommandBufferBuilder + { + public: + CommandBufferBuilder() = default; + CommandBufferBuilder(const CommandBufferBuilder&) = delete; + CommandBufferBuilder(CommandBufferBuilder&&) = default; + virtual ~CommandBufferBuilder(); + + virtual void BeginDebugRegion(const std::string_view& regionName, const Nz::Color& color) = 0; + + virtual void BindIndexBuffer(Nz::AbstractBuffer* indexBuffer, UInt64 offset = 0) = 0; + virtual void BindShaderBinding(ShaderBinding& binding) = 0; + virtual void BindVertexBuffer(UInt32 binding, Nz::AbstractBuffer* vertexBuffer, UInt64 offset = 0) = 0; + + inline void CopyBuffer(const RenderBufferView& source, const RenderBufferView& target); + virtual void CopyBuffer(const RenderBufferView& source, const RenderBufferView& target, UInt64 size, UInt64 fromOffset = 0, UInt64 toOffset = 0) = 0; + inline void CopyBuffer(const UploadPool::Allocation& allocation, const RenderBufferView& target); + virtual void CopyBuffer(const UploadPool::Allocation& allocation, const RenderBufferView& target, UInt64 size, UInt64 fromOffset = 0, UInt64 toOffset = 0) = 0; + + virtual void Draw(UInt32 vertexCount, UInt32 instanceCount = 1, UInt32 firstVertex = 0, UInt32 firstInstance = 0) = 0; + virtual void DrawIndexed(UInt32 indexCount, UInt32 instanceCount = 1, UInt32 firstVertex = 0, UInt32 firstInstance = 0) = 0; + + virtual void EndDebugRegion() = 0; + + virtual void PreTransferBarrier() = 0; + virtual void PostTransferBarrier() = 0; + + virtual void SetScissor(Nz::Recti scissorRegion) = 0; + virtual void SetViewport(Nz::Recti viewportRegion) = 0; + + CommandBufferBuilder& operator=(const CommandBufferBuilder&) = delete; + CommandBufferBuilder& operator=(CommandBufferBuilder&&) = default; + }; +} + +#include + +#endif // NAZARA_COMMANDBUFFERBUILDER_HPP diff --git a/include/Nazara/Renderer/CommandBufferBuilder.inl b/include/Nazara/Renderer/CommandBufferBuilder.inl new file mode 100644 index 000000000..c0a726580 --- /dev/null +++ b/include/Nazara/Renderer/CommandBufferBuilder.inl @@ -0,0 +1,21 @@ +// Copyright (C) 2020 Jérôme Leclercq +// This file is part of the "Nazara Engine - Utility module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#include + +namespace Nz +{ + inline void CommandBufferBuilder::CopyBuffer(const RenderBufferView& from, const RenderBufferView& to) + { + return CopyBuffer(from, to, from.GetSize()); + } + + inline void CommandBufferBuilder::CopyBuffer(const UploadPool::Allocation& allocation, const RenderBufferView& target) + { + return CopyBuffer(allocation, target, allocation.size); + } +} + +#include diff --git a/include/Nazara/Renderer/RenderBuffer.hpp b/include/Nazara/Renderer/RenderBuffer.hpp index 9e501a002..897270ac2 100644 --- a/include/Nazara/Renderer/RenderBuffer.hpp +++ b/include/Nazara/Renderer/RenderBuffer.hpp @@ -27,14 +27,15 @@ namespace Nz RenderBuffer(RenderBuffer&&) = default; ~RenderBuffer() = default; - bool Fill(const void* data, UInt32 offset, UInt32 size) final; + bool Fill(const void* data, UInt64 offset, UInt64 size) final; - bool Initialize(UInt32 size, BufferUsageFlags usage) override; + bool Initialize(UInt64 size, BufferUsageFlags usage) override; AbstractBuffer* GetHardwareBuffer(RenderDevice* device); + UInt64 GetSize() const override; DataStorage GetStorage() const override; - void* Map(BufferAccess access, UInt32 offset = 0, UInt32 size = 0) final; + void* Map(BufferAccess access, UInt64 offset = 0, UInt64 size = 0) final; bool Unmap() final; RenderBuffer& operator=(const RenderBuffer&) = delete; diff --git a/include/Nazara/Renderer/RenderBufferView.hpp b/include/Nazara/Renderer/RenderBufferView.hpp new file mode 100644 index 000000000..f653866eb --- /dev/null +++ b/include/Nazara/Renderer/RenderBufferView.hpp @@ -0,0 +1,41 @@ +// Copyright (C) 2020 Jérôme Leclercq +// This file is part of the "Nazara Engine - Utility module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#pragma once + +#ifndef NAZARA_RENDERBUFFERVIEW_HPP +#define NAZARA_RENDERBUFFERVIEW_HPP + +#include +#include +#include + +namespace Nz +{ + class RenderBufferView + { + public: + inline RenderBufferView(AbstractBuffer* buffer); + inline RenderBufferView(AbstractBuffer* buffer, UInt64 offset, UInt64 size); + RenderBufferView(const RenderBufferView&) = delete; + RenderBufferView(RenderBufferView&&) = default; + ~RenderBufferView() = default; + + inline AbstractBuffer* GetBuffer() const; + inline UInt64 GetOffset() const; + inline UInt64 GetSize() const; + + RenderBufferView& operator=(const RenderBufferView&) = delete; + RenderBufferView& operator=(RenderBufferView&&) = default; + + private: + UInt64 m_offset; + UInt64 m_size; + AbstractBuffer* m_buffer; + }; +} + +#include + +#endif // NAZARA_RENDERBUFFERVIEW_HPP diff --git a/include/Nazara/Renderer/RenderBufferView.inl b/include/Nazara/Renderer/RenderBufferView.inl new file mode 100644 index 000000000..a0cb08aa5 --- /dev/null +++ b/include/Nazara/Renderer/RenderBufferView.inl @@ -0,0 +1,39 @@ +// Copyright (C) 2020 Jérôme Leclercq +// This file is part of the "Nazara Engine - Utility module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#include +#include + +namespace Nz +{ + inline RenderBufferView::RenderBufferView(AbstractBuffer* buffer) : + RenderBufferView(buffer, 0, buffer->GetSize()) + { + } + + inline RenderBufferView::RenderBufferView(AbstractBuffer* buffer, UInt64 offset, UInt64 size) : + m_buffer(buffer), + m_offset(offset), + m_size(size) + { + } + + inline AbstractBuffer* RenderBufferView::GetBuffer() const + { + return m_buffer; + } + + inline UInt64 RenderBufferView::GetOffset() const + { + return m_offset; + } + + inline UInt64 RenderBufferView::GetSize() const + { + return m_size; + } +} + +#include diff --git a/include/Nazara/Renderer/RenderImage.hpp b/include/Nazara/Renderer/RenderImage.hpp new file mode 100644 index 000000000..2661f45c7 --- /dev/null +++ b/include/Nazara/Renderer/RenderImage.hpp @@ -0,0 +1,42 @@ +// Copyright (C) 2020 Jérôme Leclercq +// This file is part of the "Nazara Engine - Renderer module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#pragma once + +#ifndef NAZARA_RENDERIMAGE_HPP +#define NAZARA_RENDERIMAGE_HPP + +#include +#include +#include + +namespace Nz +{ + class CommandBuffer; + class CommandBufferBuilder; + class UploadPool; + + class NAZARA_RENDERER_API RenderImage + { + public: + RenderImage() = default; + virtual ~RenderImage(); + + virtual void Execute(const std::function& callback, bool isGraphical) = 0; + + virtual UploadPool& GetUploadPool() = 0; + + virtual void SubmitCommandBuffer(CommandBuffer* commandBuffer, bool isGraphical) = 0; + + virtual void Present() = 0; + + protected: + RenderImage(const RenderImage&) = delete; + RenderImage(RenderImage&&) = default; + }; +} + +#include + +#endif // NAZARA_RENDERIMAGE_HPP diff --git a/include/Nazara/Renderer/RenderImage.inl b/include/Nazara/Renderer/RenderImage.inl new file mode 100644 index 000000000..20f3103f8 --- /dev/null +++ b/include/Nazara/Renderer/RenderImage.inl @@ -0,0 +1,12 @@ +// Copyright (C) 2020 Jérôme Leclercq +// This file is part of the "Nazara Engine - Renderer module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#include + +namespace Nz +{ +} + +#include diff --git a/include/Nazara/Renderer/RenderWindowImpl.hpp b/include/Nazara/Renderer/RenderWindowImpl.hpp index df67001c5..f0636e77a 100644 --- a/include/Nazara/Renderer/RenderWindowImpl.hpp +++ b/include/Nazara/Renderer/RenderWindowImpl.hpp @@ -13,11 +13,14 @@ #include #include #include -#include +#include namespace Nz { + class CommandBuffer; + class CommandBufferBuilder; class RendererImpl; + class RenderImage; class RenderSurface; class NAZARA_RENDERER_API RenderWindowImpl @@ -26,6 +29,10 @@ namespace Nz RenderWindowImpl() = default; virtual ~RenderWindowImpl(); + virtual RenderImage& Acquire() = 0; + + virtual std::unique_ptr BuildCommandBuffer(const std::function& callback) = 0; + virtual bool Create(RendererImpl* renderer, RenderSurface* surface, const Vector2ui& size, const RenderWindowParameters& parameters) = 0; virtual std::shared_ptr GetRenderDevice() = 0; diff --git a/include/Nazara/Renderer/UploadPool.hpp b/include/Nazara/Renderer/UploadPool.hpp new file mode 100644 index 000000000..85368e413 --- /dev/null +++ b/include/Nazara/Renderer/UploadPool.hpp @@ -0,0 +1,52 @@ +// Copyright (C) 2020 Jérôme Leclercq +// This file is part of the "Nazara Engine - Renderer module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#pragma once + +#ifndef NAZARA_RENDERER_UPLOADPOOL_HPP +#define NAZARA_RENDERER_UPLOADPOOL_HPP + +#include +#include + +namespace Nz +{ + class NAZARA_RENDERER_API UploadPool + { + public: + struct Allocation; + + UploadPool() = default; + UploadPool(const UploadPool&) = delete; + UploadPool(UploadPool&&) noexcept = default; + ~UploadPool() = default; + + virtual Allocation& Allocate(UInt64 size) = 0; + virtual Allocation& Allocate(UInt64 size, UInt64 alignment) = 0; + + virtual void Reset() = 0; + + UploadPool& operator=(const UploadPool&) = delete; + UploadPool& operator=(UploadPool&&) = delete; + + struct NAZARA_RENDERER_API Allocation + { + Allocation() = default; + Allocation(const Allocation&) = delete; + Allocation(Allocation&&) = default; + ~Allocation(); + + Allocation& operator=(const Allocation&) = delete; + Allocation& operator=(Allocation&&) = default; + + void* mappedPtr; + UInt64 offset; + UInt64 size; + }; + }; +} + +#include + +#endif // NAZARA_RENDERER_UPLOADPOOL_HPP diff --git a/include/Nazara/Renderer/UploadPool.inl b/include/Nazara/Renderer/UploadPool.inl new file mode 100644 index 000000000..346aa1076 --- /dev/null +++ b/include/Nazara/Renderer/UploadPool.inl @@ -0,0 +1,12 @@ +// Copyright (C) 2020 Jérôme Leclercq +// This file is part of the "Nazara Engine - Vulkan Renderer" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#include + +namespace Nz +{ +} + +#include diff --git a/include/Nazara/Utility/AbstractBuffer.hpp b/include/Nazara/Utility/AbstractBuffer.hpp index a2d36ce2e..346e96bab 100644 --- a/include/Nazara/Utility/AbstractBuffer.hpp +++ b/include/Nazara/Utility/AbstractBuffer.hpp @@ -18,13 +18,14 @@ namespace Nz AbstractBuffer() = default; virtual ~AbstractBuffer(); - virtual bool Fill(const void* data, UInt32 offset, UInt32 size) = 0; + virtual bool Fill(const void* data, UInt64 offset, UInt64 size) = 0; - virtual bool Initialize(UInt32 size, BufferUsageFlags usage) = 0; + virtual bool Initialize(UInt64 size, BufferUsageFlags usage) = 0; + virtual UInt64 GetSize() const = 0; virtual DataStorage GetStorage() const = 0; - virtual void* Map(BufferAccess access, UInt32 offset = 0, UInt32 size = 0) = 0; + virtual void* Map(BufferAccess access, UInt64 offset = 0, UInt64 size = 0) = 0; virtual bool Unmap() = 0; }; } diff --git a/include/Nazara/Utility/SoftwareBuffer.hpp b/include/Nazara/Utility/SoftwareBuffer.hpp index 574aebb50..25e951795 100644 --- a/include/Nazara/Utility/SoftwareBuffer.hpp +++ b/include/Nazara/Utility/SoftwareBuffer.hpp @@ -19,16 +19,17 @@ namespace Nz { public: SoftwareBuffer(Buffer* parent, BufferType type); - ~SoftwareBuffer(); + ~SoftwareBuffer() = default; - bool Fill(const void* data, UInt32 offset, UInt32 size) override; + bool Fill(const void* data, UInt64 offset, UInt64 size) override; - bool Initialize(UInt32 size, BufferUsageFlags usage) override; + bool Initialize(UInt64 size, BufferUsageFlags usage) override; const UInt8* GetData() const; + UInt64 GetSize() const; DataStorage GetStorage() const override; - void* Map(BufferAccess access, UInt32 offset = 0, UInt32 size = 0) override; + void* Map(BufferAccess access, UInt64 offset = 0, UInt64 size = 0) override; bool Unmap() override; private: diff --git a/include/Nazara/VulkanRenderer.hpp b/include/Nazara/VulkanRenderer.hpp index 6cc1db9dd..b3a003a2a 100644 --- a/include/Nazara/VulkanRenderer.hpp +++ b/include/Nazara/VulkanRenderer.hpp @@ -35,8 +35,11 @@ #include #include #include +#include +#include #include #include +#include #include #include #include diff --git a/include/Nazara/VulkanRenderer/VkRenderTarget.hpp b/include/Nazara/VulkanRenderer/VkRenderTarget.hpp index c98580e67..e120d1184 100644 --- a/include/Nazara/VulkanRenderer/VkRenderTarget.hpp +++ b/include/Nazara/VulkanRenderer/VkRenderTarget.hpp @@ -26,15 +26,11 @@ namespace Nz VkRenderTarget(VkRenderTarget&&) = delete; ///TOOD? virtual ~VkRenderTarget(); - virtual bool Acquire(UInt32* imageIndex, VkSemaphore signalSemaphore = VK_NULL_HANDLE, VkFence signalFence = VK_NULL_HANDLE) const = 0; - virtual const Vk::Framebuffer& GetFrameBuffer(UInt32 imageIndex) const = 0; virtual UInt32 GetFramebufferCount() const = 0; inline const Vk::RenderPass& GetRenderPass() const; - virtual void Present(UInt32 imageIndex, VkSemaphore waitSemaphore = VK_NULL_HANDLE) = 0; - VkRenderTarget& operator=(const VkRenderTarget&) = delete; VkRenderTarget& operator=(VkRenderTarget&&) = delete; ///TOOD? diff --git a/include/Nazara/VulkanRenderer/VkRenderWindow.hpp b/include/Nazara/VulkanRenderer/VkRenderWindow.hpp index d58dbe883..719e9bd8e 100644 --- a/include/Nazara/VulkanRenderer/VkRenderWindow.hpp +++ b/include/Nazara/VulkanRenderer/VkRenderWindow.hpp @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -37,7 +38,9 @@ namespace Nz VkRenderWindow(VkRenderWindow&&) = delete; ///TODO virtual ~VkRenderWindow(); - bool Acquire(UInt32* index, VkSemaphore signalSemaphore = VK_NULL_HANDLE, VkFence signalFence = VK_NULL_HANDLE) const override; + VulkanRenderImage& Acquire() override; + + std::unique_ptr BuildCommandBuffer(const std::function& callback) override; bool Create(RendererImpl* renderer, RenderSurface* surface, const Vector2ui& size, const RenderWindowParameters& parameters) override; @@ -45,12 +48,12 @@ namespace Nz inline UInt32 GetFramebufferCount() const override; inline VulkanDevice& GetDevice(); inline const VulkanDevice& GetDevice() const; - inline UInt32 GetPresentableFamilyQueue() const; + inline Vk::QueueHandle& GetGraphicsQueue(); inline const Vk::Swapchain& GetSwapchain() const; std::shared_ptr GetRenderDevice() override; - void Present(UInt32 imageIndex, VkSemaphore waitSemaphore = VK_NULL_HANDLE) override; + void Present(UInt32 imageIndex, VkSemaphore waitSemaphore = VK_NULL_HANDLE); VkRenderWindow& operator=(const VkRenderWindow&) = delete; VkRenderWindow& operator=(VkRenderWindow&&) = delete; ///TODO @@ -60,18 +63,27 @@ namespace Nz bool SetupRenderPass(); bool SetupSwapchain(const Vk::PhysicalDevice& deviceInfo, Vk::Surface& surface, const Vector2ui& size); + struct ImageData + { + Vk::Framebuffer framebuffer; + Vk::Fence* inFlightFence = nullptr; + }; + + std::size_t m_currentFrame; Clock m_clock; VkColorSpaceKHR m_colorSpace; VkFormat m_colorFormat; VkFormat m_depthStencilFormat; std::shared_ptr m_device; - std::vector m_frameBuffers; + std::vector m_imageData; + std::vector m_concurrentImageData; + Vk::CommandPool m_graphicsCommandPool; Vk::DeviceMemory m_depthBufferMemory; Vk::Image m_depthBuffer; Vk::ImageView m_depthBufferView; + Vk::QueueHandle m_graphicsQueue; Vk::QueueHandle m_presentQueue; Vk::Swapchain m_swapchain; - UInt32 m_presentableFamilyQueue; }; } diff --git a/include/Nazara/VulkanRenderer/VkRenderWindow.inl b/include/Nazara/VulkanRenderer/VkRenderWindow.inl index 4d9cf9e92..c3700bf21 100644 --- a/include/Nazara/VulkanRenderer/VkRenderWindow.inl +++ b/include/Nazara/VulkanRenderer/VkRenderWindow.inl @@ -17,19 +17,19 @@ namespace Nz return *m_device; } + inline Vk::QueueHandle& VkRenderWindow::GetGraphicsQueue() + { + return m_graphicsQueue; + } + inline const Vk::Framebuffer& VkRenderWindow::GetFrameBuffer(UInt32 imageIndex) const { - return m_frameBuffers[imageIndex]; + return m_imageData[imageIndex].framebuffer; } inline UInt32 VkRenderWindow::GetFramebufferCount() const { - return static_cast(m_frameBuffers.size()); - } - - inline UInt32 VkRenderWindow::GetPresentableFamilyQueue() const - { - return m_presentableFamilyQueue; + return static_cast(m_imageData.size()); } inline const Vk::Swapchain& VkRenderWindow::GetSwapchain() const @@ -44,9 +44,11 @@ namespace Nz inline void VkRenderWindow::Present(UInt32 imageIndex, VkSemaphore waitSemaphore) { - NazaraAssert(imageIndex < m_frameBuffers.size(), "Invalid image index"); + NazaraAssert(imageIndex < m_imageData.size(), "Invalid image index"); m_presentQueue.Present(m_swapchain, imageIndex, waitSemaphore); + + m_currentFrame = (m_currentFrame + 1) % m_imageData.size(); } } diff --git a/include/Nazara/VulkanRenderer/Vulkan.hpp b/include/Nazara/VulkanRenderer/Vulkan.hpp index f3c40959c..d87afbec1 100644 --- a/include/Nazara/VulkanRenderer/Vulkan.hpp +++ b/include/Nazara/VulkanRenderer/Vulkan.hpp @@ -36,7 +36,7 @@ namespace Nz ~Vulkan() = delete; static std::shared_ptr CreateDevice(const Vk::PhysicalDevice& deviceInfo); - static std::shared_ptr CreateDevice(const Vk::PhysicalDevice& deviceInfo, const Vk::Surface& surface, UInt32* presentableFamilyQueue); + static std::shared_ptr CreateDevice(const Vk::PhysicalDevice& deviceInfo, const Vk::Surface& surface, UInt32* graphicsFamilyIndex, UInt32* presentableFamilyIndex); static std::shared_ptr CreateDevice(const Vk::PhysicalDevice& deviceInfo, const QueueFamily* queueFamilies, std::size_t queueFamilyCount); static Vk::Instance& GetInstance(); @@ -49,7 +49,7 @@ namespace Nz static bool IsInitialized(); static std::shared_ptr SelectDevice(const Vk::PhysicalDevice& deviceInfo); - static std::shared_ptr SelectDevice(const Vk::PhysicalDevice& deviceInfo, const Vk::Surface& surface, UInt32* presentableFamilyQueue); + static std::shared_ptr SelectDevice(const Vk::PhysicalDevice& deviceInfo, const Vk::Surface& surface, UInt32* graphicsFamilyIndex, UInt32* presentableFamilyIndex); static void Uninitialize(); diff --git a/include/Nazara/VulkanRenderer/VulkanBuffer.hpp b/include/Nazara/VulkanRenderer/VulkanBuffer.hpp index 8cdab89f4..cbee94283 100644 --- a/include/Nazara/VulkanRenderer/VulkanBuffer.hpp +++ b/include/Nazara/VulkanRenderer/VulkanBuffer.hpp @@ -26,14 +26,15 @@ namespace Nz VulkanBuffer(VulkanBuffer&&) = delete; ///TODO virtual ~VulkanBuffer(); - bool Fill(const void* data, UInt32 offset, UInt32 size) override; + bool Fill(const void* data, UInt64 offset, UInt64 size) override; + + bool Initialize(UInt64 size, BufferUsageFlags usage) override; inline VkBuffer GetBuffer(); - bool Initialize(UInt32 size, BufferUsageFlags usage) override; - + UInt64 GetSize() const override; DataStorage GetStorage() const override; - void* Map(BufferAccess access, UInt32 offset, UInt32 size) override; + void* Map(BufferAccess access, UInt64 offset, UInt64 size) override; bool Unmap() override; VulkanBuffer& operator=(const VulkanBuffer&) = delete; @@ -42,7 +43,7 @@ namespace Nz private: BufferType m_type; BufferUsageFlags m_usage; - UInt32 m_size; + UInt64 m_size; VkBuffer m_buffer; VkBuffer m_stagingBuffer; VmaAllocation m_allocation; diff --git a/include/Nazara/VulkanRenderer/VulkanCommandBuffer.hpp b/include/Nazara/VulkanRenderer/VulkanCommandBuffer.hpp new file mode 100644 index 000000000..608dda616 --- /dev/null +++ b/include/Nazara/VulkanRenderer/VulkanCommandBuffer.hpp @@ -0,0 +1,37 @@ +// Copyright (C) 2020 Jérôme Leclercq +// This file is part of the "Nazara Engine - Renderer module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#pragma once + +#ifndef NAZARA_VULKANRENDERER_VULKANCOMMANDBUFFER_HPP +#define NAZARA_VULKANRENDERER_VULKANCOMMANDBUFFER_HPP + +#include +#include +#include +#include + +namespace Nz +{ + class NAZARA_VULKANRENDERER_API VulkanCommandBuffer final : public CommandBuffer + { + public: + inline VulkanCommandBuffer(Vk::AutoCommandBuffer commandBuffer); + VulkanCommandBuffer(const VulkanCommandBuffer&) = delete; + VulkanCommandBuffer(VulkanCommandBuffer&&) noexcept = default; + ~VulkanCommandBuffer() = default; + + inline Vk::CommandBuffer& GetCommandBuffer(); + + VulkanCommandBuffer& operator=(const VulkanCommandBuffer&) = delete; + VulkanCommandBuffer& operator=(VulkanCommandBuffer&&) = delete; + + private: + Vk::AutoCommandBuffer m_commandBuffer; + }; +} + +#include + +#endif // NAZARA_VULKANRENDERER_VULKANCOMMANDBUFFER_HPP diff --git a/include/Nazara/VulkanRenderer/VulkanCommandBuffer.inl b/include/Nazara/VulkanRenderer/VulkanCommandBuffer.inl new file mode 100644 index 000000000..23d1b9f58 --- /dev/null +++ b/include/Nazara/VulkanRenderer/VulkanCommandBuffer.inl @@ -0,0 +1,21 @@ +// Copyright (C) 2020 Jérôme Leclercq +// This file is part of the "Nazara Engine - Vulkan Renderer" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#include + +namespace Nz +{ + inline VulkanCommandBuffer::VulkanCommandBuffer(Vk::AutoCommandBuffer commandBuffer) : + m_commandBuffer(std::move(commandBuffer)) + { + } + + inline Vk::CommandBuffer& VulkanCommandBuffer::GetCommandBuffer() + { + return m_commandBuffer.Get(); + } +} + +#include diff --git a/include/Nazara/VulkanRenderer/VulkanCommandBufferBuilder.hpp b/include/Nazara/VulkanRenderer/VulkanCommandBufferBuilder.hpp new file mode 100644 index 000000000..66baec47b --- /dev/null +++ b/include/Nazara/VulkanRenderer/VulkanCommandBufferBuilder.hpp @@ -0,0 +1,57 @@ +// Copyright (C) 2020 Jérôme Leclercq +// This file is part of the "Nazara Engine - Renderer module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#pragma once + +#ifndef NAZARA_VULKANRENDERER_VULKANCOMMANDBUFFERBUILDER_HPP +#define NAZARA_VULKANRENDERER_VULKANCOMMANDBUFFERBUILDER_HPP + +#include +#include +#include +#include + +namespace Nz +{ + class NAZARA_VULKANRENDERER_API VulkanCommandBufferBuilder final : public CommandBufferBuilder + { + public: + inline VulkanCommandBufferBuilder(Vk::CommandBuffer& commandBuffer); + VulkanCommandBufferBuilder(const VulkanCommandBufferBuilder&) = delete; + VulkanCommandBufferBuilder(VulkanCommandBufferBuilder&&) noexcept = default; + ~VulkanCommandBufferBuilder() = default; + + void BeginDebugRegion(const std::string_view& regionName, const Nz::Color& color) override; + + void BindIndexBuffer(AbstractBuffer* indexBuffer, UInt64 offset = 0) override; + void BindShaderBinding(ShaderBinding& binding) override; + void BindVertexBuffer(UInt32 binding, Nz::AbstractBuffer* vertexBuffer, UInt64 offset = 0) override; + + void CopyBuffer(const RenderBufferView& source, const RenderBufferView& target, UInt64 size, UInt64 sourceOffset = 0, UInt64 targetOffset = 0) override; + void CopyBuffer(const UploadPool::Allocation& allocation, const RenderBufferView& target, UInt64 size, UInt64 sourceOffset = 0, UInt64 targetOffset = 0) override; + + void Draw(UInt32 vertexCount, UInt32 instanceCount = 1, UInt32 firstVertex = 0, UInt32 firstInstance = 0) override; + void DrawIndexed(UInt32 indexCount, UInt32 instanceCount = 1, UInt32 firstVertex = 0, UInt32 firstInstance = 0) override; + + void EndDebugRegion() override; + + inline Vk::CommandBuffer& GetCommandBuffer(); + + void PreTransferBarrier() override; + void PostTransferBarrier() override; + + void SetScissor(Nz::Recti scissorRegion) override; + void SetViewport(Nz::Recti viewportRegion) override; + + VulkanCommandBufferBuilder& operator=(const VulkanCommandBufferBuilder&) = delete; + VulkanCommandBufferBuilder& operator=(VulkanCommandBufferBuilder&&) = delete; + + private: + Vk::CommandBuffer& m_commandBuffer; + }; +} + +#include + +#endif // NAZARA_VULKANRENDERER_VULKANCOMMANDBUFFERBUILDER_HPP diff --git a/include/Nazara/VulkanRenderer/VulkanCommandBufferBuilder.inl b/include/Nazara/VulkanRenderer/VulkanCommandBufferBuilder.inl new file mode 100644 index 000000000..1d4b865cb --- /dev/null +++ b/include/Nazara/VulkanRenderer/VulkanCommandBufferBuilder.inl @@ -0,0 +1,21 @@ +// Copyright (C) 2020 Jérôme Leclercq +// This file is part of the "Nazara Engine - Vulkan Renderer" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#include + +namespace Nz +{ + inline VulkanCommandBufferBuilder::VulkanCommandBufferBuilder(Vk::CommandBuffer& commandBuffer) : + m_commandBuffer(commandBuffer) + { + } + + inline Vk::CommandBuffer& VulkanCommandBufferBuilder::GetCommandBuffer() + { + return m_commandBuffer; + } +} + +#include diff --git a/include/Nazara/VulkanRenderer/VulkanRenderImage.hpp b/include/Nazara/VulkanRenderer/VulkanRenderImage.hpp new file mode 100644 index 000000000..576109245 --- /dev/null +++ b/include/Nazara/VulkanRenderer/VulkanRenderImage.hpp @@ -0,0 +1,65 @@ +// Copyright (C) 2020 Jérôme Leclercq +// This file is part of the "Nazara Engine - Renderer module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#pragma once + +#ifndef NAZARA_VULKANRENDERER_VULKANRENDERIMAGE_HPP +#define NAZARA_VULKANRENDERER_VULKANRENDERIMAGE_HPP + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace Nz +{ + class VkRenderWindow; + + class NAZARA_VULKANRENDERER_API VulkanRenderImage : public RenderImage + { + public: + VulkanRenderImage(VkRenderWindow& owner); + VulkanRenderImage(const VulkanRenderImage&) = delete; + VulkanRenderImage(VulkanRenderImage&&) noexcept = default; + ~VulkanRenderImage(); + + void Execute(const std::function& callback, bool isGraphical) override; + + inline Vk::Fence& GetInFlightFence(); + inline Vk::Semaphore& GetImageAvailableSemaphore(); + inline UInt32 GetImageIndex(); + inline Vk::Semaphore& GetRenderFinishedSemaphore(); + VulkanUploadPool& GetUploadPool() override; + + void SubmitCommandBuffer(CommandBuffer* commandBuffer, bool isGraphical) override; + void SubmitCommandBuffer(VkCommandBuffer commandBuffer, bool isGraphical); + + void Present() override; + + inline void Reset(UInt32 imageIndex); + + VulkanRenderImage& operator=(const VulkanRenderImage&) = delete; + VulkanRenderImage& operator=(VulkanRenderImage&&) = delete; + + private: + std::size_t m_currentCommandBuffer; + std::vector m_inFlightCommandBuffers; + std::vector m_graphicalCommandsBuffers; + VkRenderWindow& m_owner; + Vk::CommandPool m_commandPool; + Vk::Fence m_inFlightFence; + Vk::Semaphore m_imageAvailableSemaphore; + Vk::Semaphore m_renderFinishedSemaphore; + VulkanUploadPool m_uploadPool; + UInt32 m_imageIndex; + }; +} + +#include + +#endif // NAZARA_VULKANRENDERER_VULKANRENDERIMAGE_HPP diff --git a/include/Nazara/VulkanRenderer/VulkanRenderImage.inl b/include/Nazara/VulkanRenderer/VulkanRenderImage.inl new file mode 100644 index 000000000..521233611 --- /dev/null +++ b/include/Nazara/VulkanRenderer/VulkanRenderImage.inl @@ -0,0 +1,39 @@ +// Copyright (C) 2020 Jérôme Leclercq +// This file is part of the "Nazara Engine - Vulkan Renderer" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#include + +namespace Nz +{ + inline Vk::Fence& Nz::VulkanRenderImage::GetInFlightFence() + { + return m_inFlightFence; + } + + inline Vk::Semaphore& VulkanRenderImage::GetImageAvailableSemaphore() + { + return m_imageAvailableSemaphore; + } + + inline UInt32 VulkanRenderImage::GetImageIndex() + { + return m_imageIndex; + } + + inline Vk::Semaphore& VulkanRenderImage::GetRenderFinishedSemaphore() + { + return m_renderFinishedSemaphore; + } + + inline void VulkanRenderImage::Reset(UInt32 imageIndex) + { + m_graphicalCommandsBuffers.clear(); + m_currentCommandBuffer = 0; + m_imageIndex = imageIndex; + m_uploadPool.Reset(); + } +} + +#include diff --git a/include/Nazara/VulkanRenderer/VulkanShaderBinding.hpp b/include/Nazara/VulkanRenderer/VulkanShaderBinding.hpp index 8d92b3697..8fa00eccf 100644 --- a/include/Nazara/VulkanRenderer/VulkanShaderBinding.hpp +++ b/include/Nazara/VulkanRenderer/VulkanShaderBinding.hpp @@ -24,6 +24,7 @@ namespace Nz ~VulkanShaderBinding() = default; inline Vk::DescriptorSet& GetDescriptorSet(); + inline VulkanRenderPipelineLayout& GetOwner(); void Update(std::initializer_list bindings) override; diff --git a/include/Nazara/VulkanRenderer/VulkanShaderBinding.inl b/include/Nazara/VulkanRenderer/VulkanShaderBinding.inl index 4300cf788..f82cd6303 100644 --- a/include/Nazara/VulkanRenderer/VulkanShaderBinding.inl +++ b/include/Nazara/VulkanRenderer/VulkanShaderBinding.inl @@ -17,6 +17,11 @@ namespace Nz { return m_descriptorSet; } + + inline VulkanRenderPipelineLayout& VulkanShaderBinding::GetOwner() + { + return m_owner; + } } #include diff --git a/include/Nazara/VulkanRenderer/VulkanUploadPool.hpp b/include/Nazara/VulkanRenderer/VulkanUploadPool.hpp index 2383f88c8..b2ff27dba 100644 --- a/include/Nazara/VulkanRenderer/VulkanUploadPool.hpp +++ b/include/Nazara/VulkanRenderer/VulkanUploadPool.hpp @@ -9,6 +9,7 @@ #include #include +#include #include #include #include @@ -16,28 +17,23 @@ namespace Nz { - class NAZARA_VULKANRENDERER_API VulkanUploadPool + class NAZARA_VULKANRENDERER_API VulkanUploadPool : public UploadPool { public: - struct AllocationData; + struct VulkanAllocation : Allocation + { + VkBuffer buffer; + }; inline VulkanUploadPool(Vk::Device& device, UInt64 blockSize); VulkanUploadPool(const VulkanUploadPool&) = delete; VulkanUploadPool(VulkanUploadPool&&) noexcept = default; ~VulkanUploadPool() = default; - std::optional Allocate(UInt64 size); - std::optional Allocate(UInt64 size, UInt64 alignment); + VulkanAllocation& Allocate(UInt64 size) override; + VulkanAllocation& Allocate(UInt64 size, UInt64 alignment) override; - void Reset(); - - struct AllocationData - { - VkBuffer buffer; - void* mappedPtr; - UInt64 offset; - UInt64 size; - }; + void Reset() override; VulkanUploadPool& operator=(const VulkanUploadPool&) = delete; VulkanUploadPool& operator=(VulkanUploadPool&&) = delete; @@ -53,6 +49,7 @@ namespace Nz UInt64 m_blockSize; Vk::Device& m_device; std::vector m_blocks; + std::vector m_allocations; }; } diff --git a/include/Nazara/VulkanRenderer/Wrapper/CommandBuffer.hpp b/include/Nazara/VulkanRenderer/Wrapper/CommandBuffer.hpp index 47982a0be..b3286b01f 100644 --- a/include/Nazara/VulkanRenderer/Wrapper/CommandBuffer.hpp +++ b/include/Nazara/VulkanRenderer/Wrapper/CommandBuffer.hpp @@ -55,7 +55,7 @@ namespace Nz inline void ClearDepthStencilImage(VkImage image, VkImageLayout imageLayout, const VkClearDepthStencilValue& depthStencil, const VkImageSubresourceRange& range); inline void ClearDepthStencilImage(VkImage image, VkImageLayout imageLayout, const VkClearDepthStencilValue& depthStencil, UInt32 rangeCount, const VkImageSubresourceRange* ranges); - inline void CopyBuffer(VkBuffer source, VkBuffer target, UInt32 size, UInt32 sourceOffset = 0, UInt32 targetOffset = 0); + inline void CopyBuffer(VkBuffer source, VkBuffer target, UInt64 size, UInt64 sourceOffset = 0, UInt64 targetOffset = 0); inline void CopyBufferToImage(VkBuffer source, VkImage target, VkImageLayout targetLayout, UInt32 width, UInt32 height, UInt32 depth = 1); inline void Draw(UInt32 vertexCount, UInt32 instanceCount = 1, UInt32 firstVertex = 0, UInt32 firstInstance = 0); @@ -68,6 +68,8 @@ namespace Nz inline void Free(); + inline CommandPool& GetPool(); + inline void InsertDebugLabel(const char* label); inline void InsertDebugLabel(const char* label, Nz::Color color); diff --git a/include/Nazara/VulkanRenderer/Wrapper/CommandBuffer.inl b/include/Nazara/VulkanRenderer/Wrapper/CommandBuffer.inl index a34dde3f5..96cadade6 100644 --- a/include/Nazara/VulkanRenderer/Wrapper/CommandBuffer.inl +++ b/include/Nazara/VulkanRenderer/Wrapper/CommandBuffer.inl @@ -216,7 +216,7 @@ namespace Nz return m_pool->GetDevice()->vkCmdClearDepthStencilImage(m_handle, image, imageLayout, &depthStencil, rangeCount, ranges); } - inline void CommandBuffer::CopyBuffer(VkBuffer source, VkBuffer target, UInt32 size, UInt32 sourceOffset, UInt32 targetOffset) + inline void CommandBuffer::CopyBuffer(VkBuffer source, VkBuffer target, UInt64 size, UInt64 sourceOffset, UInt64 targetOffset) { VkBufferCopy region; region.dstOffset = targetOffset; @@ -292,6 +292,11 @@ namespace Nz } } + inline CommandPool& CommandBuffer::GetPool() + { + return *m_pool; + } + inline void CommandBuffer::InsertDebugLabel(const char* label) { Vk::Device* device = m_pool->GetDevice(); diff --git a/include/Nazara/VulkanRenderer/Wrapper/QueueHandle.hpp b/include/Nazara/VulkanRenderer/Wrapper/QueueHandle.hpp index d34649164..e4569efca 100644 --- a/include/Nazara/VulkanRenderer/Wrapper/QueueHandle.hpp +++ b/include/Nazara/VulkanRenderer/Wrapper/QueueHandle.hpp @@ -20,13 +20,14 @@ namespace Nz { public: inline QueueHandle(); - inline QueueHandle(Device& device, VkQueue queue); + inline QueueHandle(Device& device, VkQueue queue, UInt32 queueFamilyIndex); QueueHandle(const QueueHandle& queue) = delete; QueueHandle(QueueHandle&& queue) noexcept = default; ~QueueHandle() = default; inline Device& GetDevice() const; inline VkResult GetLastErrorCode() const; + inline UInt32 GetQueueFamilyIndex() const; inline bool Present(const VkPresentInfoKHR& presentInfo) const; inline bool Present(VkSwapchainKHR swapchain, UInt32 imageIndex, VkSemaphore waitSemaphore = VK_NULL_HANDLE) const; @@ -51,6 +52,7 @@ namespace Nz MovablePtr m_device; VkQueue m_handle; mutable VkResult m_lastErrorCode; + UInt32 m_queueFamilyIndex; }; } } diff --git a/include/Nazara/VulkanRenderer/Wrapper/QueueHandle.inl b/include/Nazara/VulkanRenderer/Wrapper/QueueHandle.inl index 20ee10c4e..95462c1af 100644 --- a/include/Nazara/VulkanRenderer/Wrapper/QueueHandle.inl +++ b/include/Nazara/VulkanRenderer/Wrapper/QueueHandle.inl @@ -18,10 +18,11 @@ namespace Nz { } - inline QueueHandle::QueueHandle(Device& device, VkQueue queue) : + inline QueueHandle::QueueHandle(Device& device, VkQueue queue, UInt32 queueFamilyIndex) : m_device(&device), m_handle(queue), - m_lastErrorCode(VkResult::VK_SUCCESS) + m_lastErrorCode(VkResult::VK_SUCCESS), + m_queueFamilyIndex(queueFamilyIndex) { } @@ -35,6 +36,11 @@ namespace Nz return m_lastErrorCode; } + inline UInt32 QueueHandle::GetQueueFamilyIndex() const + { + return m_queueFamilyIndex; + } + inline bool QueueHandle::Present(const VkPresentInfoKHR& presentInfo) const { m_lastErrorCode = m_device->vkQueuePresentKHR(m_handle, &presentInfo); diff --git a/src/Nazara/Renderer/CommandBuffer.cpp b/src/Nazara/Renderer/CommandBuffer.cpp new file mode 100644 index 000000000..c93ff6fee --- /dev/null +++ b/src/Nazara/Renderer/CommandBuffer.cpp @@ -0,0 +1,11 @@ +// Copyright (C) 2015 Jérôme Leclercq +// This file is part of the "Nazara Engine - Renderer module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#include + +namespace Nz +{ + CommandBuffer::~CommandBuffer() = default; +} diff --git a/src/Nazara/Renderer/CommandBufferBuilder.cpp b/src/Nazara/Renderer/CommandBufferBuilder.cpp new file mode 100644 index 000000000..e45605d48 --- /dev/null +++ b/src/Nazara/Renderer/CommandBufferBuilder.cpp @@ -0,0 +1,11 @@ +// Copyright (C) 2015 Jérôme Leclercq +// This file is part of the "Nazara Engine - Renderer module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#include + +namespace Nz +{ + CommandBufferBuilder::~CommandBufferBuilder() = default; +} diff --git a/src/Nazara/Renderer/RenderBuffer.cpp b/src/Nazara/Renderer/RenderBuffer.cpp index a78660fe3..4526d79f3 100644 --- a/src/Nazara/Renderer/RenderBuffer.cpp +++ b/src/Nazara/Renderer/RenderBuffer.cpp @@ -8,7 +8,7 @@ namespace Nz { - bool RenderBuffer::Fill(const void* data, UInt32 offset, UInt32 size) + bool RenderBuffer::Fill(const void* data, UInt64 offset, UInt64 size) { if (m_softwareBuffer.Fill(data, offset, size)) { @@ -21,7 +21,7 @@ namespace Nz return false; } - bool RenderBuffer::Initialize(UInt32 size, BufferUsageFlags usage) + bool RenderBuffer::Initialize(UInt64 size, BufferUsageFlags usage) { m_size = size; m_softwareBuffer.Initialize(size, usage); @@ -37,12 +37,17 @@ namespace Nz return nullptr; } + UInt64 RenderBuffer::GetSize() const + { + return m_size; + } + DataStorage RenderBuffer::GetStorage() const { return DataStorage::DataStorage_Hardware; } - void* RenderBuffer::Map(BufferAccess access, UInt32 offset, UInt32 size) + void* RenderBuffer::Map(BufferAccess access, UInt64 offset, UInt64 size) { if (void* ptr = m_softwareBuffer.Map(access, offset, size)) { diff --git a/src/Nazara/Renderer/RenderImage.cpp b/src/Nazara/Renderer/RenderImage.cpp new file mode 100644 index 000000000..9724386e2 --- /dev/null +++ b/src/Nazara/Renderer/RenderImage.cpp @@ -0,0 +1,11 @@ +// Copyright (C) 2015 Jérôme Leclercq +// This file is part of the "Nazara Engine - Renderer module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#include + +namespace Nz +{ + RenderImage::~RenderImage() = default; +} diff --git a/src/Nazara/Renderer/UploadPool.cpp b/src/Nazara/Renderer/UploadPool.cpp new file mode 100644 index 000000000..5443181f8 --- /dev/null +++ b/src/Nazara/Renderer/UploadPool.cpp @@ -0,0 +1,12 @@ +// Copyright (C) 2020 Jérôme Leclercq +// This file is part of the "Nazara Engine - Vulkan Renderer" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#include +#include + +namespace Nz +{ + UploadPool::Allocation::~Allocation() = default; +} diff --git a/src/Nazara/Utility/SoftwareBuffer.cpp b/src/Nazara/Utility/SoftwareBuffer.cpp index 8867fa517..3b3c51489 100644 --- a/src/Nazara/Utility/SoftwareBuffer.cpp +++ b/src/Nazara/Utility/SoftwareBuffer.cpp @@ -14,11 +14,7 @@ namespace Nz { } - SoftwareBuffer::~SoftwareBuffer() - { - } - - bool SoftwareBuffer::Fill(const void* data, UInt32 offset, UInt32 size) + bool SoftwareBuffer::Fill(const void* data, UInt64 offset, UInt64 size) { NazaraAssert(!m_mapped, "Buffer is already mapped"); @@ -26,7 +22,7 @@ namespace Nz return true; } - bool SoftwareBuffer::Initialize(UInt32 size, BufferUsageFlags /*usage*/) + bool SoftwareBuffer::Initialize(UInt64 size, BufferUsageFlags /*usage*/) { // Protect the allocation to prevent a memory exception to escape the function try @@ -49,12 +45,17 @@ namespace Nz return m_buffer.data(); } + UInt64 SoftwareBuffer::GetSize() const + { + return UInt64(m_buffer.size()); + } + DataStorage SoftwareBuffer::GetStorage() const { return DataStorage_Software; } - void* SoftwareBuffer::Map(BufferAccess /*access*/, UInt32 offset, UInt32 /*size*/) + void* SoftwareBuffer::Map(BufferAccess /*access*/, UInt64 offset, UInt64 /*size*/) { NazaraAssert(!m_mapped, "Buffer is already mapped"); diff --git a/src/Nazara/VulkanRenderer/VkRenderWindow.cpp b/src/Nazara/VulkanRenderer/VkRenderWindow.cpp index 72588bfd4..e9114c6c2 100644 --- a/src/Nazara/VulkanRenderer/VkRenderWindow.cpp +++ b/src/Nazara/VulkanRenderer/VkRenderWindow.cpp @@ -7,6 +7,8 @@ #include #include #include +#include +#include #include #include #include @@ -16,6 +18,7 @@ namespace Nz { VkRenderWindow::VkRenderWindow() : + m_currentFrame(0), m_depthStencilFormat(VK_FORMAT_MAX_ENUM) { } @@ -25,22 +28,52 @@ namespace Nz if (m_device) m_device->WaitForIdle(); - m_frameBuffers.clear(); + m_concurrentImageData.clear(); + m_graphicsCommandPool.Destroy(); + m_imageData.clear(); m_renderPass.Destroy(); m_swapchain.Destroy(); VkRenderTarget::Destroy(); } - bool VkRenderWindow::Acquire(UInt32* imageIndex, VkSemaphore signalSemaphore, VkFence signalFence) const + VulkanRenderImage& VkRenderWindow::Acquire() { - if (!m_swapchain.AcquireNextImage(std::numeric_limits::max(), signalSemaphore, signalFence, imageIndex)) - { - NazaraError("Failed to acquire next image"); - return false; - } + VulkanRenderImage& currentFrame = m_concurrentImageData[m_currentFrame]; + Vk::Fence& inFlightFence = currentFrame.GetInFlightFence(); - return true; + // Wait until previous rendering to this image has been done + inFlightFence.Wait(); + + UInt32 imageIndex; + if (!m_swapchain.AcquireNextImage(std::numeric_limits::max(), currentFrame.GetImageAvailableSemaphore(), VK_NULL_HANDLE, &imageIndex)) + throw std::runtime_error("Failed to acquire next image: " + TranslateVulkanError(m_swapchain.GetLastErrorCode())); + + if (m_imageData[imageIndex].inFlightFence) + m_imageData[imageIndex].inFlightFence->Wait(); + + m_imageData[imageIndex].inFlightFence = &inFlightFence; + m_imageData[imageIndex].inFlightFence->Reset(); + + currentFrame.Reset(imageIndex); + + return currentFrame; + } + + std::unique_ptr VkRenderWindow::BuildCommandBuffer(const std::function& callback) + { + Vk::AutoCommandBuffer commandBuffer = m_graphicsCommandPool.AllocateCommandBuffer(VK_COMMAND_BUFFER_LEVEL_PRIMARY); + + if (!commandBuffer->Begin()) + throw std::runtime_error("failed to begin command buffer: " + TranslateVulkanError(commandBuffer->GetLastErrorCode())); + + VulkanCommandBufferBuilder builder(commandBuffer.Get()); + callback(builder); + + if (!commandBuffer->End()) + throw std::runtime_error("failed to build command buffer: " + TranslateVulkanError(commandBuffer->GetLastErrorCode())); + + return std::make_unique(std::move(commandBuffer)); } bool VkRenderWindow::Create(RendererImpl* /*renderer*/, RenderSurface* surface, const Vector2ui& size, const RenderWindowParameters& parameters) @@ -49,14 +82,17 @@ namespace Nz Vk::Surface& vulkanSurface = static_cast(surface)->GetSurface(); - m_device = Vulkan::SelectDevice(deviceInfo, vulkanSurface, &m_presentableFamilyQueue); + UInt32 graphicsFamilyQueueIndex; + UInt32 presentableFamilyQueueIndex; + m_device = Vulkan::SelectDevice(deviceInfo, vulkanSurface, &graphicsFamilyQueueIndex, &presentableFamilyQueueIndex); if (!m_device) { NazaraError("Failed to get compatible Vulkan device"); return false; } - m_presentQueue = m_device->GetQueue(m_presentableFamilyQueue, 0); + m_graphicsQueue = m_device->GetQueue(graphicsFamilyQueueIndex, 0); + m_presentQueue = m_device->GetQueue(presentableFamilyQueueIndex, 0); std::vector surfaceFormats; if (!vulkanSurface.GetFormats(deviceInfo.physDevice, &surfaceFormats)) @@ -144,10 +180,10 @@ namespace Nz UInt32 imageCount = m_swapchain.GetBufferCount(); // Framebuffers - m_frameBuffers.resize(imageCount); + m_imageData.resize(imageCount); for (UInt32 i = 0; i < imageCount; ++i) { - std::array attachments = {m_swapchain.GetBuffer(i).view, m_depthBufferView}; + std::array attachments = { m_swapchain.GetBuffer(i).view, m_depthBufferView }; VkFramebufferCreateInfo frameBufferCreate = { VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO, // VkStructureType sType; @@ -161,13 +197,25 @@ namespace Nz 1U // uint32_t layers; }; - if (!m_frameBuffers[i].Create(*m_device, frameBufferCreate)) + if (!m_imageData[i].framebuffer.Create(*m_device, frameBufferCreate)) { - NazaraError("Failed to create framebuffer for image #" + String::Number(i)); + NazaraError("Failed to create framebuffer for image #" + String::Number(i) + ": " + TranslateVulkanError(m_imageData[i].framebuffer.GetLastErrorCode())); return false; } } + if (!m_graphicsCommandPool.Create(*m_device, m_graphicsQueue.GetQueueFamilyIndex())) + { + NazaraError("Failed to create graphics command pool: " + TranslateVulkanError(m_graphicsCommandPool.GetLastErrorCode())); + return false; + } + + const std::size_t MaxConcurrentImage = imageCount; + m_concurrentImageData.reserve(MaxConcurrentImage); + + for (std::size_t i = 0; i < MaxConcurrentImage; ++i) + m_concurrentImageData.emplace_back(*this); + m_clock.Restart(); return true; @@ -181,7 +229,7 @@ namespace Nz 0U, // VkImageCreateFlags flags; VK_IMAGE_TYPE_2D, // VkImageType imageType; m_depthStencilFormat, // VkFormat format; - {size.x, size.y, 1U}, // VkExtent3D extent; + {size.x, size.y, 1U}, // VkExtent3D extent; 1U, // uint32_t mipLevels; 1U, // uint32_t arrayLayers; VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits samples; diff --git a/src/Nazara/VulkanRenderer/Vulkan.cpp b/src/Nazara/VulkanRenderer/Vulkan.cpp index ff9095478..a71043605 100644 --- a/src/Nazara/VulkanRenderer/Vulkan.cpp +++ b/src/Nazara/VulkanRenderer/Vulkan.cpp @@ -297,7 +297,7 @@ namespace Nz return CreateDevice(deviceInfo, queuesFamilies.data(), queuesFamilies.size()); } - std::shared_ptr Vulkan::CreateDevice(const Vk::PhysicalDevice& deviceInfo, const Vk::Surface& surface, UInt32* presentableFamilyQueue) + std::shared_ptr Vulkan::CreateDevice(const Vk::PhysicalDevice& deviceInfo, const Vk::Surface& surface, UInt32* graphicsFamilyIndex, UInt32* presentableFamilyIndex) { Nz::ErrorFlags errFlags(ErrorFlag_ThrowException, true); @@ -362,7 +362,8 @@ namespace Nz } }; - *presentableFamilyQueue = presentQueueNodeIndex; + *graphicsFamilyIndex = graphicsQueueNodeIndex; + *presentableFamilyIndex = presentQueueNodeIndex; return CreateDevice(deviceInfo, queuesFamilies.data(), queuesFamilies.size()); } @@ -496,7 +497,7 @@ namespace Nz return CreateDevice(deviceInfo); } - std::shared_ptr Vulkan::SelectDevice(const Vk::PhysicalDevice& deviceInfo, const Vk::Surface& surface, UInt32* presentableFamilyQueue) + std::shared_ptr Vulkan::SelectDevice(const Vk::PhysicalDevice& deviceInfo, const Vk::Surface& surface, UInt32* graphicsFamilyIndex, UInt32* presentableFamilyIndex) { // First, try to find a device compatible with that surface for (auto it = s_devices.begin(); it != s_devices.end();) @@ -505,6 +506,7 @@ namespace Nz if (devicePtr->GetPhysicalDevice() == deviceInfo.physDevice) { const std::vector& queueFamilyInfo = devicePtr->GetEnabledQueues(); + UInt32 graphicsQueueFamilyIndex = UINT32_MAX; UInt32 presentableQueueFamilyIndex = UINT32_MAX; for (const Vk::Device::QueueFamilyInfo& queueInfo : queueFamilyInfo) { @@ -515,14 +517,29 @@ namespace Nz { presentableQueueFamilyIndex = queueInfo.familyIndex; if (queueInfo.flags & VK_QUEUE_GRAPHICS_BIT) + { + *graphicsFamilyIndex = queueInfo.familyIndex; break; + } + } + } + } + + if (graphicsQueueFamilyIndex == UINT32_MAX) + { + for (const Vk::Device::QueueFamilyInfo& queueInfo : queueFamilyInfo) + { + if (queueInfo.flags & VK_QUEUE_GRAPHICS_BIT) + { + *graphicsFamilyIndex = queueInfo.familyIndex; + break; } } } if (presentableQueueFamilyIndex != UINT32_MAX) { - *presentableFamilyQueue = presentableQueueFamilyIndex; + *presentableFamilyIndex = presentableQueueFamilyIndex; return devicePtr; } } @@ -531,7 +548,7 @@ namespace Nz } // No device had support for that surface, create one - return CreateDevice(deviceInfo, surface, presentableFamilyQueue); + return CreateDevice(deviceInfo, surface, graphicsFamilyIndex, presentableFamilyIndex); } void Vulkan::Uninitialize() diff --git a/src/Nazara/VulkanRenderer/VulkanBuffer.cpp b/src/Nazara/VulkanRenderer/VulkanBuffer.cpp index d31298e5c..e338ac9e7 100644 --- a/src/Nazara/VulkanRenderer/VulkanBuffer.cpp +++ b/src/Nazara/VulkanRenderer/VulkanBuffer.cpp @@ -17,7 +17,7 @@ namespace Nz vmaDestroyBuffer(m_device.GetMemoryAllocator(), m_buffer, m_allocation); } - bool VulkanBuffer::Fill(const void* data, UInt32 offset, UInt32 size) + bool VulkanBuffer::Fill(const void* data, UInt64 offset, UInt64 size) { void* ptr = Map(BufferAccess_WriteOnly, offset, size); if (!ptr) @@ -30,7 +30,7 @@ namespace Nz return true; } - bool VulkanBuffer::Initialize(UInt32 size, BufferUsageFlags usage) + bool VulkanBuffer::Initialize(UInt64 size, BufferUsageFlags usage) { m_size = size; m_usage = usage; @@ -69,12 +69,17 @@ namespace Nz return true; } + UInt64 VulkanBuffer::GetSize() const + { + return m_size; + } + DataStorage VulkanBuffer::GetStorage() const { return DataStorage_Hardware; } - void* VulkanBuffer::Map(BufferAccess /*access*/, UInt32 offset, UInt32 size) + void* VulkanBuffer::Map(BufferAccess /*access*/, UInt64 offset, UInt64 size) { if (m_usage & BufferUsage_DirectMapping) { diff --git a/src/Nazara/VulkanRenderer/VulkanCommandBuffer.cpp b/src/Nazara/VulkanRenderer/VulkanCommandBuffer.cpp new file mode 100644 index 000000000..92f60a953 --- /dev/null +++ b/src/Nazara/VulkanRenderer/VulkanCommandBuffer.cpp @@ -0,0 +1,10 @@ +// Copyright (C) 2020 Jérôme Leclercq +// This file is part of the "Nazara Engine - Vulkan Renderer" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#include + +namespace Nz +{ +} diff --git a/src/Nazara/VulkanRenderer/VulkanCommandBufferBuilder.cpp b/src/Nazara/VulkanRenderer/VulkanCommandBufferBuilder.cpp new file mode 100644 index 000000000..1d5063c78 --- /dev/null +++ b/src/Nazara/VulkanRenderer/VulkanCommandBufferBuilder.cpp @@ -0,0 +1,98 @@ +// Copyright (C) 2020 Jérôme Leclercq +// This file is part of the "Nazara Engine - Vulkan Renderer" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#include +#include +#include +#include +#include +#include + +namespace Nz +{ + void VulkanCommandBufferBuilder::BeginDebugRegion(const std::string_view& regionName, const Nz::Color& color) + { + // Ensure \0 at the end of string + StackArray regionNameEOS = NazaraStackArrayNoInit(char, regionName.size() + 1); + std::memcpy(regionNameEOS.data(), regionName.data(), regionName.size()); + regionNameEOS[regionName.size()] = '\0'; + + m_commandBuffer.BeginDebugRegion(regionNameEOS.data(), color); + } + + void VulkanCommandBufferBuilder::BindIndexBuffer(Nz::AbstractBuffer* indexBuffer, UInt64 offset) + { + VulkanBuffer& vkBuffer = *static_cast(indexBuffer); + + m_commandBuffer.BindIndexBuffer(vkBuffer.GetBuffer(), offset, VK_INDEX_TYPE_UINT16); //< Fuck me right? + } + + void VulkanCommandBufferBuilder::BindShaderBinding(ShaderBinding& binding) + { + VulkanShaderBinding& vkBinding = static_cast(binding); + + VulkanRenderPipelineLayout& pipelineLayout = vkBinding.GetOwner(); + + m_commandBuffer.BindDescriptorSet(VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout.GetPipelineLayout(), 0U, vkBinding.GetDescriptorSet()); + } + + void VulkanCommandBufferBuilder::BindVertexBuffer(UInt32 binding, Nz::AbstractBuffer* vertexBuffer, UInt64 offset) + { + VulkanBuffer& vkBuffer = *static_cast(vertexBuffer); + + m_commandBuffer.BindVertexBuffer(binding, vkBuffer.GetBuffer(), offset); + } + + void VulkanCommandBufferBuilder::CopyBuffer(const RenderBufferView& source, const RenderBufferView& target, UInt64 size, UInt64 sourceOffset, UInt64 targetOffset) + { + VulkanBuffer& sourceBuffer = *static_cast(source.GetBuffer()); + VulkanBuffer& targetBuffer = *static_cast(target.GetBuffer()); + + m_commandBuffer.CopyBuffer(sourceBuffer.GetBuffer(), targetBuffer.GetBuffer(), size, sourceOffset + source.GetOffset(), targetOffset + target.GetOffset()); + } + + void VulkanCommandBufferBuilder::CopyBuffer(const UploadPool::Allocation& allocation, const RenderBufferView& target, UInt64 size, UInt64 sourceOffset, UInt64 targetOffset) + { + const auto& vkAllocation = static_cast(allocation); + VulkanBuffer& targetBuffer = *static_cast(target.GetBuffer()); + + m_commandBuffer.CopyBuffer(vkAllocation.buffer, targetBuffer.GetBuffer(), size, vkAllocation.offset + sourceOffset, target.GetOffset() + targetOffset); + } + + void VulkanCommandBufferBuilder::Draw(UInt32 vertexCount, UInt32 instanceCount, UInt32 firstVertex, UInt32 firstInstance) + { + m_commandBuffer.Draw(vertexCount, instanceCount, firstVertex, firstInstance); + } + + void VulkanCommandBufferBuilder::DrawIndexed(UInt32 indexCount, UInt32 instanceCount, UInt32 firstVertex, UInt32 firstInstance) + { + m_commandBuffer.DrawIndexed(indexCount, instanceCount, firstVertex, 0, firstInstance); + } + + void VulkanCommandBufferBuilder::EndDebugRegion() + { + m_commandBuffer.EndDebugRegion(); + } + + void VulkanCommandBufferBuilder::PreTransferBarrier() + { + m_commandBuffer.MemoryBarrier(VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0U, VK_ACCESS_TRANSFER_READ_BIT); + } + + void VulkanCommandBufferBuilder::PostTransferBarrier() + { + m_commandBuffer.MemoryBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_VERTEX_SHADER_BIT, VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_UNIFORM_READ_BIT); + } + + void VulkanCommandBufferBuilder::SetScissor(Nz::Recti scissorRegion) + { + m_commandBuffer.SetScissor(scissorRegion); + } + + void VulkanCommandBufferBuilder::SetViewport(Nz::Recti viewportRegion) + { + m_commandBuffer.SetViewport(Nz::Rectf(viewportRegion), 0.f, 1.f); + } +} diff --git a/src/Nazara/VulkanRenderer/VulkanRenderImage.cpp b/src/Nazara/VulkanRenderer/VulkanRenderImage.cpp new file mode 100644 index 000000000..9cade7921 --- /dev/null +++ b/src/Nazara/VulkanRenderer/VulkanRenderImage.cpp @@ -0,0 +1,93 @@ +// Copyright (C) 2020 Jérôme Leclercq +// This file is part of the "Nazara Engine - Vulkan Renderer" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#include +#include +#include +#include +#include + +namespace Nz +{ + VulkanRenderImage::VulkanRenderImage(VkRenderWindow& owner) : + m_owner(owner), + m_uploadPool(m_owner.GetDevice(), 2 * 1024 * 1024) + { + Vk::QueueHandle& graphicsQueue = m_owner.GetGraphicsQueue(); + if (!m_commandPool.Create(m_owner.GetDevice(), graphicsQueue.GetQueueFamilyIndex(), VK_COMMAND_POOL_CREATE_TRANSIENT_BIT | VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT)) + throw std::runtime_error("failed to create command pool: " + TranslateVulkanError(m_commandPool.GetLastErrorCode())); + + if (!m_imageAvailableSemaphore.Create(m_owner.GetDevice())) + throw std::runtime_error("failed to create image available semaphore: " + TranslateVulkanError(m_imageAvailableSemaphore.GetLastErrorCode())); + + if (!m_renderFinishedSemaphore.Create(m_owner.GetDevice())) + throw std::runtime_error("failed to create image finished semaphore: " + TranslateVulkanError(m_imageAvailableSemaphore.GetLastErrorCode())); + + if (!m_inFlightFence.Create(m_owner.GetDevice(), VK_FENCE_CREATE_SIGNALED_BIT)) + throw std::runtime_error("failed to create in-flight fence: " + TranslateVulkanError(m_inFlightFence.GetLastErrorCode())); + } + + VulkanRenderImage::~VulkanRenderImage() + { + m_inFlightCommandBuffers.clear(); + } + + void VulkanRenderImage::Execute(const std::function& callback, bool isGraphical) + { + Vk::CommandBuffer* commandBuffer; + if (m_currentCommandBuffer >= m_inFlightCommandBuffers.size()) + { + Vk::AutoCommandBuffer& newlyAllocatedBuffer = m_inFlightCommandBuffers.emplace_back(m_commandPool.AllocateCommandBuffer(VK_COMMAND_BUFFER_LEVEL_PRIMARY)); + commandBuffer = &newlyAllocatedBuffer.Get(); + m_currentCommandBuffer++; + } + else + commandBuffer = &m_inFlightCommandBuffers[m_currentCommandBuffer++].Get(); + + if (!commandBuffer->Begin(VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT)) + throw std::runtime_error("failed to begin command buffer: " + TranslateVulkanError(commandBuffer->GetLastErrorCode())); + + VulkanCommandBufferBuilder builder(*commandBuffer); + callback(builder); + + if (!commandBuffer->End()) + throw std::runtime_error("failed to build command buffer: " + TranslateVulkanError(commandBuffer->GetLastErrorCode())); + + SubmitCommandBuffer(*commandBuffer, isGraphical); + } + + VulkanUploadPool& VulkanRenderImage::GetUploadPool() + { + return m_uploadPool; + } + + void VulkanRenderImage::SubmitCommandBuffer(CommandBuffer* commandBuffer, bool isGraphical) + { + VulkanCommandBuffer& vkCommandBuffer = *static_cast(commandBuffer); + + return SubmitCommandBuffer(vkCommandBuffer.GetCommandBuffer(), isGraphical); + } + + void VulkanRenderImage::SubmitCommandBuffer(VkCommandBuffer commandBuffer, bool isGraphical) + { + if (isGraphical) + m_graphicalCommandsBuffers.push_back(commandBuffer); + else + { + Vk::QueueHandle& graphicsQueue = m_owner.GetGraphicsQueue(); + if (!graphicsQueue.Submit(commandBuffer)) + throw std::runtime_error("Failed to submit command buffer: " + TranslateVulkanError(graphicsQueue.GetLastErrorCode())); + } + } + + void VulkanRenderImage::Present() + { + Vk::QueueHandle& graphicsQueue = m_owner.GetGraphicsQueue(); + if (!graphicsQueue.Submit(UInt32(m_graphicalCommandsBuffers.size()), m_graphicalCommandsBuffers.data(), m_imageAvailableSemaphore, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, m_renderFinishedSemaphore, m_inFlightFence)) + throw std::runtime_error("Failed to submit command buffers: " + TranslateVulkanError(graphicsQueue.GetLastErrorCode())); + + m_owner.Present(m_imageIndex, m_renderFinishedSemaphore); + } +} diff --git a/src/Nazara/VulkanRenderer/VulkanRenderPipelineLayout.cpp b/src/Nazara/VulkanRenderer/VulkanRenderPipelineLayout.cpp index 3af7735fc..9257f6d72 100644 --- a/src/Nazara/VulkanRenderer/VulkanRenderPipelineLayout.cpp +++ b/src/Nazara/VulkanRenderer/VulkanRenderPipelineLayout.cpp @@ -39,16 +39,16 @@ namespace Nz DescriptorPool pool; if (!pool.descriptorPool.Create(*m_device, MaxSet, UInt32(poolSizes.size()), poolSizes.data(), VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT)) - { - //return {}; - } + throw std::runtime_error("Failed to allocate new descriptor pool: " + TranslateVulkanError(pool.descriptorPool.GetLastErrorCode())); pool.allocatedSets.reserve(MaxSet); auto& poolData = m_descriptorPools.emplace_back(std::move(pool)); Vk::DescriptorSet descriptorSet = poolData.descriptorPool.AllocateDescriptorSet(m_descriptorSetLayout); - //if (descriptorSet) - return poolData.allocatedSets.emplace_back(*this, std::move(descriptorSet)); + if (!descriptorSet) + throw std::runtime_error("Failed to allocate descriptor set: " + TranslateVulkanError(pool.descriptorPool.GetLastErrorCode())); + + return poolData.allocatedSets.emplace_back(*this, std::move(descriptorSet)); } bool VulkanRenderPipelineLayout::Create(Vk::Device& device, RenderPipelineLayoutInfo layoutInfo) diff --git a/src/Nazara/VulkanRenderer/VulkanUploadPool.cpp b/src/Nazara/VulkanRenderer/VulkanUploadPool.cpp index ffbf17f1a..3d0027332 100644 --- a/src/Nazara/VulkanRenderer/VulkanUploadPool.cpp +++ b/src/Nazara/VulkanRenderer/VulkanUploadPool.cpp @@ -4,11 +4,12 @@ #include #include +#include #include namespace Nz { - auto VulkanUploadPool::Allocate(UInt64 size) -> std::optional + auto VulkanUploadPool::Allocate(UInt64 size) -> VulkanAllocation& { const auto& deviceProperties = m_device.GetPhysicalDeviceInfo().properties; UInt64 preferredAlignement = deviceProperties.limits.optimalBufferCopyOffsetAlignment; @@ -16,7 +17,7 @@ namespace Nz return Allocate(size, preferredAlignement); } - auto VulkanUploadPool::Allocate(UInt64 size, UInt64 alignment) -> std::optional + auto VulkanUploadPool::Allocate(UInt64 size, UInt64 alignment) -> VulkanAllocation& { assert(size <= m_blockSize); @@ -49,37 +50,25 @@ namespace Nz { Block newBlock; if (!newBlock.buffer.Create(m_device, 0U, m_blockSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT)) - { - NazaraError("Failed to create block buffer: " + TranslateVulkanError(newBlock.buffer.GetLastErrorCode())); - return {}; - } + throw std::runtime_error("Failed to create block buffer: " + TranslateVulkanError(newBlock.buffer.GetLastErrorCode())); VkMemoryRequirements requirement = newBlock.buffer.GetMemoryRequirements(); if (!newBlock.blockMemory.Create(m_device, requirement.size, requirement.memoryTypeBits, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT)) - { - NazaraError("Failed to allocate block memory: " + TranslateVulkanError(newBlock.blockMemory.GetLastErrorCode())); - return {}; - } + throw std::runtime_error("Failed to allocate block memory: " + TranslateVulkanError(newBlock.blockMemory.GetLastErrorCode())); if (!newBlock.buffer.BindBufferMemory(newBlock.blockMemory)) - { - NazaraError("Failed to bind buffer memory: " + TranslateVulkanError(newBlock.buffer.GetLastErrorCode())); - return {}; - } + throw std::runtime_error("Failed to bind buffer memory: " + TranslateVulkanError(newBlock.buffer.GetLastErrorCode())); if (!newBlock.blockMemory.Map()) - { - NazaraError("Failed to map buffer memory: " + TranslateVulkanError(newBlock.buffer.GetLastErrorCode())); - return {}; - } + throw std::runtime_error("Failed to map buffer memory: " + TranslateVulkanError(newBlock.buffer.GetLastErrorCode())); bestBlock.block = &m_blocks.emplace_back(std::move(newBlock)); bestBlock.alignedOffset = 0; bestBlock.lostSpace = 0; } - AllocationData allocationData; + VulkanAllocation& allocationData = m_allocations.emplace_back(); allocationData.buffer = bestBlock.block->buffer; allocationData.mappedPtr = static_cast(bestBlock.block->blockMemory.GetMappedPointer()) + bestBlock.alignedOffset; allocationData.offset = bestBlock.alignedOffset; @@ -92,5 +81,7 @@ namespace Nz { for (Block& block : m_blocks) block.freeOffset = 0; + + m_allocations.clear(); } } diff --git a/src/Nazara/VulkanRenderer/Wrapper/Device.cpp b/src/Nazara/VulkanRenderer/Wrapper/Device.cpp index 49d22d586..6c02c7381 100644 --- a/src/Nazara/VulkanRenderer/Wrapper/Device.cpp +++ b/src/Nazara/VulkanRenderer/Wrapper/Device.cpp @@ -231,7 +231,7 @@ namespace Nz const auto& queues = GetEnabledQueues(queueFamilyIndex); NazaraAssert(queueIndex < queues.size(), "Invalid queue index"); - return QueueHandle(*this, queues[queueIndex].queue); + return QueueHandle(*this, queues[queueIndex].queue, queueFamilyIndex); } void Device::ResetPointers()