VulkanRenderer: Handle window resize
This commit is contained in:
parent
982d28cace
commit
cbdac32f5f
|
|
@ -26,6 +26,7 @@ TOOL.Files = {
|
|||
|
||||
TOOL.Libraries = {
|
||||
"NazaraCore",
|
||||
"NazaraPlatform",
|
||||
"NazaraRenderer",
|
||||
"NazaraShader",
|
||||
"NazaraUtility"
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ TOOL.Files = {
|
|||
|
||||
TOOL.Libraries = {
|
||||
"NazaraCore",
|
||||
"NazaraPlatform",
|
||||
"NazaraRenderer",
|
||||
"NazaraShader",
|
||||
"NazaraUtility"
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ int main()
|
|||
Nz::Initializer<Nz::Renderer> loader;
|
||||
if (!loader)
|
||||
{
|
||||
std::cout << "Failed to initialize Vulkan" << std::endl;;
|
||||
std::cout << "Failed to initialize Vulkan" << std::endl;
|
||||
return __LINE__;
|
||||
}
|
||||
|
||||
|
|
@ -172,33 +172,41 @@ int main()
|
|||
Nz::AbstractBuffer* indexBufferImpl = renderBufferIB->GetHardwareBuffer(renderDevice);
|
||||
Nz::AbstractBuffer* vertexBufferImpl = renderBufferVB->GetHardwareBuffer(renderDevice);
|
||||
|
||||
std::unique_ptr<Nz::CommandBuffer> drawCommandBuffer = commandPool->BuildCommandBuffer([&](Nz::CommandBufferBuilder& builder)
|
||||
std::unique_ptr<Nz::CommandBuffer> drawCommandBuffer;
|
||||
auto RebuildCommandBuffer = [&]
|
||||
{
|
||||
Nz::Recti renderRect(0, 0, window.GetSize().x, window.GetSize().y);
|
||||
Nz::Vector2ui windowSize = window.GetSize();
|
||||
|
||||
Nz::CommandBufferBuilder::ClearValues clearValues[2];
|
||||
clearValues[0].color = Nz::Color::Black;
|
||||
clearValues[1].depth = 1.f;
|
||||
clearValues[1].stencil = 0;
|
||||
|
||||
builder.BeginDebugRegion("Main window rendering", Nz::Color::Green);
|
||||
drawCommandBuffer = commandPool->BuildCommandBuffer([&](Nz::CommandBufferBuilder& builder)
|
||||
{
|
||||
builder.BeginRenderPass(windowImpl->GetFramebuffer(), windowImpl->GetRenderPass(), renderRect, { clearValues[0], clearValues[1] });
|
||||
Nz::Recti renderRect(0, 0, window.GetSize().x, window.GetSize().y);
|
||||
|
||||
Nz::CommandBufferBuilder::ClearValues clearValues[2];
|
||||
clearValues[0].color = Nz::Color::Black;
|
||||
clearValues[1].depth = 1.f;
|
||||
clearValues[1].stencil = 0;
|
||||
|
||||
builder.BeginDebugRegion("Main window rendering", Nz::Color::Green);
|
||||
{
|
||||
builder.BindIndexBuffer(indexBufferImpl);
|
||||
builder.BindPipeline(*pipeline);
|
||||
builder.BindVertexBuffer(0, vertexBufferImpl);
|
||||
builder.BindShaderBinding(*shaderBinding);
|
||||
builder.BeginRenderPass(windowImpl->GetFramebuffer(), windowImpl->GetRenderPass(), renderRect, { clearValues[0], clearValues[1] });
|
||||
{
|
||||
builder.BindIndexBuffer(indexBufferImpl);
|
||||
builder.BindPipeline(*pipeline);
|
||||
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) });
|
||||
builder.SetScissor(Nz::Recti{ 0, 0, int(windowSize.x), int(windowSize.y) });
|
||||
builder.SetViewport(Nz::Recti{ 0, 0, int(windowSize.x), int(windowSize.y) });
|
||||
|
||||
builder.DrawIndexed(drfreakIB->GetIndexCount());
|
||||
builder.DrawIndexed(drfreakIB->GetIndexCount());
|
||||
}
|
||||
builder.EndRenderPass();
|
||||
}
|
||||
builder.EndRenderPass();
|
||||
}
|
||||
builder.EndDebugRegion();
|
||||
});
|
||||
builder.EndDebugRegion();
|
||||
});
|
||||
};
|
||||
RebuildCommandBuffer();
|
||||
|
||||
|
||||
Nz::Vector3f viewerPos = Nz::Vector3f::Zero();
|
||||
|
||||
|
|
@ -210,6 +218,7 @@ int main()
|
|||
Nz::Clock updateClock;
|
||||
Nz::Clock secondClock;
|
||||
unsigned int fps = 0;
|
||||
bool uboUpdate = true;
|
||||
|
||||
Nz::Mouse::SetRelativeMouseMode(true);
|
||||
|
||||
|
|
@ -236,8 +245,20 @@ int main()
|
|||
camAngles.pitch = Nz::Clamp(camAngles.pitch + event.mouseMove.deltaY*sensitivity, -89.f, 89.f);
|
||||
|
||||
camQuat = camAngles;
|
||||
|
||||
uboUpdate = true;
|
||||
break;
|
||||
|
||||
case Nz::WindowEventType_Resized:
|
||||
{
|
||||
Nz::Vector2ui windowSize = window.GetSize();
|
||||
ubo.projectionMatrix = Nz::Matrix4f::Perspective(70.f, float(windowSize.x) / windowSize.y, 0.1f, 1000.f);
|
||||
uboUpdate = true;
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -268,30 +289,44 @@ int main()
|
|||
// Contrôle (Gauche ou droite) pour descendre dans l'espace global, etc...
|
||||
if (Nz::Keyboard::IsKeyPressed(Nz::Keyboard::VKey::LControl) || Nz::Keyboard::IsKeyPressed(Nz::Keyboard::VKey::RControl))
|
||||
viewerPos += Nz::Vector3f::Down() * cameraSpeed;
|
||||
|
||||
uboUpdate = true;
|
||||
}
|
||||
|
||||
Nz::RenderImage& renderImage = windowImpl->Acquire();
|
||||
Nz::RenderFrame frame = windowImpl->Acquire();
|
||||
if (!frame)
|
||||
continue;
|
||||
|
||||
if (frame.IsFramebufferInvalidated())
|
||||
RebuildCommandBuffer();
|
||||
|
||||
ubo.viewMatrix = Nz::Matrix4f::ViewMatrix(viewerPos, camAngles);
|
||||
|
||||
auto& allocation = renderImage.GetUploadPool().Allocate(uniformSize);
|
||||
|
||||
std::memcpy(allocation.mappedPtr, &ubo, sizeof(ubo));
|
||||
|
||||
renderImage.Execute([&](Nz::CommandBufferBuilder& builder)
|
||||
if (uboUpdate)
|
||||
{
|
||||
builder.BeginDebugRegion("UBO Update", Nz::Color::Yellow);
|
||||
auto& allocation = frame.GetUploadPool().Allocate(uniformSize);
|
||||
|
||||
std::memcpy(allocation.mappedPtr, &ubo, sizeof(ubo));
|
||||
|
||||
frame.Execute([&](Nz::CommandBufferBuilder& builder)
|
||||
{
|
||||
builder.PreTransferBarrier();
|
||||
builder.CopyBuffer(allocation, uniformBuffer.get());
|
||||
builder.PostTransferBarrier();
|
||||
}
|
||||
builder.EndDebugRegion();
|
||||
}, Nz::QueueType::Transfer);
|
||||
builder.BeginDebugRegion("UBO Update", Nz::Color::Yellow);
|
||||
{
|
||||
builder.PreTransferBarrier();
|
||||
builder.CopyBuffer(allocation, uniformBuffer.get());
|
||||
builder.PostTransferBarrier();
|
||||
}
|
||||
builder.EndDebugRegion();
|
||||
}, Nz::QueueType::Transfer);
|
||||
|
||||
renderImage.SubmitCommandBuffer(drawCommandBuffer.get(), Nz::QueueType::Graphics);
|
||||
uboUpdate = false;
|
||||
}
|
||||
|
||||
renderImage.Present();
|
||||
frame.SubmitCommandBuffer(drawCommandBuffer.get(), Nz::QueueType::Graphics);
|
||||
|
||||
frame.Present();
|
||||
|
||||
window.Display();
|
||||
|
||||
// On incrémente le compteur de FPS improvisé
|
||||
fps++;
|
||||
|
|
|
|||
|
|
@ -20,15 +20,17 @@
|
|||
|
||||
namespace Nz
|
||||
{
|
||||
class RenderWindow;
|
||||
|
||||
class NAZARA_OPENGLRENDERER_API OpenGLRenderWindow : public RenderWindowImpl
|
||||
{
|
||||
public:
|
||||
OpenGLRenderWindow();
|
||||
OpenGLRenderWindow(RenderWindow& owner);
|
||||
~OpenGLRenderWindow() = default;
|
||||
|
||||
OpenGLRenderImage& Acquire() override;
|
||||
RenderFrame Acquire() override;
|
||||
|
||||
bool Create(RendererImpl* renderer, RenderSurface* surface, const Vector2ui& size, const RenderWindowParameters& parameters) override;
|
||||
bool Create(RendererImpl* renderer, RenderSurface* surface, const RenderWindowParameters& parameters) override;
|
||||
std::unique_ptr<CommandPool> CreateCommandPool(QueueType queueType) override;
|
||||
|
||||
inline GL::Context& GetContext();
|
||||
|
|
@ -46,6 +48,7 @@ namespace Nz
|
|||
std::unique_ptr<GL::Context> m_context;
|
||||
OpenGLRenderPass m_renderPass;
|
||||
OpenGLWindowFramebuffer m_framebuffer;
|
||||
RenderWindow& m_owner;
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ namespace Nz
|
|||
~OpenGLRenderer();
|
||||
|
||||
std::unique_ptr<RenderSurface> CreateRenderSurfaceImpl() override;
|
||||
std::unique_ptr<RenderWindowImpl> CreateRenderWindowImpl() override;
|
||||
std::unique_ptr<RenderWindowImpl> CreateRenderWindowImpl(RenderWindow& owner) override;
|
||||
|
||||
std::shared_ptr<RenderDevice> InstanciateRenderDevice(std::size_t deviceIndex) override;
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,54 @@
|
|||
// 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_RENDERFRAME_HPP
|
||||
#define NAZARA_RENDERFRAME_HPP
|
||||
|
||||
#include <Nazara/Prerequisites.hpp>
|
||||
#include <Nazara/Renderer/Config.hpp>
|
||||
#include <Nazara/Renderer/Enums.hpp>
|
||||
#include <functional>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
class CommandBuffer;
|
||||
class CommandBufferBuilder;
|
||||
class RenderImage;
|
||||
class UploadPool;
|
||||
|
||||
class NAZARA_RENDERER_API RenderFrame
|
||||
{
|
||||
public:
|
||||
inline explicit RenderFrame();
|
||||
inline explicit RenderFrame(RenderImage* renderImage, bool framebufferInvalidation);
|
||||
RenderFrame(const RenderFrame&) = delete;
|
||||
RenderFrame(RenderFrame&&) = delete;
|
||||
~RenderFrame() = default;
|
||||
|
||||
void Execute(const std::function<void(CommandBufferBuilder& builder)>& callback, QueueTypeFlags queueTypeFlags);
|
||||
|
||||
UploadPool& GetUploadPool();
|
||||
|
||||
inline bool IsFramebufferInvalidated() const;
|
||||
|
||||
void SubmitCommandBuffer(CommandBuffer* commandBuffer, QueueTypeFlags queueTypeFlags) ;
|
||||
|
||||
void Present();
|
||||
|
||||
inline explicit operator bool();
|
||||
|
||||
RenderFrame& operator=(const RenderFrame&) = delete;
|
||||
RenderFrame& operator=(RenderFrame&&) = delete;
|
||||
|
||||
private:
|
||||
RenderImage* m_image;
|
||||
bool m_framebufferInvalidation;
|
||||
};
|
||||
}
|
||||
|
||||
#include <Nazara/Renderer/RenderFrame.inl>
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
// 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 <Nazara/Renderer/RenderFrame.hpp>
|
||||
#include <Nazara/Renderer/Debug.hpp>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
inline RenderFrame::RenderFrame() :
|
||||
RenderFrame(nullptr, false)
|
||||
{
|
||||
}
|
||||
|
||||
inline RenderFrame::RenderFrame(RenderImage* renderImage, bool framebufferInvalidation) :
|
||||
m_image(renderImage),
|
||||
m_framebufferInvalidation(framebufferInvalidation)
|
||||
{
|
||||
}
|
||||
|
||||
inline bool RenderFrame::IsFramebufferInvalidated() const
|
||||
{
|
||||
return m_framebufferInvalidation;
|
||||
}
|
||||
|
||||
inline RenderFrame::operator bool()
|
||||
{
|
||||
return m_image != nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
#include <Nazara/Renderer/DebugOff.hpp>
|
||||
|
|
@ -21,7 +21,6 @@ namespace Nz
|
|||
class NAZARA_RENDERER_API RenderImage
|
||||
{
|
||||
public:
|
||||
RenderImage() = default;
|
||||
virtual ~RenderImage();
|
||||
|
||||
virtual void Execute(const std::function<void(CommandBufferBuilder& builder)>& callback, QueueTypeFlags queueTypeFlags) = 0;
|
||||
|
|
@ -33,6 +32,7 @@ namespace Nz
|
|||
virtual void Present() = 0;
|
||||
|
||||
protected:
|
||||
RenderImage() = default;
|
||||
RenderImage(const RenderImage&) = delete;
|
||||
RenderImage(RenderImage&&) = default;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -36,8 +36,9 @@ namespace Nz
|
|||
|
||||
void EnableVerticalSync(bool enabled);
|
||||
|
||||
inline RenderWindowImpl *GetImpl();
|
||||
inline RenderWindowImpl* GetImpl();
|
||||
std::shared_ptr<RenderDevice> GetRenderDevice();
|
||||
inline RenderSurface* GetSurface();
|
||||
|
||||
inline bool IsValid() const;
|
||||
|
||||
|
|
|
|||
|
|
@ -46,11 +46,16 @@ namespace Nz
|
|||
return Window::Create(handle);
|
||||
}
|
||||
|
||||
inline RenderWindowImpl* Nz::RenderWindow::GetImpl()
|
||||
inline RenderWindowImpl* RenderWindow::GetImpl()
|
||||
{
|
||||
return m_impl.get();
|
||||
}
|
||||
|
||||
inline RenderSurface* RenderWindow::GetSurface()
|
||||
{
|
||||
return m_surface.get();
|
||||
}
|
||||
|
||||
inline bool RenderWindow::IsValid() const
|
||||
{
|
||||
return m_impl != nullptr;
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@
|
|||
#include <Nazara/Platform/WindowHandle.hpp>
|
||||
#include <Nazara/Renderer/Config.hpp>
|
||||
#include <Nazara/Renderer/RenderDevice.hpp>
|
||||
#include <Nazara/Renderer/RenderFrame.hpp>
|
||||
#include <Nazara/Renderer/RenderWindowParameters.hpp>
|
||||
|
||||
namespace Nz
|
||||
|
|
@ -19,7 +20,6 @@ namespace Nz
|
|||
class CommandPool;
|
||||
class Framebuffer;
|
||||
class RendererImpl;
|
||||
class RenderImage;
|
||||
class RenderPass;
|
||||
class RenderSurface;
|
||||
|
||||
|
|
@ -29,9 +29,9 @@ namespace Nz
|
|||
RenderWindowImpl() = default;
|
||||
virtual ~RenderWindowImpl();
|
||||
|
||||
virtual RenderImage& Acquire() = 0;
|
||||
virtual RenderFrame Acquire() = 0;
|
||||
|
||||
virtual bool Create(RendererImpl* renderer, RenderSurface* surface, const Vector2ui& size, const RenderWindowParameters& parameters) = 0;
|
||||
virtual bool Create(RendererImpl* renderer, RenderSurface* surface, const RenderWindowParameters& parameters) = 0;
|
||||
virtual std::unique_ptr<CommandPool> CreateCommandPool(QueueType queueType) = 0;
|
||||
|
||||
virtual const Framebuffer& GetFramebuffer() const = 0;
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ namespace Nz
|
|||
class RendererImpl;
|
||||
class RenderDevice;
|
||||
class RenderSurface;
|
||||
class RenderWindow;
|
||||
class RenderWindowImpl;
|
||||
|
||||
using CreateRendererImplFunc = RendererImpl*(*)();
|
||||
|
|
@ -34,7 +35,7 @@ namespace Nz
|
|||
virtual ~RendererImpl();
|
||||
|
||||
virtual std::unique_ptr<RenderSurface> CreateRenderSurfaceImpl() = 0;
|
||||
virtual std::unique_ptr<RenderWindowImpl> CreateRenderWindowImpl() = 0;
|
||||
virtual std::unique_ptr<RenderWindowImpl> CreateRenderWindowImpl(RenderWindow& owner) = 0;
|
||||
|
||||
virtual std::shared_ptr<RenderDevice> InstanciateRenderDevice(std::size_t deviceIndex) = 0;
|
||||
|
||||
|
|
|
|||
|
|
@ -37,24 +37,25 @@ namespace Nz
|
|||
class NAZARA_VULKANRENDERER_API VkRenderWindow : public VkRenderTarget, public RenderWindowImpl
|
||||
{
|
||||
public:
|
||||
VkRenderWindow();
|
||||
VkRenderWindow(RenderWindow& owner);
|
||||
VkRenderWindow(const VkRenderWindow&) = delete;
|
||||
VkRenderWindow(VkRenderWindow&&) = delete; ///TODO
|
||||
~VkRenderWindow();
|
||||
|
||||
VulkanRenderImage& Acquire() override;
|
||||
RenderFrame Acquire() override;
|
||||
|
||||
bool Create(RendererImpl* renderer, RenderSurface* surface, const RenderWindowParameters& parameters) override;
|
||||
|
||||
bool Create(RendererImpl* renderer, RenderSurface* surface, const Vector2ui& size, const RenderWindowParameters& parameters) override;
|
||||
std::unique_ptr<CommandPool> CreateCommandPool(QueueType queueType) override;
|
||||
|
||||
inline const VulkanMultipleFramebuffer& GetFramebuffer() const override;
|
||||
inline VulkanDevice& GetDevice();
|
||||
inline const VulkanDevice& GetDevice() const;
|
||||
inline Vk::QueueHandle& GetGraphicsQueue();
|
||||
const VulkanRenderPass& GetRenderPass() const override;
|
||||
inline const VulkanRenderPass& GetRenderPass() const override;
|
||||
inline const Vk::Swapchain& GetSwapchain() const;
|
||||
|
||||
std::shared_ptr<RenderDevice> GetRenderDevice() override;
|
||||
inline std::shared_ptr<RenderDevice> GetRenderDevice() override;
|
||||
|
||||
void Present(UInt32 imageIndex, VkSemaphore waitSemaphore = VK_NULL_HANDLE);
|
||||
|
||||
|
|
@ -62,17 +63,16 @@ namespace Nz
|
|||
VkRenderWindow& operator=(VkRenderWindow&&) = delete; ///TODO
|
||||
|
||||
private:
|
||||
bool CreateSwapchain(Vk::Surface& surface, const Vector2ui& size);
|
||||
bool SetupDepthBuffer(const Vector2ui& size);
|
||||
bool SetupFrameBuffers(const Vector2ui& size);
|
||||
bool SetupRenderPass();
|
||||
bool SetupSwapchain(const Vk::PhysicalDevice& deviceInfo, Vk::Surface& surface, const Vector2ui& size);
|
||||
|
||||
std::size_t m_currentFrame;
|
||||
Clock m_clock;
|
||||
VkFormat m_depthStencilFormat;
|
||||
VkSurfaceFormatKHR m_surfaceFormat;
|
||||
std::optional<VulkanMultipleFramebuffer> m_framebuffer;
|
||||
std::optional<VulkanRenderPass> m_renderPass;
|
||||
std::shared_ptr<VulkanDevice> m_device;
|
||||
std::size_t m_currentFrame;
|
||||
std::vector<Vk::Fence*> m_inflightFences;
|
||||
std::vector<VulkanRenderImage> m_concurrentImageData;
|
||||
Vk::DeviceMemory m_depthBufferMemory;
|
||||
|
|
@ -82,6 +82,12 @@ namespace Nz
|
|||
Vk::QueueHandle m_presentQueue;
|
||||
Vk::QueueHandle m_transferQueue;
|
||||
Vk::Swapchain m_swapchain;
|
||||
Clock m_clock;
|
||||
RenderWindow& m_owner;
|
||||
Vector2ui m_swapchainSize;
|
||||
VkFormat m_depthStencilFormat;
|
||||
VkSurfaceFormatKHR m_surfaceFormat;
|
||||
bool m_shouldRecreateSwapchain;
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -27,24 +27,20 @@ namespace Nz
|
|||
return m_graphicsQueue;
|
||||
}
|
||||
|
||||
inline const VulkanRenderPass& VkRenderWindow::GetRenderPass() const
|
||||
{
|
||||
return *m_renderPass;
|
||||
}
|
||||
|
||||
inline const Vk::Swapchain& VkRenderWindow::GetSwapchain() const
|
||||
{
|
||||
return m_swapchain;
|
||||
}
|
||||
|
||||
inline std::shared_ptr<RenderDevice> Nz::VkRenderWindow::GetRenderDevice()
|
||||
inline std::shared_ptr<RenderDevice> VkRenderWindow::GetRenderDevice()
|
||||
{
|
||||
return m_device;
|
||||
}
|
||||
|
||||
inline void VkRenderWindow::Present(UInt32 imageIndex, VkSemaphore waitSemaphore)
|
||||
{
|
||||
NazaraAssert(imageIndex < m_inflightFences.size(), "Invalid image index");
|
||||
|
||||
m_presentQueue.Present(m_swapchain, imageIndex, waitSemaphore);
|
||||
|
||||
m_currentFrame = (m_currentFrame + 1) % m_inflightFences.size();
|
||||
}
|
||||
}
|
||||
|
||||
#include <Nazara/VulkanRenderer/DebugOff.hpp>
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ namespace Nz
|
|||
~VulkanRenderer();
|
||||
|
||||
std::unique_ptr<RenderSurface> CreateRenderSurfaceImpl() override;
|
||||
std::unique_ptr<RenderWindowImpl> CreateRenderWindowImpl() override;
|
||||
std::unique_ptr<RenderWindowImpl> CreateRenderWindowImpl(RenderWindow& owner) override;
|
||||
|
||||
std::shared_ptr<RenderDevice> InstanciateRenderDevice(std::size_t deviceIndex) override;
|
||||
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@ namespace Nz
|
|||
inline bool IsSupported() const;
|
||||
|
||||
Swapchain& operator=(const Swapchain&) = delete;
|
||||
Swapchain& operator=(Swapchain&&) = delete;
|
||||
Swapchain& operator=(Swapchain&&) = default;
|
||||
|
||||
struct Buffer
|
||||
{
|
||||
|
|
|
|||
|
|
@ -7,22 +7,24 @@
|
|||
#include <Nazara/OpenGLRenderer/OpenGLCommandPool.hpp>
|
||||
#include <Nazara/OpenGLRenderer/OpenGLRenderer.hpp>
|
||||
#include <Nazara/Renderer/CommandPool.hpp>
|
||||
#include <Nazara/Renderer/RenderWindow.hpp>
|
||||
#include <Nazara/OpenGLRenderer/Debug.hpp>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
OpenGLRenderWindow::OpenGLRenderWindow() :
|
||||
OpenGLRenderWindow::OpenGLRenderWindow(RenderWindow& owner) :
|
||||
m_currentFrame(0),
|
||||
m_framebuffer(*this)
|
||||
m_framebuffer(*this),
|
||||
m_owner(owner)
|
||||
{
|
||||
}
|
||||
|
||||
OpenGLRenderImage& OpenGLRenderWindow::Acquire()
|
||||
RenderFrame OpenGLRenderWindow::Acquire()
|
||||
{
|
||||
return m_renderImage[m_currentFrame];
|
||||
return RenderFrame(&m_renderImage[m_currentFrame], false);
|
||||
}
|
||||
|
||||
bool OpenGLRenderWindow::Create(RendererImpl* renderer, RenderSurface* surface, const Vector2ui& size, const RenderWindowParameters& parameters)
|
||||
bool OpenGLRenderWindow::Create(RendererImpl* renderer, RenderSurface* surface, const RenderWindowParameters& parameters)
|
||||
{
|
||||
DummySurface* dummySurface = static_cast<DummySurface*>(surface);
|
||||
OpenGLRenderer* glRenderer = static_cast<OpenGLRenderer*>(renderer);
|
||||
|
|
|
|||
|
|
@ -31,9 +31,9 @@ namespace Nz
|
|||
return std::make_unique<DummySurface>();
|
||||
}
|
||||
|
||||
std::unique_ptr<RenderWindowImpl> OpenGLRenderer::CreateRenderWindowImpl()
|
||||
std::unique_ptr<RenderWindowImpl> OpenGLRenderer::CreateRenderWindowImpl(RenderWindow& owner)
|
||||
{
|
||||
return std::make_unique<OpenGLRenderWindow>();
|
||||
return std::make_unique<OpenGLRenderWindow>(owner);
|
||||
}
|
||||
|
||||
std::shared_ptr<RenderDevice> OpenGLRenderer::InstanciateRenderDevice(std::size_t deviceIndex)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,44 @@
|
|||
// 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 <Nazara/Renderer/RenderFrame.hpp>
|
||||
#include <Nazara/Renderer/RenderImage.hpp>
|
||||
#include <stdexcept>
|
||||
#include <Nazara/Renderer/Debug.hpp>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
void RenderFrame::Execute(const std::function<void(CommandBufferBuilder& builder)>& callback, QueueTypeFlags queueTypeFlags)
|
||||
{
|
||||
if (!m_image)
|
||||
throw std::runtime_error("frame is either invalid or has already been presented");
|
||||
|
||||
return m_image->Execute(callback, queueTypeFlags);
|
||||
}
|
||||
|
||||
UploadPool& RenderFrame::GetUploadPool()
|
||||
{
|
||||
if (!m_image)
|
||||
throw std::runtime_error("frame is either invalid or has already been presented");
|
||||
|
||||
return m_image->GetUploadPool();
|
||||
}
|
||||
|
||||
void RenderFrame::SubmitCommandBuffer(CommandBuffer* commandBuffer, QueueTypeFlags queueTypeFlags)
|
||||
{
|
||||
if (!m_image)
|
||||
throw std::runtime_error("frame is either invalid or has already been presented");
|
||||
|
||||
m_image->SubmitCommandBuffer(commandBuffer, queueTypeFlags);
|
||||
}
|
||||
|
||||
void RenderFrame::Present()
|
||||
{
|
||||
if (!m_image)
|
||||
throw std::runtime_error("frame is either invalid or has already been presented");
|
||||
|
||||
m_image->Present();
|
||||
m_image = nullptr;
|
||||
}
|
||||
}
|
||||
|
|
@ -46,8 +46,8 @@ namespace Nz
|
|||
return false;
|
||||
}
|
||||
|
||||
auto impl = rendererImpl->CreateRenderWindowImpl();
|
||||
if (!impl->Create(rendererImpl, surface.get(), GetSize(), m_parameters))
|
||||
auto impl = rendererImpl->CreateRenderWindowImpl(*this);
|
||||
if (!impl->Create(rendererImpl, surface.get(), m_parameters))
|
||||
{
|
||||
NazaraError("Failed to create render window implementation: " + Error::GetLastError());
|
||||
return false;
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@
|
|||
#include <Nazara/Core/ErrorFlags.hpp>
|
||||
#include <Nazara/Core/StackArray.hpp>
|
||||
#include <Nazara/Math/Vector2.hpp>
|
||||
#include <Nazara/Renderer/RenderWindow.hpp>
|
||||
#include <Nazara/Utility/PixelFormat.hpp>
|
||||
#include <Nazara/VulkanRenderer/Vulkan.hpp>
|
||||
#include <Nazara/VulkanRenderer/VulkanCommandPool.hpp>
|
||||
|
|
@ -18,9 +19,11 @@
|
|||
|
||||
namespace Nz
|
||||
{
|
||||
VkRenderWindow::VkRenderWindow() :
|
||||
VkRenderWindow::VkRenderWindow(RenderWindow& owner) :
|
||||
m_currentFrame(0),
|
||||
m_depthStencilFormat(VK_FORMAT_MAX_ENUM)
|
||||
m_depthStencilFormat(VK_FORMAT_MAX_ENUM),
|
||||
m_owner(owner),
|
||||
m_shouldRecreateSwapchain(false)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
@ -35,8 +38,26 @@ namespace Nz
|
|||
m_swapchain.Destroy();
|
||||
}
|
||||
|
||||
VulkanRenderImage& VkRenderWindow::Acquire()
|
||||
RenderFrame VkRenderWindow::Acquire()
|
||||
{
|
||||
bool invalidateFramebuffer = false;
|
||||
|
||||
Vector2ui size = m_owner.GetSize();
|
||||
// Special case: window is minimized
|
||||
if (size == Nz::Vector2ui::Zero() || m_owner.IsMinimized())
|
||||
return RenderFrame();
|
||||
|
||||
if (m_shouldRecreateSwapchain || size != m_swapchainSize)
|
||||
{
|
||||
Vk::Surface& vulkanSurface = static_cast<VulkanSurface*>(m_owner.GetSurface())->GetSurface();
|
||||
|
||||
if (!CreateSwapchain(vulkanSurface, size))
|
||||
throw std::runtime_error("failed to recreate swapchain");
|
||||
|
||||
m_shouldRecreateSwapchain = false;
|
||||
invalidateFramebuffer = true;
|
||||
}
|
||||
|
||||
VulkanRenderImage& currentFrame = m_concurrentImageData[m_currentFrame];
|
||||
Vk::Fence& inFlightFence = currentFrame.GetInFlightFence();
|
||||
|
||||
|
|
@ -44,8 +65,33 @@ namespace Nz
|
|||
inFlightFence.Wait();
|
||||
|
||||
UInt32 imageIndex;
|
||||
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()));
|
||||
m_swapchain.AcquireNextImage(std::numeric_limits<UInt64>::max(), currentFrame.GetImageAvailableSemaphore(), VK_NULL_HANDLE, &imageIndex);
|
||||
|
||||
switch (m_swapchain.GetLastErrorCode())
|
||||
{
|
||||
case VK_SUCCESS:
|
||||
break;
|
||||
|
||||
case VK_SUBOPTIMAL_KHR:
|
||||
m_shouldRecreateSwapchain = true; //< Recreate swapchain next time
|
||||
break;
|
||||
|
||||
case VK_ERROR_OUT_OF_DATE_KHR:
|
||||
m_shouldRecreateSwapchain = true;
|
||||
return Acquire();
|
||||
|
||||
// Not expected (since timeout is infinite)
|
||||
case VK_TIMEOUT:
|
||||
case VK_NOT_READY:
|
||||
// Unhandled errors
|
||||
case VK_ERROR_DEVICE_LOST:
|
||||
case VK_ERROR_OUT_OF_DEVICE_MEMORY:
|
||||
case VK_ERROR_OUT_OF_HOST_MEMORY:
|
||||
case VK_ERROR_SURFACE_LOST_KHR: //< TODO: Handle it by recreating the surface?
|
||||
case VK_ERROR_FULL_SCREEN_EXCLUSIVE_MODE_LOST_EXT:
|
||||
default:
|
||||
throw std::runtime_error("Failed to acquire next image: " + TranslateVulkanError(m_swapchain.GetLastErrorCode()));
|
||||
}
|
||||
|
||||
if (m_inflightFences[imageIndex])
|
||||
m_inflightFences[imageIndex]->Wait();
|
||||
|
|
@ -55,10 +101,10 @@ namespace Nz
|
|||
|
||||
currentFrame.Reset(imageIndex);
|
||||
|
||||
return currentFrame;
|
||||
return RenderFrame(¤tFrame, invalidateFramebuffer);
|
||||
}
|
||||
|
||||
bool VkRenderWindow::Create(RendererImpl* /*renderer*/, RenderSurface* surface, const Vector2ui& size, const RenderWindowParameters& parameters)
|
||||
bool VkRenderWindow::Create(RendererImpl* /*renderer*/, RenderSurface* surface, const RenderWindowParameters& parameters)
|
||||
{
|
||||
const auto& deviceInfo = Vulkan::GetPhysicalDevices()[0];
|
||||
|
||||
|
|
@ -156,61 +202,18 @@ namespace Nz
|
|||
}
|
||||
}
|
||||
|
||||
if (!SetupSwapchain(deviceInfo, vulkanSurface, size))
|
||||
{
|
||||
NazaraError("Failed to create swapchain");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (m_depthStencilFormat != VK_FORMAT_MAX_ENUM && !SetupDepthBuffer(size))
|
||||
{
|
||||
NazaraError("Failed to create depth buffer");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!SetupRenderPass())
|
||||
{
|
||||
NazaraError("Failed to create render pass");
|
||||
return false;
|
||||
}
|
||||
|
||||
UInt32 imageCount = m_swapchain.GetBufferCount();
|
||||
|
||||
// Framebuffers
|
||||
m_inflightFences.resize(imageCount);
|
||||
|
||||
Nz::StackArray<Vk::Framebuffer> framebuffers = NazaraStackArray(Vk::Framebuffer, imageCount);
|
||||
for (UInt32 i = 0; i < imageCount; ++i)
|
||||
if (!CreateSwapchain(vulkanSurface, m_owner.GetSize()))
|
||||
{
|
||||
std::array<VkImageView, 2> attachments = { m_swapchain.GetBuffer(i).view, m_depthBufferView };
|
||||
|
||||
VkFramebufferCreateInfo frameBufferCreate = {
|
||||
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 (!framebuffers[i].Create(*m_device, frameBufferCreate))
|
||||
{
|
||||
NazaraError("Failed to create framebuffer for image #" + String::Number(i) + ": " + TranslateVulkanError(framebuffers[i].GetLastErrorCode()));
|
||||
return false;
|
||||
}
|
||||
NazaraError("failed to create swapchain");
|
||||
return false;
|
||||
}
|
||||
|
||||
m_framebuffer.emplace(framebuffers.data(), framebuffers.size());
|
||||
|
||||
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;
|
||||
|
|
@ -237,9 +240,60 @@ namespace Nz
|
|||
return std::make_unique<VulkanCommandPool>(*m_device, queueFamilyIndex);
|
||||
}
|
||||
|
||||
const VulkanRenderPass& VkRenderWindow::GetRenderPass() const
|
||||
void VkRenderWindow::Present(UInt32 imageIndex, VkSemaphore waitSemaphore)
|
||||
{
|
||||
return *m_renderPass;
|
||||
NazaraAssert(imageIndex < m_inflightFences.size(), "Invalid image index");
|
||||
|
||||
m_currentFrame = (m_currentFrame + 1) % m_inflightFences.size();
|
||||
|
||||
m_presentQueue.Present(m_swapchain, imageIndex, waitSemaphore);
|
||||
|
||||
switch (m_presentQueue.GetLastErrorCode())
|
||||
{
|
||||
case VK_SUCCESS:
|
||||
break;
|
||||
|
||||
case VK_ERROR_OUT_OF_DATE_KHR:
|
||||
case VK_SUBOPTIMAL_KHR:
|
||||
{
|
||||
// Recreate swapchain next time
|
||||
m_shouldRecreateSwapchain = true;
|
||||
break;
|
||||
}
|
||||
|
||||
// Unhandled errors
|
||||
case VK_ERROR_DEVICE_LOST:
|
||||
case VK_ERROR_OUT_OF_DEVICE_MEMORY:
|
||||
case VK_ERROR_OUT_OF_HOST_MEMORY:
|
||||
case VK_ERROR_SURFACE_LOST_KHR: //< TODO: Handle it by recreating the surface?
|
||||
case VK_ERROR_FULL_SCREEN_EXCLUSIVE_MODE_LOST_EXT:
|
||||
default:
|
||||
throw std::runtime_error("Failed to present image: " + TranslateVulkanError(m_swapchain.GetLastErrorCode()));
|
||||
}
|
||||
}
|
||||
|
||||
bool VkRenderWindow::CreateSwapchain(Vk::Surface& surface, const Vector2ui& size)
|
||||
{
|
||||
assert(m_device);
|
||||
if (!SetupSwapchain(m_device->GetPhysicalDeviceInfo(), surface, size))
|
||||
{
|
||||
NazaraError("Failed to create swapchain");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (m_depthStencilFormat != VK_FORMAT_MAX_ENUM && !SetupDepthBuffer(size))
|
||||
{
|
||||
NazaraError("Failed to create depth buffer");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!SetupFrameBuffers(size))
|
||||
{
|
||||
NazaraError("failed to create framebuffers");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool VkRenderWindow::SetupDepthBuffer(const Vector2ui& size)
|
||||
|
|
@ -312,6 +366,38 @@ namespace Nz
|
|||
return true;
|
||||
}
|
||||
|
||||
bool VkRenderWindow::SetupFrameBuffers(const Vector2ui& size)
|
||||
{
|
||||
UInt32 imageCount = m_swapchain.GetBufferCount();
|
||||
|
||||
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,
|
||||
nullptr,
|
||||
0,
|
||||
m_renderPass->GetRenderPass(),
|
||||
(attachments[1] != VK_NULL_HANDLE) ? 2U : 1U,
|
||||
attachments.data(),
|
||||
size.x,
|
||||
size.y,
|
||||
1U
|
||||
};
|
||||
|
||||
if (!framebuffers[i].Create(*m_device, frameBufferCreate))
|
||||
{
|
||||
NazaraError("Failed to create framebuffer for image #" + String::Number(i) + ": " + TranslateVulkanError(framebuffers[i].GetLastErrorCode()));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
m_framebuffer.emplace(framebuffers.data(), framebuffers.size());
|
||||
return true;
|
||||
}
|
||||
|
||||
bool VkRenderWindow::SetupRenderPass()
|
||||
{
|
||||
std::array<VkAttachmentDescription, 2> attachments = {
|
||||
|
|
@ -468,15 +554,31 @@ namespace Nz
|
|||
VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR,
|
||||
swapchainPresentMode,
|
||||
VK_TRUE,
|
||||
VK_NULL_HANDLE
|
||||
m_swapchain
|
||||
};
|
||||
|
||||
if (!m_swapchain.Create(*m_device, swapchainInfo))
|
||||
Vk::Swapchain newSwapchain;
|
||||
if (!newSwapchain.Create(*m_device, swapchainInfo))
|
||||
{
|
||||
NazaraError("Failed to create swapchain");
|
||||
NazaraError("failed to create swapchain: " + TranslateVulkanError(newSwapchain.GetLastErrorCode()));
|
||||
return false;
|
||||
}
|
||||
|
||||
m_swapchain = std::move(newSwapchain);
|
||||
m_swapchainSize = size;
|
||||
|
||||
// Framebuffers
|
||||
m_inflightFences.resize(imageCount);
|
||||
|
||||
if (m_concurrentImageData.size() != imageCount)
|
||||
{
|
||||
m_concurrentImageData.clear();
|
||||
m_concurrentImageData.reserve(imageCount);
|
||||
|
||||
for (std::size_t i = 0; i < imageCount; ++i)
|
||||
m_concurrentImageData.emplace_back(*this);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -25,9 +25,9 @@ namespace Nz
|
|||
return std::make_unique<VulkanSurface>();
|
||||
}
|
||||
|
||||
std::unique_ptr<RenderWindowImpl> VulkanRenderer::CreateRenderWindowImpl()
|
||||
std::unique_ptr<RenderWindowImpl> VulkanRenderer::CreateRenderWindowImpl(RenderWindow& owner)
|
||||
{
|
||||
return std::make_unique<VkRenderWindow>();
|
||||
return std::make_unique<VkRenderWindow>(owner);
|
||||
}
|
||||
|
||||
std::shared_ptr<RenderDevice> VulkanRenderer::InstanciateRenderDevice(std::size_t deviceIndex)
|
||||
|
|
|
|||
Loading…
Reference in New Issue