Let the backend manage the shadowmap buffers

This commit is contained in:
Magnus Norddahl 2023-05-01 02:10:43 +02:00 committed by Christoph Oelckers
parent 930107636e
commit b413c80e49
11 changed files with 49 additions and 140 deletions

View file

@ -92,7 +92,7 @@ bool ShadowMap::ShadowTest(const DVector3 &lpos, const DVector3 &pos)
return true;
}
bool ShadowMap::PerformUpdate()
void ShadowMap::PerformUpdate()
{
UpdateCycles.Reset();
@ -103,55 +103,18 @@ bool ShadowMap::PerformUpdate()
if (CollectLights != nullptr)
{
UpdateCycles.Clock();
UploadAABBTree();
UploadLights();
return true;
}
return false;
}
void ShadowMap::UploadLights()
{
mLights.Resize(1024 * 4);
CollectLights();
mLights.Resize(1024 * 4);
CollectLights();
if (mLightList == nullptr)
mLightList = fb->CreateShadowmapLightsBuffer();
mLightList->SetData(sizeof(float) * mLights.Size(), &mLights[0], BufferUsageType::Stream);
}
void ShadowMap::UploadAABBTree()
{
if (mNewTree)
{
fb->SetShadowMaps(mLights, mAABBTree, mNewTree);
mNewTree = false;
if (!mNodesBuffer)
mNodesBuffer = fb->CreateShadowmapNodesBuffer();
mNodesBuffer->SetData(mAABBTree->NodesSize(), mAABBTree->Nodes(), BufferUsageType::Static);
if (!mLinesBuffer)
mLinesBuffer = fb->CreateShadowmapLinesBuffer();
mLinesBuffer->SetData(mAABBTree->LinesSize(), mAABBTree->Lines(), BufferUsageType::Static);
UpdateCycles.Unclock();
}
else if (mAABBTree->Update())
{
mNodesBuffer->SetSubData(mAABBTree->DynamicNodesOffset(), mAABBTree->DynamicNodesSize(), mAABBTree->DynamicNodes());
mLinesBuffer->SetSubData(mAABBTree->DynamicLinesOffset(), mAABBTree->DynamicLinesSize(), mAABBTree->DynamicLines());
}
}
void ShadowMap::Reset()
{
delete mLightList; mLightList = nullptr;
delete mNodesBuffer; mNodesBuffer = nullptr;
delete mLinesBuffer; mLinesBuffer = nullptr;
}
ShadowMap::~ShadowMap()
{
Reset();
}

View file

@ -17,8 +17,6 @@ public:
ShadowMap(DFrameBuffer* fb) : fb(fb) { }
virtual ~ShadowMap();
void Reset();
// Test if a world position is in shadow relative to the specified light and returns false if it is
bool ShadowTest(const DVector3 &lpos, const DVector3 &pos);
@ -26,11 +24,7 @@ public:
static int LightsProcessed;
static int LightsShadowmapped;
bool PerformUpdate();
void FinishUpdate()
{
UpdateCycles.Clock();
}
void PerformUpdate();
unsigned int NodesCount() const
{
@ -67,10 +61,6 @@ public:
}
protected:
// Upload the AABB-tree to the GPU
void UploadAABBTree();
void UploadLights();
// Working buffer for creating the list of lights. Stored here to avoid allocating memory each frame
TArray<float> mLights;
@ -81,15 +71,6 @@ protected:
ShadowMap(const ShadowMap &) = delete;
ShadowMap &operator=(ShadowMap &) = delete;
// OpenGL storage buffer with the list of lights in the shadow map texture
// These buffers need to be accessed by the OpenGL backend directly so that they can be bound.
public:
IBuffer* mLightList = nullptr;
// OpenGL storage buffers for the AABB tree
IBuffer* mNodesBuffer = nullptr;
IBuffer* mLinesBuffer = nullptr;
std::function<void()> CollectLights = nullptr;
};

