Graphics: Rework RenderTargets

- RenderTarget have been moved to the Graphics module and are now lightweight objects between the target of rendering (swapchain or texture)
- RenderTexture no longer require a blit between the framegraph texture and the target texture (the target texture is now directly rendered onto using a new feature of the framegraph)
- ForwardFramePipeline viewers are now properly ordered by render order
This commit is contained in:
SirLynix 2023-11-20 23:00:06 +01:00
parent d06f9bda89
commit 938ba09d45
41 changed files with 445 additions and 254 deletions

View File

@ -1037,7 +1037,7 @@ int main(int argc, char* argv[])
builder.Draw(3);
});
graph.MarkAsFinalOutput(toneMappingOutput);
graph.AddBackbufferOutput(toneMappingOutput);
return graph.Bake();
}();

View File

@ -61,7 +61,7 @@ int main(int argc, char* argv[])
Nz::Vector2ui windowSize = window.GetSize();
Nz::Camera camera(&windowSwapchain);
Nz::Camera camera(std::make_shared<Nz::RenderWindow>(windowSwapchain));
//camera.UpdateClearColor(Nz::Color::Gray);
Nz::ViewerInstance& viewerInstance = camera.GetViewerInstance();

View File

@ -44,7 +44,7 @@ int main(int argc, char* argv[])
entt::handle viewer = world.CreateEntity();
{
viewer.emplace<Nz::NodeComponent>();
auto& cameraComponent = viewer.emplace<Nz::CameraComponent>(&windowSwapchain, Nz::ProjectionType::Orthographic);
auto& cameraComponent = viewer.emplace<Nz::CameraComponent>(std::make_shared<Nz::RenderWindow>(windowSwapchain), Nz::ProjectionType::Orthographic);
cameraComponent.UpdateRenderMask(1);
cameraComponent.UpdateClearColor(Nz::Color(0.5f, 0.5f, 0.5f));
}

View File

@ -96,7 +96,7 @@ int main(int argc, char* argv[])
entt::handle viewer = world.CreateEntity();
{
viewer.emplace<Nz::NodeComponent>();
auto& cameraComponent = viewer.emplace<Nz::CameraComponent>(&windowSwapchain);
auto& cameraComponent = viewer.emplace<Nz::CameraComponent>(std::make_shared<Nz::RenderWindow>(windowSwapchain));
cameraComponent.UpdateRenderMask(1);
cameraComponent.UpdateClearColor(Nz::Color(0.5f, 0.5f, 0.5f));
}

View File

@ -348,7 +348,7 @@ int main(int argc, char* argv[])
{
cameraEntity.emplace<Nz::NodeComponent>();
auto& cameraComponent = cameraEntity.emplace<Nz::CameraComponent>(&windowSwapchain, Nz::ProjectionType::Perspective);
auto& cameraComponent = cameraEntity.emplace<Nz::CameraComponent>(std::make_shared<Nz::RenderWindow>(windowSwapchain), Nz::ProjectionType::Perspective);
cameraComponent.UpdateFOV(70.f);
cameraComponent.UpdateClearColor(Nz::Color::sRGBToLinear(Nz::Color(0.46f, 0.48f, 0.84f, 1.f)));
}

View File

