Vulkan: Add renderpass and framebuffers

This commit is contained in:
Lynix
2020-04-10 17:36:05 +02:00
parent 9507c56fc9
commit d9a08640d6
41 changed files with 659 additions and 95 deletions

View File

@@ -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 <Nazara/Renderer/Framebuffer.hpp>
#include <Nazara/Renderer/Debug.hpp>
namespace Nz
{
Framebuffer::~Framebuffer() = default;
}

View File

@@ -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 <Nazara/Renderer/RenderPass.hpp>
#include <Nazara/Renderer/Debug.hpp>
namespace Nz
{
RenderPass::~RenderPass() = default;
}

View File

@@ -11,9 +11,4 @@ namespace Nz
{
OnRenderTargetRelease(this);
}
void VkRenderTarget::Destroy()
{
m_renderPass.Destroy();
}
}

View File

@@ -5,6 +5,8 @@
#include <Nazara/VulkanRenderer/VkRenderWindow.hpp>
#include <Nazara/Core/Error.hpp>
#include <Nazara/Core/ErrorFlags.hpp>
#include <Nazara/Core/StackArray.hpp>
#include <Nazara/Math/Vector2.hpp>
#include <Nazara/Utility/PixelFormat.hpp>
#include <Nazara/VulkanRenderer/Vulkan.hpp>
#include <Nazara/VulkanRenderer/VulkanCommandPool.hpp>
@@ -28,11 +30,9 @@ namespace Nz
m_device->WaitForIdle();
m_concurrentImageData.clear();
m_imageData.clear();
m_renderPass.Destroy();
m_renderPass.reset();
m_framebuffer.reset();
m_swapchain.Destroy();
VkRenderTarget::Destroy();
}
VulkanRenderImage& VkRenderWindow::Acquire()
@@ -47,11 +47,11 @@ namespace Nz
if (!m_swapchain.AcquireNextImage(std::numeric_limits<UInt64>::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();
if (m_inflightFences[imageIndex])
m_inflightFences[imageIndex]->Wait();
m_imageData[imageIndex].inFlightFence = &inFlightFence;
m_imageData[imageIndex].inFlightFence->Reset();
m_inflightFences[imageIndex] = &inFlightFence;
m_inflightFences[imageIndex]->Reset();
currentFrame.Reset(imageIndex);
@@ -164,30 +164,34 @@ namespace Nz
UInt32 imageCount = m_swapchain.GetBufferCount();
// Framebuffers
m_imageData.resize(imageCount);
m_inflightFences.resize(imageCount);
Nz::StackArray<Vk::Framebuffer> framebuffers = NazaraStackArray(Vk::Framebuffer, imageCount);
for (UInt32 i = 0; i < imageCount; ++i)
{
std::array<VkImageView, 2> attachments = { m_swapchain.GetBuffer(i).view, m_depthBufferView };
VkFramebufferCreateInfo frameBufferCreate = {
VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO, // VkStructureType sType;
nullptr, // const void* pNext;
0, // VkFramebufferCreateFlags flags;
m_renderPass, // VkRenderPass renderPass;
(attachments[1] != VK_NULL_HANDLE) ? 2U : 1U, // uint32_t attachmentCount;
attachments.data(), // const VkImageView* pAttachments;
size.x, // uint32_t width;
size.y, // uint32_t height;
1U // uint32_t layers;
VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,
nullptr,
0,
m_renderPass->GetRenderPass(),
(attachments[1] != VK_NULL_HANDLE) ? 2U : 1U,
attachments.data(),
size.x,
size.y,
1U
};
if (!m_imageData[i].framebuffer.Create(*m_device, frameBufferCreate))
if (!framebuffers[i].Create(*m_device, frameBufferCreate))
{
NazaraError("Failed to create framebuffer for image #" + String::Number(i) + ": " + TranslateVulkanError(m_imageData[i].framebuffer.GetLastErrorCode()));
NazaraError("Failed to create framebuffer for image #" + String::Number(i) + ": " + TranslateVulkanError(framebuffers[i].GetLastErrorCode()));
return false;
}
}
m_framebuffer.emplace(framebuffers.data(), framebuffers.size());
const std::size_t MaxConcurrentImage = imageCount;
m_concurrentImageData.reserve(MaxConcurrentImage);
@@ -220,6 +224,11 @@ namespace Nz
return std::make_unique<VulkanCommandPool>(*m_device, queueFamilyIndex);
}
const VulkanRenderPass& VkRenderWindow::GetRenderPass() const
{
return *m_renderPass;
}
bool VkRenderWindow::SetupDepthBuffer(const Vector2ui& size)
{
VkImageCreateInfo imageCreateInfo = {
@@ -375,7 +384,16 @@ namespace Nz
dependencies.data() // const VkSubpassDependency* pDependencies;
};
return m_renderPass.Create(*m_device, createInfo);
Vk::RenderPass renderPass;
if (!renderPass.Create(*m_device, createInfo))
{
NazaraError("Failed to create render pass: " + TranslateVulkanError(renderPass.GetLastErrorCode()));
return false;
}
std::initializer_list<PixelFormat> fixmeplease = { PixelFormat::PixelFormat_RGB8, PixelFormat::PixelFormat_Depth24Stencil8 };
m_renderPass.emplace(std::move(renderPass), fixmeplease);
return true;
}
bool VkRenderWindow::SetupSwapchain(const Vk::PhysicalDevice& deviceInfo, Vk::Surface& surface, const Vector2ui& size)

View File

@@ -5,7 +5,11 @@
#include <Nazara/VulkanRenderer/VulkanCommandBufferBuilder.hpp>
#include <Nazara/Core/StackArray.hpp>
#include <Nazara/VulkanRenderer/VulkanBuffer.hpp>
#include <Nazara/VulkanRenderer/VulkanMultipleFramebuffer.hpp>
#include <Nazara/VulkanRenderer/VulkanRenderPass.hpp>
#include <Nazara/VulkanRenderer/VulkanRenderPipeline.hpp>
#include <Nazara/VulkanRenderer/VulkanRenderPipelineLayout.hpp>
#include <Nazara/VulkanRenderer/VulkanSingleFramebuffer.hpp>
#include <Nazara/VulkanRenderer/VulkanShaderBinding.hpp>
#include <Nazara/VulkanRenderer/VulkanUploadPool.hpp>
#include <Nazara/VulkanRenderer/Debug.hpp>
@@ -22,6 +26,73 @@ namespace Nz
m_commandBuffer.BeginDebugRegion(regionNameEOS.data(), color);
}
void VulkanCommandBufferBuilder::BeginRenderPass(const Framebuffer& framebuffer, const RenderPass& renderPass, Nz::Recti renderRect, std::initializer_list<ClearValues> clearValues)
{
const VulkanRenderPass& vkRenderPass = static_cast<const VulkanRenderPass&>(renderPass);
const Vk::Framebuffer& vkFramebuffer = [&] () -> const Vk::Framebuffer&
{
const VulkanFramebuffer& vkFramebuffer = static_cast<const VulkanFramebuffer&>(framebuffer);
switch (vkFramebuffer.GetType())
{
case VulkanFramebuffer::Type::Multiple:
{
const VulkanMultipleFramebuffer& vkMultipleFramebuffer = static_cast<const VulkanMultipleFramebuffer&>(vkFramebuffer);
m_framebufferCount = std::max(m_framebufferCount, vkMultipleFramebuffer.GetFramebufferCount());
return vkMultipleFramebuffer.GetFramebuffer(m_imageIndex);
}
case VulkanFramebuffer::Type::Single:
return static_cast<const VulkanSingleFramebuffer&>(vkFramebuffer).GetFramebuffer();
}
throw std::runtime_error("Unhandled framebuffer type " + std::to_string(UnderlyingCast(vkFramebuffer.GetType())));
}();
VkRect2D renderArea;
renderArea.offset.x = renderRect.x;
renderArea.offset.y = renderRect.y;
renderArea.extent.width = renderRect.width;
renderArea.extent.height = renderRect.height;
StackArray<VkClearValue> vkClearValues = NazaraStackArray(VkClearValue, clearValues.size());
std::size_t index = 0;
for (const ClearValues& values : clearValues)
{
auto& vkValues = vkClearValues[index];
if (PixelFormatInfo::GetContent(vkRenderPass.GetAttachmentFormat(index)) == PixelFormatContent_ColorRGBA)
{
vkValues.color.float32[0] = values.color.r / 255.f;
vkValues.color.float32[1] = values.color.g / 255.f;
vkValues.color.float32[2] = values.color.b / 255.f;
vkValues.color.float32[3] = values.color.a / 255.f;
}
else
{
vkValues.depthStencil.depth = values.depth;
vkValues.depthStencil.stencil = values.stencil;
}
index++;
}
VkRenderPassBeginInfo beginInfo = { VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO };
beginInfo.renderPass = vkRenderPass.GetRenderPass();
beginInfo.framebuffer = vkFramebuffer;
beginInfo.renderArea.offset.x = renderRect.x;
beginInfo.renderArea.offset.y = renderRect.y;
beginInfo.renderArea.extent.width = renderRect.width;
beginInfo.renderArea.extent.height = renderRect.height;
beginInfo.clearValueCount = vkClearValues.size();
beginInfo.pClearValues = vkClearValues.data();
m_commandBuffer.BeginRenderPass(beginInfo);
m_currentRenderPass = &vkRenderPass;
}
void VulkanCommandBufferBuilder::BindIndexBuffer(Nz::AbstractBuffer* indexBuffer, UInt64 offset)
{
VulkanBuffer& vkBuffer = *static_cast<VulkanBuffer*>(indexBuffer);
@@ -29,11 +100,21 @@ namespace Nz
m_commandBuffer.BindIndexBuffer(vkBuffer.GetBuffer(), offset, VK_INDEX_TYPE_UINT16); //< Fuck me right?
}
void VulkanCommandBufferBuilder::BindShaderBinding(ShaderBinding& binding)
void VulkanCommandBufferBuilder::BindPipeline(const RenderPipeline& pipeline)
{
VulkanShaderBinding& vkBinding = static_cast<VulkanShaderBinding&>(binding);
if (!m_currentRenderPass)
throw std::runtime_error("BindPipeline must be called in a RenderPass");
VulkanRenderPipelineLayout& pipelineLayout = vkBinding.GetOwner();
const VulkanRenderPipeline& vkBinding = static_cast<const VulkanRenderPipeline&>(pipeline);
m_commandBuffer.BindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, vkBinding.Get(m_currentRenderPass->GetRenderPass()));
}
void VulkanCommandBufferBuilder::BindShaderBinding(const ShaderBinding& binding)
{
const VulkanShaderBinding& vkBinding = static_cast<const VulkanShaderBinding&>(binding);
const VulkanRenderPipelineLayout& pipelineLayout = vkBinding.GetOwner();
m_commandBuffer.BindDescriptorSet(VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout.GetPipelineLayout(), 0U, vkBinding.GetDescriptorSet());
}
@@ -76,6 +157,12 @@ namespace Nz
m_commandBuffer.EndDebugRegion();
}
void VulkanCommandBufferBuilder::EndRenderPass()
{
m_commandBuffer.EndRenderPass();
m_currentRenderPass = nullptr;
}
void VulkanCommandBufferBuilder::PreTransferBarrier()
{
m_commandBuffer.MemoryBarrier(VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0U, VK_ACCESS_TRANSFER_READ_BIT);

View File

@@ -12,17 +12,27 @@ namespace Nz
{
std::unique_ptr<CommandBuffer> VulkanCommandPool::BuildCommandBuffer(const std::function<void(CommandBufferBuilder& builder)>& callback)
{
Vk::AutoCommandBuffer commandBuffer = m_commandPool.AllocateCommandBuffer(VK_COMMAND_BUFFER_LEVEL_PRIMARY);
std::vector<Vk::AutoCommandBuffer> commandBuffers;
auto BuildCommandBuffer = [&](std::size_t imageIndex)
{
Vk::AutoCommandBuffer& commandBuffer = commandBuffers.emplace_back(m_commandPool.AllocateCommandBuffer(VK_COMMAND_BUFFER_LEVEL_PRIMARY));
if (!commandBuffer->Begin())
throw std::runtime_error("failed to begin command buffer: " + TranslateVulkanError(commandBuffer->GetLastErrorCode()));
if (!commandBuffer->Begin(VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT))
throw std::runtime_error("failed to begin command buffer: " + TranslateVulkanError(commandBuffer->GetLastErrorCode()));
VulkanCommandBufferBuilder builder(commandBuffer.Get());
callback(builder);
VulkanCommandBufferBuilder builder(commandBuffer.Get(), imageIndex);
callback(builder);
if (!commandBuffer->End())
throw std::runtime_error("failed to build command buffer: " + TranslateVulkanError(commandBuffer->GetLastErrorCode()));
if (!commandBuffer->End())
throw std::runtime_error("failed to build command buffer: " + TranslateVulkanError(commandBuffer->GetLastErrorCode()));
return std::make_unique<VulkanCommandBuffer>(std::move(commandBuffer));
return builder.GetMaxFramebufferCount();
};
std::size_t maxFramebufferCount = BuildCommandBuffer(0);
for (std::size_t i = 1; i < maxFramebufferCount; ++i)
BuildCommandBuffer(i);
return std::make_unique<VulkanCommandBuffer>(std::move(commandBuffers));
}
}

View File

@@ -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 <Nazara/VulkanRenderer/VulkanFramebuffer.hpp>
#include <Nazara/VulkanRenderer/Debug.hpp>
namespace Nz
{
}

View File

@@ -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 <Nazara/VulkanRenderer/VulkanMultipleFramebuffer.hpp>
#include <Nazara/VulkanRenderer/Debug.hpp>
namespace Nz
{
}

View File

@@ -49,7 +49,7 @@ namespace Nz
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);
VulkanCommandBufferBuilder builder(*commandBuffer, m_imageIndex);
callback(builder);
if (!commandBuffer->End())
@@ -67,7 +67,7 @@ namespace Nz
{
VulkanCommandBuffer& vkCommandBuffer = *static_cast<VulkanCommandBuffer*>(commandBuffer);
return SubmitCommandBuffer(vkCommandBuffer.GetCommandBuffer(), queueTypeFlags);
return SubmitCommandBuffer(vkCommandBuffer.GetCommandBuffer(m_imageIndex), queueTypeFlags);
}
void VulkanRenderImage::SubmitCommandBuffer(VkCommandBuffer commandBuffer, QueueTypeFlags queueTypeFlags)

View File

@@ -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 <Nazara/VulkanRenderer/VulkanRenderPass.hpp>
#include <Nazara/VulkanRenderer/Debug.hpp>
namespace Nz
{
}

View File

@@ -19,7 +19,7 @@ namespace Nz
m_pipelineCreateInfo = BuildCreateInfo(m_pipelineInfo);
}
VkPipeline VulkanRenderPipeline::Get(const Vk::RenderPass& renderPass)
VkPipeline VulkanRenderPipeline::Get(const Vk::RenderPass& renderPass) const
{
if (auto it = m_pipelines.find(renderPass); it != m_pipelines.end())
return it->second;

View File

@@ -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 <Nazara/VulkanRenderer/VulkanSingleFramebuffer.hpp>
#include <Nazara/VulkanRenderer/Debug.hpp>
namespace Nz
{
}