View file

@ -157,10 +157,6 @@ public:
virtual bool IsVulkan() { return false; }
virtual bool IsPoly() { return false; }
virtual bool CompileNextShader() { return true; }
void SetAABBTree(hwrenderer::LevelAABBTree * tree)
{
mShadowMap->SetAABBTree(tree);
}
virtual void SetLevelMesh(hwrenderer::LevelMesh *mesh) { }
bool allowSSBO() const
{
@ -233,11 +229,6 @@ public:
virtual IBuffer* CreateIndexBuffer() { return nullptr; }
bool BuffersArePersistent() { return !!(hwcaps & RFL_BUFFER_STORAGE); }
// To do: these buffers shouldn't be created by the hwrenderer layer - it will be simpler if the backend manages them completely
virtual IBuffer* CreateShadowmapNodesBuffer() { return nullptr; }
virtual IBuffer* CreateShadowmapLinesBuffer() { return nullptr; }
virtual IBuffer* CreateShadowmapLightsBuffer() { return nullptr; }
// This is overridable in case Vulkan does it differently.
virtual bool RenderTextureIsFlipped() const
{
@ -252,7 +243,7 @@ public:
virtual void FirstEye() {}
virtual void NextEye(int eyecount) {}
virtual void SetSceneRenderTarget(bool useSSAO) {}
virtual void UpdateShadowMap() {}
virtual void SetShadowMaps(const TArray<float>& lights, hwrenderer::LevelAABBTree* tree, bool newTree) {}
virtual void WaitForCommands(bool finish) {}
virtual void SetSaveBuffers(bool yes) {}
virtual void ImageTransitionScene(bool unknown) {}

View file

@ -49,6 +49,10 @@ void VkBufferManager::Init()
Bonebuffer.SSO.reset(new VkHardwareDataBuffer(fb, true, false));
Bonebuffer.SSO->SetData(Bonebuffer.Count * sizeof(VSMatrix), nullptr, BufferUsageType::Persistent);
Shadowmap.Nodes.reset(new VkHardwareDataBuffer(fb, true, false));
Shadowmap.Lines.reset(new VkHardwareDataBuffer(fb, true, false));
Shadowmap.Lights.reset(new VkHardwareDataBuffer(fb, true, false));
CreateFanToTrisIndexBuffer();
}
@ -57,6 +61,9 @@ void VkBufferManager::Deinit()
Viewpoint.UBO.reset();
Lightbuffer.SSO.reset();
Bonebuffer.SSO.reset();
Shadowmap.Nodes.reset();
Shadowmap.Lines.reset();
Shadowmap.Lights.reset();
while (!Buffers.empty())
RemoveBuffer(Buffers.back());
@ -72,11 +79,6 @@ void VkBufferManager::RemoveBuffer(VkHardwareBuffer* buffer)
buffer->Reset();
buffer->fb = nullptr;
Buffers.erase(buffer->it);
for (VkHardwareDataBuffer** knownbuf : { &LightNodes, &LightLines, &LightList})
{
if (buffer == *knownbuf) *knownbuf = nullptr;
}
}
IBuffer* VkBufferManager::CreateVertexBuffer(int numBindingPoints, int numAttributes, size_t stride, const FVertexBufferAttribute* attrs)
@ -89,24 +91,6 @@ IBuffer* VkBufferManager::CreateIndexBuffer()
return new VkHardwareIndexBuffer(fb);
}
IBuffer* VkBufferManager::CreateShadowmapNodesBuffer()
{
LightNodes = new VkHardwareDataBuffer(fb, true, false);
return LightNodes;
}
IBuffer* VkBufferManager::CreateShadowmapLinesBuffer()
{
LightLines = new VkHardwareDataBuffer(fb, true, false);
return LightLines;
}
IBuffer* VkBufferManager::CreateShadowmapLightsBuffer()
{
LightList = new VkHardwareDataBuffer(fb, true, false);
return LightList;
}
void VkBufferManager::CreateFanToTrisIndexBuffer()
{
TArray<uint32_t> data;

View file

@ -24,10 +24,6 @@ public:
IBuffer* CreateVertexBuffer(int numBindingPoints, int numAttributes, size_t stride, const FVertexBufferAttribute* attrs);
IBuffer* CreateIndexBuffer();
IBuffer* CreateShadowmapNodesBuffer();
IBuffer* CreateShadowmapLinesBuffer();
IBuffer* CreateShadowmapLightsBuffer();
void AddBuffer(VkHardwareBuffer* buffer);
void RemoveBuffer(VkHardwareBuffer* buffer);
@ -53,9 +49,12 @@ public:
std::unique_ptr<VkHardwareDataBuffer> SSO;
} Bonebuffer;
VkHardwareDataBuffer* LightNodes = nullptr;
VkHardwareDataBuffer* LightLines = nullptr;
VkHardwareDataBuffer* LightList = nullptr;
struct
{
std::unique_ptr<VkHardwareDataBuffer> Nodes;
std::unique_ptr<VkHardwareDataBuffer> Lines;
std::unique_ptr<VkHardwareDataBuffer> Lights;
} Shadowmap;
std::unique_ptr<VkStreamBuffer> MatrixBuffer;
std::unique_ptr<VkStreamBuffer> StreamBuffer;