@ -105,7 +105,7 @@ int main(int argc, char* argv[])
cameraNode.SetPosition(Nz::Vector3f::Up() * 2.f + Nz::Vector3f::Backward());
//cameraNode.SetParent(playerRotNode);
auto& cameraComponent = playerCamera.emplace<Nz::CameraComponent>(&windowSwapchain);
auto& cameraComponent = playerCamera.emplace<Nz::CameraComponent>(std::make_shared<Nz::RenderWindow>(windowSwapchain));
cameraComponent.UpdateZNear(0.2f);
cameraComponent.UpdateZFar(10000.f);
cameraComponent.UpdateRenderMask(1);
@ -412,26 +412,31 @@ int main(int argc, char* argv[])
}
}
Nz::TextureInfo screenTextureInfo = {
.pixelFormat = Nz::PixelFormat::RGBA8,
.type = Nz::ImageType::E2D,
.levelCount = 1,
.height = 360,
.width = 480
};
std::shared_ptr<Nz::Texture> screenTexture;
{
Nz::TextureInfo screenTextureInfo = {
.pixelFormat = Nz::PixelFormat::RGBA8,
.type = Nz::ImageType::E2D,
.usageFlags = Nz::TextureUsage::ColorAttachment | Nz::TextureUsage::ShaderSampling | Nz::TextureUsage::TransferDestination,
.levelCount = 1,
.height = 360,
.width = 480
};
std::shared_ptr<Nz::Texture> screenTexture = device->InstantiateTexture(screenTextureInfo);
std::size_t size = Nz::PixelFormatInfo::ComputeSize(screenTextureInfo.pixelFormat, screenTextureInfo.width, screenTextureInfo.height, screenTextureInfo.depth);
Nz::RenderTexture renderTexture(screenTexture);
std::vector<std::uint8_t> defaultScreen(size, 0xFF);
screenTexture = device->InstantiateTexture(screenTextureInfo, defaultScreen.data(), false);
}
entt::handle tvCameraEntity = world.CreateEntity();
{
auto& cameraNode = tvCameraEntity.emplace<Nz::NodeComponent>();
cameraNode.SetParentJoint(bobEntity, "Head");
cameraNode.SetRotation(Nz::EulerAnglesf(-30.f, 180.f, 0.f));
//cameraNode.SetParent(playerCamera);
//cameraNode.SetParentJoint(bobEntity, "Head");
//cameraNode.SetRotation(Nz::EulerAnglesf(-30.f, 180.f, 0.f));
cameraNode.SetParent(playerCamera);
auto& cameraComponent = tvCameraEntity.emplace<Nz::CameraComponent>(&renderTexture);
auto& cameraComponent = tvCameraEntity.emplace<Nz::CameraComponent>(std::make_shared<Nz::RenderTexture>(screenTexture));
cameraComponent.UpdateZNear(0.2f);
cameraComponent.UpdateZFar(1000.f);
cameraComponent.UpdateRenderMask(1);

View File

@ -26,7 +26,7 @@ int main(int argc, char* argv[])
{
cameraEntity.emplace<Nz::NodeComponent>();
auto& cameraComponent = cameraEntity.emplace<Nz::CameraComponent>(&windowSwapchain, Nz::ProjectionType::Orthographic);
auto& cameraComponent = cameraEntity.emplace<Nz::CameraComponent>(std::make_shared<Nz::RenderWindow>(windowSwapchain), Nz::ProjectionType::Orthographic);
cameraComponent.UpdateClearColor(Nz::Color(0.46f, 0.48f, 0.84f, 1.f));
}

View File

@ -27,7 +27,7 @@ int main(int argc, char* argv[])
{
cameraEntity.emplace<Nz::NodeComponent>();
auto& cameraComponent = cameraEntity.emplace<Nz::CameraComponent>(&windowSwapchain, Nz::ProjectionType::Orthographic);
auto& cameraComponent = cameraEntity.emplace<Nz::CameraComponent>(std::make_shared<Nz::RenderWindow>(windowSwapchain), Nz::ProjectionType::Orthographic);
cameraComponent.UpdateClearColor(Nz::Color(0.46f, 0.48f, 0.84f, 1.f));
}

View File

@ -105,7 +105,7 @@ int main(int argc, char* argv[])
{
viewer2D.emplace<Nz::NodeComponent>();
auto& cameraComponent = viewer2D.emplace<Nz::CameraComponent>(&windowSwapchain, Nz::ProjectionType::Orthographic);
auto& cameraComponent = viewer2D.emplace<Nz::CameraComponent>(std::make_shared<Nz::RenderWindow>(windowSwapchain), Nz::ProjectionType::Orthographic);
cameraComponent.UpdateClearColor(Nz::Color(0.46f, 0.48f, 0.84f, 1.f));
}

View File

@ -80,6 +80,9 @@
#include <Nazara/Graphics/RenderQueueRegistry.hpp>
#include <Nazara/Graphics/RenderSpriteChain.hpp>
#include <Nazara/Graphics/RenderSubmesh.hpp>
#include <Nazara/Graphics/RenderTarget.hpp>
#include <Nazara/Graphics/RenderTexture.hpp>
#include <Nazara/Graphics/RenderWindow.hpp>
#include <Nazara/Graphics/ShaderReflection.hpp>
#include <Nazara/Graphics/ShadowViewer.hpp>
#include <Nazara/Graphics/SkeletonInstance.hpp>

View File

@ -10,10 +10,10 @@
#include <NazaraUtils/Prerequisites.hpp>
#include <Nazara/Graphics/Enums.hpp>
#include <Nazara/Graphics/PipelineViewer.hpp>
#include <Nazara/Graphics/RenderTarget.hpp>
#include <Nazara/Graphics/ViewerInstance.hpp>
#include <Nazara/Math/Rect.hpp>
#include <Nazara/Math/Vector2.hpp>
#include <Nazara/Renderer/RenderTarget.hpp>
namespace Nz
{
@ -22,8 +22,8 @@ namespace Nz
class NAZARA_GRAPHICS_API Camera : public PipelineViewer
{
public:
inline Camera(const RenderTarget* renderTarget, std::shared_ptr<PipelinePassList> pipelinePasses, ProjectionType projectionType = ProjectionType::Perspective);
Camera(const RenderTarget* renderTarget, ProjectionType projectionType = ProjectionType::Perspective);
inline Camera(std::shared_ptr<const RenderTarget> renderTarget, std::shared_ptr<PipelinePassList> pipelinePasses, ProjectionType projectionType = ProjectionType::Perspective);
Camera(std::shared_ptr<const RenderTarget> renderTarget, ProjectionType projectionType = ProjectionType::Perspective);
inline Camera(const Camera& camera);
inline Camera(Camera&& camera) noexcept;
~Camera() = default;
@ -53,7 +53,7 @@ namespace Nz
inline void UpdateRenderMask(UInt32 renderMask);
inline void UpdateRenderOrder(Int32 renderOrder);
inline void UpdateSize(const Vector2f& size);
void UpdateTarget(const RenderTarget* framebuffer);
void UpdateTarget(std::shared_ptr<const RenderTarget> renderTarget);
inline void UpdateTargetRegion(const Rectf& targetRegion);
inline void UpdateViewport(const Recti& viewport);
inline void UpdateZFar(float zFar);
@ -71,7 +71,7 @@ namespace Nz
NazaraSlot(RenderTarget, OnRenderTargetSizeChange, m_onRenderTargetSizeChange);
std::shared_ptr<PipelinePassList> m_framePipelinePasses;
const RenderTarget* m_renderTarget;
std::shared_ptr<const RenderTarget> m_renderTarget;
Color m_clearColor;
DegreeAnglef m_fov;
Int32 m_renderOrder;

View File

@ -7,9 +7,8 @@
namespace Nz
{
inline Camera::Camera(const RenderTarget* renderTarget, std::shared_ptr<PipelinePassList> pipelinePasses, ProjectionType projectionType) :
inline Camera::Camera(std::shared_ptr<const RenderTarget> renderTarget, std::shared_ptr<PipelinePassList> pipelinePasses, ProjectionType projectionType) :
m_framePipelinePasses(std::move(pipelinePasses)),
m_renderTarget(nullptr),
m_clearColor(Color::Black()),
m_fov(90.f),
m_renderOrder(0),
@ -21,12 +20,11 @@ namespace Nz
m_zFar((projectionType == ProjectionType::Perspective) ? 1000.f : 1.f),
m_zNear((projectionType == ProjectionType::Perspective) ? 1.f : -1.f)
{
UpdateTarget(renderTarget);
UpdateTarget(std::move(renderTarget));
}
inline Camera::Camera(const Camera& camera) :
m_framePipelinePasses(camera.m_framePipelinePasses),
m_renderTarget(nullptr),
m_clearColor(camera.m_clearColor),
m_fov(camera.m_fov),
m_renderOrder(camera.m_renderOrder),
@ -44,7 +42,6 @@ namespace Nz
inline Camera::Camera(Camera&& camera) noexcept :
m_framePipelinePasses(std::move(camera.m_framePipelinePasses)),
m_renderTarget(nullptr),
m_clearColor(camera.m_clearColor),
m_fov(camera.m_fov),
m_renderOrder(camera.m_renderOrder),
@ -57,7 +54,7 @@ namespace Nz
m_zFar(camera.m_zFar),
m_zNear(camera.m_zNear)
{
UpdateTarget(camera.m_renderTarget);
UpdateTarget(std::move(camera.m_renderTarget));
}
inline float Camera::GetAspectRatio() const

View File

@ -80,7 +80,7 @@ namespace Nz
ForwardFramePipeline& operator=(ForwardFramePipeline&&) = delete;
private:
BakedFrameGraph BuildFrameGraph(RenderFrame& renderFrame);
BakedFrameGraph BuildFrameGraph();
void RegisterMaterialInstance(MaterialInstance* materialPass);
void UnregisterMaterialInstance(MaterialInstance* material);

View File

@ -39,10 +39,11 @@ namespace Nz
inline std::size_t AddAttachmentCubeFace(std::size_t attachmentId, CubemapFace face);
inline std::size_t AddAttachmentProxy(std::string name, std::size_t attachmentId);
inline FramePass& AddPass(std::string name);
inline void AddBackbufferOutput(std::size_t attachmentIndex);
BakedFrameGraph Bake();
inline void MarkAsFinalOutput(std::size_t attachmentIndex);
inline void BindAttachmentToExternalTexture(std::size_t attachmentIndex, std::shared_ptr<Texture> texture);
FrameGraph& operator=(const FrameGraph&) = delete;
FrameGraph& operator=(FrameGraph&&) noexcept = default;
@ -139,9 +140,10 @@ namespace Nz
using AttachmentType = std::variant<FramePassAttachment, AttachmentProxy, AttachmentArray, AttachmentCube, AttachmentLayer>;
std::vector<std::size_t> m_finalOutputs;
std::vector<std::size_t> m_backbufferOutputs;
std::vector<FramePass> m_framePasses;
std::vector<AttachmentType> m_attachments;
std::unordered_map<std::size_t, std::shared_ptr<Texture>> m_externalTextures;
WorkData m_pending;
};
}

View File

@ -84,9 +84,14 @@ namespace Nz
return m_framePasses.emplace_back(*this, id, std::move(name));
}
inline void FrameGraph::MarkAsFinalOutput(std::size_t attachmentIndex)
inline void FrameGraph::AddBackbufferOutput(std::size_t attachmentIndex)
{
m_finalOutputs.push_back(attachmentIndex);
m_backbufferOutputs.push_back(attachmentIndex);
}
inline void FrameGraph::BindAttachmentToExternalTexture(std::size_t attachmentIndex, std::shared_ptr<Texture> texture)
{
m_externalTextures[attachmentIndex] = std::move(texture);
}
}

View File

