Skip to content
Permalink
Browse files

- implement shadow maps

  • Loading branch information...
dpjudas committed Mar 15, 2019
1 parent 8369384 commit cce96ca87a5b2e5f88542a5c939568c4d55b7898
@@ -91,6 +91,7 @@ OpenGLFrameBuffer::~OpenGLFrameBuffer()
if (mSkyData != nullptr) delete mSkyData;
if (mViewpoints != nullptr) delete mViewpoints;
if (mLights != nullptr) delete mLights;
mShadowMap.Reset();

if (GLRenderer)
{
@@ -8,7 +8,10 @@ enum
{
LIGHTBUF_BINDINGPOINT = 1,
POSTPROCESS_BINDINGPOINT = 2,
VIEWPOINT_BINDINGPOINT = 3
VIEWPOINT_BINDINGPOINT = 3,
LIGHTNODES_BINDINGPOINT = 4,
LIGHTLINES_BINDINGPOINT = 5,
LIGHTLIST_BINDINGPOINT = 6
};

enum class UniformType
@@ -24,6 +24,7 @@
#include "hwrenderer/utility/hw_cvars.h"
#include "hwrenderer/dynlights/hw_dynlightdata.h"
#include "hwrenderer/data/buffers.h"
#include "hwrenderer/data/shaderuniforms.h"
#include "stats.h"
#include "g_levellocals.h"
#include "v_video.h"
@@ -188,7 +189,7 @@ void IShadowMap::UploadLights()
CollectLights();

if (mLightList == nullptr)
mLightList = screen->CreateDataBuffer(4, true);
mLightList = screen->CreateDataBuffer(LIGHTLIST_BINDINGPOINT, true);

mLightList->SetData(sizeof(float) * mLights.Size(), &mLights[0]);
}
@@ -199,11 +200,11 @@ void IShadowMap::UploadAABBTree()
if (!ValidateAABBTree(&level))
{
if (!mNodesBuffer)
mNodesBuffer = screen->CreateDataBuffer(2, true);
mNodesBuffer = screen->CreateDataBuffer(LIGHTNODES_BINDINGPOINT, true);
mNodesBuffer->SetData(mAABBTree->NodesSize(), mAABBTree->Nodes());

if (!mLinesBuffer)
mLinesBuffer = screen->CreateDataBuffer(3, true);
mLinesBuffer = screen->CreateDataBuffer(LIGHTLINES_BINDINGPOINT, true);
mLinesBuffer->SetData(mAABBTree->LinesSize(), mAABBTree->Lines());
}
else if (mAABBTree->Update())
@@ -213,10 +214,15 @@ void IShadowMap::UploadAABBTree()
}
}

void IShadowMap::Reset()
{
delete mLightList; mLightList = nullptr;
delete mNodesBuffer; mNodesBuffer = nullptr;
delete mLinesBuffer; mLinesBuffer = nullptr;
}

IShadowMap::~IShadowMap()
{
if (mLightList) delete mLightList;
if (mNodesBuffer) delete mNodesBuffer;
if (mLinesBuffer) delete mLinesBuffer;
Reset();
}

@@ -16,6 +16,8 @@ class IShadowMap
IShadowMap() { }
virtual ~IShadowMap();

void Reset();

// Test if a world position is in shadow relative to the specified light and returns false if it is
bool ShadowTest(FDynamicLight *light, const DVector3 &pos);

@@ -17,6 +17,7 @@ Postprocess::Postprocess()
Managers.Push(new PPTonemap());
Managers.Push(new PPAmbientOcclusion());
Managers.Push(new PPPresent());
Managers.Push(new PPShadowMap());
}

Postprocess::~Postprocess()
@@ -892,3 +893,32 @@ void PPPresent::UpdateTextures()
void PPPresent::UpdateSteps()
{
}

/////////////////////////////////////////////////////////////////////////////

void PPShadowMap::DeclareShaders()
{
hw_postprocess.Shaders["ShadowMap"] = { "shaders/glsl/shadowmap.fp", "", ShadowMapUniforms::Desc() };
}

void PPShadowMap::UpdateTextures()
{
}

