Graphics: Add support for multi-viewer rendering (a bit hacky)
This commit is contained in:
parent
342c053faa
commit
ecd1e43890
|
|
@ -789,7 +789,7 @@ int main()
|
||||||
bloomBlendPass.AddInput(bloomTextureB);
|
bloomBlendPass.AddInput(bloomTextureB);
|
||||||
bloomBlendPass.AddOutput(backbuffer);
|
bloomBlendPass.AddOutput(backbuffer);
|
||||||
|
|
||||||
graph.SetBackbufferOutput(backbuffer);
|
graph.AddBackbufferOutput(backbuffer);
|
||||||
|
|
||||||
return graph.Bake();
|
return graph.Bake();
|
||||||
}();
|
}();
|
||||||
|
|
|
||||||
|
|
@ -158,9 +158,12 @@ int main()
|
||||||
|
|
||||||
entt::entity text2D = registry.create();
|
entt::entity text2D = registry.create();
|
||||||
{
|
{
|
||||||
|
std::shared_ptr<Nz::TextSprite> sprite2D = std::make_shared<Nz::TextSprite>(spriteMaterial);
|
||||||
|
sprite2D->Update(Nz::SimpleTextDrawer::Draw("Voix ambiguë d'un cœur qui, au zéphyr, préfère les jattes de kiwis", 72));
|
||||||
|
|
||||||
registry.emplace<Nz::NodeComponent>(text2D).SetPosition(Nz::Vector3f(0.f, 200.f, 0.f));
|
registry.emplace<Nz::NodeComponent>(text2D).SetPosition(Nz::Vector3f(0.f, 200.f, 0.f));
|
||||||
auto& gfxComponent = registry.emplace<Nz::GraphicsComponent>(text2D);
|
auto& gfxComponent = registry.emplace<Nz::GraphicsComponent>(text2D);
|
||||||
gfxComponent.AttachRenderable(sprite, 2);
|
gfxComponent.AttachRenderable(sprite2D, 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
entt::entity viewer = registry.create();
|
entt::entity viewer = registry.create();
|
||||||
|
|
@ -254,7 +257,7 @@ int main()
|
||||||
Nz::Clock secondClock;
|
Nz::Clock secondClock;
|
||||||
unsigned int fps = 0;
|
unsigned int fps = 0;
|
||||||
|
|
||||||
//Nz::Mouse::SetRelativeMouseMode(true);
|
Nz::Mouse::SetRelativeMouseMode(true);
|
||||||
|
|
||||||
float elapsedTime = 0.f;
|
float elapsedTime = 0.f;
|
||||||
Nz::UInt64 time = Nz::GetElapsedMicroseconds();
|
Nz::UInt64 time = Nz::GetElapsedMicroseconds();
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,7 @@
|
||||||
namespace Nz
|
namespace Nz
|
||||||
{
|
{
|
||||||
class RenderFrame;
|
class RenderFrame;
|
||||||
|
class RenderTarget;
|
||||||
|
|
||||||
class NAZARA_GRAPHICS_API ForwardFramePipeline : public FramePipeline
|
class NAZARA_GRAPHICS_API ForwardFramePipeline : public FramePipeline
|
||||||
{
|
{
|
||||||
|
|
@ -99,6 +100,7 @@ namespace Nz
|
||||||
std::unordered_map<AbstractViewer*, ViewerData> m_viewers;
|
std::unordered_map<AbstractViewer*, ViewerData> m_viewers;
|
||||||
std::unordered_map<MaterialPass*, MaterialData> m_materials;
|
std::unordered_map<MaterialPass*, MaterialData> m_materials;
|
||||||
std::unordered_map<WorldInstancePtr, std::unordered_map<const InstancedRenderable*, RenderableData>> m_renderables;
|
std::unordered_map<WorldInstancePtr, std::unordered_map<const InstancedRenderable*, RenderableData>> m_renderables;
|
||||||
|
std::unordered_map<const RenderTarget*, std::vector<const ViewerData*>> m_viewerPerTarget;
|
||||||
std::unordered_set<AbstractViewer*> m_invalidatedViewerInstances;
|
std::unordered_set<AbstractViewer*> m_invalidatedViewerInstances;
|
||||||
std::unordered_set<MaterialPass*> m_invalidatedMaterials;
|
std::unordered_set<MaterialPass*> m_invalidatedMaterials;
|
||||||
std::unordered_set<WorldInstance*> m_invalidatedWorldInstances;
|
std::unordered_set<WorldInstance*> m_invalidatedWorldInstances;
|
||||||
|
|
|
||||||
|
|
@ -31,12 +31,11 @@ namespace Nz
|
||||||
~FrameGraph() = default;
|
~FrameGraph() = default;
|
||||||
|
|
||||||
inline std::size_t AddAttachment(FramePassAttachment attachment);
|
inline std::size_t AddAttachment(FramePassAttachment attachment);
|
||||||
|
inline void AddBackbufferOutput(std::size_t backbufferOutput);
|
||||||
inline FramePass& AddPass(std::string name);
|
inline FramePass& AddPass(std::string name);
|
||||||
|
|
||||||
BakedFrameGraph Bake();
|
BakedFrameGraph Bake();
|
||||||
|
|
||||||
inline void SetBackbufferOutput(std::size_t backbufferOutput);
|
|
||||||
|
|
||||||
FrameGraph& operator=(const FrameGraph&) = delete;
|
FrameGraph& operator=(const FrameGraph&) = delete;
|
||||||
FrameGraph& operator=(FrameGraph&&) noexcept = default;
|
FrameGraph& operator=(FrameGraph&&) noexcept = default;
|
||||||
|
|
||||||
|
|
@ -86,7 +85,6 @@ namespace Nz
|
||||||
|
|
||||||
struct WorkData
|
struct WorkData
|
||||||
{
|
{
|
||||||
std::size_t backbufferResourceIndex;
|
|
||||||
std::vector<std::shared_ptr<RenderPass>> renderPasses;
|
std::vector<std::shared_ptr<RenderPass>> renderPasses;
|
||||||
std::vector<PhysicalPassData> physicalPasses;
|
std::vector<PhysicalPassData> physicalPasses;
|
||||||
std::vector<TextureData> textures;
|
std::vector<TextureData> textures;
|
||||||
|
|
@ -109,7 +107,7 @@ namespace Nz
|
||||||
void ReorderPasses();
|
void ReorderPasses();
|
||||||
void TraverseGraph(std::size_t passIndex);
|
void TraverseGraph(std::size_t passIndex);
|
||||||
|
|
||||||
std::optional<std::size_t> m_backbufferOutput;
|
std::vector<std::size_t> m_backbufferOutputs;
|
||||||
std::vector<FramePass> m_framePasses;
|
std::vector<FramePass> m_framePasses;
|
||||||
std::vector<FramePassAttachment> m_attachments;
|
std::vector<FramePassAttachment> m_attachments;
|
||||||
WorkData m_pending;
|
WorkData m_pending;
|
||||||
|
|
|
||||||
|
|
@ -16,16 +16,16 @@ namespace Nz
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline void FrameGraph::AddBackbufferOutput(std::size_t backbufferOutput)
|
||||||
|
{
|
||||||
|
m_backbufferOutputs.push_back(backbufferOutput);
|
||||||
|
}
|
||||||
|
|
||||||
inline FramePass& FrameGraph::AddPass(std::string name)
|
inline FramePass& FrameGraph::AddPass(std::string name)
|
||||||
{
|
{
|
||||||
std::size_t id = m_framePasses.size();
|
std::size_t id = m_framePasses.size();
|
||||||
return m_framePasses.emplace_back(*this, id, std::move(name));
|
return m_framePasses.emplace_back(*this, id, std::move(name));
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void FrameGraph::SetBackbufferOutput(std::size_t backbufferOutput)
|
|
||||||
{
|
|
||||||
m_backbufferOutput = backbufferOutput;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#include <Nazara/Graphics/DebugOff.hpp>
|
#include <Nazara/Graphics/DebugOff.hpp>
|
||||||
|
|
|
||||||
|
|
@ -136,8 +136,6 @@ namespace Nz
|
||||||
// Update UBOs and materials
|
// Update UBOs and materials
|
||||||
UploadPool& uploadPool = renderFrame.GetUploadPool();
|
UploadPool& uploadPool = renderFrame.GetUploadPool();
|
||||||
|
|
||||||
bool prepare = false;
|
|
||||||
|
|
||||||
renderFrame.Execute([&](CommandBufferBuilder& builder)
|
renderFrame.Execute([&](CommandBufferBuilder& builder)
|
||||||
{
|
{
|
||||||
builder.BeginDebugRegion("UBO Update", Color::Yellow);
|
builder.BeginDebugRegion("UBO Update", Color::Yellow);
|
||||||
|
|
@ -336,6 +334,7 @@ namespace Nz
|
||||||
m_bakedFrameGraph.Execute(renderFrame);
|
m_bakedFrameGraph.Execute(renderFrame);
|
||||||
m_rebuildFrameGraph = false;
|
m_rebuildFrameGraph = false;
|
||||||
|
|
||||||
|
m_viewerPerTarget.clear();
|
||||||
const Vector2ui& frameSize = renderFrame.GetSize();
|
const Vector2ui& frameSize = renderFrame.GetSize();
|
||||||
for (auto&& [viewer, viewerData] : m_viewers)
|
for (auto&& [viewer, viewerData] : m_viewers)
|
||||||
{
|
{
|
||||||
|
|
@ -344,13 +343,25 @@ namespace Nz
|
||||||
viewerData.prepare = false;
|
viewerData.prepare = false;
|
||||||
|
|
||||||
const RenderTarget& renderTarget = viewer->GetRenderTarget();
|
const RenderTarget& renderTarget = viewer->GetRenderTarget();
|
||||||
|
|
||||||
|
m_viewerPerTarget[&renderTarget].push_back(&viewerData);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto&& [renderTargetPtr, viewerDataVec] : m_viewerPerTarget)
|
||||||
|
{
|
||||||
Recti renderRegion(0, 0, frameSize.x, frameSize.y);
|
Recti renderRegion(0, 0, frameSize.x, frameSize.y);
|
||||||
const ShaderBindingPtr& blitShaderBinding = viewerData.blitShaderBinding;
|
|
||||||
const std::shared_ptr<Texture>& sourceTexture = m_bakedFrameGraph.GetAttachmentTexture(viewerData.colorAttachment);
|
const RenderTarget& renderTarget = *renderTargetPtr;
|
||||||
|
const auto& viewers = viewerDataVec;
|
||||||
|
|
||||||
renderFrame.Execute([&](CommandBufferBuilder& builder)
|
renderFrame.Execute([&](CommandBufferBuilder& builder)
|
||||||
{
|
{
|
||||||
builder.TextureBarrier(PipelineStage::ColorOutput, PipelineStage::FragmentShader, MemoryAccess::ColorWrite, MemoryAccess::ShaderRead, TextureLayout::ColorOutput, TextureLayout::ColorInput, *sourceTexture);
|
for (const ViewerData* viewerData : viewers)
|
||||||
|
{
|
||||||
|
const std::shared_ptr<Texture>& sourceTexture = m_bakedFrameGraph.GetAttachmentTexture(viewerData->colorAttachment);
|
||||||
|
|
||||||
|
builder.TextureBarrier(PipelineStage::ColorOutput, PipelineStage::FragmentShader, MemoryAccess::ColorWrite, MemoryAccess::ShaderRead, TextureLayout::ColorOutput, TextureLayout::ColorInput, *sourceTexture);
|
||||||
|
}
|
||||||
|
|
||||||
std::array<CommandBufferBuilder::ClearValues, 2> clearValues;
|
std::array<CommandBufferBuilder::ClearValues, 2> clearValues;
|
||||||
clearValues[0].color = Color::Black;
|
clearValues[0].color = Color::Black;
|
||||||
|
|
@ -363,12 +374,16 @@ namespace Nz
|
||||||
{
|
{
|
||||||
builder.SetScissor(renderRegion);
|
builder.SetScissor(renderRegion);
|
||||||
builder.SetViewport(renderRegion);
|
builder.SetViewport(renderRegion);
|
||||||
|
|
||||||
builder.BindPipeline(*graphics->GetBlitPipeline());
|
builder.BindPipeline(*graphics->GetBlitPipeline());
|
||||||
builder.BindVertexBuffer(0, *graphics->GetFullscreenVertexBuffer());
|
builder.BindVertexBuffer(0, *graphics->GetFullscreenVertexBuffer());
|
||||||
builder.BindShaderBinding(0, *blitShaderBinding);
|
|
||||||
|
|
||||||
builder.Draw(3);
|
for (const ViewerData* viewerData : viewers)
|
||||||
|
{
|
||||||
|
const ShaderBindingPtr& blitShaderBinding = viewerData->blitShaderBinding;
|
||||||
|
|
||||||
|
builder.BindShaderBinding(0, *blitShaderBinding);
|
||||||
|
builder.Draw(3);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
builder.EndDebugRegion();
|
builder.EndDebugRegion();
|
||||||
}
|
}
|
||||||
|
|
@ -503,9 +518,8 @@ namespace Nz
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
//FIXME: This doesn't handle multiple window viewers
|
|
||||||
for (auto&& [viewer, viewerData] : m_viewers)
|
for (auto&& [viewer, viewerData] : m_viewers)
|
||||||
frameGraph.SetBackbufferOutput(viewerData.colorAttachment);
|
frameGraph.AddBackbufferOutput(viewerData.colorAttachment);
|
||||||
|
|
||||||
return frameGraph.Bake();
|
return frameGraph.Bake();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -33,7 +33,7 @@ namespace Nz
|
||||||
|
|
||||||
BakedFrameGraph FrameGraph::Bake()
|
BakedFrameGraph FrameGraph::Bake()
|
||||||
{
|
{
|
||||||
if (!m_backbufferOutput.has_value())
|
if (m_backbufferOutputs.empty())
|
||||||
throw std::runtime_error("no backbuffer output has been set");
|
throw std::runtime_error("no backbuffer output has been set");
|
||||||
|
|
||||||
m_pending.attachmentReadList.clear();
|
m_pending.attachmentReadList.clear();
|
||||||
|
|
@ -46,17 +46,18 @@ namespace Nz
|
||||||
m_pending.renderPasses.clear();
|
m_pending.renderPasses.clear();
|
||||||
m_pending.textures.clear();
|
m_pending.textures.clear();
|
||||||
|
|
||||||
m_pending.backbufferResourceIndex = m_backbufferOutput.value();
|
|
||||||
|
|
||||||
BuildReadWriteList();
|
BuildReadWriteList();
|
||||||
|
|
||||||
auto it = m_pending.attachmentWriteList.find(m_pending.backbufferResourceIndex);
|
for (std::size_t output : m_backbufferOutputs)
|
||||||
if (it == m_pending.attachmentWriteList.end())
|
{
|
||||||
throw std::runtime_error("no pass writes to backbuffer");
|
auto it = m_pending.attachmentWriteList.find(output);
|
||||||
|
if (it == m_pending.attachmentWriteList.end())
|
||||||
|
throw std::runtime_error("no pass writes to backbuffer");
|
||||||
|
|
||||||
const std::vector<std::size_t>& backbufferPasses = it->second;
|
const std::vector<std::size_t>& backbufferPasses = it->second;
|
||||||
for (std::size_t passIndex : backbufferPasses)
|
for (std::size_t passIndex : backbufferPasses)
|
||||||
TraverseGraph(passIndex);
|
TraverseGraph(passIndex);
|
||||||
|
}
|
||||||
|
|
||||||
std::reverse(m_pending.passList.begin(), m_pending.passList.end());
|
std::reverse(m_pending.passList.begin(), m_pending.passList.end());
|
||||||
|
|
||||||
|
|
@ -88,8 +89,22 @@ namespace Nz
|
||||||
bakedSubpass.commandCallback = framePass.GetCommandCallback();
|
bakedSubpass.commandCallback = framePass.GetCommandCallback();
|
||||||
|
|
||||||
for (const auto& output : framePass.GetOutputs())
|
for (const auto& output : framePass.GetOutputs())
|
||||||
|
{
|
||||||
bakedPass.outputTextureIndices.push_back(Retrieve(m_pending.attachmentToTextures, output.attachmentId));
|
bakedPass.outputTextureIndices.push_back(Retrieve(m_pending.attachmentToTextures, output.attachmentId));
|
||||||
|
|
||||||
|
auto& clearValues = bakedPass.outputClearValues.emplace_back();
|
||||||
|
if (output.clearColor)
|
||||||
|
clearValues.color = *output.clearColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add depth-stencil clear values
|
||||||
|
auto& dsClearValues = bakedPass.outputClearValues.emplace_back();
|
||||||
|
if (const auto& depthStencilClear = framePass.GetDepthStencilClear())
|
||||||
|
{
|
||||||
|
dsClearValues.depth = depthStencilClear->depth;
|
||||||
|
dsClearValues.stencil = depthStencilClear->stencil;
|
||||||
|
}
|
||||||
|
|
||||||
std::size_t attachmentId;
|
std::size_t attachmentId;
|
||||||
if (attachmentId = framePass.GetDepthStencilOutput(); attachmentId != FramePass::InvalidAttachmentId)
|
if (attachmentId = framePass.GetDepthStencilOutput(); attachmentId != FramePass::InvalidAttachmentId)
|
||||||
bakedPass.outputTextureIndices.push_back(Retrieve(m_pending.attachmentToTextures, attachmentId));
|
bakedPass.outputTextureIndices.push_back(Retrieve(m_pending.attachmentToTextures, attachmentId));
|
||||||
|
|
@ -228,12 +243,14 @@ namespace Nz
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add TextureUsage::Sampled to backbuffer output
|
// Add TextureUsage::Sampled to backbuffer output
|
||||||
|
for (std::size_t output : m_backbufferOutputs)
|
||||||
|
{
|
||||||
|
auto it = m_pending.attachmentToTextures.find(output);
|
||||||
|
assert(it != m_pending.attachmentToTextures.end());
|
||||||
|
|
||||||
auto it = m_pending.attachmentToTextures.find(m_pending.backbufferResourceIndex);
|
auto& backbufferTexture = m_pending.textures[it->second];
|
||||||
assert(it != m_pending.attachmentToTextures.end());
|
backbufferTexture.usage |= TextureUsage::ShaderSampling;
|
||||||
|
}
|
||||||
auto& backbufferTexture = m_pending.textures[it->second];
|
|
||||||
backbufferTexture.usage |= TextureUsage::ShaderSampling;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void FrameGraph::BuildBarriers()
|
void FrameGraph::BuildBarriers()
|
||||||
|
|
|
||||||
|
|
@ -163,6 +163,16 @@ namespace Nz
|
||||||
throw std::runtime_error("failed to instantiate blit shader");
|
throw std::runtime_error("failed to instantiate blit shader");
|
||||||
|
|
||||||
RenderPipelineInfo pipelineInfo;
|
RenderPipelineInfo pipelineInfo;
|
||||||
|
|
||||||
|
// Alpha blending
|
||||||
|
pipelineInfo.blending = true;
|
||||||
|
pipelineInfo.blend.modeColor = BlendEquation::Add;
|
||||||
|
pipelineInfo.blend.modeAlpha = BlendEquation::Add;
|
||||||
|
pipelineInfo.blend.srcColor = BlendFunc::One;
|
||||||
|
pipelineInfo.blend.dstColor = BlendFunc::One;
|
||||||
|
pipelineInfo.blend.srcAlpha = BlendFunc::One;
|
||||||
|
pipelineInfo.blend.dstAlpha = BlendFunc::One;
|
||||||
|
|
||||||
pipelineInfo.pipelineLayout = m_blitPipelineLayout;
|
pipelineInfo.pipelineLayout = m_blitPipelineLayout;
|
||||||
pipelineInfo.shaderModules.push_back(std::move(blitShader));
|
pipelineInfo.shaderModules.push_back(std::move(blitShader));
|
||||||
pipelineInfo.vertexBuffers.assign({
|
pipelineInfo.vertexBuffers.assign({
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue