VulkanRenderer: Handle window resize
This commit is contained in:
parent
982d28cace
commit
cbdac32f5f
|
|
@ -26,6 +26,7 @@ TOOL.Files = {
|
||||||
|
|
||||||
TOOL.Libraries = {
|
TOOL.Libraries = {
|
||||||
"NazaraCore",
|
"NazaraCore",
|
||||||
|
"NazaraPlatform",
|
||||||
"NazaraRenderer",
|
"NazaraRenderer",
|
||||||
"NazaraShader",
|
"NazaraShader",
|
||||||
"NazaraUtility"
|
"NazaraUtility"
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,7 @@ TOOL.Files = {
|
||||||
|
|
||||||
TOOL.Libraries = {
|
TOOL.Libraries = {
|
||||||
"NazaraCore",
|
"NazaraCore",
|
||||||
|
"NazaraPlatform",
|
||||||
"NazaraRenderer",
|
"NazaraRenderer",
|
||||||
"NazaraShader",
|
"NazaraShader",
|
||||||
"NazaraUtility"
|
"NazaraUtility"
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@ int main()
|
||||||
Nz::Initializer<Nz::Renderer> loader;
|
Nz::Initializer<Nz::Renderer> loader;
|
||||||
if (!loader)
|
if (!loader)
|
||||||
{
|
{
|
||||||
std::cout << "Failed to initialize Vulkan" << std::endl;;
|
std::cout << "Failed to initialize Vulkan" << std::endl;
|
||||||
return __LINE__;
|
return __LINE__;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -172,33 +172,41 @@ int main()
|
||||||
Nz::AbstractBuffer* indexBufferImpl = renderBufferIB->GetHardwareBuffer(renderDevice);
|
Nz::AbstractBuffer* indexBufferImpl = renderBufferIB->GetHardwareBuffer(renderDevice);
|
||||||
Nz::AbstractBuffer* vertexBufferImpl = renderBufferVB->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];
|
drawCommandBuffer = commandPool->BuildCommandBuffer([&](Nz::CommandBufferBuilder& builder)
|
||||||
clearValues[0].color = Nz::Color::Black;
|
|
||||||
clearValues[1].depth = 1.f;
|
|
||||||
clearValues[1].stencil = 0;
|
|
||||||
|
|
||||||
builder.BeginDebugRegion("Main window rendering", Nz::Color::Green);
|
|
||||||
{
|
{
|
||||||
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.BeginRenderPass(windowImpl->GetFramebuffer(), windowImpl->GetRenderPass(), renderRect, { clearValues[0], clearValues[1] });
|
||||||
builder.BindPipeline(*pipeline);
|
{
|
||||||
builder.BindVertexBuffer(0, vertexBufferImpl);
|
builder.BindIndexBuffer(indexBufferImpl);
|
||||||
builder.BindShaderBinding(*shaderBinding);
|
builder.BindPipeline(*pipeline);
|
||||||
|
builder.BindVertexBuffer(0, vertexBufferImpl);
|
||||||
|
builder.BindShaderBinding(*shaderBinding);
|
||||||
|
|
||||||
builder.SetScissor(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.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();
|
Nz::Vector3f viewerPos = Nz::Vector3f::Zero();
|
||||||
|
|
||||||
|
|
@ -210,6 +218,7 @@ int main()
|
||||||
Nz::Clock updateClock;
|
Nz::Clock updateClock;
|
||||||
Nz::Clock secondClock;
|
Nz::Clock secondClock;
|
||||||
unsigned int fps = 0;
|
unsigned int fps = 0;
|
||||||
|
bool uboUpdate = true;
|
||||||
|
|
||||||
Nz::Mouse::SetRelativeMouseMode(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);
|
camAngles.pitch = Nz::Clamp(camAngles.pitch + event.mouseMove.deltaY*sensitivity, -89.f, 89.f);
|
||||||
|
|
||||||
camQuat = camAngles;
|
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;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -268,30 +289,44 @@ int main()
|
||||||
// Contrôle (Gauche ou droite) pour descendre dans l'espace global, etc...
|
// 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))
|
if (Nz::Keyboard::IsKeyPressed(Nz::Keyboard::VKey::LControl) || Nz::Keyboard::IsKeyPressed(Nz::Keyboard::VKey::RControl))
|
||||||
viewerPos += Nz::Vector3f::Down() * cameraSpeed;
|
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);
|
ubo.viewMatrix = Nz::Matrix4f::ViewMatrix(viewerPos, camAngles);
|
||||||
|
|
||||||
auto& allocation = renderImage.GetUploadPool().Allocate(uniformSize);
|
if (uboUpdate)
|
||||||
|
|
||||||
std::memcpy(allocation.mappedPtr, &ubo, sizeof(ubo));
|
|
||||||
|
|
||||||
renderImage.Execute([&](Nz::CommandBufferBuilder& builder)
|
|
||||||
{
|
{
|
||||||
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.BeginDebugRegion("UBO Update", Nz::Color::Yellow);
|
||||||
builder.CopyBuffer(allocation, uniformBuffer.get());
|
{
|
||||||
builder.PostTransferBarrier();
|
builder.PreTransferBarrier();
|
||||||
}
|
builder.CopyBuffer(allocation, uniformBuffer.get());
|
||||||
builder.EndDebugRegion();
|
builder.PostTransferBarrier();
|
||||||
}, Nz::QueueType::Transfer);
|
}
|
||||||
|
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é
|
// On incrémente le compteur de FPS improvisé
|
||||||
fps++;
|
fps++;
|
||||||
|
|
|
||||||
|
|
@ -20,15 +20,17 @@
|
||||||
|
|
||||||
namespace Nz
|
namespace Nz
|
||||||
{
|
{
|
||||||
|
class RenderWindow;
|
||||||
|
|
||||||
class NAZARA_OPENGLRENDERER_API OpenGLRenderWindow : public RenderWindowImpl
|
class NAZARA_OPENGLRENDERER_API OpenGLRenderWindow : public RenderWindowImpl
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
OpenGLRenderWindow();
|
OpenGLRenderWindow(RenderWindow& owner);
|
||||||
~OpenGLRenderWindow() = default;
|
~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;
|
std::unique_ptr<CommandPool> CreateCommandPool(QueueType queueType) override;
|
||||||
|
|
||||||
inline GL::Context& GetContext();
|
inline GL::Context& GetContext();
|
||||||
|
|
@ -46,6 +48,7 @@ namespace Nz
|
||||||
std::unique_ptr<GL::Context> m_context;
|
std::unique_ptr<GL::Context> m_context;
|
||||||
OpenGLRenderPass m_renderPass;
|
OpenGLRenderPass m_renderPass;
|
||||||
OpenGLWindowFramebuffer m_framebuffer;
|
OpenGLWindowFramebuffer m_framebuffer;
|
||||||
|
RenderWindow& m_owner;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,7 @@ namespace Nz
|
||||||
~OpenGLRenderer();
|
~OpenGLRenderer();
|
||||||
|
|
||||||
std::unique_ptr<RenderSurface> CreateRenderSurfaceImpl() override;
|
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;
|
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
|
class NAZARA_RENDERER_API RenderImage
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
RenderImage() = default;
|
|
||||||
virtual ~RenderImage();
|
virtual ~RenderImage();
|
||||||
|
|
||||||
virtual void Execute(const std::function<void(CommandBufferBuilder& builder)>& callback, QueueTypeFlags queueTypeFlags) = 0;
|
virtual void Execute(const std::function<void(CommandBufferBuilder& builder)>& callback, QueueTypeFlags queueTypeFlags) = 0;
|
||||||
|
|
@ -33,6 +32,7 @@ namespace Nz
|
||||||
virtual void Present() = 0;
|
virtual void Present() = 0;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
RenderImage() = default;
|
||||||
RenderImage(const RenderImage&) = delete;
|
RenderImage(const RenderImage&) = delete;
|
||||||
RenderImage(RenderImage&&) = default;
|
RenderImage(RenderImage&&) = default;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -36,8 +36,9 @@ namespace Nz
|
||||||
|
|
||||||
void EnableVerticalSync(bool enabled);
|
void EnableVerticalSync(bool enabled);
|
||||||
|
|
||||||
inline RenderWindowImpl *GetImpl();
|
inline RenderWindowImpl* GetImpl();
|
||||||
std::shared_ptr<RenderDevice> GetRenderDevice();
|
std::shared_ptr<RenderDevice> GetRenderDevice();
|
||||||
|
inline RenderSurface* GetSurface();
|
||||||
|
|
||||||
inline bool IsValid() const;
|
inline bool IsValid() const;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -46,11 +46,16 @@ namespace Nz
|
||||||
return Window::Create(handle);
|
return Window::Create(handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline RenderWindowImpl* Nz::RenderWindow::GetImpl()
|
inline RenderWindowImpl* RenderWindow::GetImpl()
|
||||||
{
|
{
|
||||||
return m_impl.get();
|
return m_impl.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline RenderSurface* RenderWindow::GetSurface()
|
||||||
|
{
|
||||||
|
return m_surface.get();
|
||||||
|
}
|
||||||
|
|
||||||
inline bool RenderWindow::IsValid() const
|
inline bool RenderWindow::IsValid() const
|
||||||
{
|
{
|
||||||
return m_impl != nullptr;
|
return m_impl != nullptr;
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,7 @@
|
||||||
#include <Nazara/Platform/WindowHandle.hpp>
|
#include <Nazara/Platform/WindowHandle.hpp>
|
||||||
#include <Nazara/Renderer/Config.hpp>
|
#include <Nazara/Renderer/Config.hpp>
|
||||||
#include <Nazara/Renderer/RenderDevice.hpp>
|
#include <Nazara/Renderer/RenderDevice.hpp>
|
||||||
|
#include <Nazara/Renderer/RenderFrame.hpp>
|
||||||
#include <Nazara/Renderer/RenderWindowParameters.hpp>
|
#include <Nazara/Renderer/RenderWindowParameters.hpp>
|
||||||
|
|
||||||
namespace Nz
|
namespace Nz
|
||||||
|
|
@ -19,7 +20,6 @@ namespace Nz
|
||||||
class CommandPool;
|
class CommandPool;
|
||||||
class Framebuffer;
|
class Framebuffer;
|
||||||
class RendererImpl;
|
class RendererImpl;
|
||||||
class RenderImage;
|
|
||||||
class RenderPass;
|
class RenderPass;
|
||||||
class RenderSurface;
|
class RenderSurface;
|
||||||
|
|
||||||
|
|
@ -29,9 +29,9 @@ namespace Nz
|
||||||
RenderWindowImpl() = default;
|
RenderWindowImpl() = default;
|
||||||
virtual ~RenderWindowImpl();
|
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 std::unique_ptr<CommandPool> CreateCommandPool(QueueType queueType) = 0;
|
||||||
|
|
||||||
virtual const Framebuffer& GetFramebuffer() const = 0;
|
virtual const Framebuffer& GetFramebuffer() const = 0;
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,7 @@ namespace Nz
|
||||||
class RendererImpl;
|
class RendererImpl;
|
||||||
class RenderDevice;
|
class RenderDevice;
|
||||||
class RenderSurface;
|
class RenderSurface;
|
||||||
|
class RenderWindow;
|
||||||
class RenderWindowImpl;
|
class RenderWindowImpl;
|
||||||
|
|
||||||
using CreateRendererImplFunc = RendererImpl*(*)();
|
using CreateRendererImplFunc = RendererImpl*(*)();
|
||||||
|
|
@ -34,7 +35,7 @@ namespace Nz
|
||||||
virtual ~RendererImpl();
|
virtual ~RendererImpl();
|
||||||
|
|
||||||
virtual std::unique_ptr<RenderSurface> CreateRenderSurfaceImpl() = 0;
|
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;
|
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
|
class NAZARA_VULKANRENDERER_API VkRenderWindow : public VkRenderTarget, public RenderWindowImpl
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
VkRenderWindow();
|
VkRenderWindow(RenderWindow& owner);
|
||||||
VkRenderWindow(const VkRenderWindow&) = delete;
|
VkRenderWindow(const VkRenderWindow&) = delete;
|
||||||
VkRenderWindow(VkRenderWindow&&) = delete; ///TODO
|
VkRenderWindow(VkRenderWindow&&) = delete; ///TODO
|
||||||
~VkRenderWindow();
|
~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;
|
std::unique_ptr<CommandPool> CreateCommandPool(QueueType queueType) override;
|
||||||
|
|
||||||
inline const VulkanMultipleFramebuffer& GetFramebuffer() const override;
|
inline const VulkanMultipleFramebuffer& GetFramebuffer() const override;
|
||||||
inline VulkanDevice& GetDevice();
|
inline VulkanDevice& GetDevice();
|
||||||
inline const VulkanDevice& GetDevice() const;
|
inline const VulkanDevice& GetDevice() const;
|
||||||
inline Vk::QueueHandle& GetGraphicsQueue();
|
inline Vk::QueueHandle& GetGraphicsQueue();
|
||||||
const VulkanRenderPass& GetRenderPass() const override;
|
inline const VulkanRenderPass& GetRenderPass() const override;
|
||||||
inline const Vk::Swapchain& GetSwapchain() const;
|
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);
|
void Present(UInt32 imageIndex, VkSemaphore waitSemaphore = VK_NULL_HANDLE);
|
||||||
|
|
||||||
|
|
@ -62,17 +63,16 @@ namespace Nz
|
||||||
VkRenderWindow& operator=(VkRenderWindow&&) = delete; ///TODO
|
VkRenderWindow& operator=(VkRenderWindow&&) = delete; ///TODO
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
bool CreateSwapchain(Vk::Surface& surface, const Vector2ui& size);
|
||||||
bool SetupDepthBuffer(const Vector2ui& size);
|
bool SetupDepthBuffer(const Vector2ui& size);
|
||||||
|
bool SetupFrameBuffers(const Vector2ui& size);
|
||||||
bool SetupRenderPass();
|
bool SetupRenderPass();
|
||||||
bool SetupSwapchain(const Vk::PhysicalDevice& deviceInfo, Vk::Surface& surface, const Vector2ui& size);
|
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<VulkanMultipleFramebuffer> m_framebuffer;
|
||||||
std::optional<VulkanRenderPass> m_renderPass;
|
std::optional<VulkanRenderPass> m_renderPass;
|
||||||
std::shared_ptr<VulkanDevice> m_device;
|
std::shared_ptr<VulkanDevice> m_device;
|
||||||
|
std::size_t m_currentFrame;
|
||||||
std::vector<Vk::Fence*> m_inflightFences;
|
std::vector<Vk::Fence*> m_inflightFences;
|
||||||
std::vector<VulkanRenderImage> m_concurrentImageData;
|
std::vector<VulkanRenderImage> m_concurrentImageData;
|
||||||
Vk::DeviceMemory m_depthBufferMemory;
|
Vk::DeviceMemory m_depthBufferMemory;
|
||||||
|
|
@ -82,6 +82,12 @@ namespace Nz
|
||||||
Vk::QueueHandle m_presentQueue;
|
Vk::QueueHandle m_presentQueue;
|
||||||
Vk::QueueHandle m_transferQueue;
|
Vk::QueueHandle m_transferQueue;
|
||||||
Vk::Swapchain m_swapchain;
|
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;
|
return m_graphicsQueue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline const VulkanRenderPass& VkRenderWindow::GetRenderPass() const
|
||||||
|
{
|
||||||
|
return *m_renderPass;
|
||||||
|
}
|
||||||
|
|
||||||
inline const Vk::Swapchain& VkRenderWindow::GetSwapchain() const
|
inline const Vk::Swapchain& VkRenderWindow::GetSwapchain() const
|
||||||
{
|
{
|
||||||
return m_swapchain;
|
return m_swapchain;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline std::shared_ptr<RenderDevice> Nz::VkRenderWindow::GetRenderDevice()
|
inline std::shared_ptr<RenderDevice> VkRenderWindow::GetRenderDevice()
|
||||||
{
|
{
|
||||||
return m_device;
|
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>
|
#include <Nazara/VulkanRenderer/DebugOff.hpp>
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,7 @@ namespace Nz
|
||||||
~VulkanRenderer();
|
~VulkanRenderer();
|
||||||
|
|
||||||
std::unique_ptr<RenderSurface> CreateRenderSurfaceImpl() override;
|
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;
|
std::shared_ptr<RenderDevice> InstanciateRenderDevice(std::size_t deviceIndex) override;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -38,7 +38,7 @@ namespace Nz
|
||||||
inline bool IsSupported() const;
|
inline bool IsSupported() const;
|
||||||
|
|
||||||
Swapchain& operator=(const Swapchain&) = delete;
|
Swapchain& operator=(const Swapchain&) = delete;
|
||||||
Swapchain& operator=(Swapchain&&) = delete;
|
Swapchain& operator=(Swapchain&&) = default;
|
||||||
|
|
||||||
struct Buffer
|
struct Buffer
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -7,22 +7,24 @@
|
||||||
#include <Nazara/OpenGLRenderer/OpenGLCommandPool.hpp>
|
#include <Nazara/OpenGLRenderer/OpenGLCommandPool.hpp>
|
||||||
#include <Nazara/OpenGLRenderer/OpenGLRenderer.hpp>
|
#include <Nazara/OpenGLRenderer/OpenGLRenderer.hpp>
|
||||||
#include <Nazara/Renderer/CommandPool.hpp>
|
#include <Nazara/Renderer/CommandPool.hpp>
|
||||||
|
#include <Nazara/Renderer/RenderWindow.hpp>
|
||||||
#include <Nazara/OpenGLRenderer/Debug.hpp>
|
#include <Nazara/OpenGLRenderer/Debug.hpp>
|
||||||
|
|
||||||
namespace Nz
|
namespace Nz
|
||||||
{
|
{
|
||||||
OpenGLRenderWindow::OpenGLRenderWindow() :
|
OpenGLRenderWindow::OpenGLRenderWindow(RenderWindow& owner) :
|
||||||
m_currentFrame(0),
|
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);
|
DummySurface* dummySurface = static_cast<DummySurface*>(surface);
|
||||||
OpenGLRenderer* glRenderer = static_cast<OpenGLRenderer*>(renderer);
|
OpenGLRenderer* glRenderer = static_cast<OpenGLRenderer*>(renderer);
|
||||||
|
|
|
||||||
|
|
@ -31,9 +31,9 @@ namespace Nz
|
||||||
return std::make_unique<DummySurface>();
|
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)
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto impl = rendererImpl->CreateRenderWindowImpl();
|
auto impl = rendererImpl->CreateRenderWindowImpl(*this);
|
||||||
if (!impl->Create(rendererImpl, surface.get(), GetSize(), m_parameters))
|
if (!impl->Create(rendererImpl, surface.get(), m_parameters))
|
||||||
{
|
{
|
||||||
NazaraError("Failed to create render window implementation: " + Error::GetLastError());
|
NazaraError("Failed to create render window implementation: " + Error::GetLastError());
|
||||||
return false;
|
return false;
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@
|
||||||
#include <Nazara/Core/ErrorFlags.hpp>
|
#include <Nazara/Core/ErrorFlags.hpp>
|
||||||
#include <Nazara/Core/StackArray.hpp>
|
#include <Nazara/Core/StackArray.hpp>
|
||||||
#include <Nazara/Math/Vector2.hpp>
|
#include <Nazara/Math/Vector2.hpp>
|
||||||
|
#include <Nazara/Renderer/RenderWindow.hpp>
|
||||||
#include <Nazara/Utility/PixelFormat.hpp>
|
#include <Nazara/Utility/PixelFormat.hpp>
|
||||||
#include <Nazara/VulkanRenderer/Vulkan.hpp>
|
#include <Nazara/VulkanRenderer/Vulkan.hpp>
|
||||||
#include <Nazara/VulkanRenderer/VulkanCommandPool.hpp>
|
#include <Nazara/VulkanRenderer/VulkanCommandPool.hpp>
|
||||||
|
|
@ -18,9 +19,11 @@
|
||||||
|
|
||||||
namespace Nz
|
namespace Nz
|
||||||
{
|
{
|
||||||
VkRenderWindow::VkRenderWindow() :
|
VkRenderWindow::VkRenderWindow(RenderWindow& owner) :
|
||||||
m_currentFrame(0),
|
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();
|
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];
|
VulkanRenderImage& currentFrame = m_concurrentImageData[m_currentFrame];
|
||||||
Vk::Fence& inFlightFence = currentFrame.GetInFlightFence();
|
Vk::Fence& inFlightFence = currentFrame.GetInFlightFence();
|
||||||
|
|
||||||
|
|
@ -44,8 +65,33 @@ namespace Nz
|
||||||
inFlightFence.Wait();
|
inFlightFence.Wait();
|
||||||
|
|
||||||
UInt32 imageIndex;
|
UInt32 imageIndex;
|
||||||
if (!m_swapchain.AcquireNextImage(std::numeric_limits<UInt64>::max(), currentFrame.GetImageAvailableSemaphore(), VK_NULL_HANDLE, &imageIndex))
|
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()));
|
|
||||||
|
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])
|
if (m_inflightFences[imageIndex])
|
||||||
m_inflightFences[imageIndex]->Wait();
|
m_inflightFences[imageIndex]->Wait();
|
||||||
|
|
@ -55,10 +101,10 @@ namespace Nz
|
||||||
|
|
||||||
currentFrame.Reset(imageIndex);
|
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];
|
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())
|
if (!SetupRenderPass())
|
||||||
{
|
{
|
||||||
NazaraError("Failed to create render pass");
|
NazaraError("Failed to create render pass");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
UInt32 imageCount = m_swapchain.GetBufferCount();
|
if (!CreateSwapchain(vulkanSurface, m_owner.GetSize()))
|
||||||
|
|
||||||
// Framebuffers
|
|
||||||
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 };
|
NazaraError("failed to create swapchain");
|
||||||
|
return false;
|
||||||
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());
|
|
||||||
|
|
||||||
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();
|
m_clock.Restart();
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
@ -237,9 +240,60 @@ namespace Nz
|
||||||
return std::make_unique<VulkanCommandPool>(*m_device, queueFamilyIndex);
|
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)
|
bool VkRenderWindow::SetupDepthBuffer(const Vector2ui& size)
|
||||||
|
|
@ -312,6 +366,38 @@ namespace Nz
|
||||||
return true;
|
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()
|
bool VkRenderWindow::SetupRenderPass()
|
||||||
{
|
{
|
||||||
std::array<VkAttachmentDescription, 2> attachments = {
|
std::array<VkAttachmentDescription, 2> attachments = {
|
||||||
|
|
@ -468,15 +554,31 @@ namespace Nz
|
||||||
VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR,
|
VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR,
|
||||||
swapchainPresentMode,
|
swapchainPresentMode,
|
||||||
VK_TRUE,
|
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;
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -25,9 +25,9 @@ namespace Nz
|
||||||
return std::make_unique<VulkanSurface>();
|
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)
|
std::shared_ptr<RenderDevice> VulkanRenderer::InstanciateRenderDevice(std::size_t deviceIndex)
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue