- convert PPStep to PPRenderState

This commit is contained in:
Magnus Norddahl 2019-03-15 23:24:31 +01:00
parent cce96ca87a
commit 05f0730c9d
10 changed files with 988 additions and 999 deletions

View file

@ -64,26 +64,22 @@ void FGLRenderer::RenderScreenQuad()
void FGLRenderer::PostProcessScene(int fixedcm, const std::function<void()> &afterBloomDrawEndScene2D)
{
hw_postprocess.fixedcm = fixedcm;
hw_postprocess.SceneWidth = mBuffers->GetSceneWidth();
hw_postprocess.SceneHeight = mBuffers->GetSceneHeight();
int sceneWidth = mBuffers->GetSceneWidth();
int sceneHeight = mBuffers->GetSceneHeight();
hw_postprocess.DeclareShaders();
hw_postprocess.UpdateTextures();
hw_postprocess.UpdateSteps();
GLPPRenderState renderstate(mBuffers);
mBuffers->CompileEffectShaders();
mBuffers->UpdateEffectTextures();
mBuffers->RenderEffect("UpdateCameraExposure");
hw_postprocess.exposure.Render(&renderstate, sceneWidth, sceneHeight);
mCustomPostProcessShaders->Run("beforebloom");
mBuffers->RenderEffect("BloomScene");
hw_postprocess.bloom.RenderBloom(&renderstate, sceneWidth, sceneHeight, fixedcm);
mBuffers->BindCurrentFB();
afterBloomDrawEndScene2D();
mBuffers->RenderEffect("TonemapScene");
mBuffers->RenderEffect("ColormapScene");
mBuffers->RenderEffect("LensDistortScene");
mBuffers->RenderEffect("ApplyFXAA");
hw_postprocess.tonemap.Render(&renderstate);
hw_postprocess.colormap.Render(&renderstate, fixedcm);
hw_postprocess.lens.Render(&renderstate);
hw_postprocess.fxaa.Render(&renderstate);
mCustomPostProcessShaders->Run("scene");
}
@ -95,43 +91,32 @@ void FGLRenderer::PostProcessScene(int fixedcm, const std::function<void()> &aft
void FGLRenderer::AmbientOccludeScene(float m5)
{
hw_postprocess.SceneWidth = mBuffers->GetSceneWidth();
hw_postprocess.SceneHeight = mBuffers->GetSceneHeight();
hw_postprocess.m5 = m5;
int sceneWidth = mBuffers->GetSceneWidth();
int sceneHeight = mBuffers->GetSceneHeight();
hw_postprocess.DeclareShaders();
hw_postprocess.UpdateTextures();
hw_postprocess.UpdateSteps();
mBuffers->CompileEffectShaders();
mBuffers->UpdateEffectTextures();
mBuffers->RenderEffect("AmbientOccludeScene");
GLPPRenderState renderstate(mBuffers);
hw_postprocess.ssao.Render(&renderstate, m5, sceneWidth, sceneHeight);
}
void FGLRenderer::BlurScene(float gameinfobluramount)
{
hw_postprocess.gameinfobluramount = gameinfobluramount;
int sceneWidth = mBuffers->GetSceneWidth();
int sceneHeight = mBuffers->GetSceneHeight();
hw_postprocess.DeclareShaders();
hw_postprocess.UpdateTextures();
hw_postprocess.UpdateSteps();
mBuffers->CompileEffectShaders();
mBuffers->UpdateEffectTextures();
GLPPRenderState renderstate(mBuffers);
auto vrmode = VRMode::GetVRMode(true);
int eyeCount = vrmode->mEyeCount;
for (int i = 0; i < eyeCount; ++i)
{
mBuffers->RenderEffect("BlurScene");
hw_postprocess.bloom.RenderBlur(&renderstate, sceneWidth, sceneHeight, gameinfobluramount);
if (eyeCount - i > 1) mBuffers->NextEye(eyeCount);
}
}
void FGLRenderer::ClearTonemapPalette()
{
hw_postprocess.Textures.Remove("Tonemap.Palette");
hw_postprocess.tonemap.ClearTonemapPalette();
}
//-----------------------------------------------------------------------------

View file

@ -792,19 +792,16 @@ bool FGLRenderBuffers::FailedCreate = false;
//
//==========================================================================
void FGLRenderBuffers::UpdateEffectTextures()
PPGLTextureBackend *GLPPRenderState::GetGLTexture(PPTexture *texture)
{
FGLPostProcessState savedState;
TMap<FString, PPTextureDesc>::Iterator it(hw_postprocess.Textures);
TMap<FString, PPTextureDesc>::Pair *pair;
while (it.NextPair(pair))
if (!texture->Backend)
{
auto &gltexture = GLTextures[pair->Key];
auto &glframebuffer = GLTextureFBs[pair->Key];
FGLPostProcessState savedState;
auto backend = std::make_unique<PPGLTextureBackend>();
int glformat;
switch (pair->Value.Format)
switch (texture->Format)
{
default:
case PixelFormat::Rgba8: glformat = GL_RGBA8; break;
@ -814,28 +811,14 @@ void FGLRenderBuffers::UpdateEffectTextures()
case PixelFormat::Rgba16_snorm: glformat = GL_RGBA16_SNORM; break;
}
if (gltexture && (gltexture.Width != pair->Value.Width || gltexture.Height != pair->Value.Height))
{
if (gltexture.handle != 0)
{
glDeleteTextures(1, &gltexture.handle);
gltexture.handle = 0;
}
if (glframebuffer.handle != 0)
{
glDeleteFramebuffers(1, &glframebuffer.handle);
glframebuffer.handle = 0;
}
}
if (texture->Data)
backend->Tex = buffers->Create2DTexture("PPTexture", glformat, texture->Width, texture->Height, texture->Data.get());
else
backend->Tex = buffers->Create2DTexture("PPTexture", glformat, texture->Width, texture->Height);
if (!gltexture)
{
if (pair->Value.Data)
gltexture = Create2DTexture(pair->Key.GetChars(), glformat, pair->Value.Width, pair->Value.Height, pair->Value.Data.get());
else
gltexture = Create2DTexture(pair->Key.GetChars(), glformat, pair->Value.Width, pair->Value.Height);
}
texture->Backend = std::move(backend);
}
return static_cast<PPGLTextureBackend*>(texture->Backend.get());
}
//==========================================================================
@ -844,30 +827,26 @@ void FGLRenderBuffers::UpdateEffectTextures()
//
//==========================================================================
void FGLRenderBuffers::CompileEffectShaders()
FShaderProgram *GLPPRenderState::GetGLShader(PPShader *shader)
{
TMap<FString, PPShader>::Iterator it(hw_postprocess.Shaders);
TMap<FString, PPShader>::Pair *pair;
while (it.NextPair(pair))
if (!shader->Backend)
{
const auto &desc = pair->Value;
auto &glshader = GLShaders[pair->Key];
if (!glshader)
{
glshader = std::make_unique<FShaderProgram>();
auto glshader = std::make_unique<FShaderProgram>();
FString prolog;
if (!desc.Uniforms.empty())
prolog = UniformBlockDecl::Create("Uniforms", desc.Uniforms, POSTPROCESS_BINDINGPOINT);
prolog += desc.Defines;
FString prolog;
if (!shader->Uniforms.empty())
prolog = UniformBlockDecl::Create("Uniforms", shader->Uniforms, POSTPROCESS_BINDINGPOINT);
prolog += shader->Defines;
glshader->Compile(FShaderProgram::Vertex, desc.VertexShader, "", desc.Version);
glshader->Compile(FShaderProgram::Fragment, desc.FragmentShader, prolog, desc.Version);
glshader->Link(pair->Key.GetChars());
if (!desc.Uniforms.empty())
glshader->SetUniformBufferLocation(POSTPROCESS_BINDINGPOINT, "Uniforms");
}
glshader->Compile(FShaderProgram::Vertex, shader->VertexShader, "", shader->Version);
glshader->Compile(FShaderProgram::Fragment, shader->FragmentShader, prolog, shader->Version);
glshader->Link(shader->FragmentShader.GetChars());
if (!shader->Uniforms.empty())
glshader->SetUniformBufferLocation(POSTPROCESS_BINDINGPOINT, "Uniforms");
shader->Backend = std::move(glshader);
}
return static_cast<FShaderProgram*>(shader->Backend.get());
}
//==========================================================================
@ -876,130 +855,124 @@ void FGLRenderBuffers::CompileEffectShaders()
//
//==========================================================================
void FGLRenderBuffers::RenderEffect(const FString &name)
void GLPPRenderState::Draw()
{
if (hw_postprocess.Effects[name].Size() == 0)
return;
FGLDebug::PushGroup(name.GetChars());
//FGLDebug::PushGroup(name.GetChars());
FGLPostProcessState savedState;
for (const PPStep &step : hw_postprocess.Effects[name])
// Bind input textures
for (unsigned int index = 0; index < Textures.Size(); index++)
{
// Bind input textures
for (unsigned int index = 0; index < step.Textures.Size(); index++)
{
savedState.SaveTextureBindings(index + 1);
savedState.SaveTextureBindings(index + 1);
const PPTextureInput &input = step.Textures[index];
int filter = (input.Filter == PPFilterMode::Nearest) ? GL_NEAREST : GL_LINEAR;
int wrap = (input.Wrap == PPWrapMode::Clamp) ? GL_CLAMP : GL_REPEAT;
const PPTextureInput &input = Textures[index];
int filter = (input.Filter == PPFilterMode::Nearest) ? GL_NEAREST : GL_LINEAR;
int wrap = (input.Wrap == PPWrapMode::Clamp) ? GL_CLAMP : GL_REPEAT;
switch (input.Type)
{
default:
case PPTextureType::CurrentPipelineTexture:
BindCurrentTexture(index, filter, wrap);
break;
case PPTextureType::NextPipelineTexture:
I_FatalError("PPTextureType::NextPipelineTexture not allowed as input\n");
break;
case PPTextureType::PPTexture:
GLTextures[input.Texture].Bind(index, filter, wrap);
break;
case PPTextureType::SceneColor:
BindSceneColorTexture(index);
break;
case PPTextureType::SceneFog:
BindSceneFogTexture(index);
break;
case PPTextureType::SceneNormal:
BindSceneNormalTexture(index);
break;
case PPTextureType::SceneDepth:
BindSceneDepthTexture(index);
break;
}
}
// Set render target
switch (step.Output.Type)
switch (input.Type)
{
default:
I_FatalError("Unsupported postprocess output type\n");
break;
case PPTextureType::CurrentPipelineTexture:
BindCurrentFB();
buffers->BindCurrentTexture(index, filter, wrap);
break;
case PPTextureType::NextPipelineTexture:
BindNextFB();
I_FatalError("PPTextureType::NextPipelineTexture not allowed as input\n");
break;
case PPTextureType::PPTexture:
if (GLTextureFBs[step.Output.Texture])
GLTextureFBs[step.Output.Texture].Bind();
else
GLTextureFBs[step.Output.Texture] = CreateFrameBuffer(step.Output.Texture.GetChars(), GLTextures[step.Output.Texture]);
GetGLTexture(input.Texture)->Tex.Bind(index, filter, wrap);
break;
case PPTextureType::SceneColor:
BindSceneFB(false);
buffers->BindSceneColorTexture(index);
break;
case PPTextureType::SceneFog:
buffers->BindSceneFogTexture(index);
break;
case PPTextureType::SceneNormal:
buffers->BindSceneNormalTexture(index);
break;
case PPTextureType::SceneDepth:
buffers->BindSceneDepthTexture(index);
break;
}
// Set blend mode
if (step.BlendMode.BlendOp == STYLEOP_Add && step.BlendMode.SrcAlpha == STYLEALPHA_One && step.BlendMode.DestAlpha == STYLEALPHA_Zero && step.BlendMode.Flags == 0)
{
glDisable(GL_BLEND);
}
else
{
// To do: support all the modes
glEnable(GL_BLEND);
glBlendEquation(GL_FUNC_ADD);
if (step.BlendMode.SrcAlpha == STYLEALPHA_One && step.BlendMode.DestAlpha == STYLEALPHA_One)
glBlendFunc(GL_ONE, GL_ONE);
else
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
}
// Setup viewport
glViewport(step.Viewport.left, step.Viewport.top, step.Viewport.width, step.Viewport.height);
auto &shader = GLShaders[step.ShaderName];
// Set uniforms
if (step.Uniforms.Data.Size() > 0)
{
if (!shader->Uniforms)
shader->Uniforms.reset(screen->CreateDataBuffer(POSTPROCESS_BINDINGPOINT, false));
shader->Uniforms->SetData(step.Uniforms.Data.Size(), step.Uniforms.Data.Data());
shader->Uniforms->BindBase();
}
// Set shader
shader->Bind();
// Draw the screen quad
GLRenderer->RenderScreenQuad();
// Advance to next PP texture if our output was sent there
if (step.Output.Type == PPTextureType::NextPipelineTexture)
NextTexture();
}
// Set render target
switch (Output.Type)
{
default:
I_FatalError("Unsupported postprocess output type\n");
break;
case PPTextureType::CurrentPipelineTexture:
buffers->BindCurrentFB();
break;
case PPTextureType::NextPipelineTexture:
buffers->BindNextFB();
break;
case PPTextureType::PPTexture:
if (GetGLTexture(Output.Texture)->FB)
GetGLTexture(Output.Texture)->FB.Bind();
else
GetGLTexture(Output.Texture)->FB = buffers->CreateFrameBuffer("PPTextureFB"/*Output.Texture.GetChars()*/, GetGLTexture(Output.Texture)->Tex);
break;
case PPTextureType::SceneColor:
buffers->BindSceneFB(false);
break;
}
// Set blend mode
if (BlendMode.BlendOp == STYLEOP_Add && BlendMode.SrcAlpha == STYLEALPHA_One && BlendMode.DestAlpha == STYLEALPHA_Zero && BlendMode.Flags == 0)
{
glDisable(GL_BLEND);
}
else
{
// To do: support all the modes
glEnable(GL_BLEND);
glBlendEquation(GL_FUNC_ADD);
if (BlendMode.SrcAlpha == STYLEALPHA_One && BlendMode.DestAlpha == STYLEALPHA_One)
glBlendFunc(GL_ONE, GL_ONE);
else
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
}
// Setup viewport
glViewport(Viewport.left, Viewport.top, Viewport.width, Viewport.height);
auto shader = GetGLShader(Shader);
// Set uniforms
if (Uniforms.Data.Size() > 0)
{
if (!shader->Uniforms)
shader->Uniforms.reset(screen->CreateDataBuffer(POSTPROCESS_BINDINGPOINT, false));
shader->Uniforms->SetData(Uniforms.Data.Size(), Uniforms.Data.Data());
shader->Uniforms->BindBase();
}
// Set shader
shader->Bind();
// Draw the screen quad
GLRenderer->RenderScreenQuad();
// Advance to next PP texture if our output was sent there
if (Output.Type == PPTextureType::NextPipelineTexture)
buffers->NextTexture();
glViewport(screen->mScreenViewport.left, screen->mScreenViewport.top, screen->mScreenViewport.width, screen->mScreenViewport.height);
FGLDebug::PopGroup();
//FGLDebug::PopGroup();
}

View file

@ -29,6 +29,7 @@ private:
GLuint handle = 0;
friend class FGLRenderBuffers;
friend class PPGLTextureBackend;
};
class PPGLFrameBuffer
@ -45,6 +46,7 @@ private:
GLuint handle = 0;
friend class FGLRenderBuffers;
friend class PPGLTextureBackend;
};
class PPGLRenderBuffer
@ -57,8 +59,42 @@ private:
friend class FGLRenderBuffers;
};
class PPGLTextureBackend : public PPTextureBackend
{
public:
~PPGLTextureBackend()
{
if (Tex.handle != 0)
{
glDeleteTextures(1, &Tex.handle);
Tex.handle = 0;
}
if (FB.handle != 0)
{
glDeleteFramebuffers(1, &FB.handle);
FB.handle = 0;
}
}
PPGLTexture Tex;
PPGLFrameBuffer FB;
};
class FShaderProgram;
class GLPPRenderState : public PPRenderState
{
public:
GLPPRenderState(FGLRenderBuffers *buffers) : buffers(buffers) { }
void Draw() override;
private:
PPGLTextureBackend *GetGLTexture(PPTexture *texture);
FShaderProgram *GetGLShader(PPShader *shader);
FGLRenderBuffers *buffers;
};
class FGLRenderBuffers
{
public:
@ -67,10 +103,6 @@ public:
void Setup(int width, int height, int sceneWidth, int sceneHeight);
void UpdateEffectTextures();
void CompileEffectShaders();
void RenderEffect(const FString &name);
void BindSceneFB(bool sceneData);
void BindSceneColorTexture(int index);
void BindSceneFogTexture(int index);
@ -167,12 +199,9 @@ private:
PPGLTexture mDitherTexture;
// Postprocess OpenGL objects
TMap<PPTextureName, PPGLTexture> GLTextures;
TMap<PPTextureName, PPGLFrameBuffer> GLTextureFBs;
TMap<PPShaderName, std::shared_ptr<FShaderProgram>> GLShaders;
static bool FailedCreate;
friend class GLPPRenderState;
};
}