void PPShadowMap::UpdateSteps()
{
ShadowMapUniforms uniforms;
uniforms.ShadowmapQuality = (float)gl_shadowmap_quality;

PPStep step;
step.ShaderName = "ShadowMap";
step.Uniforms.Set(uniforms);
step.Viewport = { 0, 0, gl_shadowmap_quality, 1024 };
step.SetShadowMapBuffers(true);
step.SetOutputShadowMap();
step.SetNoBlend();

TArray<PPStep> steps;
steps.Push(step);
hw_postprocess.Effects["UpdateShadowMap"] = steps;
}
@@ -11,7 +11,7 @@ typedef IntRect PPViewport;

enum class PPFilterMode { Nearest, Linear };
enum class PPWrapMode { Clamp, Repeat };
enum class PPTextureType { CurrentPipelineTexture, NextPipelineTexture, PPTexture, SceneColor, SceneFog, SceneNormal, SceneDepth, SwapChain };
enum class PPTextureType { CurrentPipelineTexture, NextPipelineTexture, PPTexture, SceneColor, SceneFog, SceneNormal, SceneDepth, SwapChain, ShadowMap };

class PPTextureInput
{
@@ -120,6 +120,11 @@ class PPStep
tex.Texture = "";
}

void SetShadowMapBuffers(bool enable)
{
ShadowMapBuffers = enable;
}

void SetOutputTexture(PPTextureName texture)
{
Output.Type = PPTextureType::PPTexture;
@@ -150,6 +155,12 @@ class PPStep
Output.Texture = "";
}

void SetOutputShadowMap()
{
Output.Type = PPTextureType::ShadowMap;
Output.Texture = "";
}

void SetNoBlend()
{
BlendMode.BlendOp = STYLEOP_Add;
@@ -180,6 +191,7 @@ class PPStep
PPViewport Viewport;
PPBlendMode BlendMode;
PPOutput Output;
bool ShadowMapBuffers = false;
};

enum class PixelFormat
@@ -658,3 +670,11 @@ struct ShadowMapUniforms
};
}
};

class PPShadowMap : public PPEffectManager
{
public:
void DeclareShaders() override;
void UpdateTextures() override;
void UpdateSteps() override;
};
@@ -225,6 +225,23 @@ void VkPostprocess::ClearTonemapPalette()
hw_postprocess.Textures.Remove("Tonemap.Palette");
}

void VkPostprocess::UpdateShadowMap()
{
if (screen->mShadowMap.PerformUpdate())
{
RenderEffect("UpdateShadowMap");

auto fb = GetVulkanFrameBuffer();
auto buffers = fb->GetBuffers();

VkPPImageTransition imageTransition;
imageTransition.addImage(buffers->Shadowmap.get(), &buffers->ShadowmapLayout, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, false);
imageTransition.execute(fb->GetDrawCommands());

screen->mShadowMap.FinishUpdate();
}
}

