Graphics: Add RenderTexture class
This commit is contained in:
committed by
Jérôme Leclercq
parent
4f08d0b3c1
commit
aaf3d97954
@@ -153,6 +153,13 @@ namespace Nz
|
||||
texDimensions.y *= textureData.height;
|
||||
texDimensions /= 100'000;
|
||||
break;
|
||||
|
||||
case FramePassAttachmentSize::ViewerTargetFactor:
|
||||
texDimensions = viewerTargetSizes[textureData.viewerIndex];
|
||||
texDimensions.x *= textureData.width;
|
||||
texDimensions.y *= textureData.height;
|
||||
texDimensions /= 100'000;
|
||||
break;
|
||||
}
|
||||
|
||||
return texDimensions;
|
||||
|
||||
@@ -55,10 +55,10 @@ namespace Nz
|
||||
return m_viewport;
|
||||
}
|
||||
|
||||
std::size_t Camera::RegisterPasses(const std::vector<std::unique_ptr<FramePipelinePass>>& passes, FrameGraph& frameGraph, const FunctionRef<void(std::size_t passIndex, FramePass& framePass, FramePipelinePassFlags flags)>& passCallback) const
|
||||
std::size_t Camera::RegisterPasses(const std::vector<std::unique_ptr<FramePipelinePass>>& passes, FrameGraph& frameGraph, std::optional<unsigned int> viewerIndex, const FunctionRef<void(std::size_t passIndex, FramePass& framePass, FramePipelinePassFlags flags)>& passCallback) const
|
||||
{
|
||||
assert(m_framePipelinePasses);
|
||||
return m_framePipelinePasses->RegisterPasses(passes, frameGraph, passCallback);
|
||||
return m_framePipelinePasses->RegisterPasses(passes, frameGraph, viewerIndex, passCallback);
|
||||
}
|
||||
|
||||
void Camera::UpdateTarget(const RenderTarget* renderTarget)
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
#include <Nazara/Renderer/RenderTarget.hpp>
|
||||
#include <Nazara/Renderer/UploadPool.hpp>
|
||||
#include <NazaraUtils/StackArray.hpp>
|
||||
#include <NazaraUtils/StackVector.hpp>
|
||||
#include <array>
|
||||
#include <Nazara/Graphics/Debug.hpp>
|
||||
|
||||
@@ -368,16 +369,26 @@ namespace Nz
|
||||
}
|
||||
m_removedWorldInstances.Clear();
|
||||
|
||||
StackVector<Vector2ui> viewerSizes = NazaraStackVector(Vector2ui, m_viewerPool.size());
|
||||
for (auto& viewerData : m_viewerPool)
|
||||
{
|
||||
if (viewerData.pendingDestruction)
|
||||
continue;
|
||||
|
||||
Recti viewport = viewerData.viewer->GetViewport();
|
||||
viewerSizes.emplace_back(Vector2i(viewport.width, viewport.height));
|
||||
}
|
||||
|
||||
bool frameGraphInvalidated;
|
||||
if (m_rebuildFrameGraph)
|
||||
{
|
||||
renderFrame.PushForRelease(std::move(m_bakedFrameGraph));
|
||||
m_bakedFrameGraph = BuildFrameGraph(renderFrame);
|
||||
m_bakedFrameGraph.Resize(renderFrame);
|
||||
m_bakedFrameGraph.Resize(renderFrame, viewerSizes);
|
||||
frameGraphInvalidated = true;
|
||||
}
|
||||
else
|
||||
frameGraphInvalidated = m_bakedFrameGraph.Resize(renderFrame);
|
||||
frameGraphInvalidated = m_bakedFrameGraph.Resize(renderFrame, viewerSizes);
|
||||
|
||||
// Find active lights (i.e. visible in any frustum)
|
||||
m_activeLights.Clear();
|
||||
@@ -658,6 +669,7 @@ namespace Nz
|
||||
lightData->shadowData->RegisterToFrameGraph(frameGraph, nullptr);
|
||||
}
|
||||
|
||||
unsigned int viewerIndex = 0;
|
||||
for (auto& viewerData : m_viewerPool)
|
||||
{
|
||||
if (viewerData.pendingDestruction)
|
||||
@@ -684,7 +696,7 @@ namespace Nz
|
||||
}
|
||||
};
|
||||
|
||||
viewerData.finalColorAttachment = viewerData.viewer->RegisterPasses(viewerData.passes, frameGraph, framePassCallback);
|
||||
viewerData.finalColorAttachment = viewerData.viewer->RegisterPasses(viewerData.passes, frameGraph, viewerIndex++, framePassCallback);
|
||||
}
|
||||
|
||||
using ViewerPair = std::pair<const RenderTarget*, const ViewerData*>;
|
||||
@@ -760,14 +772,14 @@ namespace Nz
|
||||
}
|
||||
});
|
||||
|
||||
frameGraph.AddBackbufferOutput(renderTargetData.finalAttachment);
|
||||
frameGraph.MarkAsFinalOutput(renderTargetData.finalAttachment);
|
||||
}
|
||||
else if (targetViewers.size() == 1)
|
||||
{
|
||||
// Single viewer on that target
|
||||
const auto& viewer = *targetViewers.front();
|
||||
|
||||
frameGraph.AddBackbufferOutput(viewer.finalColorAttachment);
|
||||
frameGraph.MarkAsFinalOutput(viewer.finalColorAttachment);
|
||||
renderTargetData.finalAttachment = viewer.finalColorAttachment;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,7 +28,7 @@ namespace Nz
|
||||
|
||||
BakedFrameGraph FrameGraph::Bake()
|
||||
{
|
||||
if (m_backbufferOutputs.empty())
|
||||
if (m_finalOutputs.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_backbufferOutputs)
|
||||
for (std::size_t output : m_finalOutputs)
|
||||
{
|
||||
auto it = m_pending.attachmentWriteList.find(output);
|
||||
if (it == m_pending.attachmentWriteList.end())
|
||||
@@ -101,10 +101,7 @@ namespace Nz
|
||||
// Add depth-stencil clear values
|
||||
if (const auto& depthStencilClear = framePass.GetDepthStencilClear())
|
||||
{
|
||||
std::size_t depthClearIndex = colorOutputs.size();
|
||||
bakedPass.outputClearValues.resize(depthClearIndex + 1);
|
||||
|
||||
auto& dsClearValues = bakedPass.outputClearValues[depthClearIndex];
|
||||
auto& dsClearValues = bakedPass.outputClearDepthStencil.emplace();
|
||||
dsClearValues.depth = depthStencilClear->depth;
|
||||
dsClearValues.stencil = depthStencilClear->stencil;
|
||||
}
|
||||
@@ -261,36 +258,42 @@ namespace Nz
|
||||
if (std::holds_alternative<FramePassAttachment>(attachmentData))
|
||||
{
|
||||
std::size_t textureId = Retrieve(m_pending.attachmentToTextures, attachmentId);
|
||||
|
||||
assert(std::find(m_pending.texture2DPool.begin(), m_pending.texture2DPool.end(), textureId) == m_pending.texture2DPool.end());
|
||||
m_pending.texture2DPool.push_back(textureId);
|
||||
if (m_pending.textures[textureId].canReuse)
|
||||
{
|
||||
assert(std::find(m_pending.texture2DPool.begin(), m_pending.texture2DPool.end(), textureId) == m_pending.texture2DPool.end());
|
||||
m_pending.texture2DPool.push_back(textureId);
|
||||
}
|
||||
}
|
||||
else if (std::holds_alternative<AttachmentArray>(attachmentData))
|
||||
{
|
||||
std::size_t textureId = Retrieve(m_pending.attachmentToTextures, attachmentId);
|
||||
|
||||
assert(std::find(m_pending.textureCubePool.begin(), m_pending.textureCubePool.end(), textureId) == m_pending.textureCubePool.end());
|
||||
m_pending.texture2DArrayPool.push_back(textureId);
|
||||
if (m_pending.textures[textureId].canReuse)
|
||||
{
|
||||
assert(std::find(m_pending.textureCubePool.begin(), m_pending.textureCubePool.end(), textureId) == m_pending.textureCubePool.end());
|
||||
m_pending.texture2DArrayPool.push_back(textureId);
|
||||
}
|
||||
}
|
||||
else if (std::holds_alternative<AttachmentCube>(attachmentData))
|
||||
{
|
||||
std::size_t textureId = Retrieve(m_pending.attachmentToTextures, attachmentId);
|
||||
|
||||
assert(std::find(m_pending.textureCubePool.begin(), m_pending.textureCubePool.end(), textureId) == m_pending.textureCubePool.end());
|
||||
m_pending.textureCubePool.push_back(textureId);
|
||||
if (m_pending.textures[textureId].canReuse)
|
||||
{
|
||||
assert(std::find(m_pending.textureCubePool.begin(), m_pending.textureCubePool.end(), textureId) == m_pending.textureCubePool.end());
|
||||
m_pending.textureCubePool.push_back(textureId);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Add TextureUsage::ShaderSampling to backbuffer output
|
||||
for (std::size_t output : m_backbufferOutputs)
|
||||
// Add TextureUsage::ShaderSampling and TextureUsage::TransferSource to final outputs
|
||||
for (std::size_t output : m_finalOutputs)
|
||||
{
|
||||
auto it = m_pending.attachmentToTextures.find(output);
|
||||
assert(it != m_pending.attachmentToTextures.end());
|
||||
|
||||
auto& backbufferTexture = m_pending.textures[it->second];
|
||||
backbufferTexture.usage |= TextureUsage::ShaderSampling;
|
||||
auto& finalTexture = m_pending.textures[it->second];
|
||||
finalTexture.usage |= TextureUsage::ShaderSampling | TextureUsage::TransferSource;
|
||||
}
|
||||
|
||||
// Apply texture view usage to their parents
|
||||
@@ -1015,6 +1018,9 @@ namespace Nz
|
||||
data.size != attachmentData.size)
|
||||
continue;
|
||||
|
||||
if (data.size == FramePassAttachmentSize::ViewerTargetFactor && data.viewerIndex != attachmentData.viewerIndex)
|
||||
continue;
|
||||
|
||||
m_pending.texture2DPool.erase(it);
|
||||
m_pending.attachmentToTextures.emplace(attachmentIndex, textureId);
|
||||
|
||||
@@ -1035,7 +1041,19 @@ namespace Nz
|
||||
data.height = attachmentData.height;
|
||||
data.size = attachmentData.size;
|
||||
data.layerCount = 1;
|
||||
data.usage = attachmentData.additionalUsage;
|
||||
data.usage = attachmentData.additionalUsages;
|
||||
data.viewerIndex = attachmentData.viewerIndex;
|
||||
data.canReuse = true;
|
||||
|
||||
// Final outputs cannot be reused
|
||||
for (std::size_t outputAttachmentIndex : m_finalOutputs)
|
||||
{
|
||||
if (attachmentIndex == outputAttachmentIndex)
|
||||
{
|
||||
data.canReuse = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return textureId;
|
||||
}
|
||||
@@ -1058,6 +1076,9 @@ namespace Nz
|
||||
data.layerCount != attachmentData.layerCount)
|
||||
continue;
|
||||
|
||||
if (data.size == FramePassAttachmentSize::ViewerTargetFactor && data.viewerIndex != attachmentData.viewerIndex)
|
||||
continue;
|
||||
|
||||
m_pending.texture2DArrayPool.erase(it);
|
||||
m_pending.attachmentToTextures.emplace(attachmentIndex, textureId);
|
||||
|
||||
@@ -1078,7 +1099,19 @@ namespace Nz
|
||||
data.height = attachmentData.height;
|
||||
data.size = attachmentData.size;
|
||||
data.layerCount = attachmentData.layerCount;
|
||||
data.usage = attachmentData.additionalUsage;
|
||||
data.usage = attachmentData.additionalUsages;
|
||||
data.viewerIndex = attachmentData.viewerIndex;
|
||||
data.canReuse = true;
|
||||
|
||||
// Final outputs cannot be reused
|
||||
for (std::size_t outputAttachmentIndex : m_finalOutputs)
|
||||
{
|
||||
if (attachmentIndex == outputAttachmentIndex)
|
||||
{
|
||||
data.canReuse = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return textureId;
|
||||
}
|
||||
@@ -1100,6 +1133,9 @@ namespace Nz
|
||||
data.size != attachmentData.size)
|
||||
continue;
|
||||
|
||||
if (data.size == FramePassAttachmentSize::ViewerTargetFactor && data.viewerIndex != attachmentData.viewerIndex)
|
||||
continue;
|
||||
|
||||
m_pending.textureCubePool.erase(it);
|
||||
m_pending.attachmentToTextures.emplace(attachmentIndex, textureId);
|
||||
|
||||
@@ -1120,7 +1156,19 @@ namespace Nz
|
||||
data.height = attachmentData.height;
|
||||
data.size = attachmentData.size;
|
||||
data.layerCount = 1;
|
||||
data.usage = attachmentData.additionalUsage;
|
||||
data.usage = attachmentData.additionalUsages;
|
||||
data.viewerIndex = attachmentData.viewerIndex;
|
||||
data.canReuse = true;
|
||||
|
||||
// Final outputs cannot be reused
|
||||
for (std::size_t outputAttachmentIndex : m_finalOutputs)
|
||||
{
|
||||
if (attachmentIndex == outputAttachmentIndex)
|
||||
{
|
||||
data.canReuse = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return textureId;
|
||||
}
|
||||
@@ -1147,6 +1195,7 @@ namespace Nz
|
||||
parentTextureId,
|
||||
texLayer.layerIndex
|
||||
};
|
||||
data.viewerIndex = parentTexture.viewerIndex;
|
||||
|
||||
return textureId;
|
||||
}
|
||||
|
||||
@@ -27,7 +27,7 @@ namespace Nz
|
||||
return passes;
|
||||
}
|
||||
|
||||
std::size_t PipelinePassList::RegisterPasses(const std::vector<std::unique_ptr<FramePipelinePass>>& passes, FrameGraph& frameGraph, const FunctionRef<void(std::size_t passIndex, FramePass& framePass, FramePipelinePassFlags flags)>& passCallback) const
|
||||
std::size_t PipelinePassList::RegisterPasses(const std::vector<std::unique_ptr<FramePipelinePass>>& passes, FrameGraph& frameGraph, std::optional<unsigned int> viewerIndex, const FunctionRef<void(std::size_t passIndex, FramePass& framePass, FramePipelinePassFlags flags)>& passCallback) const
|
||||
{
|
||||
NazaraAssert(m_passes.size() == passes.size(), "pass vector size doesn't match passlist size");
|
||||
|
||||
@@ -47,7 +47,19 @@ namespace Nz
|
||||
{
|
||||
using T = std::decay_t<decltype(arg)>;
|
||||
if constexpr (std::is_same_v<T, FramePassAttachment>)
|
||||
return frameGraph.AddAttachment(arg);
|
||||
{
|
||||
if (arg.size == FramePassAttachmentSize::ViewerTargetFactor)
|
||||
{
|
||||
if (!viewerIndex)
|
||||
throw std::runtime_error(Format("no viewer index but attachment {} depends on viewer target size", arg.name));
|
||||
|
||||
FramePassAttachment attachment = arg;
|
||||
attachment.viewerIndex = *viewerIndex;
|
||||
return frameGraph.AddAttachment(attachment);
|
||||
}
|
||||
else
|
||||
return frameGraph.AddAttachment(arg);
|
||||
}
|
||||
else if constexpr (std::is_same_v<T, AttachmentProxy>)
|
||||
return frameGraph.AddAttachmentProxy(arg.name, GetAttachmentIndex(arg.attachmentIndex));
|
||||
else
|
||||
|
||||
45
src/Nazara/Renderer/RenderTexture.cpp
Normal file
45
src/Nazara/Renderer/RenderTexture.cpp
Normal file
@@ -0,0 +1,45 @@
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
@@ -30,21 +30,6 @@ namespace Nz
|
||||
ConnectSignals();
|
||||
}
|
||||
|
||||
const Framebuffer& WindowSwapchain::GetFramebuffer(std::size_t i) const
|
||||
{
|
||||
return m_swapchain->GetFramebuffer(i);
|
||||
}
|
||||
|
||||
std::size_t WindowSwapchain::GetFramebufferCount() const
|
||||
{
|
||||
return m_swapchain->GetFramebufferCount();
|
||||
}
|
||||
|
||||
const RenderPass& WindowSwapchain::GetRenderPass() const
|
||||
{
|
||||
return m_swapchain->GetRenderPass();
|
||||
}
|
||||
|
||||
const Vector2ui& WindowSwapchain::GetSize() const
|
||||
{
|
||||
return (m_swapchain) ? m_swapchain->GetSize() : m_window->GetSize();
|
||||
|
||||
Reference in New Issue
Block a user