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:
@@ -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
|
||||
|
||||
@@ -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*)
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
{
|
||||
35
src/Nazara/Graphics/RenderTexture.cpp
Normal file
35
src/Nazara/Graphics/RenderTexture.cpp
Normal 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;
|
||||
}
|
||||
}
|
||||
84
src/Nazara/Graphics/RenderWindow.cpp
Normal file
84
src/Nazara/Graphics/RenderWindow.cpp
Normal 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);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -132,7 +132,7 @@ namespace Nz
|
||||
|
||||
void OpenGLSwapchain::NotifyResize(const Vector2ui& newSize)
|
||||
{
|
||||
OnRenderTargetSizeChange(this, newSize);
|
||||
OnSwapchainResize(this, newSize);
|
||||
|
||||
m_size = newSize;
|
||||
m_sizeInvalidated = true;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
});
|
||||
|
||||
@@ -326,7 +326,7 @@ namespace Nz
|
||||
|
||||
void VulkanSwapchain::NotifyResize(const Vector2ui& newSize)
|
||||
{
|
||||
OnRenderTargetSizeChange(this, newSize);
|
||||
OnSwapchainResize(this, newSize);
|
||||
|
||||
m_swapchainSize = newSize;
|
||||
m_shouldRecreateSwapchain = true;
|
||||
|
||||
Reference in New Issue
Block a user