View file

@ -8,7 +8,7 @@
namespace OpenGLRenderer
{
class FShaderProgram
class FShaderProgram : public PPShaderBackend
{
public:
FShaderProgram();

View file

@ -87,6 +87,8 @@ OpenGLFrameBuffer::OpenGLFrameBuffer(void *hMonitor, bool fullscreen) :
OpenGLFrameBuffer::~OpenGLFrameBuffer()
{
PPResource::ResetAll();
if (mVertexData != nullptr) delete mVertexData;
if (mSkyData != nullptr) delete mSkyData;
if (mViewpoints != nullptr) delete mViewpoints;

File diff suppressed because it is too large Load diff

View file

@ -3,12 +3,12 @@
#include "hwrenderer/data/shaderuniforms.h"
#include <memory>
typedef FString PPTextureName;
typedef FString PPShaderName;
typedef FRenderStyle PPBlendMode;
typedef IntRect PPViewport;
class PPTexture;
class PPShader;
enum class PPFilterMode { Nearest, Linear };
enum class PPWrapMode { Clamp, Repeat };
enum class PPTextureType { CurrentPipelineTexture, NextPipelineTexture, PPTexture, SceneColor, SceneFog, SceneNormal, SceneDepth, SwapChain, ShadowMap };
@ -16,17 +16,17 @@ enum class PPTextureType { CurrentPipelineTexture, NextPipelineTexture, PPTextur
class PPTextureInput
{
public:
PPFilterMode Filter;
PPWrapMode Wrap;
PPTextureType Type;
PPTextureName Texture;
PPFilterMode Filter = PPFilterMode::Nearest;
PPWrapMode Wrap = PPWrapMode::Clamp;
PPTextureType Type = PPTextureType::CurrentPipelineTexture;
PPTexture *Texture = nullptr;
};
class PPOutput
{
public:
PPTextureType Type;
PPTextureName Texture;
PPTextureType Type = PPTextureType::NextPipelineTexture;
PPTexture *Texture = nullptr;
};
class PPUniforms
@ -70,10 +70,25 @@ public:
TArray<uint8_t> Data;
};
class PPStep
class PPRenderState
{
public:
void SetInputTexture(int index, PPTextureName texture, PPFilterMode filter = PPFilterMode::Nearest, PPWrapMode wrap = PPWrapMode::Clamp)
virtual ~PPRenderState() = default;
virtual void Draw() = 0;
void Clear()
{
Shader = nullptr;
Textures = TArray<PPTextureInput>();
Uniforms = PPUniforms();
Viewport = PPViewport();
BlendMode = PPBlendMode();
Output = PPOutput();
ShadowMapBuffers = false;
}
void SetInputTexture(int index, PPTexture *texture, PPFilterMode filter = PPFilterMode::Nearest, PPWrapMode wrap = PPWrapMode::Clamp)
{
if ((int)Textures.Size() < index + 1)
Textures.Resize(index + 1);
@ -117,7 +132,7 @@ public:
tex.Filter = filter;
tex.Wrap = wrap;
tex.Type = type;
tex.Texture = "";
tex.Texture = nullptr;
}
void SetShadowMapBuffers(bool enable)
@ -125,7 +140,7 @@ public:
ShadowMapBuffers = enable;
}
void SetOutputTexture(PPTextureName texture)
void SetOutputTexture(PPTexture *texture)
{
Output.Type = PPTextureType::PPTexture;
Output.Texture = texture;
@ -134,31 +149,31 @@ public:
void SetOutputCurrent()
{
Output.Type = PPTextureType::CurrentPipelineTexture;
Output.Texture = "";
Output.Texture = nullptr;
}
void SetOutputNext()
{
Output.Type = PPTextureType::NextPipelineTexture;
Output.Texture = "";
Output.Texture = nullptr;
}
void SetOutputSceneColor()
{
Output.Type = PPTextureType::SceneColor;
Output.Texture = "";
Output.Texture = nullptr;
}
void SetOutputSwapChain()
{
Output.Type = PPTextureType::SwapChain;
Output.Texture = "";
Output.Texture = nullptr;
}
void SetOutputShadowMap()
{
Output.Type = PPTextureType::ShadowMap;
Output.Texture = "";
Output.Texture = nullptr;
}
void SetNoBlend()
@ -185,7 +200,7 @@ public:
BlendMode.Flags = 0;
}
PPShaderName ShaderName;
PPShader *Shader;
TArray<PPTextureInput> Textures;
PPUniforms Uniforms;
PPViewport Viewport;
@ -203,65 +218,94 @@ enum class PixelFormat
Rgba16_snorm
};
class PPTextureDesc
class PPResource
{
public:
PPTextureDesc() { }
PPTextureDesc(int width, int height, PixelFormat format, std::shared_ptr<void> data = {}) : Width(width), Height(height), Format(format), Data(data) { }
PPResource()
{
Next = First;
First = this;
if (Next) Next->Prev = this;
}
PPResource(const PPResource &)
{
Next = First;
First = this;
if (Next) Next->Prev = this;
}
~PPResource()
{
if (Next) Next->Prev = Prev;
if (Prev) Prev->Next = Next;
else First = Next;
}
PPResource &operator=(const PPResource &other)
{
return *this;
}
static void ResetAll()
{
for (PPResource *cur = First; cur; cur = cur->Next)
cur->ResetBackend();
}
virtual void ResetBackend() = 0;
private:
static PPResource *First;
PPResource *Prev = nullptr;
PPResource *Next = nullptr;
};
class PPTextureBackend
{
public:
virtual ~PPTextureBackend() = default;
};
class PPTexture : public PPResource
{
public:
PPTexture() = default;
PPTexture(int width, int height, PixelFormat format, std::shared_ptr<void> data = {}) : Width(width), Height(height), Format(format), Data(data) { }
void ResetBackend() override { Backend.reset(); }
int Width;
int Height;
PixelFormat Format;
std::shared_ptr<void> Data;
std::unique_ptr<PPTextureBackend> Backend;
};
class PPShader
class PPShaderBackend
{
public:
virtual ~PPShaderBackend() = default;
};
class PPShader : public PPResource
{
public:
PPShader() { }
PPShader(const FString &fragment, const FString &defines, const std::vector<UniformFieldDesc> &uniforms, int version = 330) : FragmentShader(fragment), Defines(defines), Uniforms(uniforms), Version(version) { }
void ResetBackend() override { Backend.reset(); }
FString VertexShader = "shaders/glsl/screenquad.vp";
FString FragmentShader;
FString Defines;
std::vector<UniformFieldDesc> Uniforms;
int Version = 330;
std::unique_ptr<PPShaderBackend> Backend;
};
class PPEffectManager
{
public:
virtual ~PPEffectManager() { }
virtual void DeclareShaders() { }
virtual void UpdateTextures() { }
virtual void UpdateSteps() { }
};
class Postprocess
{
public:
Postprocess();
~Postprocess();
void DeclareShaders() { for (unsigned int i = 0; i < Managers.Size(); i++) Managers[i]->DeclareShaders(); }
void UpdateTextures() { for (unsigned int i = 0; i < Managers.Size(); i++) Managers[i]->UpdateTextures(); }
void UpdateSteps() { for (unsigned int i = 0; i < Managers.Size(); i++) Managers[i]->UpdateSteps(); }
int SceneWidth = 0;
int SceneHeight = 0;
int fixedcm = 0;
float gameinfobluramount = 0.0f;
float m5 = 0.0f;
TMap<FString, TArray<PPStep>> Effects;
TMap<FString, PPTextureDesc> Textures;
TMap<FString, PPShader> Shaders;
TArray<PPEffectManager*> Managers;
};
extern Postprocess hw_postprocess;
/////////////////////////////////////////////////////////////////////////////
struct ExtractUniforms
@ -305,26 +349,31 @@ class PPBlurLevel
{
public:
PPViewport Viewport;
PPTextureName VTexture;
PPTextureName HTexture;
PPTexture VTexture;
PPTexture HTexture;
};
class PPBloom : public PPEffectManager
class PPBloom
{
public:
void DeclareShaders() override;
void UpdateTextures() override;
void UpdateSteps() override;
void RenderBloom(PPRenderState *renderstate, int sceneWidth, int sceneHeight, int fixedcm);
void RenderBlur(PPRenderState *renderstate, int sceneWidth, int sceneHeight, float gameinfobluramount);
private:
void UpdateBlurSteps();
PPStep BlurStep(const BlurUniforms &blurUniforms, PPTextureName input, PPTextureName output, PPViewport viewport, bool vertical);
void BlurStep(PPRenderState *renderstate, const BlurUniforms &blurUniforms, PPTexture &input, PPTexture &output, PPViewport viewport, bool vertical);
void UpdateTextures(int width, int height);
static float ComputeBlurGaussian(float n, float theta);
static void ComputeBlurSamples(int sampleCount, float blurAmount, float *sampleWeights);
PPBlurLevel levels[NumBloomLevels];
int lastWidth = 0;
int lastHeight = 0;
PPShader BloomCombine = { "shaders/glsl/bloomcombine.fp", "", {} };
PPShader BloomExtract = { "shaders/glsl/bloomextract.fp", "", ExtractUniforms::Desc() };
PPShader BlurVertical = { "shaders/glsl/blur.fp", "#define BLUR_VERTICAL\n", BlurUniforms::Desc() };
PPShader BlurHorizontal = { "shaders/glsl/blur.fp", "#define BLUR_HORIZONTAL\n", BlurUniforms::Desc() };
};
/////////////////////////////////////////////////////////////////////////////
@ -351,11 +400,13 @@ struct LensUniforms
}
};
class PPLensDistort : public PPEffectManager
class PPLensDistort
{
public:
void DeclareShaders() override;
void UpdateSteps() override;
void Render(PPRenderState *renderstate);
private:
PPShader Lens = { "shaders/glsl/lensdistortion.fp", "", LensUniforms::Desc() };
};
/////////////////////////////////////////////////////////////////////////////
@ -376,15 +427,19 @@ struct FXAAUniforms
}
};
class PPFXAA : public PPEffectManager
class PPFXAA
{
public:
void DeclareShaders() override;
void UpdateSteps() override;
void Render(PPRenderState *renderstate);
private:
void CreateShaders();
int GetMaxVersion();
FString GetDefines();
PPShader FXAALuma;
PPShader FXAA;
int LastQuality = -1;
};
/////////////////////////////////////////////////////////////////////////////
@ -427,19 +482,25 @@ class PPExposureLevel
{
public:
PPViewport Viewport;
PPTextureName Texture;
PPTexture Texture;
};
class PPCameraExposure : public PPEffectManager
class PPCameraExposure
{
public:
void DeclareShaders() override;
void UpdateTextures() override;
void UpdateSteps() override;
void Render(PPRenderState *renderstate, int sceneWidth, int sceneHeight);
PPTexture CameraTexture = { 1, 1, PixelFormat::R32f };
private:
TArray<PPExposureLevel> ExposureLevels;
void UpdateTextures(int width, int height);
std::vector<PPExposureLevel> ExposureLevels;
bool FirstExposureFrame = true;
PPShader ExposureExtract = { "shaders/glsl/exposureextract.fp", "", ExposureExtractUniforms::Desc() };
PPShader ExposureAverage = { "shaders/glsl/exposureaverage.fp", "", {}, 400 };
PPShader ExposureCombine = { "shaders/glsl/exposurecombine.fp", "", ExposureCombineUniforms::Desc() };
};
/////////////////////////////////////////////////////////////////////////////
@ -459,21 +520,33 @@ struct ColormapUniforms
}
};
class PPColormap : public PPEffectManager
class PPColormap
{
public:
void DeclareShaders() override;
void UpdateSteps() override;
void Render(PPRenderState *renderstate, int fixedcm);
private:
PPShader Colormap = { "shaders/glsl/colormap.fp", "", ColormapUniforms::Desc() };
};
/////////////////////////////////////////////////////////////////////////////
class PPTonemap : public PPEffectManager
class PPTonemap
{
public:
void DeclareShaders() override;
void UpdateTextures() override;
void UpdateSteps() override;
void Render(PPRenderState *renderstate);
void ClearTonemapPalette() { PaletteTexture = {}; }
private:
void UpdateTextures();
PPTexture PaletteTexture;
PPShader LinearShader = { "shaders/glsl/tonemap.fp", "#define LINEAR\n", {} };
PPShader ReinhardShader = { "shaders/glsl/tonemap.fp", "#define REINHARD\n", {} };
PPShader HejlDawsonShader = { "shaders/glsl/tonemap.fp", "#define HEJLDAWSON\n", {} };
PPShader Uncharted2Shader = { "shaders/glsl/tonemap.fp", "#define UNCHARTED2\n", {} };
PPShader PaletteShader = { "shaders/glsl/tonemap.fp", "#define PALETTE\n", {} };
enum TonemapMode
{
@ -592,14 +665,16 @@ struct AmbientCombineUniforms
}
};
class PPAmbientOcclusion : public PPEffectManager
class PPAmbientOcclusion
{
public:
void DeclareShaders() override;
void UpdateTextures() override;
void UpdateSteps() override;
PPAmbientOcclusion();
void Render(PPRenderState *renderstate, float m5, int sceneWidth, int sceneHeight);
private:
void CreateShaders();
void UpdateTextures(int width, int height);
enum Quality
{
Off,
@ -612,8 +687,25 @@ private:
int AmbientWidth = 0;
int AmbientHeight = 0;
int LastQuality = -1;
int LastWidth = 0;
int LastHeight = 0;
PPShader LinearDepth;
PPShader LinearDepthMS;
PPShader AmbientOcclude;
PPShader AmbientOccludeMS;
PPShader BlurVertical;
PPShader BlurHorizontal;
PPShader Combine;
PPShader CombineMS;
PPTexture LinearDepthTexture;
PPTexture Ambient0;
PPTexture Ambient1;
enum { NumAmbientRandomTextures = 3 };
PPTextureName AmbientRandomTexture[NumAmbientRandomTextures];
PPTexture AmbientRandomTexture[NumAmbientRandomTextures];
};
struct PresentUniforms
@ -646,12 +738,17 @@ struct PresentUniforms
}
};
class PPPresent : public PPEffectManager
class PPPresent
{
public:
void DeclareShaders() override;
void UpdateTextures() override;
void UpdateSteps() override;
PPPresent();
PPTexture Dither;
PPShader Present = { "shaders/glsl/present.fp", "", PresentUniforms::Desc() };
PPShader Checker3D = { "shaders/glsl/present_checker3d.fp", "", PresentUniforms::Desc() };
PPShader Column3D = { "shaders/glsl/present_column3d.fp", "", PresentUniforms::Desc() };
PPShader Row3D = { "shaders/glsl/present_row3d.fp", "", PresentUniforms::Desc() };
};
struct ShadowMapUniforms
@ -671,10 +768,29 @@ struct ShadowMapUniforms
}
};
class PPShadowMap : public PPEffectManager
class PPShadowMap
{
public:
void DeclareShaders() override;
void UpdateTextures() override;
void UpdateSteps() override;
void Update(PPRenderState *renderstate);
private:
PPShader ShadowMap = { "shaders/glsl/shadowmap.fp", "", ShadowMapUniforms::Desc() };
};
/////////////////////////////////////////////////////////////////////////////
class Postprocess
{
public:
PPBloom bloom;
PPLensDistort lens;
PPFXAA fxaa;
PPCameraExposure exposure;
PPColormap colormap;
PPTonemap tonemap;
PPAmbientOcclusion ssao;
PPPresent present;
PPShadowMap shadowmap;
};
extern Postprocess hw_postprocess;

View file

@ -40,18 +40,22 @@ void VkPostprocess::SetActiveRenderTarget()
void VkPostprocess::PostProcessScene(int fixedcm, const std::function<void()> &afterBloomDrawEndScene2D)
{
auto fb = GetVulkanFrameBuffer();
int sceneWidth = fb->GetBuffers()->GetSceneWidth();
int sceneHeight = fb->GetBuffers()->GetSceneHeight();
hw_postprocess.fixedcm = fixedcm;
VkPPRenderState renderstate;
RenderEffect("UpdateCameraExposure");
hw_postprocess.exposure.Render(&renderstate, sceneWidth, sceneHeight);
//mCustomPostProcessShaders->Run("beforebloom");
RenderEffect("BloomScene");
hw_postprocess.bloom.RenderBloom(&renderstate, sceneWidth, sceneHeight, fixedcm);
SetActiveRenderTarget();
afterBloomDrawEndScene2D();
RenderEffect("TonemapScene");
RenderEffect("ColormapScene");
RenderEffect("LensDistortScene");
RenderEffect("ApplyFXAA");
hw_postprocess.tonemap.Render(&renderstate);
hw_postprocess.colormap.Render(&renderstate, fixedcm);
hw_postprocess.lens.Render(&renderstate);
hw_postprocess.fxaa.Render(&renderstate);
//mCustomPostProcessShaders->Run("scene");
}
@ -183,53 +187,56 @@ void VkPostprocess::DrawPresentTexture(const IntRect &box, bool applyGamma, bool
uniforms.Scale = { screen->mScreenViewport.width / (float)fb->GetBuffers()->GetWidth(), -screen->mScreenViewport.height / (float)fb->GetBuffers()->GetHeight() };
uniforms.Offset = { 0.0f, 1.0f };
PPStep step;
step.ShaderName = "Present";
step.Uniforms.Set(uniforms);
step.Viewport = box;
step.SetInputCurrent(0, ViewportLinearScale() ? PPFilterMode::Linear : PPFilterMode::Nearest);
step.SetInputTexture(1, "PresentDither", PPFilterMode::Nearest, PPWrapMode::Repeat);
step.SetOutputSwapChain();
step.SetNoBlend();
//if (clearBorders) step.SetClearBorders();
TArray<PPStep> steps;
steps.Push(step);
hw_postprocess.Effects["Present"] = steps;
RenderEffect("Present");
VkPPRenderState renderstate;
renderstate.Shader = &hw_postprocess.present.Present;
renderstate.Uniforms.Set(uniforms);
renderstate.Viewport = box;
renderstate.SetInputCurrent(0, ViewportLinearScale() ? PPFilterMode::Linear : PPFilterMode::Nearest);
renderstate.SetInputTexture(1, &hw_postprocess.present.Dither, PPFilterMode::Nearest, PPWrapMode::Repeat);
renderstate.SetOutputSwapChain();
renderstate.SetNoBlend();
//if (clearBorders) renderstate.SetClearBorders();
renderstate.Draw();
}
void VkPostprocess::AmbientOccludeScene(float m5)
{
hw_postprocess.m5 = m5;
auto fb = GetVulkanFrameBuffer();
int sceneWidth = fb->GetBuffers()->GetSceneWidth();
int sceneHeight = fb->GetBuffers()->GetSceneHeight();
RenderEffect("AmbientOccludeScene");
VkPPRenderState renderstate;
hw_postprocess.ssao.Render(&renderstate, m5, sceneWidth, sceneHeight);
}
void VkPostprocess::BlurScene(float gameinfobluramount)
{
hw_postprocess.gameinfobluramount = gameinfobluramount;
auto fb = GetVulkanFrameBuffer();
int sceneWidth = fb->GetBuffers()->GetSceneWidth();
int sceneHeight = fb->GetBuffers()->GetSceneHeight();
VkPPRenderState renderstate;
auto vrmode = VRMode::GetVRMode(true);
int eyeCount = vrmode->mEyeCount;
for (int i = 0; i < eyeCount; ++i)
{
RenderEffect("BlurScene");
hw_postprocess.bloom.RenderBlur(&renderstate, sceneWidth, sceneHeight, gameinfobluramount);
if (eyeCount - i > 1) NextEye(eyeCount);
}
}
void VkPostprocess::ClearTonemapPalette()
{
hw_postprocess.Textures.Remove("Tonemap.Palette");
hw_postprocess.tonemap.ClearTonemapPalette();
}
void VkPostprocess::UpdateShadowMap()
{
if (screen->mShadowMap.PerformUpdate())
{
RenderEffect("UpdateShadowMap");
VkPPRenderState renderstate;
hw_postprocess.shadowmap.Update(&renderstate);
auto fb = GetVulkanFrameBuffer();
auto buffers = fb->GetBuffers();
@ -255,17 +262,6 @@ void VkPostprocess::BeginFrame()
mDescriptorPool = builder.create(GetVulkanFrameBuffer()->device);
mDescriptorPool->SetDebugName("VkPostprocess.mDescriptorPool");
}
auto fb = GetVulkanFrameBuffer();
hw_postprocess.SceneWidth = fb->GetBuffers()->GetSceneWidth();
hw_postprocess.SceneHeight = fb->GetBuffers()->GetSceneHeight();
hw_postprocess.DeclareShaders();
hw_postprocess.UpdateTextures();
hw_postprocess.UpdateSteps();
CompileEffectShaders();
UpdateEffectTextures();
}
void VkPostprocess::RenderBuffersReset()
@ -273,128 +269,125 @@ void VkPostprocess::RenderBuffersReset()
mRenderPassSetup.clear();
}
void VkPostprocess::UpdateEffectTextures()
VulkanSampler *VkPostprocess::GetSampler(PPFilterMode filter, PPWrapMode wrap)
{
int index = (((int)filter) << 2) | (int)wrap;
auto &sampler = mSamplers[index];
if (sampler)
return sampler.get();
SamplerBuilder builder;
builder.setMipmapMode(VK_SAMPLER_MIPMAP_MODE_NEAREST);
builder.setMinFilter(filter == PPFilterMode::Nearest ? VK_FILTER_NEAREST : VK_FILTER_LINEAR);
builder.setMagFilter(filter == PPFilterMode::Nearest ? VK_FILTER_NEAREST : VK_FILTER_LINEAR);
builder.setAddressMode(wrap == PPWrapMode::Clamp ? VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE : VK_SAMPLER_ADDRESS_MODE_REPEAT);
sampler = builder.create(GetVulkanFrameBuffer()->device);
sampler->SetDebugName("VkPostprocess.mSamplers");
return sampler.get();
}
void VkPostprocess::NextEye(int eyeCount)
{
}
/////////////////////////////////////////////////////////////////////////////
VkPPTexture::VkPPTexture(PPTexture *texture)
{
auto fb = GetVulkanFrameBuffer();
TMap<FString, PPTextureDesc>::Iterator it(hw_postprocess.Textures);
TMap<FString, PPTextureDesc>::Pair *pair;
while (it.NextPair(pair))
VkFormat format;
int pixelsize;
switch (texture->Format)
{
const auto &desc = pair->Value;
auto &vktex = mTextures[pair->Key];
default:
case PixelFormat::Rgba8: format = VK_FORMAT_R8G8B8A8_UNORM; pixelsize = 4; break;
case PixelFormat::Rgba16f: format = VK_FORMAT_R16G16B16A16_SFLOAT; pixelsize = 8; break;
case PixelFormat::R32f: format = VK_FORMAT_R32_SFLOAT; pixelsize = 4; break;
case PixelFormat::Rg16f: format = VK_FORMAT_R16G16_SFLOAT; pixelsize = 4; break;
case PixelFormat::Rgba16_snorm: format = VK_FORMAT_R16G16B16A16_SNORM; pixelsize = 8; break;
}
if (vktex && (vktex->Image->width != desc.Width || vktex->Image->height != desc.Height))
vktex.reset();
ImageBuilder imgbuilder;
imgbuilder.setFormat(format);
imgbuilder.setSize(texture->Width, texture->Height);
if (texture->Data)
imgbuilder.setUsage(VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT);
else
imgbuilder.setUsage(VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT);
if (!imgbuilder.isFormatSupported(fb->device))
I_FatalError("Vulkan device does not support the image format required by a postprocess texture\n");
Image = imgbuilder.create(fb->device);
Image->SetDebugName("VkPPTexture");
Format = format;
if (!vktex)
{
vktex.reset(new VkPPTexture());
ImageViewBuilder viewbuilder;
viewbuilder.setImage(Image.get(), format);
View = viewbuilder.create(fb->device);
View->SetDebugName("VkPPTextureView");
VkFormat format;
int pixelsize;
switch (pair->Value.Format)
{
default:
case PixelFormat::Rgba8: format = VK_FORMAT_R8G8B8A8_UNORM; pixelsize = 4; break;
case PixelFormat::Rgba16f: format = VK_FORMAT_R16G16B16A16_SFLOAT; pixelsize = 8; break;
case PixelFormat::R32f: format = VK_FORMAT_R32_SFLOAT; pixelsize = 4; break;
case PixelFormat::Rg16f: format = VK_FORMAT_R16G16_SFLOAT; pixelsize = 4; break;
case PixelFormat::Rgba16_snorm: format = VK_FORMAT_R16G16B16A16_SNORM; pixelsize = 8; break;
}
if (texture->Data)
{
size_t totalsize = texture->Width * texture->Height * pixelsize;
BufferBuilder stagingbuilder;
stagingbuilder.setSize(totalsize);
stagingbuilder.setUsage(VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VMA_MEMORY_USAGE_CPU_ONLY);
Staging = stagingbuilder.create(fb->device);
Staging->SetDebugName("VkPPTextureStaging");
ImageBuilder imgbuilder;
imgbuilder.setFormat(format);
imgbuilder.setSize(desc.Width, desc.Height);
if (desc.Data)
imgbuilder.setUsage(VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT);
else
imgbuilder.setUsage(VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT);
if (!imgbuilder.isFormatSupported(fb->device))
I_FatalError("Vulkan device does not support the image format required by %s\n", pair->Key.GetChars());
vktex->Image = imgbuilder.create(fb->device);
vktex->Image->SetDebugName(pair->Key.GetChars());
vktex->Format = format;
PipelineBarrier barrier0;
barrier0.addImage(Image.get(), VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 0, VK_ACCESS_TRANSFER_WRITE_BIT);
barrier0.execute(fb->GetUploadCommands(), VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT);
ImageViewBuilder viewbuilder;
viewbuilder.setImage(vktex->Image.get(), format);
vktex->View = viewbuilder.create(fb->device);
vktex->View->SetDebugName(pair->Key.GetChars());
void *data = Staging->Map(0, totalsize);
memcpy(data, texture->Data.get(), totalsize);
Staging->Unmap();
if (desc.Data)
{
size_t totalsize = desc.Width * desc.Height * pixelsize;
BufferBuilder stagingbuilder;
stagingbuilder.setSize(totalsize);
stagingbuilder.setUsage(VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VMA_MEMORY_USAGE_CPU_ONLY);
vktex->Staging = stagingbuilder.create(fb->device);
vktex->Staging->SetDebugName(pair->Key.GetChars());
VkBufferImageCopy region = {};
region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
region.imageSubresource.layerCount = 1;
region.imageExtent.depth = 1;
region.imageExtent.width = texture->Width;
region.imageExtent.height = texture->Height;
fb->GetUploadCommands()->copyBufferToImage(Staging->buffer, Image->image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &region);
PipelineBarrier barrier0;
barrier0.addImage(vktex->Image.get(), VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 0, VK_ACCESS_TRANSFER_WRITE_BIT);
barrier0.execute(fb->GetUploadCommands(), VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT);
void *data = vktex->Staging->Map(0, totalsize);
memcpy(data, desc.Data.get(), totalsize);
vktex->Staging->Unmap();
VkBufferImageCopy region = {};
region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
region.imageSubresource.layerCount = 1;
region.imageExtent.depth = 1;
region.imageExtent.width = desc.Width;
region.imageExtent.height = desc.Height;
fb->GetUploadCommands()->copyBufferToImage(vktex->Staging->buffer, vktex->Image->image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &region);
PipelineBarrier barrier1;
barrier1.addImage(vktex->Image.get(), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT);
barrier1.execute(fb->GetUploadCommands(), VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT);
vktex->Layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
}
else
{
PipelineBarrier barrier;
barrier.addImage(vktex->Image.get(), VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, 0, VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_COLOR_ATTACHMENT_READ_BIT);
barrier.execute(fb->GetUploadCommands(), VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT);
vktex->Layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
}
}
PipelineBarrier barrier1;
barrier1.addImage(Image.get(), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT);
barrier1.execute(fb->GetUploadCommands(), VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT);
Layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
}
else
{
PipelineBarrier barrier;
barrier.addImage(Image.get(), VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, 0, VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_COLOR_ATTACHMENT_READ_BIT);
barrier.execute(fb->GetUploadCommands(), VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT);
Layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
}
}
void VkPostprocess::CompileEffectShaders()
/////////////////////////////////////////////////////////////////////////////
VkPPShader::VkPPShader(PPShader *shader)
{
auto fb = GetVulkanFrameBuffer();
TMap<FString, PPShader>::Iterator it(hw_postprocess.Shaders);
TMap<FString, PPShader>::Pair *pair;
while (it.NextPair(pair))
{
const auto &desc = pair->Value;
auto &vkshader = mShaders[pair->Key];
if (!vkshader)
{
vkshader.reset(new VkPPShader());
FString prolog;
if (!shader->Uniforms.empty())
prolog = UniformBlockDecl::Create("Uniforms", shader->Uniforms, -1);
prolog += shader->Defines;
FString prolog;
if (!desc.Uniforms.empty())
prolog = UniformBlockDecl::Create("Uniforms", desc.Uniforms, -1);
prolog += desc.Defines;
ShaderBuilder vertbuilder;
vertbuilder.setVertexShader(LoadShaderCode(shader->VertexShader, "", shader->Version));
VertexShader = vertbuilder.create(fb->device);
VertexShader->SetDebugName(shader->VertexShader.GetChars());
ShaderBuilder vertbuilder;
vertbuilder.setVertexShader(LoadShaderCode(desc.VertexShader, "", desc.Version));
vkshader->VertexShader = vertbuilder.create(fb->device);
vkshader->VertexShader->SetDebugName(desc.VertexShader.GetChars());
ShaderBuilder fragbuilder;
fragbuilder.setFragmentShader(LoadShaderCode(desc.FragmentShader, prolog, desc.Version));
vkshader->FragmentShader = fragbuilder.create(fb->device);
vkshader->FragmentShader->SetDebugName(desc.FragmentShader.GetChars());
}
}
ShaderBuilder fragbuilder;
fragbuilder.setFragmentShader(LoadShaderCode(shader->FragmentShader, prolog, shader->Version));
FragmentShader = fragbuilder.create(fb->device);
FragmentShader->SetDebugName(shader->FragmentShader.GetChars());
}
FString VkPostprocess::LoadShaderCode(const FString &lumpName, const FString &defines, int version)
FString VkPPShader::LoadShaderCode(const FString &lumpName, const FString &defines, int version)
{
int lump = Wads.CheckNumForFullName(lumpName);
if (lump == -1) I_FatalError("Unable to load '%s'", lumpName.GetChars());
@ -408,50 +401,49 @@ FString VkPostprocess::LoadShaderCode(const FString &lumpName, const FString &de
return patchedCode;
}
void VkPostprocess::RenderEffect(const FString &name)
/////////////////////////////////////////////////////////////////////////////
void VkPPRenderState::Draw()
{
GetVulkanFrameBuffer()->GetRenderState()->EndRenderPass();
auto fb = GetVulkanFrameBuffer();
auto pp = fb->GetPostprocess();
if (hw_postprocess.Effects[name].Size() == 0)
return;
fb->GetRenderState()->EndRenderPass();
for (const PPStep &step : hw_postprocess.Effects[name])
VkPPRenderPassKey key;
key.BlendMode = BlendMode;
key.InputTextures = Textures.Size();
key.Uniforms = Uniforms.Data.Size();
key.Shader = GetVkShader(Shader);
key.SwapChain = (Output.Type == PPTextureType::SwapChain);
key.ShadowMapBuffers = ShadowMapBuffers;
if (Output.Type == PPTextureType::PPTexture)
key.OutputFormat = GetVkTexture(Output.Texture)->Format;
else if (Output.Type == PPTextureType::SwapChain)
key.OutputFormat = GetVulkanFrameBuffer()->swapChain->swapChainFormat.format;
else if (Output.Type == PPTextureType::ShadowMap)
key.OutputFormat = VK_FORMAT_R32_SFLOAT;
else
key.OutputFormat = VK_FORMAT_R16G16B16A16_SFLOAT;
auto &passSetup = pp->mRenderPassSetup[key];
if (!passSetup)
passSetup.reset(new VkPPRenderPassSetup(key));
int framebufferWidth = 0, framebufferHeight = 0;
VulkanDescriptorSet *input = GetInput(passSetup.get(), Textures, ShadowMapBuffers);
VulkanFramebuffer *output = GetOutput(passSetup.get(), Output, framebufferWidth, framebufferHeight);
RenderScreenQuad(passSetup.get(), input, output, framebufferWidth, framebufferHeight, Viewport.left, Viewport.top, Viewport.width, Viewport.height, Uniforms.Data.Data(), Uniforms.Data.Size());
// Advance to next PP texture if our output was sent there
if (Output.Type == PPTextureType::NextPipelineTexture)
{
VkPPRenderPassKey key;
key.BlendMode = step.BlendMode;
key.InputTextures = step.Textures.Size();
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;
auto &passSetup = mRenderPassSetup[key];
if (!passSetup)
passSetup.reset(new VkPPRenderPassSetup(key));
int framebufferWidth = 0, framebufferHeight = 0;
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());
// Advance to next PP texture if our output was sent there
if (step.Output.Type == PPTextureType::NextPipelineTexture)
{
mCurrentPipelineImage = (mCurrentPipelineImage + 1) % VkRenderBuffers::NumPipelineImages;
}
pp->mCurrentPipelineImage = (pp->mCurrentPipelineImage + 1) % VkRenderBuffers::NumPipelineImages;
}
}
void VkPostprocess::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)
void VkPPRenderState::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)
{
auto fb = GetVulkanFrameBuffer();
auto cmdbuffer = fb->GetDrawCommands();
@ -491,10 +483,11 @@ void VkPostprocess::RenderScreenQuad(VkPPRenderPassSetup *passSetup, VulkanDescr
cmdbuffer->endRenderPass();
}
VulkanDescriptorSet *VkPostprocess::GetInput(VkPPRenderPassSetup *passSetup, const TArray<PPTextureInput> &textures, bool bindShadowMapBuffers)
VulkanDescriptorSet *VkPPRenderState::GetInput(VkPPRenderPassSetup *passSetup, const TArray<PPTextureInput> &textures, bool bindShadowMapBuffers)
{
auto fb = GetVulkanFrameBuffer();
auto descriptors = mDescriptorPool->allocate(passSetup->DescriptorLayout.get());
auto pp = fb->GetPostprocess();
auto descriptors = pp->mDescriptorPool->allocate(passSetup->DescriptorLayout.get());
descriptors->SetDebugName("VkPostprocess.descriptors");
WriteDescriptors write;
@ -503,7 +496,7 @@ VulkanDescriptorSet *VkPostprocess::GetInput(VkPPRenderPassSetup *passSetup, con
for (unsigned int index = 0; index < textures.Size(); index++)
{
const PPTextureInput &input = textures[index];
VulkanSampler *sampler = GetSampler(input.Filter, input.Wrap);
VulkanSampler *sampler = pp->GetSampler(input.Filter, input.Wrap);
TextureImage tex = GetTexture(input.Type, input.Texture);
write.addCombinedImageSampler(descriptors.get(), index, tex.view, sampler, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
@ -520,11 +513,11 @@ VulkanDescriptorSet *VkPostprocess::GetInput(VkPPRenderPassSetup *passSetup, con
write.updateSets(fb->device);
imageTransition.execute(fb->GetDrawCommands());
mFrameDescriptorSets.push_back(std::move(descriptors));
return mFrameDescriptorSets.back().get();
pp->mFrameDescriptorSets.push_back(std::move(descriptors));
return pp->mFrameDescriptorSets.back().get();
}
VulkanFramebuffer *VkPostprocess::GetOutput(VkPPRenderPassSetup *passSetup, const PPOutput &output, int &framebufferWidth, int &framebufferHeight)
VulkanFramebuffer *VkPPRenderState::GetOutput(VkPPRenderPassSetup *passSetup, const PPOutput &output, int &framebufferWidth, int &framebufferHeight)
{
auto fb = GetVulkanFrameBuffer();
@ -565,14 +558,14 @@ VulkanFramebuffer *VkPostprocess::GetOutput(VkPPRenderPassSetup *passSetup, cons
return framebuffer.get();
}
VkPostprocess::TextureImage VkPostprocess::GetTexture(const PPTextureType &type, const PPTextureName &name)
VkPPRenderState::TextureImage VkPPRenderState::GetTexture(const PPTextureType &type, PPTexture *pptexture)
{
auto fb = GetVulkanFrameBuffer();
TextureImage tex = {};
if (type == PPTextureType::CurrentPipelineTexture || type == PPTextureType::NextPipelineTexture)
{
int idx = mCurrentPipelineImage;
int idx = fb->GetPostprocess()->mCurrentPipelineImage;
if (type == PPTextureType::NextPipelineTexture)
idx = (idx + 1) % VkRenderBuffers::NumPipelineImages;
@ -583,10 +576,11 @@ VkPostprocess::TextureImage VkPostprocess::GetTexture(const PPTextureType &type,
}
else if (type == PPTextureType::PPTexture)
{
tex.image = mTextures[name]->Image.get();
tex.view = mTextures[name]->View.get();
tex.layout = &mTextures[name]->Layout;
tex.debugname = name.GetChars();
auto vktex = GetVkTexture(pptexture);
tex.image = vktex->Image.get();
tex.view = vktex->View.get();
tex.layout = &vktex->Layout;
tex.debugname = "PPTexture";
}
else if (type == PPTextureType::SceneColor)
{
@ -632,31 +626,24 @@ VkPostprocess::TextureImage VkPostprocess::GetTexture(const PPTextureType &type,
}
else
{
I_FatalError("VkPostprocess::GetTexture not implemented yet for this texture type");
I_FatalError("VkPPRenderState::GetTexture not implemented yet for this texture type");
}
return tex;
}
VulkanSampler *VkPostprocess::GetSampler(PPFilterMode filter, PPWrapMode wrap)
VkPPShader *VkPPRenderState::GetVkShader(PPShader *shader)
{
int index = (((int)filter) << 2) | (int)wrap;
auto &sampler = mSamplers[index];
if (sampler)
return sampler.get();
SamplerBuilder builder;
builder.setMipmapMode(VK_SAMPLER_MIPMAP_MODE_NEAREST);
builder.setMinFilter(filter == PPFilterMode::Nearest ? VK_FILTER_NEAREST : VK_FILTER_LINEAR);
builder.setMagFilter(filter == PPFilterMode::Nearest ? VK_FILTER_NEAREST : VK_FILTER_LINEAR);
builder.setAddressMode(wrap == PPWrapMode::Clamp ? VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE : VK_SAMPLER_ADDRESS_MODE_REPEAT);
sampler = builder.create(GetVulkanFrameBuffer()->device);
sampler->SetDebugName("VkPostprocess.mSamplers");
return sampler.get();
if (!shader->Backend)
shader->Backend = std::make_unique<VkPPShader>(shader);
return static_cast<VkPPShader*>(shader->Backend.get());
}
void VkPostprocess::NextEye(int eyeCount)
VkPPTexture *VkPPRenderState::GetVkTexture(PPTexture *texture)
{
if (!texture->Backend)
texture->Backend = std::make_unique<VkPPTexture>(texture);
return static_cast<VkPPTexture*>(texture->Backend.get());
}
/////////////////////////////////////////////////////////////////////////////

View file

@ -68,45 +68,36 @@ public:
void DrawPresentTexture(const IntRect &box, bool applyGamma, bool clearBorders);
private:
void UpdateEffectTextures();
void CompileEffectShaders();
FString LoadShaderCode(const FString &lumpname, const FString &defines, int version);
void RenderEffect(const FString &name);
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, bool bindShadowMapBuffers);
VulkanFramebuffer *GetOutput(VkPPRenderPassSetup *passSetup, const PPOutput &output, int &framebufferWidth, int &framebufferHeight);
VulkanSampler *GetSampler(PPFilterMode filter, PPWrapMode wrap);
struct TextureImage
{
VulkanImage *image;
VulkanImageView *view;
VkImageLayout *layout;
const char *debugname;
};
TextureImage GetTexture(const PPTextureType &type, const PPTextureName &name);
std::map<PPTextureName, std::unique_ptr<VkPPTexture>> mTextures;
std::map<PPShaderName, std::unique_ptr<VkPPShader>> mShaders;
std::array<std::unique_ptr<VulkanSampler>, 16> mSamplers;
std::map<VkPPRenderPassKey, std::unique_ptr<VkPPRenderPassSetup>> mRenderPassSetup;
std::unique_ptr<VulkanDescriptorPool> mDescriptorPool;
std::vector<std::unique_ptr<VulkanDescriptorSet>> mFrameDescriptorSets;
int mCurrentPipelineImage = 0;
friend class VkPPRenderState;
};
class VkPPShader
class VkPPShader : public PPShaderBackend
{
public:
VkPPShader(PPShader *shader);
std::unique_ptr<VulkanShader> VertexShader;
std::unique_ptr<VulkanShader> FragmentShader;
private:
FString LoadShaderCode(const FString &lumpname, const FString &defines, int version);
};
class VkPPTexture
class VkPPTexture : public PPTextureBackend
{
public:
VkPPTexture(PPTexture *texture);
std::unique_ptr<VulkanImage> Image;
std::unique_ptr<VulkanImageView> View;
std::unique_ptr<VulkanBuffer> Staging;
@ -131,3 +122,27 @@ private:
void CreatePipeline(const VkPPRenderPassKey &key);
void CreateRenderPass(const VkPPRenderPassKey &key);
};
class VkPPRenderState : public PPRenderState
{
public:
void Draw() override;
private:
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, bool bindShadowMapBuffers);
VulkanFramebuffer *GetOutput(VkPPRenderPassSetup *passSetup, const PPOutput &output, int &framebufferWidth, int &framebufferHeight);
VkPPShader *GetVkShader(PPShader *shader);
VkPPTexture *GetVkTexture(PPTexture *texture);
struct TextureImage
{
VulkanImage *image;
VulkanImageView *view;
VkImageLayout *layout;
const char *debugname;
};
TextureImage GetTexture(const PPTextureType &type, PPTexture *tex);
};

View file

@ -89,6 +89,8 @@ VulkanFrameBuffer::~VulkanFrameBuffer()
for (VkHardwareTexture *cur = VkHardwareTexture::First; cur; cur = cur->Next)
cur->Reset();
PPResource::ResetAll();
delete MatricesUBO;
delete StreamUBO;
delete mVertexData;