void VkPostprocess::BeginFrame()
{
mFrameDescriptorSets.clear();
@@ -233,6 +250,7 @@ void VkPostprocess::BeginFrame()
{
DescriptorPoolBuilder builder;
builder.addPoolSize(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 100);
builder.addPoolSize(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 4);
builder.setMaxSets(100);
mDescriptorPool = builder.create(GetVulkanFrameBuffer()->device);
mDescriptorPool->SetDebugName("VkPostprocess.mDescriptorPool");
@@ -405,10 +423,13 @@ void VkPostprocess::RenderEffect(const FString &name)
key.Uniforms = step.Uniforms.Data.Size();
key.Shader = mShaders[step.ShaderName].get();
key.SwapChain = (step.Output.Type == PPTextureType::SwapChain);
key.ShadowMapBuffers = step.ShadowMapBuffers;
if (step.Output.Type == PPTextureType::PPTexture)
key.OutputFormat = mTextures[step.Output.Texture]->Format;
else if (step.Output.Type == PPTextureType::SwapChain)
key.OutputFormat = GetVulkanFrameBuffer()->swapChain->swapChainFormat.format;
else if (step.Output.Type == PPTextureType::ShadowMap)
key.OutputFormat = VK_FORMAT_R32_SFLOAT;
else
key.OutputFormat = VK_FORMAT_R16G16B16A16_SFLOAT;

@@ -417,7 +438,7 @@ void VkPostprocess::RenderEffect(const FString &name)
passSetup.reset(new VkPPRenderPassSetup(key));

int framebufferWidth = 0, framebufferHeight = 0;
VulkanDescriptorSet *input = GetInput(passSetup.get(), step.Textures);
VulkanDescriptorSet *input = GetInput(passSetup.get(), step.Textures, step.ShadowMapBuffers);
VulkanFramebuffer *output = GetOutput(passSetup.get(), step.Output, framebufferWidth, framebufferHeight);

RenderScreenQuad(passSetup.get(), input, output, framebufferWidth, framebufferHeight, step.Viewport.left, step.Viewport.top, step.Viewport.width, step.Viewport.height, step.Uniforms.Data.Data(), step.Uniforms.Data.Size());
@@ -470,7 +491,7 @@ void VkPostprocess::RenderScreenQuad(VkPPRenderPassSetup *passSetup, VulkanDescr
cmdbuffer->endRenderPass();
}

VulkanDescriptorSet *VkPostprocess::GetInput(VkPPRenderPassSetup *passSetup, const TArray<PPTextureInput> &textures)
VulkanDescriptorSet *VkPostprocess::GetInput(VkPPRenderPassSetup *passSetup, const TArray<PPTextureInput> &textures, bool bindShadowMapBuffers)
{
auto fb = GetVulkanFrameBuffer();
auto descriptors = mDescriptorPool->allocate(passSetup->DescriptorLayout.get());
@@ -489,6 +510,13 @@ VulkanDescriptorSet *VkPostprocess::GetInput(VkPPRenderPassSetup *passSetup, con
imageTransition.addImage(tex.image, tex.layout, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, false);
}

if (bindShadowMapBuffers)
{
write.addBuffer(descriptors.get(), LIGHTNODES_BINDINGPOINT, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, fb->LightNodes->mBuffer.get());
write.addBuffer(descriptors.get(), LIGHTLINES_BINDINGPOINT, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, fb->LightLines->mBuffer.get());
write.addBuffer(descriptors.get(), LIGHTLIST_BINDINGPOINT, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, fb->LightList->mBuffer.get());
}

write.updateSets(fb->device);
imageTransition.execute(fb->GetDrawCommands());

@@ -588,6 +616,13 @@ VkPostprocess::TextureImage VkPostprocess::GetTexture(const PPTextureType &type,
tex.layout = &fb->GetBuffers()->SceneDepthStencilLayout;
tex.debugname = "SceneDepth";
}
else if (type == PPTextureType::ShadowMap)
{
tex.image = fb->GetBuffers()->Shadowmap.get();
tex.view = fb->GetBuffers()->ShadowmapView.get();
tex.layout = &fb->GetBuffers()->ShadowmapLayout;
tex.debugname = "Shadowmap";
}
else if (type == PPTextureType::SwapChain)
{
tex.image = nullptr;
@@ -639,6 +674,12 @@ void VkPPRenderPassSetup::CreateDescriptorLayout(const VkPPRenderPassKey &key)
DescriptorSetLayoutBuilder builder;
for (int i = 0; i < key.InputTextures; i++)
builder.addBinding(i, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT);
if (key.ShadowMapBuffers)
{
builder.addBinding(LIGHTNODES_BINDINGPOINT, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_FRAGMENT_BIT);
builder.addBinding(LIGHTLINES_BINDINGPOINT, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_FRAGMENT_BIT);
builder.addBinding(LIGHTLIST_BINDINGPOINT, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_FRAGMENT_BIT);
}
DescriptorLayout = builder.create(GetVulkanFrameBuffer()->device);
DescriptorLayout->SetDebugName("VkPPRenderPassSetup.DescriptorLayout");
}
@@ -25,6 +25,7 @@ class VkPPRenderPassKey
PPBlendMode BlendMode;
VkFormat OutputFormat;
int SwapChain;
int ShadowMapBuffers;

bool operator<(const VkPPRenderPassKey &other) const { return memcmp(this, &other, sizeof(VkPPRenderPassKey)) < 0; }
bool operator==(const VkPPRenderPassKey &other) const { return memcmp(this, &other, sizeof(VkPPRenderPassKey)) == 0; }
@@ -60,6 +61,8 @@ class VkPostprocess
void BlurScene(float gameinfobluramount);
void ClearTonemapPalette();

void UpdateShadowMap();

void BlitSceneToTexture();
void BlitCurrentToImage(VulkanImage *image, VkImageLayout *layout, VkImageLayout finallayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
void DrawPresentTexture(const IntRect &box, bool applyGamma, bool clearBorders);
@@ -72,7 +75,7 @@ class VkPostprocess
void NextEye(int eyeCount);
void RenderScreenQuad(VkPPRenderPassSetup *passSetup, VulkanDescriptorSet *descriptorSet, VulkanFramebuffer *framebuffer, int framebufferWidth, int framebufferHeight, int x, int y, int width, int height, const void *pushConstants, uint32_t pushConstantsSize);

VulkanDescriptorSet *GetInput(VkPPRenderPassSetup *passSetup, const TArray<PPTextureInput> &textures);
VulkanDescriptorSet *GetInput(VkPPRenderPassSetup *passSetup, const TArray<PPTextureInput> &textures, bool bindShadowMapBuffers);
VulkanFramebuffer *GetOutput(VkPPRenderPassSetup *passSetup, const PPOutput &output, int &framebufferWidth, int &framebufferHeight);
VulkanSampler *GetSampler(PPFilterMode filter, PPWrapMode wrap);

@@ -55,6 +55,8 @@ void VkRenderBuffers::BeginFrame(int width, int height, int sceneWidth, int scen
if (width != mWidth || height != mHeight || mSamples != samples)
CreateScene(width, height, samples);

CreateShadowmap();

mWidth = width;
mHeight = height;
mSamples = samples;
@@ -206,3 +208,41 @@ void VkRenderBuffers::CreateSceneNormal(int width, int height, VkSampleCountFlag
SceneNormalView = viewbuilder.create(fb->device);
SceneNormalView->SetDebugName("VkRenderBuffers.SceneNormalView");
}

void VkRenderBuffers::CreateShadowmap()
{
if (Shadowmap && Shadowmap->width == gl_shadowmap_quality)
return;

Shadowmap.reset();
ShadowmapView.reset();

auto fb = GetVulkanFrameBuffer();

ImageBuilder builder;
builder.setSize(gl_shadowmap_quality, 1024);
builder.setFormat(VK_FORMAT_R32_SFLOAT);
builder.setUsage(VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT);
Shadowmap = builder.create(fb->device);
Shadowmap->SetDebugName("VkRenderBuffers.Shadowmap");

ImageViewBuilder viewbuilder;
viewbuilder.setImage(Shadowmap.get(), VK_FORMAT_R32_SFLOAT);
ShadowmapView = viewbuilder.create(fb->device);
ShadowmapView->SetDebugName("VkRenderBuffers.ShadowmapView");

PipelineBarrier barrier;
barrier.addImage(Shadowmap.get(), VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, 0, VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT);
barrier.execute(fb->GetDrawCommands(), VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT);

if (!ShadowmapSampler)
{
SamplerBuilder builder;
builder.setMipmapMode(VK_SAMPLER_MIPMAP_MODE_NEAREST);
builder.setMinFilter(VK_FILTER_NEAREST);
builder.setMagFilter(VK_FILTER_NEAREST);
builder.setAddressMode(VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE);
ShadowmapSampler = builder.create(fb->device);
ShadowmapSampler->SetDebugName("VkRenderBuffers.ShadowmapSampler");
}
}
@@ -37,13 +37,19 @@ class VkRenderBuffers
std::unique_ptr<VulkanImageView> PipelineView[NumPipelineImages];
VkImageLayout PipelineLayout[NumPipelineImages];

std::unique_ptr<VulkanImage> Shadowmap;
std::unique_ptr<VulkanImageView> ShadowmapView;
std::unique_ptr<VulkanSampler> ShadowmapSampler;
VkImageLayout ShadowmapLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;

private:
void CreatePipeline(int width, int height);
void CreateScene(int width, int height, VkSampleCountFlagBits samples);
void CreateSceneColor(int width, int height, VkSampleCountFlagBits samples);
void CreateSceneDepthStencil(int width, int height, VkSampleCountFlagBits samples);
void CreateSceneFog(int width, int height, VkSampleCountFlagBits samples);
void CreateSceneNormal(int width, int height, VkSampleCountFlagBits samples);
void CreateShadowmap();
VkSampleCountFlagBits GetBestSampleCount();

int mWidth = 0;
Oops, something went wrong.

0 comments on commit cce96ca

Please sign in to comment.
You can’t perform that action at this time.