View file

@ -220,9 +220,9 @@ VulkanDescriptorSet* VkDescriptorSetManager::GetInput(VkPPRenderPassSetup* passS
if (bindShadowMapBuffers)
{
write.AddBuffer(descriptors.get(), 4, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, fb->GetBufferManager()->LightNodes->mBuffer.get());
write.AddBuffer(descriptors.get(), 5, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, fb->GetBufferManager()->LightLines->mBuffer.get());
write.AddBuffer(descriptors.get(), 6, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, fb->GetBufferManager()->LightList->mBuffer.get());
write.AddBuffer(descriptors.get(), 4, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, fb->GetBufferManager()->Shadowmap.Nodes->mBuffer.get());
write.AddBuffer(descriptors.get(), 5, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, fb->GetBufferManager()->Shadowmap.Lines->mBuffer.get());
write.AddBuffer(descriptors.get(), 6, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, fb->GetBufferManager()->Shadowmap.Lights->mBuffer.get());
}
write.Execute(fb->GetDevice());

View file

@ -275,17 +275,12 @@ void VkPostprocess::ClearTonemapPalette()
void VkPostprocess::UpdateShadowMap()
{
if (screen->mShadowMap->PerformUpdate())
{
VkPPRenderState renderstate(fb);
hw_postprocess.shadowmap.Update(&renderstate);
VkPPRenderState renderstate(fb);
hw_postprocess.shadowmap.Update(&renderstate);
VkImageTransition()
.AddImage(&fb->GetTextureManager()->Shadowmap, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, false)
.Execute(fb->GetCommands()->GetDrawCommands());
screen->mShadowMap->FinishUpdate();
}
VkImageTransition()
.AddImage(&fb->GetTextureManager()->Shadowmap, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, false)
.Execute(fb->GetCommands()->GetDrawCommands());
}
void VkPostprocess::NextEye(int eyeCount)

View file

@ -313,21 +313,6 @@ IBuffer*VulkanRenderDevice::CreateIndexBuffer()
return GetBufferManager()->CreateIndexBuffer();
}
IBuffer* VulkanRenderDevice::CreateShadowmapNodesBuffer()
{
return GetBufferManager()->CreateShadowmapNodesBuffer();
}
IBuffer* VulkanRenderDevice::CreateShadowmapLinesBuffer()
{
return GetBufferManager()->CreateShadowmapLinesBuffer();
}
IBuffer* VulkanRenderDevice::CreateShadowmapLightsBuffer()
{
return GetBufferManager()->CreateShadowmapLightsBuffer();
}
void VulkanRenderDevice::SetTextureFilterMode()
{
if (mSamplerManager)
@ -531,8 +516,23 @@ void VulkanRenderDevice::SetLevelMesh(hwrenderer::LevelMesh* mesh)
mRaytrace->SetLevelMesh(mesh);
}
void VulkanRenderDevice::UpdateShadowMap()
void VulkanRenderDevice::SetShadowMaps(const TArray<float>& lights, hwrenderer::LevelAABBTree* tree, bool newTree)
{
auto buffers = GetBufferManager();
buffers->Shadowmap.Lights->SetData(sizeof(float) * lights.Size(), lights.Data(), BufferUsageType::Stream);
if (newTree)
{
buffers->Shadowmap.Nodes->SetData(tree->NodesSize(), tree->Nodes(), BufferUsageType::Static);
buffers->Shadowmap.Lines->SetData(tree->LinesSize(), tree->Lines(), BufferUsageType::Static);
}
else if (tree->Update())
{
buffers->Shadowmap.Nodes->SetSubData(tree->DynamicNodesOffset(), tree->DynamicNodesSize(), tree->DynamicNodes());
buffers->Shadowmap.Lines->SetSubData(tree->DynamicLinesOffset(), tree->DynamicLinesSize(), tree->DynamicLines());
}
mPostprocess->UpdateShadowMap();
}

