From 938ba09d459fd3b441cea361d5c58eb682461383 Mon Sep 17 00:00:00 2001 From: SirLynix Date: Mon, 20 Nov 2023 23:00:06 +0100 Subject: [PATCH] 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 --- examples/DeferredShading/main.cpp | 2 +- examples/PhysicallyBasedRendering/main.cpp | 2 +- examples/Physics2DDemo/main.cpp | 2 +- examples/PhysicsDemo/main.cpp | 2 +- examples/PhysicsPlayground/main.cpp | 2 +- examples/Showcase/main.cpp | 33 ++--- examples/Tut01/main.cpp | 2 +- examples/Tut02/main.cpp | 2 +- examples/WidgetDemo/main.cpp | 2 +- include/Nazara/Graphics.hpp | 3 + include/Nazara/Graphics/Camera.hpp | 10 +- include/Nazara/Graphics/Camera.inl | 9 +- .../Nazara/Graphics/ForwardFramePipeline.hpp | 2 +- include/Nazara/Graphics/FrameGraph.hpp | 6 +- include/Nazara/Graphics/FrameGraph.inl | 9 +- include/Nazara/Graphics/FrameGraphStructs.hpp | 3 + include/Nazara/Graphics/FramePass.hpp | 2 +- .../{Renderer => Graphics}/RenderTarget.hpp | 19 +-- .../{Renderer => Graphics}/RenderTarget.inl | 6 +- .../{Renderer => Graphics}/RenderTexture.hpp | 19 +-- .../{Renderer => Graphics}/RenderTexture.inl | 7 +- include/Nazara/Graphics/RenderWindow.hpp | 50 ++++++++ include/Nazara/Graphics/RenderWindow.inl | 16 +++ include/Nazara/Renderer.hpp | 2 - include/Nazara/Renderer/Swapchain.hpp | 10 +- include/Nazara/Renderer/WindowSwapchain.hpp | 17 +-- include/Nazara/Renderer/WindowSwapchain.inl | 18 +-- src/Nazara/Graphics/AbstractViewer.cpp | 2 +- src/Nazara/Graphics/Camera.cpp | 8 +- src/Nazara/Graphics/ForwardFramePipeline.cpp | 102 +++++++++------ src/Nazara/Graphics/FrameGraph.cpp | 117 +++++++++++------- .../{Renderer => Graphics}/RenderTarget.cpp | 6 +- src/Nazara/Graphics/RenderTexture.cpp | 35 ++++++ src/Nazara/Graphics/RenderWindow.cpp | 84 +++++++++++++ src/Nazara/OpenGLRenderer/OpenGLSwapchain.cpp | 2 +- src/Nazara/Renderer/RenderTexture.cpp | 45 ------- src/Nazara/Renderer/Swapchain.cpp | 15 --- src/Nazara/Renderer/WindowSwapchain.cpp | 8 +- src/Nazara/VulkanRenderer/VulkanSwapchain.cpp | 2 +- tests/GraphicsTest/main.cpp | 2 +- tests/PresentModeTest/main.cpp | 14 +-- 41 files changed, 445 insertions(+), 254 deletions(-) rename include/Nazara/{Renderer => Graphics}/RenderTarget.hpp (55%) rename include/Nazara/{Renderer => Graphics}/RenderTarget.inl (54%) rename include/Nazara/{Renderer => Graphics}/RenderTexture.hpp (62%) rename include/Nazara/{Renderer => Graphics}/RenderTexture.inl (67%) create mode 100644 include/Nazara/Graphics/RenderWindow.hpp create mode 100644 include/Nazara/Graphics/RenderWindow.inl rename src/Nazara/{Renderer => Graphics}/RenderTarget.cpp (62%) create mode 100644 src/Nazara/Graphics/RenderTexture.cpp create mode 100644 src/Nazara/Graphics/RenderWindow.cpp delete mode 100644 src/Nazara/Renderer/RenderTexture.cpp diff --git a/examples/DeferredShading/main.cpp b/examples/DeferredShading/main.cpp index 7f6414e3f..4ed42d60c 100644 --- a/examples/DeferredShading/main.cpp +++ b/examples/DeferredShading/main.cpp @@ -1037,7 +1037,7 @@ int main(int argc, char* argv[]) builder.Draw(3); }); - graph.MarkAsFinalOutput(toneMappingOutput); + graph.AddBackbufferOutput(toneMappingOutput); return graph.Bake(); }(); diff --git a/examples/PhysicallyBasedRendering/main.cpp b/examples/PhysicallyBasedRendering/main.cpp index fa1c6cb53..1423f7329 100644 --- a/examples/PhysicallyBasedRendering/main.cpp +++ b/examples/PhysicallyBasedRendering/main.cpp @@ -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(windowSwapchain)); //camera.UpdateClearColor(Nz::Color::Gray); Nz::ViewerInstance& viewerInstance = camera.GetViewerInstance(); diff --git a/examples/Physics2DDemo/main.cpp b/examples/Physics2DDemo/main.cpp index 61a56384a..ad894d82b 100644 --- a/examples/Physics2DDemo/main.cpp +++ b/examples/Physics2DDemo/main.cpp @@ -44,7 +44,7 @@ int main(int argc, char* argv[]) entt::handle viewer = world.CreateEntity(); { viewer.emplace(); - auto& cameraComponent = viewer.emplace(&windowSwapchain, Nz::ProjectionType::Orthographic); + auto& cameraComponent = viewer.emplace(std::make_shared(windowSwapchain), Nz::ProjectionType::Orthographic); cameraComponent.UpdateRenderMask(1); cameraComponent.UpdateClearColor(Nz::Color(0.5f, 0.5f, 0.5f)); } diff --git a/examples/PhysicsDemo/main.cpp b/examples/PhysicsDemo/main.cpp index 6f2d38cc7..fd1ba87fb 100644 --- a/examples/PhysicsDemo/main.cpp +++ b/examples/PhysicsDemo/main.cpp @@ -96,7 +96,7 @@ int main(int argc, char* argv[]) entt::handle viewer = world.CreateEntity(); { viewer.emplace(); - auto& cameraComponent = viewer.emplace(&windowSwapchain); + auto& cameraComponent = viewer.emplace(std::make_shared(windowSwapchain)); cameraComponent.UpdateRenderMask(1); cameraComponent.UpdateClearColor(Nz::Color(0.5f, 0.5f, 0.5f)); } diff --git a/examples/PhysicsPlayground/main.cpp b/examples/PhysicsPlayground/main.cpp index 82f04c2a4..26f80bceb 100644 --- a/examples/PhysicsPlayground/main.cpp +++ b/examples/PhysicsPlayground/main.cpp @@ -348,7 +348,7 @@ int main(int argc, char* argv[]) { cameraEntity.emplace(); - auto& cameraComponent = cameraEntity.emplace(&windowSwapchain, Nz::ProjectionType::Perspective); + auto& cameraComponent = cameraEntity.emplace(std::make_shared(windowSwapchain), Nz::ProjectionType::Perspective); cameraComponent.UpdateFOV(70.f); cameraComponent.UpdateClearColor(Nz::Color::sRGBToLinear(Nz::Color(0.46f, 0.48f, 0.84f, 1.f))); } diff --git a/examples/Showcase/main.cpp b/examples/Showcase/main.cpp index 9e8b965cd..799f700e8 100644 --- a/examples/Showcase/main.cpp +++ b/examples/Showcase/main.cpp @@ -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(&windowSwapchain); + auto& cameraComponent = playerCamera.emplace(std::make_shared(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 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 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 defaultScreen(size, 0xFF); + screenTexture = device->InstantiateTexture(screenTextureInfo, defaultScreen.data(), false); + } entt::handle tvCameraEntity = world.CreateEntity(); { auto& cameraNode = tvCameraEntity.emplace(); - 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(&renderTexture); + auto& cameraComponent = tvCameraEntity.emplace(std::make_shared(screenTexture)); cameraComponent.UpdateZNear(0.2f); cameraComponent.UpdateZFar(1000.f); cameraComponent.UpdateRenderMask(1); diff --git a/examples/Tut01/main.cpp b/examples/Tut01/main.cpp index 3c903d34c..8e7d5b0c3 100644 --- a/examples/Tut01/main.cpp +++ b/examples/Tut01/main.cpp @@ -26,7 +26,7 @@ int main(int argc, char* argv[]) { cameraEntity.emplace(); - auto& cameraComponent = cameraEntity.emplace(&windowSwapchain, Nz::ProjectionType::Orthographic); + auto& cameraComponent = cameraEntity.emplace(std::make_shared(windowSwapchain), Nz::ProjectionType::Orthographic); cameraComponent.UpdateClearColor(Nz::Color(0.46f, 0.48f, 0.84f, 1.f)); } diff --git a/examples/Tut02/main.cpp b/examples/Tut02/main.cpp index 87b22f8bb..33ced8195 100644 --- a/examples/Tut02/main.cpp +++ b/examples/Tut02/main.cpp @@ -27,7 +27,7 @@ int main(int argc, char* argv[]) { cameraEntity.emplace(); - auto& cameraComponent = cameraEntity.emplace(&windowSwapchain, Nz::ProjectionType::Orthographic); + auto& cameraComponent = cameraEntity.emplace(std::make_shared(windowSwapchain), Nz::ProjectionType::Orthographic); cameraComponent.UpdateClearColor(Nz::Color(0.46f, 0.48f, 0.84f, 1.f)); } diff --git a/examples/WidgetDemo/main.cpp b/examples/WidgetDemo/main.cpp index 78e18a8aa..8df31e688 100644 --- a/examples/WidgetDemo/main.cpp +++ b/examples/WidgetDemo/main.cpp @@ -105,7 +105,7 @@ int main(int argc, char* argv[]) { viewer2D.emplace(); - auto& cameraComponent = viewer2D.emplace(&windowSwapchain, Nz::ProjectionType::Orthographic); + auto& cameraComponent = viewer2D.emplace(std::make_shared(windowSwapchain), Nz::ProjectionType::Orthographic); cameraComponent.UpdateClearColor(Nz::Color(0.46f, 0.48f, 0.84f, 1.f)); } diff --git a/include/Nazara/Graphics.hpp b/include/Nazara/Graphics.hpp index 05375d4c5..370edf148 100644 --- a/include/Nazara/Graphics.hpp +++ b/include/Nazara/Graphics.hpp @@ -80,6 +80,9 @@ #include #include #include +#include +#include +#include #include #include #include diff --git a/include/Nazara/Graphics/Camera.hpp b/include/Nazara/Graphics/Camera.hpp index b8375e2a6..3d171451f 100644 --- a/include/Nazara/Graphics/Camera.hpp +++ b/include/Nazara/Graphics/Camera.hpp @@ -10,10 +10,10 @@ #include #include #include +#include #include #include #include -#include namespace Nz { @@ -22,8 +22,8 @@ namespace Nz class NAZARA_GRAPHICS_API Camera : public PipelineViewer { public: - inline Camera(const RenderTarget* renderTarget, std::shared_ptr pipelinePasses, ProjectionType projectionType = ProjectionType::Perspective); - Camera(const RenderTarget* renderTarget, ProjectionType projectionType = ProjectionType::Perspective); + inline Camera(std::shared_ptr renderTarget, std::shared_ptr pipelinePasses, ProjectionType projectionType = ProjectionType::Perspective); + Camera(std::shared_ptr 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 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 m_framePipelinePasses; - const RenderTarget* m_renderTarget; + std::shared_ptr m_renderTarget; Color m_clearColor; DegreeAnglef m_fov; Int32 m_renderOrder; diff --git a/include/Nazara/Graphics/Camera.inl b/include/Nazara/Graphics/Camera.inl index 18263b0b6..83ce6b067 100644 --- a/include/Nazara/Graphics/Camera.inl +++ b/include/Nazara/Graphics/Camera.inl @@ -7,9 +7,8 @@ namespace Nz { - inline Camera::Camera(const RenderTarget* renderTarget, std::shared_ptr pipelinePasses, ProjectionType projectionType) : + inline Camera::Camera(std::shared_ptr renderTarget, std::shared_ptr 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 diff --git a/include/Nazara/Graphics/ForwardFramePipeline.hpp b/include/Nazara/Graphics/ForwardFramePipeline.hpp index a8ec868c3..a0836b6de 100644 --- a/include/Nazara/Graphics/ForwardFramePipeline.hpp +++ b/include/Nazara/Graphics/ForwardFramePipeline.hpp @@ -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); diff --git a/include/Nazara/Graphics/FrameGraph.hpp b/include/Nazara/Graphics/FrameGraph.hpp index f2e83e9f7..5c7528e53 100644 --- a/include/Nazara/Graphics/FrameGraph.hpp +++ b/include/Nazara/Graphics/FrameGraph.hpp @@ -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); FrameGraph& operator=(const FrameGraph&) = delete; FrameGraph& operator=(FrameGraph&&) noexcept = default; @@ -139,9 +140,10 @@ namespace Nz using AttachmentType = std::variant; - std::vector m_finalOutputs; + std::vector m_backbufferOutputs; std::vector m_framePasses; std::vector m_attachments; + std::unordered_map> m_externalTextures; WorkData m_pending; }; } diff --git a/include/Nazara/Graphics/FrameGraph.inl b/include/Nazara/Graphics/FrameGraph.inl index 06c5d4862..a78e56ffe 100644 --- a/include/Nazara/Graphics/FrameGraph.inl +++ b/include/Nazara/Graphics/FrameGraph.inl @@ -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) + { + m_externalTextures[attachmentIndex] = std::move(texture); } } diff --git a/include/Nazara/Graphics/FrameGraphStructs.hpp b/include/Nazara/Graphics/FrameGraphStructs.hpp index b9c0db3da..9eeb88af1 100644 --- a/include/Nazara/Graphics/FrameGraphStructs.hpp +++ b/include/Nazara/Graphics/FrameGraphStructs.hpp @@ -16,6 +16,8 @@ namespace Nz { + class Texture; + struct FrameGraphTextureData { struct ViewData @@ -25,6 +27,7 @@ namespace Nz }; std::optional viewData; + std::shared_ptr externalTexture; std::string name; ImageType type; PixelFormat format; diff --git a/include/Nazara/Graphics/FramePass.hpp b/include/Nazara/Graphics/FramePass.hpp index 39ef2c5b3..cb77c7a30 100644 --- a/include/Nazara/Graphics/FramePass.hpp +++ b/include/Nazara/Graphics/FramePass.hpp @@ -97,8 +97,8 @@ namespace Nz struct Output { - std::size_t attachmentId; std::optional clearColor; + std::size_t attachmentId; }; private: diff --git a/include/Nazara/Renderer/RenderTarget.hpp b/include/Nazara/Graphics/RenderTarget.hpp similarity index 55% rename from include/Nazara/Renderer/RenderTarget.hpp rename to include/Nazara/Graphics/RenderTarget.hpp index 1d4243d6b..bddf53cc6 100644 --- a/include/Nazara/Renderer/RenderTarget.hpp +++ b/include/Nazara/Graphics/RenderTarget.hpp @@ -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 +#include #include -#include #include 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 +#include -#endif // NAZARA_RENDERER_RENDERTARGET_HPP +#endif // NAZARA_GRAPHICS_RENDERTARGET_HPP diff --git a/include/Nazara/Renderer/RenderTarget.inl b/include/Nazara/Graphics/RenderTarget.inl similarity index 54% rename from include/Nazara/Renderer/RenderTarget.inl rename to include/Nazara/Graphics/RenderTarget.inl index dbe08b351..c172f3461 100644 --- a/include/Nazara/Renderer/RenderTarget.inl +++ b/include/Nazara/Graphics/RenderTarget.inl @@ -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 +#include namespace Nz { } -#include +#include diff --git a/include/Nazara/Renderer/RenderTexture.hpp b/include/Nazara/Graphics/RenderTexture.hpp similarity index 62% rename from include/Nazara/Renderer/RenderTexture.hpp rename to include/Nazara/Graphics/RenderTexture.hpp index e697f7899..bf846caa7 100644 --- a/include/Nazara/Renderer/RenderTexture.hpp +++ b/include/Nazara/Graphics/RenderTexture.hpp @@ -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 -#include +#include +#include #include -#include namespace Nz { class Texture; - class NAZARA_RENDERER_API RenderTexture : public RenderTarget + class NAZARA_GRAPHICS_API RenderTexture : public RenderTarget { public: inline RenderTexture(std::shared_ptr 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 +#include -#endif // NAZARA_RENDERER_RENDERTEXTURE_HPP +#endif // NAZARA_GRAPHICS_RENDERTEXTURE_HPP diff --git a/include/Nazara/Renderer/RenderTexture.inl b/include/Nazara/Graphics/RenderTexture.inl similarity index 67% rename from include/Nazara/Renderer/RenderTexture.inl rename to include/Nazara/Graphics/RenderTexture.inl index e5796b327..03e0aea5c 100644 --- a/include/Nazara/Renderer/RenderTexture.inl +++ b/include/Nazara/Graphics/RenderTexture.inl @@ -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 -#include +#include namespace Nz { @@ -13,4 +12,4 @@ namespace Nz } } -#include +#include diff --git a/include/Nazara/Graphics/RenderWindow.hpp b/include/Nazara/Graphics/RenderWindow.hpp new file mode 100644 index 000000000..cd17dddc4 --- /dev/null +++ b/include/Nazara/Graphics/RenderWindow.hpp @@ -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 +#include +#include +#include + +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 + +#endif // NAZARA_GRAPHICS_RENDERWINDOW_HPP diff --git a/include/Nazara/Graphics/RenderWindow.inl b/include/Nazara/Graphics/RenderWindow.inl new file mode 100644 index 000000000..e19a67833 --- /dev/null +++ b/include/Nazara/Graphics/RenderWindow.inl @@ -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 + +namespace Nz +{ + inline RenderWindow::RenderWindow(Swapchain& swapchain) : + m_swapchain(&swapchain), + m_windowSwapchain(nullptr) + { + } +} + +#include diff --git a/include/Nazara/Renderer.hpp b/include/Nazara/Renderer.hpp index 7b48d7bf9..ce433de98 100644 --- a/include/Nazara/Renderer.hpp +++ b/include/Nazara/Renderer.hpp @@ -51,8 +51,6 @@ #include #include #include -#include -#include #include #include #include diff --git a/include/Nazara/Renderer/Swapchain.hpp b/include/Nazara/Renderer/Swapchain.hpp index e8c064800..e35df2e29 100644 --- a/include/Nazara/Renderer/Swapchain.hpp +++ b/include/Nazara/Renderer/Swapchain.hpp @@ -12,16 +12,17 @@ #include #include #include -#include +#include #include 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 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& attachments, std::vector& subpassDescriptions, std::vector& subpassDependencies); }; diff --git a/include/Nazara/Renderer/WindowSwapchain.hpp b/include/Nazara/Renderer/WindowSwapchain.hpp index dae809996..99755141b 100644 --- a/include/Nazara/Renderer/WindowSwapchain.hpp +++ b/include/Nazara/Renderer/WindowSwapchain.hpp @@ -9,28 +9,26 @@ #include #include -#include #include #include #include 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, 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(); diff --git a/include/Nazara/Renderer/WindowSwapchain.inl b/include/Nazara/Renderer/WindowSwapchain.inl index 4028b0fac..780b77cb1 100644 --- a/include/Nazara/Renderer/WindowSwapchain.inl +++ b/include/Nazara/Renderer/WindowSwapchain.inl @@ -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() diff --git a/src/Nazara/Graphics/AbstractViewer.cpp b/src/Nazara/Graphics/AbstractViewer.cpp index d7ab68bbb..075f3f82c 100644 --- a/src/Nazara/Graphics/AbstractViewer.cpp +++ b/src/Nazara/Graphics/AbstractViewer.cpp @@ -3,8 +3,8 @@ // For conditions of distribution and use, see copyright notice in Config.hpp #include +#include #include -#include #include namespace Nz diff --git a/src/Nazara/Graphics/Camera.cpp b/src/Nazara/Graphics/Camera.cpp index 471d7b2f5..23c0e8d24 100644 --- a/src/Nazara/Graphics/Camera.cpp +++ b/src/Nazara/Graphics/Camera.cpp @@ -11,8 +11,8 @@ namespace Nz { - Camera::Camera(const RenderTarget* renderTarget, ProjectionType projectionType) : - Camera(renderTarget, Graphics::Instance()->GetDefaultPipelinePasses(), projectionType) + Camera::Camera(std::shared_ptr 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 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*) diff --git a/src/Nazara/Graphics/ForwardFramePipeline.cpp b/src/Nazara/Graphics/ForwardFramePipeline.cpp index 5d368a651..70208ca48 100644 --- a/src/Nazara/Graphics/ForwardFramePipeline.cpp +++ b/src/Nazara/Graphics/ForwardFramePipeline.cpp @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -19,7 +20,6 @@ #include #include #include -#include #include #include #include @@ -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& 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; + using ViewerPair = std::pair; StackArray viewers = NazaraStackArray(ViewerPair, m_viewerPool.size()); auto viewerIt = viewers.begin(); @@ -718,9 +689,62 @@ namespace Nz return lhs.second->renderOrder < rhs.second->renderOrder; }); + StackVector 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); } } diff --git a/src/Nazara/Graphics/FrameGraph.cpp b/src/Nazara/Graphics/FrameGraph.cpp index 33a4b1852..840605319 100644 --- a/src/Nazara/Graphics/FrameGraph.cpp +++ b/src/Nazara/Graphics/FrameGraph.cpp @@ -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(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; @@ -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) @@ -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 diff --git a/src/Nazara/Renderer/RenderTarget.cpp b/src/Nazara/Graphics/RenderTarget.cpp similarity index 62% rename from src/Nazara/Renderer/RenderTarget.cpp rename to src/Nazara/Graphics/RenderTarget.cpp index 5072407c4..c92d45dc5 100644 --- a/src/Nazara/Renderer/RenderTarget.cpp +++ b/src/Nazara/Graphics/RenderTarget.cpp @@ -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 -#include +#include +#include namespace Nz { diff --git a/src/Nazara/Graphics/RenderTexture.cpp b/src/Nazara/Graphics/RenderTexture.cpp new file mode 100644 index 000000000..fcbfbf095 --- /dev/null +++ b/src/Nazara/Graphics/RenderTexture.cpp @@ -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 +#include +#include +#include +#include + +namespace Nz +{ + RenderTexture::RenderTexture(std::shared_ptr 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; + } +} diff --git a/src/Nazara/Graphics/RenderWindow.cpp b/src/Nazara/Graphics/RenderWindow.cpp new file mode 100644 index 000000000..740a29c05 --- /dev/null +++ b/src/Nazara/Graphics/RenderWindow.cpp @@ -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 +#include +#include +#include +#include +#include +#include +#include +#include + +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 = 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); + }); + } + } +} diff --git a/src/Nazara/OpenGLRenderer/OpenGLSwapchain.cpp b/src/Nazara/OpenGLRenderer/OpenGLSwapchain.cpp index f9f2ea6f7..0ff6b866b 100644 --- a/src/Nazara/OpenGLRenderer/OpenGLSwapchain.cpp +++ b/src/Nazara/OpenGLRenderer/OpenGLSwapchain.cpp @@ -132,7 +132,7 @@ namespace Nz void OpenGLSwapchain::NotifyResize(const Vector2ui& newSize) { - OnRenderTargetSizeChange(this, newSize); + OnSwapchainResize(this, newSize); m_size = newSize; m_sizeInvalidated = true; diff --git a/src/Nazara/Renderer/RenderTexture.cpp b/src/Nazara/Renderer/RenderTexture.cpp deleted file mode 100644 index 777535274..000000000 --- a/src/Nazara/Renderer/RenderTexture.cpp +++ /dev/null @@ -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 -#include -#include -#include - -namespace Nz -{ - RenderTexture::RenderTexture(std::shared_ptr 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; - } -} diff --git a/src/Nazara/Renderer/Swapchain.cpp b/src/Nazara/Renderer/Swapchain.cpp index dcee0347b..3526b0633 100644 --- a/src/Nazara/Renderer/Swapchain.cpp +++ b/src/Nazara/Renderer/Swapchain.cpp @@ -3,7 +3,6 @@ // For conditions of distribution and use, see copyright notice in Config.hpp #include -#include #include #include @@ -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& attachments, std::vector& subpassDescriptions, std::vector& subpassDependencies) { assert(colorFormat != PixelFormat::Undefined); diff --git a/src/Nazara/Renderer/WindowSwapchain.cpp b/src/Nazara/Renderer/WindowSwapchain.cpp index ae6417167..21b5bd225 100644 --- a/src/Nazara/Renderer/WindowSwapchain.cpp +++ b/src/Nazara/Renderer/WindowSwapchain.cpp @@ -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; }); diff --git a/src/Nazara/VulkanRenderer/VulkanSwapchain.cpp b/src/Nazara/VulkanRenderer/VulkanSwapchain.cpp index 717715709..3c349bdb9 100644 --- a/src/Nazara/VulkanRenderer/VulkanSwapchain.cpp +++ b/src/Nazara/VulkanRenderer/VulkanSwapchain.cpp @@ -326,7 +326,7 @@ namespace Nz void VulkanSwapchain::NotifyResize(const Vector2ui& newSize) { - OnRenderTargetSizeChange(this, newSize); + OnSwapchainResize(this, newSize); m_swapchainSize = newSize; m_shouldRecreateSwapchain = true; diff --git a/tests/GraphicsTest/main.cpp b/tests/GraphicsTest/main.cpp index 228c21bdc..95f3f1c51 100644 --- a/tests/GraphicsTest/main.cpp +++ b/tests/GraphicsTest/main.cpp @@ -76,7 +76,7 @@ int main() Nz::Vector2ui windowSize = window.GetSize(); - Nz::Camera camera(&windowSwapchain); + Nz::Camera camera(std::make_shared(windowSwapchain)); camera.UpdateClearColor(Nz::Color::Gray()); Nz::ViewerInstance& viewerInstance = camera.GetViewerInstance(); diff --git a/tests/PresentModeTest/main.cpp b/tests/PresentModeTest/main.cpp index da1061c23..13a3a1aa5 100644 --- a/tests/PresentModeTest/main.cpp +++ b/tests/PresentModeTest/main.cpp @@ -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(); - viewer.emplace(&windowSwapchain, Nz::ProjectionType::Orthographic); + viewer.emplace(std::make_shared(windowSwapchain), Nz::ProjectionType::Orthographic); } // Turn present mode flags into vector for easier processing Nz::FixedVector> 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)