@ -16,6 +16,8 @@
namespace Nz
{
class Texture;
struct FrameGraphTextureData
{
struct ViewData
@ -25,6 +27,7 @@ namespace Nz
};
std::optional<ViewData> viewData;
std::shared_ptr<Texture> externalTexture;
std::string name;
ImageType type;
PixelFormat format;

View File

@ -97,8 +97,8 @@ namespace Nz
struct Output
{
std::size_t attachmentId;
std::optional<Color> clearColor;
std::size_t attachmentId;
};
private:

View File

@ -1,32 +1,35 @@
// Copyright (C) 2023 Jérôme "Lynix" Leclercq (lynix680@gmail.com)
// This file is part of the "Nazara Engine - Renderer module"
// This file is part of the "Nazara Engine - Graphics module"
// For conditions of distribution and use, see copyright notice in Config.hpp
#pragma once
#ifndef NAZARA_RENDERER_RENDERTARGET_HPP
#define NAZARA_RENDERER_RENDERTARGET_HPP
#ifndef NAZARA_GRAPHICS_RENDERTARGET_HPP
#define NAZARA_GRAPHICS_RENDERTARGET_HPP
#include <NazaraUtils/Prerequisites.hpp>
#include <Nazara/Graphics/Config.hpp>
#include <Nazara/Math/Vector2.hpp>
#include <Nazara/Renderer/Config.hpp>
#include <NazaraUtils/Signal.hpp>
namespace Nz
{
class BakedFrameGraph;
class CommandBufferBuilder;
class Framebuffer;
class FrameGraph;
class RenderFrame;
class RenderPass;
class Texture;
class NAZARA_RENDERER_API RenderTarget
class NAZARA_GRAPHICS_API RenderTarget
{
public:
RenderTarget() = default;
virtual ~RenderTarget();
virtual void BlitTexture(RenderFrame& renderFrame, CommandBufferBuilder& builder, const Texture& texture) const = 0;
virtual void OnBuildGraph(FrameGraph& frameGraph, std::size_t attachmentIndex) const = 0;
virtual void OnRenderEnd(RenderFrame& renderFrame, const BakedFrameGraph& frameGraph, std::size_t finalAttachment) const = 0;
virtual const Vector2ui& GetSize() const = 0;
@ -35,6 +38,6 @@ namespace Nz
};
}
#include <Nazara/Renderer/RenderTarget.inl>
#include <Nazara/Graphics/RenderTarget.inl>
#endif // NAZARA_RENDERER_RENDERTARGET_HPP
#endif // NAZARA_GRAPHICS_RENDERTARGET_HPP

View File

@ -1,11 +1,11 @@
// Copyright (C) 2023 Jérôme "Lynix" Leclercq (lynix680@gmail.com)
// This file is part of the "Nazara Engine - Renderer module"
// This file is part of the "Nazara Engine - Graphics module"
// For conditions of distribution and use, see copyright notice in Config.hpp
#include <Nazara/Renderer/Debug.hpp>
#include <Nazara/Graphics/Debug.hpp>
namespace Nz
{
}
#include <Nazara/Renderer/DebugOff.hpp>
#include <Nazara/Graphics/DebugOff.hpp>

View File

@ -1,22 +1,22 @@
// Copyright (C) 2023 Jérôme "Lynix" Leclercq (lynix680@gmail.com)
// This file is part of the "Nazara Engine - Renderer module"
// This file is part of the "Nazara Engine - Graphics module"
// For conditions of distribution and use, see copyright notice in Config.hpp
#pragma once
#ifndef NAZARA_RENDERER_RENDERTEXTURE_HPP
#define NAZARA_RENDERER_RENDERTEXTURE_HPP
#ifndef NAZARA_GRAPHICS_RENDERTEXTURE_HPP
#define NAZARA_GRAPHICS_RENDERTEXTURE_HPP
#include <NazaraUtils/Prerequisites.hpp>
#include <Nazara/Renderer/Config.hpp>
#include <Nazara/Graphics/Config.hpp>
#include <Nazara/Graphics/RenderTarget.hpp>
#include <Nazara/Renderer/Enums.hpp>
#include <Nazara/Renderer/RenderTarget.hpp>
namespace Nz
{
class Texture;
class NAZARA_RENDERER_API RenderTexture : public RenderTarget
class NAZARA_GRAPHICS_API RenderTexture : public RenderTarget
{
public:
inline RenderTexture(std::shared_ptr<Texture> targetTexture);
@ -25,7 +25,8 @@ namespace Nz
RenderTexture(RenderTexture&&) = delete;
~RenderTexture() = default;
void BlitTexture(RenderFrame& renderFrame, CommandBufferBuilder& builder, const Texture& texture) const override;
void OnBuildGraph(FrameGraph& graph, std::size_t attachmentIndex) const override;
void OnRenderEnd(RenderFrame& renderFrame, const BakedFrameGraph& frameGraph, std::size_t finalAttachment) const override;
const Vector2ui& GetSize() const override;
@ -41,6 +42,6 @@ namespace Nz
};
}
#include <Nazara/Renderer/RenderTexture.inl>
#include <Nazara/Graphics/RenderTexture.inl>
#endif // NAZARA_RENDERER_RENDERTEXTURE_HPP
#endif // NAZARA_GRAPHICS_RENDERTEXTURE_HPP

View File

@ -1,9 +1,8 @@
// Copyright (C) 2023 Jérôme "Lynix" Leclercq (lynix680@gmail.com)
// This file is part of the "Nazara Engine - Renderer module"
// This file is part of the "Nazara Engine - Graphics module"
// For conditions of distribution and use, see copyright notice in Config.hpp
#include <Nazara/Renderer/RenderTexture.hpp>
#include <Nazara/Renderer/Debug.hpp>
#include <Nazara/Graphics/Debug.hpp>
namespace Nz
{
@ -13,4 +12,4 @@ namespace Nz
}
}
#include <Nazara/Renderer/DebugOff.hpp>
#include <Nazara/Graphics/DebugOff.hpp>

View File

@ -0,0 +1,50 @@
// Copyright (C) 2023 Jérôme "Lynix" Leclercq (lynix680@gmail.com)
// This file is part of the "Nazara Engine - Graphics module"
// For conditions of distribution and use, see copyright notice in Config.hpp
#pragma once
#ifndef NAZARA_GRAPHICS_RENDERWINDOW_HPP
#define NAZARA_GRAPHICS_RENDERWINDOW_HPP
#include <NazaraUtils/Prerequisites.hpp>
#include <Nazara/Graphics/Config.hpp>
#include <Nazara/Graphics/RenderTarget.hpp>
#include <Nazara/Renderer/WindowSwapchain.hpp>
namespace Nz
{
class FrameGraph;
class NAZARA_GRAPHICS_API RenderWindow : public RenderTarget
{
public:
inline RenderWindow(Swapchain& swapchain);
RenderWindow(WindowSwapchain& windowSwapchain);
RenderWindow(const RenderWindow&) = delete;
RenderWindow(RenderWindow&&) = delete;
~RenderWindow() = default;
void OnBuildGraph(FrameGraph& graph, std::size_t attachmentIndex) const override;
void OnRenderEnd(RenderFrame& renderFrame, const BakedFrameGraph& frameGraph, std::size_t attachmentId) const override;
const Vector2ui& GetSize() const override;
RenderWindow& operator=(const RenderWindow&) = delete;
RenderWindow& operator=(RenderWindow&&) = delete;
private:
void SetSwapchain(Swapchain* swapchain);
NazaraSlot(Swapchain, OnSwapchainResize, m_onSwapchainResize);
NazaraSlot(WindowSwapchain, OnSwapchainCreated, m_onSwapchainCreated);
NazaraSlot(WindowSwapchain, OnSwapchainDestroy, m_onSwapchainDestroy);
Swapchain* m_swapchain;
WindowSwapchain* m_windowSwapchain;
};
}
#include <Nazara/Graphics/RenderWindow.inl>
#endif // NAZARA_GRAPHICS_RENDERWINDOW_HPP

View File

@ -0,0 +1,16 @@
// Copyright (C) 2023 Jérôme "Lynix" Leclercq (lynix680@gmail.com)
// This file is part of the "Nazara Engine - Graphics module"
// For conditions of distribution and use, see copyright notice in Config.hpp
#include <Nazara/Graphics/Debug.hpp>
namespace Nz
{
inline RenderWindow::RenderWindow(Swapchain& swapchain) :
m_swapchain(&swapchain),
m_windowSwapchain(nullptr)
{
}
}
#include <Nazara/Graphics/DebugOff.hpp>

View File

@ -51,8 +51,6 @@
#include <Nazara/Renderer/RenderPipeline.hpp>
#include <Nazara/Renderer/RenderPipelineLayout.hpp>
#include <Nazara/Renderer/RenderStates.hpp>
#include <Nazara/Renderer/RenderTarget.hpp>
#include <Nazara/Renderer/RenderTexture.hpp>
#include <Nazara/Renderer/ShaderBinding.hpp>
#include <Nazara/Renderer/ShaderModule.hpp>
#include <Nazara/Renderer/Swapchain.hpp>

View File

@ -12,16 +12,17 @@
#include <Nazara/Renderer/Config.hpp>
#include <Nazara/Renderer/RenderFrame.hpp>
#include <Nazara/Renderer/RenderPass.hpp>
#include <Nazara/Renderer/RenderTarget.hpp>
#include <NazaraUtils/Signal.hpp>
#include <vector>
namespace Nz
{
class CommandPool;
class Framebuffer;
class RenderDevice;
class TransientResources;
class NAZARA_RENDERER_API Swapchain : public RenderTarget
class NAZARA_RENDERER_API Swapchain
{
public:
Swapchain() = default;
@ -29,14 +30,13 @@ namespace Nz
virtual RenderFrame AcquireFrame() = 0;
void BlitTexture(RenderFrame& renderFrame, CommandBufferBuilder& builder, const Texture& texture) const override;
virtual std::shared_ptr<CommandPool> CreateCommandPool(QueueType queueType) = 0;
virtual const Framebuffer& GetFramebuffer(std::size_t i) const = 0;
virtual std::size_t GetFramebufferCount() const = 0;
virtual PresentMode GetPresentMode() const = 0;
virtual const RenderPass& GetRenderPass() const = 0;
virtual const Vector2ui& GetSize() const = 0;
virtual PresentModeFlags GetSupportedPresentModes() const = 0;
virtual void NotifyResize(const Vector2ui& newSize) = 0;
@ -45,6 +45,8 @@ namespace Nz
virtual TransientResources& Transient() = 0;
NazaraSignal(OnSwapchainResize, Swapchain* /*swapchain*/, const Vector2ui& /*newSize*/);
protected:
static void BuildRenderPass(PixelFormat colorFormat, PixelFormat depthFormat, std::vector<RenderPass::Attachment>& attachments, std::vector<RenderPass::SubpassDescription>& subpassDescriptions, std::vector<RenderPass::SubpassDependency>& subpassDependencies);
};

View File

@ -9,28 +9,26 @@
#include <NazaraUtils/Prerequisites.hpp>
#include <Nazara/Platform/WindowEventHandler.hpp>
#include <Nazara/Renderer/RenderTarget.hpp>
#include <Nazara/Renderer/Swapchain.hpp>
#include <Nazara/Renderer/SwapchainParameters.hpp>
#include <memory>
namespace Nz
{
class Framebuffer;
class RenderDevice;
class Window;
class NAZARA_RENDERER_API WindowSwapchain : public RenderTarget
class NAZARA_RENDERER_API WindowSwapchain
{
public:
WindowSwapchain(std::shared_ptr<RenderDevice> renderDevice, Window& window, SwapchainParameters parameters = SwapchainParameters());
WindowSwapchain(const WindowSwapchain&) = delete;
WindowSwapchain(WindowSwapchain&&) = delete;
inline ~WindowSwapchain();
~WindowSwapchain() = default;
inline RenderFrame AcquireFrame();
inline void BlitTexture(RenderFrame& renderFrame, CommandBufferBuilder& builder, const Texture& texture) const override;
inline bool DoesRenderOnlyIfFocused() const;
inline void EnableRenderOnlyIfFocused(bool enable = true);
@ -38,15 +36,18 @@ namespace Nz
inline const Framebuffer& GetFramebuffer(std::size_t i) const;
inline std::size_t GetFramebufferCount() const;
inline const RenderPass& GetRenderPass() const;
const Vector2ui& GetSize() const override;
inline Swapchain& GetSwapchain();
inline const Swapchain& GetSwapchain() const;
const Vector2ui& GetSize() const;
inline Swapchain* GetSwapchain();
inline const Swapchain* GetSwapchain() const;
inline TransientResources& Transient();
WindowSwapchain& operator=(const WindowSwapchain&) = delete;
WindowSwapchain& operator=(WindowSwapchain&& windowSwapchain) = delete;
NazaraSignal(OnSwapchainCreated, WindowSwapchain* /*swapchain*/, Swapchain& /*swapchain*/);
NazaraSignal(OnSwapchainDestroy, WindowSwapchain* /*swapchain*/);
private:
void ConnectSignals();
inline void DisconnectSignals();

View File

@ -7,11 +7,6 @@
namespace Nz
{
inline WindowSwapchain::~WindowSwapchain()
{
OnRenderTargetRelease(this);
}
inline RenderFrame WindowSwapchain::AcquireFrame()
{
if (m_isMinimized || (!m_hasFocus && m_renderOnlyIfFocused))
@ -20,11 +15,6 @@ namespace Nz
return m_swapchain->AcquireFrame();
}
inline void WindowSwapchain::BlitTexture(RenderFrame& renderFrame, CommandBufferBuilder& builder, const Texture& texture) const
{
return m_swapchain->BlitTexture(renderFrame, builder, texture);
}
inline bool WindowSwapchain::DoesRenderOnlyIfFocused() const
{
return m_renderOnlyIfFocused;
@ -53,14 +43,14 @@ namespace Nz
return m_swapchain->GetRenderPass();
}
inline Swapchain& WindowSwapchain::GetSwapchain()
inline Swapchain* WindowSwapchain::GetSwapchain()
{
return *m_swapchain;
return m_swapchain.get();
}
inline const Swapchain& WindowSwapchain::GetSwapchain() const
inline const Swapchain* WindowSwapchain::GetSwapchain() const
{
return *m_swapchain;
return m_swapchain.get();
}
inline TransientResources& WindowSwapchain::Transient()

View File

@ -3,8 +3,8 @@
// For conditions of distribution and use, see copyright notice in Config.hpp
#include <Nazara/Graphics/AbstractViewer.hpp>
#include <Nazara/Graphics/RenderTarget.hpp>
#include <Nazara/Graphics/ViewerInstance.hpp>
#include <Nazara/Renderer/RenderTarget.hpp>
#include <Nazara/Graphics/Debug.hpp>
namespace Nz

View File

@ -11,8 +11,8 @@
namespace Nz
{
Camera::Camera(const RenderTarget* renderTarget, ProjectionType projectionType) :
Camera(renderTarget, Graphics::Instance()->GetDefaultPipelinePasses(), projectionType)
Camera::Camera(std::shared_ptr<const RenderTarget> renderTarget, ProjectionType projectionType) :
Camera(std::move(renderTarget), Graphics::Instance()->GetDefaultPipelinePasses(), projectionType)
{
}
@ -61,12 +61,12 @@ namespace Nz
return m_framePipelinePasses->RegisterPasses(passes, frameGraph, viewerIndex, passCallback);
}
void Camera::UpdateTarget(const RenderTarget* renderTarget)
void Camera::UpdateTarget(std::shared_ptr<const RenderTarget> renderTarget)
{
m_onRenderTargetRelease.Disconnect();
m_onRenderTargetSizeChange.Disconnect();
m_renderTarget = renderTarget;
m_renderTarget = std::move(renderTarget);
if (m_renderTarget)
{
m_onRenderTargetRelease.Connect(m_renderTarget->OnRenderTargetRelease, [this](const RenderTarget*)

View File

@ -11,6 +11,7 @@
#include <Nazara/Graphics/PointLight.hpp>
#include <Nazara/Graphics/PredefinedShaderStructs.hpp>
#include <Nazara/Graphics/RenderElement.hpp>
#include <Nazara/Graphics/RenderTarget.hpp>
#include <Nazara/Graphics/SpotLight.hpp>
#include <Nazara/Graphics/ViewerInstance.hpp>
#include <Nazara/Graphics/WorldInstance.hpp>
@ -19,7 +20,6 @@
#include <Nazara/Renderer/CommandBufferBuilder.hpp>
#include <Nazara/Renderer/Framebuffer.hpp>
#include <Nazara/Renderer/RenderFrame.hpp>
#include <Nazara/Renderer/RenderTarget.hpp>
#include <Nazara/Renderer/UploadPool.hpp>
#include <NazaraUtils/StackArray.hpp>
#include <NazaraUtils/StackVector.hpp>
@ -383,7 +383,7 @@ namespace Nz
if (m_rebuildFrameGraph)
{
renderFrame.PushForRelease(std::move(m_bakedFrameGraph));
m_bakedFrameGraph = BuildFrameGraph(renderFrame);
m_bakedFrameGraph = BuildFrameGraph();
m_bakedFrameGraph.Resize(renderFrame, viewerSizes);
frameGraphInvalidated = true;
}
@ -509,10 +509,11 @@ namespace Nz
{
const RenderTarget& renderTarget = *renderTargetPtr;
const auto& data = renderTargetData;
renderTarget.OnRenderEnd(renderFrame, m_bakedFrameGraph, data.finalAttachment);
renderFrame.Execute([&](CommandBufferBuilder& builder)
{
const std::shared_ptr<Texture>& sourceTexture = m_bakedFrameGraph.GetAttachmentTexture(data.finalAttachment);
renderTarget.BlitTexture(renderFrame, builder, *sourceTexture);
}, QueueType::Graphics);
}
@ -658,7 +659,7 @@ namespace Nz
}
}
BakedFrameGraph ForwardFramePipeline::BuildFrameGraph(RenderFrame& renderFrame)
BakedFrameGraph ForwardFramePipeline::BuildFrameGraph()
{
FrameGraph frameGraph;
@ -669,37 +670,7 @@ namespace Nz
lightData->shadowData->RegisterToFrameGraph(frameGraph, nullptr);
}
unsigned int viewerIndex = 0;
for (auto& viewerData : m_viewerPool)
{
if (viewerData.pendingDestruction)
continue;
UInt32 renderMask = viewerData.viewer->GetRenderMask();
for (std::size_t i : m_shadowCastingLights.IterBits())
{
LightData* lightData = m_lightPool.RetrieveFromIndex(i);
if (lightData->shadowData->IsPerViewer() && (renderMask & lightData->renderMask) != 0)
lightData->shadowData->RegisterToFrameGraph(frameGraph, viewerData.viewer);
}
auto framePassCallback = [this, &viewerData, renderMask](std::size_t /*passIndex*/, FramePass& framePass, FramePipelinePassFlags flags)
{
if (flags.Test(FramePipelinePassFlag::LightShadowing))
{
for (std::size_t i : m_shadowCastingLights.IterBits())
{
LightData* lightData = m_lightPool.RetrieveFromIndex(i);
if ((renderMask & lightData->renderMask) != 0)
lightData->shadowData->RegisterPassInputs(framePass, (lightData->shadowData->IsPerViewer()) ? viewerData.viewer : nullptr);
}
}
};
viewerData.finalColorAttachment = viewerData.viewer->RegisterPasses(viewerData.passes, frameGraph, viewerIndex++, framePassCallback);
}
using ViewerPair = std::pair<const RenderTarget*, const ViewerData*>;
using ViewerPair = std::pair<const RenderTarget*, ViewerData*>;
StackArray<ViewerPair> viewers = NazaraStackArray(ViewerPair, m_viewerPool.size());
auto viewerIt = viewers.begin();
@ -718,9 +689,62 @@ namespace Nz
return lhs.second->renderOrder < rhs.second->renderOrder;
});
StackVector<std::size_t> dependenciesColorAttachments = NazaraStackVector(std::size_t, viewers.size());
m_renderTargets.clear();
for (auto&& [renderTarget, viewerData] : viewers)
unsigned int viewerIndex = 0;
for (auto it = viewers.begin(), prevIt = it; it != viewers.end(); ++it)
{
auto&& [renderTarget, viewerData] = *it;
UInt32 renderMask = viewerData->viewer->GetRenderMask();
for (std::size_t i : m_shadowCastingLights.IterBits())
{
LightData* lightData = m_lightPool.RetrieveFromIndex(i);
if (lightData->shadowData->IsPerViewer() && (renderMask & lightData->renderMask) != 0)
lightData->shadowData->RegisterToFrameGraph(frameGraph, viewerData->viewer);
}
// Keep track of previous dependencies attachments (from viewers having a smaller render order)
Int32 renderOrder = viewerData->renderOrder;
for (auto it2 = prevIt; prevIt != it; ++prevIt)
{
ViewerData* prevViewerData = prevIt->second;
Int32 prevRenderOrder = prevViewerData->renderOrder;
if (prevRenderOrder >= renderOrder)
break;
dependenciesColorAttachments.push_back(prevViewerData->finalColorAttachment);
prevIt = it2;
}
auto framePassCallback = [&, viewerData, renderMask](std::size_t /*passIndex*/, FramePass& framePass, FramePipelinePassFlags flags)
{
// Inject previous final attachments as inputs for all passes, to force framegraph to order viewers passes relative to each other
// TODO: Allow the user to define which pass of viewer A uses viewer B rendering
for (std::size_t finalAttachment : dependenciesColorAttachments)
{
std::size_t inputIndex = framePass.AddInput(finalAttachment);
// Disable ReadInput to prevent the framegraph from transitionning the texture layout (for now it's handled externally)
// (however if we manage to get rid of the texture blit from RenderTexture by making the framegraph use the external texture directly, this would be necessary)
framePass.SetReadInput(inputIndex, false);
}
if (flags.Test(FramePipelinePassFlag::LightShadowing))
{
for (std::size_t i : m_shadowCastingLights.IterBits())
{
LightData* lightData = m_lightPool.RetrieveFromIndex(i);
if ((renderMask & lightData->renderMask) != 0)
lightData->shadowData->RegisterPassInputs(framePass, (lightData->shadowData->IsPerViewer()) ? viewerData->viewer : nullptr);
}
}
};
viewerData->finalColorAttachment = viewerData->viewer->RegisterPasses(viewerData->passes, frameGraph, viewerIndex++, framePassCallback);
// Group viewers by render targets
auto& renderTargetData = m_renderTargets[renderTarget];
renderTargetData.viewers.push_back(viewerData);
}
@ -772,15 +796,15 @@ namespace Nz
}
});
frameGraph.MarkAsFinalOutput(renderTargetData.finalAttachment);
renderTarget->OnBuildGraph(frameGraph, renderTargetData.finalAttachment);
}
else if (targetViewers.size() == 1)
{
// Single viewer on that target
const auto& viewer = *targetViewers.front();
frameGraph.MarkAsFinalOutput(viewer.finalColorAttachment);
renderTargetData.finalAttachment = viewer.finalColorAttachment;
renderTarget->OnBuildGraph(frameGraph, renderTargetData.finalAttachment);
}
}