View file

@ -63,7 +63,7 @@ public:
void AmbientOccludeScene(float m5) override;
void SetSceneRenderTarget(bool useSSAO) override;
void SetLevelMesh(hwrenderer::LevelMesh* mesh) override;
void UpdateShadowMap() override;
void SetShadowMaps(const TArray<float>& lights, hwrenderer::LevelAABBTree* tree, bool newTree) override;
void SetSaveBuffers(bool yes) override;
void ImageTransitionScene(bool unknown) override;
void SetActiveRenderTarget() override;
@ -74,10 +74,6 @@ public:
IBuffer* CreateVertexBuffer(int numBindingPoints, int numAttributes, size_t stride, const FVertexBufferAttribute* attrs) override;
IBuffer* CreateIndexBuffer() override;
IBuffer* CreateShadowmapNodesBuffer() override;
IBuffer* CreateShadowmapLinesBuffer() override;
IBuffer* CreateShadowmapLightsBuffer() override;
FTexture *WipeStartScreen() override;
FTexture *WipeEndScreen() override;

View file

@ -376,7 +376,7 @@ void FLevelLocals::ClearLevelData(bool fullgc)
aabbTree = nullptr;
levelMesh = nullptr;
if (screen)
screen->SetAABBTree(nullptr);
screen->mShadowMap->SetAABBTree(nullptr);
}
//==========================================================================

View file

@ -110,16 +110,16 @@ sector_t* RenderViewpoint(FRenderViewpoint& mainvp, AActor* camera, IntRect* bou
if (mainview && toscreen && !(camera->Level->flags3 & LEVEL3_NOSHADOWMAP) && camera->Level->HasDynamicLights && gl_light_shadowmap && screen->allowSSBO() && (screen->hwcaps & RFL_SHADER_STORAGE_BUFFER))
{
screen->SetAABBTree(camera->Level->aabbTree);
screen->mShadowMap->SetAABBTree(camera->Level->aabbTree);
screen->mShadowMap->SetCollectLights([=] {
CollectLights(camera->Level);
});
screen->UpdateShadowMap();
screen->mShadowMap->PerformUpdate();
}
else
{
// null all references to the level if we do not need a shadowmap. This will shortcut all internal calculations without further checks.
screen->SetAABBTree(nullptr);
screen->mShadowMap->SetAABBTree(nullptr);
screen->mShadowMap->SetCollectLights(nullptr);
}