View File

@ -28,7 +28,7 @@ namespace Nz
BakedFrameGraph FrameGraph::Bake()
{
if (m_finalOutputs.empty())
if (m_backbufferOutputs.empty())
throw std::runtime_error("no backbuffer output has been set");
m_pending.attachmentReadList.clear();
@ -45,7 +45,7 @@ namespace Nz
BuildReadWriteList();
for (std::size_t output : m_finalOutputs)
for (std::size_t output : m_backbufferOutputs)
{
auto it = m_pending.attachmentWriteList.find(output);
if (it == m_pending.attachmentWriteList.end())
@ -123,6 +123,7 @@ namespace Nz
{
auto& bakedTexture = bakedTextures.emplace_back();
static_cast<FrameGraphTextureData&>(bakedTexture) = std::move(texture);
bakedTexture.texture = bakedTexture.externalTexture;
}
return BakedFrameGraph(std::move(bakedPasses), std::move(bakedTextures), std::move(m_pending.attachmentToTextures), std::move(m_pending.passIdToPhysicalPassIndex));
@ -290,7 +291,7 @@ namespace Nz
}
// Add TextureUsage::ShaderSampling and TextureUsage::TransferSource to final outputs
for (std::size_t output : m_finalOutputs)
for (std::size_t output : m_backbufferOutputs)
{
auto it = m_pending.attachmentToTextures.find(output);
assert(it != m_pending.attachmentToTextures.end());
@ -1000,6 +1001,54 @@ namespace Nz
if (auto it = m_pending.attachmentToTextures.find(attachmentIndex); it != m_pending.attachmentToTextures.end())
return it->second;
auto InsertTexture = [this](ImageType imageType, std::size_t attachmentIndex, const FramePassAttachment& attachmentData, std::size_t& textureId) -> FrameGraphTextureData&
{
textureId = m_pending.textures.size();
m_pending.attachmentToTextures.emplace(attachmentIndex, textureId);
FrameGraphTextureData& data = m_pending.textures.emplace_back();
data.type = imageType;
data.name = attachmentData.name;
data.format = attachmentData.format;
data.width = attachmentData.width;
data.height = attachmentData.height;
data.size = attachmentData.size;
data.layerCount = 1;
data.usage = attachmentData.additionalUsages;
data.viewerIndex = attachmentData.viewerIndex;
data.canReuse = true;
return data;
};
auto CheckExternalTexture = [this](std::size_t attachmentIndex, FrameGraphTextureData& data)
{
// Check if texture
if (auto externalIt = m_externalTextures.find(attachmentIndex); externalIt != m_externalTextures.end())
{
if (data.viewData)
throw std::runtime_error("texture views cannot be bound to external textures");
data.externalTexture = externalIt->second;
data.canReuse = false;
data.size = FramePassAttachmentSize::Fixed;
const TextureInfo& textureInfo = data.externalTexture->GetTextureInfo();
data.width = textureInfo.width;
data.height = textureInfo.height;
// Check that texture settings match
if (textureInfo.type != data.type)
throw std::runtime_error("external texture type doesn't match attachment type");
if (textureInfo.layerCount != data.layerCount)
throw std::runtime_error("external texture layer count doesn't match attachment type");
if (textureInfo.pixelFormat != data.format)
throw std::runtime_error("external texture format doesn't match attachment type");
}
};
return std::visit([&](auto&& arg) -> std::size_t
{
using T = std::decay_t<decltype(arg)>;
@ -1033,23 +1082,14 @@ namespace Nz
return textureId;
}
std::size_t textureId = m_pending.textures.size();
m_pending.attachmentToTextures.emplace(attachmentIndex, textureId);
FrameGraphTextureData& data = m_pending.textures.emplace_back();
data.type = ImageType::E2D;
data.name = attachmentData.name;
data.format = attachmentData.format;
data.width = attachmentData.width;
data.height = attachmentData.height;
data.size = attachmentData.size;
std::size_t textureId;
FrameGraphTextureData& data = InsertTexture(ImageType::E2D, attachmentIndex, attachmentData, textureId);
data.layerCount = 1;
data.usage = attachmentData.additionalUsages;
data.viewerIndex = attachmentData.viewerIndex;
data.canReuse = true;
CheckExternalTexture(attachmentIndex, data);
// Final outputs cannot be reused
for (std::size_t outputAttachmentIndex : m_finalOutputs)
for (std::size_t outputAttachmentIndex : m_backbufferOutputs)
{
if (attachmentIndex == outputAttachmentIndex)
{
@ -1091,23 +1131,14 @@ namespace Nz
return textureId;
}
std::size_t textureId = m_pending.textures.size();
m_pending.attachmentToTextures.emplace(attachmentIndex, textureId);
FrameGraphTextureData& data = m_pending.textures.emplace_back();
data.type = ImageType::E2D_Array;
data.name = attachmentData.name;
data.format = attachmentData.format;
data.width = attachmentData.width;
data.height = attachmentData.height;
data.size = attachmentData.size;
std::size_t textureId;
FrameGraphTextureData& data = InsertTexture(ImageType::E2D_Array, attachmentIndex, attachmentData, textureId);
data.layerCount = attachmentData.layerCount;
data.usage = attachmentData.additionalUsages;
data.viewerIndex = attachmentData.viewerIndex;
data.canReuse = true;
CheckExternalTexture(attachmentIndex, data);
// Final outputs cannot be reused
for (std::size_t outputAttachmentIndex : m_finalOutputs)
for (std::size_t outputAttachmentIndex : m_backbufferOutputs)
{
if (attachmentIndex == outputAttachmentIndex)
{
@ -1148,23 +1179,14 @@ namespace Nz
return textureId;
}
std::size_t textureId = m_pending.textures.size();
m_pending.attachmentToTextures.emplace(attachmentIndex, textureId);
FrameGraphTextureData& data = m_pending.textures.emplace_back();
data.type = ImageType::Cubemap;
data.name = attachmentData.name;
data.format = attachmentData.format;
data.width = attachmentData.width;
data.height = attachmentData.height;
data.size = attachmentData.size;
std::size_t textureId;
FrameGraphTextureData& data = InsertTexture(ImageType::Cubemap, attachmentIndex, attachmentData, textureId);
data.layerCount = 1;
data.usage = attachmentData.additionalUsages;
data.viewerIndex = attachmentData.viewerIndex;
data.canReuse = true;
CheckExternalTexture(attachmentIndex, data);
// Final outputs cannot be reused
for (std::size_t outputAttachmentIndex : m_finalOutputs)
for (std::size_t outputAttachmentIndex : m_backbufferOutputs)
{
if (attachmentIndex == outputAttachmentIndex)
{
@ -1200,6 +1222,8 @@ namespace Nz
};
data.viewerIndex = parentTexture.viewerIndex;
CheckExternalTexture(attachmentIndex, data);
return textureId;
}
else if constexpr (std::is_same_v<T, AttachmentProxy>)
@ -1209,6 +1233,9 @@ namespace Nz
std::size_t textureId = RegisterTexture(proxy.attachmentId);
m_pending.attachmentToTextures.emplace(attachmentIndex, textureId);
if (m_externalTextures.contains(proxy.attachmentId))
throw std::runtime_error("proxy attachments cannot be bound to external textures");
return textureId;
}
else

View File

@ -1,9 +1,9 @@
// Copyright (C) 2023 Jérôme "Lynix" Leclercq (lynix680@gmail.com)
// This file is part of the "Nazara Engine - Renderer module"
// This file is part of the "Nazara Engine - Graphics module"
// For conditions of distribution and use, see copyright notice in Config.hpp
#include <Nazara/Renderer/RenderTarget.hpp>
#include <Nazara/Renderer/Debug.hpp>
#include <Nazara/Graphics/RenderTarget.hpp>
#include <Nazara/Graphics/Debug.hpp>
namespace Nz
{

View File

@ -0,0 +1,35 @@
// Copyright (C) 2023 Jérôme "Lynix" Leclercq (lynix680@gmail.com)
// This file is part of the "Nazara Engine - Graphics module"
// For conditions of distribution and use, see copyright notice in Config.hpp
#include <Nazara/Graphics/RenderTexture.hpp>
#include <Nazara/Graphics/FrameGraph.hpp>
#include <Nazara/Renderer/CommandBufferBuilder.hpp>
#include <Nazara/Renderer/Texture.hpp>
#include <Nazara/Graphics/Debug.hpp>
namespace Nz
{
RenderTexture::RenderTexture(std::shared_ptr<Texture> texture, PipelineStage targetPipelineStage, MemoryAccessFlags targetMemoryFlags, TextureLayout targetLayout) :
m_targetTexture(std::move(texture)),
m_targetMemoryFlags(targetMemoryFlags),
m_targetPipelineStage(targetPipelineStage),
m_targetLayout(targetLayout),
m_textureSize(Vector2ui(m_targetTexture->GetSize()))
{
}
void RenderTexture::OnBuildGraph(FrameGraph& graph, std::size_t attachmentIndex) const
{
graph.BindAttachmentToExternalTexture(attachmentIndex, m_targetTexture);
}
void RenderTexture::OnRenderEnd(RenderFrame& /*renderFrame*/, const BakedFrameGraph& /*frameGraph*/, std::size_t /*finalAttachment*/) const
{
}
const Vector2ui& RenderTexture::GetSize() const
{
return m_textureSize;
}
}

View File

@ -0,0 +1,84 @@
// Copyright (C) 2023 Jérôme "Lynix" Leclercq (lynix680@gmail.com)
// This file is part of the "Nazara Engine - Graphics module"
// For conditions of distribution and use, see copyright notice in Config.hpp
#include <Nazara/Graphics/RenderWindow.hpp>
#include <Nazara/Graphics/BakedFrameGraph.hpp>
#include <Nazara/Graphics/FrameGraph.hpp>
#include <Nazara/Renderer/CommandBufferBuilder.hpp>
#include <Nazara/Renderer/RenderFrame.hpp>
#include <Nazara/Renderer/Swapchain.hpp>
#include <Nazara/Renderer/Texture.hpp>
#include <cassert>
#include <Nazara/Graphics/Debug.hpp>
namespace Nz
{
RenderWindow::RenderWindow(WindowSwapchain& swapchain) :
m_swapchain(nullptr),
m_windowSwapchain(&swapchain)
{
m_onSwapchainCreated.Connect(swapchain.OnSwapchainCreated, [this](WindowSwapchain* /*windowSwapchain*/, Swapchain& swapchain)
{
SetSwapchain(&swapchain);
});
m_onSwapchainDestroy.Connect(swapchain.OnSwapchainDestroy, [this](WindowSwapchain* /*windowSwapchain*/)
{
SetSwapchain(nullptr);
});
SetSwapchain(m_windowSwapchain->GetSwapchain());
}
void RenderWindow::OnRenderEnd(RenderFrame& renderFrame, const BakedFrameGraph& frameGraph, std::size_t finalAttachment) const
{
const std::shared_ptr<Texture>& texture = frameGraph.GetAttachmentTexture(finalAttachment);
Vector2ui textureSize = Vector2ui(texture->GetSize());
Boxui blitRegion(0, 0, 0, textureSize.x, textureSize.y, 1);
renderFrame.Execute([&](CommandBufferBuilder& builder)
{
builder.BeginDebugRegion("Blit to swapchain", Color::Blue());
{
builder.TextureBarrier(PipelineStage::ColorOutput, PipelineStage::Transfer, MemoryAccess::ColorWrite, MemoryAccess::TransferRead, TextureLayout::ColorOutput, TextureLayout::TransferSource, *texture);
builder.BlitTextureToSwapchain(*texture, blitRegion, TextureLayout::TransferSource, *m_swapchain, renderFrame.GetFramebufferIndex());
}
builder.EndDebugRegion();
}, QueueType::Graphics);
}
void RenderWindow::OnBuildGraph(FrameGraph& graph, std::size_t attachmentIndex) const
{
graph.AddBackbufferOutput(attachmentIndex);
}
const Vector2ui& RenderWindow::GetSize() const
{
if (m_swapchain)
return m_swapchain->GetSize();
else if (m_windowSwapchain)
return m_windowSwapchain->GetSize();
else
{
static Vector2ui dummySize(1, 1);
return dummySize;
}
}
void RenderWindow::SetSwapchain(Swapchain* swapchain)
{
m_swapchain = swapchain;
if (m_swapchain)
{
OnRenderTargetSizeChange(this, m_swapchain->GetSize());
m_onSwapchainResize.Connect(m_swapchain->OnSwapchainResize, [this]([[maybe_unused]] Swapchain* swapchain, const Vector2ui& newSize)
{
assert(m_swapchain == swapchain);
OnRenderTargetSizeChange(this, newSize);
});
}
}
}

View File

@ -132,7 +132,7 @@ namespace Nz
void OpenGLSwapchain::NotifyResize(const Vector2ui& newSize)
{
OnRenderTargetSizeChange(this, newSize);
OnSwapchainResize(this, newSize);
m_size = newSize;
m_sizeInvalidated = true;

View File

@ -1,45 +0,0 @@
// Copyright (C) 2023 Jérôme "Lynix" Leclercq (lynix680@gmail.com)
// 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/RenderTexture.hpp>
#include <Nazara/Renderer/CommandBufferBuilder.hpp>
#include <Nazara/Renderer/Texture.hpp>
#include <Nazara/Renderer/Debug.hpp>
namespace Nz
{
RenderTexture::RenderTexture(std::shared_ptr<Texture> texture, PipelineStage targetPipelineStage, MemoryAccessFlags targetMemoryFlags, TextureLayout targetLayout) :
m_targetTexture(std::move(texture)),
m_targetMemoryFlags(targetMemoryFlags),
m_targetPipelineStage(targetPipelineStage),
m_targetLayout(targetLayout),
m_textureSize(Vector2ui(m_targetTexture->GetSize()))
{
}
void RenderTexture::BlitTexture(RenderFrame& /*renderFrame*/, CommandBufferBuilder& builder, const Texture& texture) const
{
Vector3ui textureSize = texture.GetSize();
Vector3ui targetTextureSize = m_targetTexture->GetSize();
builder.BeginDebugRegion("Blit to texture", Color::Blue());
{
builder.TextureBarrier(PipelineStage::ColorOutput, PipelineStage::Transfer, MemoryAccess::ColorWrite, MemoryAccess::TransferRead, TextureLayout::ColorOutput, TextureLayout::TransferSource, texture);
builder.TextureBarrier(PipelineStage::TopOfPipe, PipelineStage::Transfer, {}, MemoryAccess::TransferWrite, TextureLayout::Undefined, TextureLayout::TransferDestination, *m_targetTexture);
Boxui fromBox(0, 0, 0, textureSize.x, textureSize.y, 1);
Boxui toBox(0, 0, 0, targetTextureSize.x, targetTextureSize.y, 1);
builder.BlitTexture(texture, fromBox, TextureLayout::TransferSource, *m_targetTexture, toBox, TextureLayout::TransferDestination, SamplerFilter::Linear);
builder.TextureBarrier(PipelineStage::Transfer, m_targetPipelineStage, MemoryAccess::TransferWrite, m_targetMemoryFlags, TextureLayout::TransferDestination, m_targetLayout, *m_targetTexture);
}
builder.EndDebugRegion();
}
const Vector2ui& RenderTexture::GetSize() const
{
return m_textureSize;
}
}

View File

@ -3,7 +3,6 @@
// For conditions of distribution and use, see copyright notice in Config.hpp
#include <Nazara/Renderer/Swapchain.hpp>
#include <Nazara/Renderer/CommandBufferBuilder.hpp>
#include <Nazara/Renderer/Texture.hpp>
#include <Nazara/Renderer/Debug.hpp>
@ -11,20 +10,6 @@ namespace Nz
{
Swapchain::~Swapchain() = default;
void Swapchain::BlitTexture(RenderFrame& renderFrame, CommandBufferBuilder& builder, const Texture& texture) const
{
Vector2ui textureSize = Vector2ui(texture.GetSize());
Boxui blitRegion(0, 0, 0, textureSize.x, textureSize.y, 1);
builder.TextureBarrier(PipelineStage::ColorOutput, PipelineStage::Transfer, MemoryAccess::ColorWrite, MemoryAccess::TransferRead, TextureLayout::ColorOutput, TextureLayout::TransferSource, texture);
builder.BeginDebugRegion("Blit to swapchain", Color::Blue());
{
builder.BlitTextureToSwapchain(texture, blitRegion, TextureLayout::TransferSource, *this, renderFrame.GetFramebufferIndex());
}
builder.EndDebugRegion();
}
void Swapchain::BuildRenderPass(PixelFormat colorFormat, PixelFormat depthFormat, std::vector<RenderPass::Attachment>& attachments, std::vector<RenderPass::SubpassDescription>& subpassDescriptions, std::vector<RenderPass::SubpassDependency>& subpassDependencies)
{
assert(colorFormat != PixelFormat::Undefined);

View File

@ -42,11 +42,15 @@ namespace Nz
{
m_isMinimized = m_window->IsMinimized();
if (!m_isMinimized)
{
m_swapchain = m_renderDevice->InstantiateSwapchain(m_window->GetHandle(), m_window->GetSize(), m_parameters);
OnSwapchainCreated(this, *m_swapchain);
}
});
m_onDestruction.Connect(windowEvents.OnDestruction, [this](const WindowEventHandler* /*eventHandler*/)
{
OnSwapchainDestroy(this);
m_swapchain.reset();
m_isMinimized = true;
});
@ -69,13 +73,15 @@ namespace Nz
m_onResized.Connect(windowEvents.OnResized, [this](const WindowEventHandler* /*eventHandler*/, const WindowEvent::SizeEvent& event)
{
m_swapchain->NotifyResize({ event.width, event.height });
OnRenderTargetSizeChange(this, m_swapchain->GetSize());
});
m_onRestored.Connect(windowEvents.OnRestored, [this](const WindowEventHandler* /*eventHandler*/)
{
if (!m_swapchain)
{
m_swapchain = m_renderDevice->InstantiateSwapchain(m_window->GetHandle(), m_window->GetSize(), m_parameters);
OnSwapchainCreated(this, *m_swapchain);
}
m_isMinimized = false;
});

View File

@ -326,7 +326,7 @@ namespace Nz
void VulkanSwapchain::NotifyResize(const Vector2ui& newSize)
{
OnRenderTargetSizeChange(this, newSize);
OnSwapchainResize(this, newSize);
m_swapchainSize = newSize;
m_shouldRecreateSwapchain = true;

View File

@ -76,7 +76,7 @@ int main()
Nz::Vector2ui windowSize = window.GetSize();
Nz::Camera camera(&windowSwapchain);
Nz::Camera camera(std::make_shared<Nz::RenderWindow>(windowSwapchain));
camera.UpdateClearColor(Nz::Color::Gray());
Nz::ViewerInstance& viewerInstance = camera.GetViewerInstance();

View File

@ -30,22 +30,22 @@ int main()
std::string windowTitle = "Physics 2D";
Nz::Window& window = windowing.CreateWindow(Nz::VideoMode(1920, 1080, 32), windowTitle);
Nz::WindowSwapchain& windowSwapchain = renderSystem.CreateSwapchain(window);
Nz::Swapchain& swapchain = windowSwapchain.GetSwapchain();
Nz::Swapchain* swapchain = windowSwapchain.GetSwapchain();
Nz::Vector2ui windowSize = window.GetSize();
entt::handle viewer = world.CreateEntity();
{
viewer.emplace<Nz::NodeComponent>();
viewer.emplace<Nz::CameraComponent>(&windowSwapchain, Nz::ProjectionType::Orthographic);
viewer.emplace<Nz::CameraComponent>(std::make_shared<Nz::RenderWindow>(windowSwapchain), Nz::ProjectionType::Orthographic);
}
// Turn present mode flags into vector for easier processing
Nz::FixedVector<Nz::PresentMode, Nz::EnumValueCount_v<Nz::PresentMode>> supportedPresentModes;
for (Nz::PresentMode presentMode : swapchain.GetSupportedPresentModes())
for (Nz::PresentMode presentMode : swapchain->GetSupportedPresentModes())
supportedPresentModes.push_back(presentMode);
auto presentFlagIt = std::find(supportedPresentModes.begin(), supportedPresentModes.end(), swapchain.GetPresentMode());
auto presentFlagIt = std::find(supportedPresentModes.begin(), supportedPresentModes.end(), swapchain->GetPresentMode());
bool limitFps = false;
@ -62,7 +62,7 @@ int main()
{
textDrawer.AppendText("- ");
if (presentMode == swapchain.GetPresentMode())
if (presentMode == swapchain->GetPresentMode())
textDrawer.SetTextColor(Nz::Color::Yellow());
else
textDrawer.SetTextColor(Nz::Color::White());
@ -120,7 +120,7 @@ int main()
if (presentFlagIt == supportedPresentModes.end())
presentFlagIt = supportedPresentModes.begin();
swapchain.SetPresentMode(*presentFlagIt);
swapchain->SetPresentMode(*presentFlagIt);
UpdatePresentModeText();
}
else if (event.virtualKey == Nz::Keyboard::VKey::Subtract)
@ -130,7 +130,7 @@ int main()
--presentFlagIt;
swapchain.SetPresentMode(*presentFlagIt);
swapchain->SetPresentMode(*presentFlagIt);
UpdatePresentModeText();
}
else if (event.virtualKey == Nz::Keyboard::VKey::Multiply)