diff --git a/src/rendering/gl/renderer/gl_postprocess.cpp b/src/rendering/gl/renderer/gl_postprocess.cpp index d276290917..8b1482565f 100644 --- a/src/rendering/gl/renderer/gl_postprocess.cpp +++ b/src/rendering/gl/renderer/gl_postprocess.cpp @@ -64,26 +64,22 @@ void FGLRenderer::RenderScreenQuad() void FGLRenderer::PostProcessScene(int fixedcm, const std::function &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 &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(); } //----------------------------------------------------------------------------- diff --git a/src/rendering/gl/renderer/gl_renderbuffers.cpp b/src/rendering/gl/renderer/gl_renderbuffers.cpp index 421e1769a5..0d0f6a3921 100644 --- a/src/rendering/gl/renderer/gl_renderbuffers.cpp +++ b/src/rendering/gl/renderer/gl_renderbuffers.cpp @@ -792,19 +792,16 @@ bool FGLRenderBuffers::FailedCreate = false; // //========================================================================== -void FGLRenderBuffers::UpdateEffectTextures() +PPGLTextureBackend *GLPPRenderState::GetGLTexture(PPTexture *texture) { - FGLPostProcessState savedState; - - TMap::Iterator it(hw_postprocess.Textures); - TMap::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(); 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(texture->Backend.get()); } //========================================================================== @@ -844,30 +827,26 @@ void FGLRenderBuffers::UpdateEffectTextures() // //========================================================================== -void FGLRenderBuffers::CompileEffectShaders() +FShaderProgram *GLPPRenderState::GetGLShader(PPShader *shader) { - TMap::Iterator it(hw_postprocess.Shaders); - TMap::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(); + auto glshader = std::make_unique(); - 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(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(); } diff --git a/src/rendering/gl/renderer/gl_renderbuffers.h b/src/rendering/gl/renderer/gl_renderbuffers.h index 4b66e75690..40e2b4c9eb 100644 --- a/src/rendering/gl/renderer/gl_renderbuffers.h +++ b/src/rendering/gl/renderer/gl_renderbuffers.h @@ -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 GLTextures; - TMap GLTextureFBs; - TMap> GLShaders; - static bool FailedCreate; + + friend class GLPPRenderState; }; } \ No newline at end of file diff --git a/src/rendering/gl/shaders/gl_shaderprogram.h b/src/rendering/gl/shaders/gl_shaderprogram.h index 87ecaae870..e073d62e04 100644 --- a/src/rendering/gl/shaders/gl_shaderprogram.h +++ b/src/rendering/gl/shaders/gl_shaderprogram.h @@ -8,7 +8,7 @@ namespace OpenGLRenderer { -class FShaderProgram +class FShaderProgram : public PPShaderBackend { public: FShaderProgram(); diff --git a/src/rendering/gl/system/gl_framebuffer.cpp b/src/rendering/gl/system/gl_framebuffer.cpp index 88faa2ff2a..c2f6d9881c 100644 --- a/src/rendering/gl/system/gl_framebuffer.cpp +++ b/src/rendering/gl/system/gl_framebuffer.cpp @@ -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; diff --git a/src/rendering/hwrenderer/postprocessing/hw_postprocess.cpp b/src/rendering/hwrenderer/postprocessing/hw_postprocess.cpp index 294cece47c..2fd47d6c4d 100644 --- a/src/rendering/hwrenderer/postprocessing/hw_postprocess.cpp +++ b/src/rendering/hwrenderer/postprocessing/hw_postprocess.cpp @@ -7,42 +7,13 @@ Postprocess hw_postprocess; -Postprocess::Postprocess() -{ - Managers.Push(new PPBloom()); - Managers.Push(new PPLensDistort()); - Managers.Push(new PPFXAA()); - Managers.Push(new PPCameraExposure()); - Managers.Push(new PPColormap()); - Managers.Push(new PPTonemap()); - Managers.Push(new PPAmbientOcclusion()); - Managers.Push(new PPPresent()); - Managers.Push(new PPShadowMap()); -} - -Postprocess::~Postprocess() -{ - for (unsigned int i = 0; i < Managers.Size(); i++) - delete Managers[i]; -} +PPResource *PPResource::First = nullptr; ///////////////////////////////////////////////////////////////////////////// -void PPBloom::DeclareShaders() +void PPBloom::UpdateTextures(int width, int height) { - hw_postprocess.Shaders["BloomCombine"] = { "shaders/glsl/bloomcombine.fp", "", {} }; - hw_postprocess.Shaders["BloomExtract"] = { "shaders/glsl/bloomextract.fp", "", ExtractUniforms::Desc() }; - hw_postprocess.Shaders["BlurVertical"] = { "shaders/glsl/blur.fp", "#define BLUR_VERTICAL\n", BlurUniforms::Desc() }; - hw_postprocess.Shaders["BlurHorizontal"] = { "shaders/glsl/blur.fp", "#define BLUR_HORIZONTAL\n", BlurUniforms::Desc() }; -} - -void PPBloom::UpdateTextures() -{ - int width = hw_postprocess.SceneWidth; - int height = hw_postprocess.SceneHeight; - - // No scene, no bloom! - if (width <= 0 || height <= 0) + if (width == lastWidth && height == lastHeight) return; int bloomWidth = (width + 1) / 2; @@ -51,35 +22,30 @@ void PPBloom::UpdateTextures() for (int i = 0; i < NumBloomLevels; i++) { auto &blevel = levels[i]; - blevel.VTexture.Format("Bloom.VTexture.%d", i); - blevel.HTexture.Format("Bloom.HTexture.%d", i); blevel.Viewport.left = 0; blevel.Viewport.top = 0; blevel.Viewport.width = (bloomWidth + 1) / 2; blevel.Viewport.height = (bloomHeight + 1) / 2; - - PPTextureDesc texture = { blevel.Viewport.width, blevel.Viewport.height, PixelFormat::Rgba16f }; - hw_postprocess.Textures[blevel.VTexture] = texture; - hw_postprocess.Textures[blevel.HTexture] = texture; + blevel.VTexture = { blevel.Viewport.width, blevel.Viewport.height, PixelFormat::Rgba16f }; + blevel.HTexture = { blevel.Viewport.width, blevel.Viewport.height, PixelFormat::Rgba16f }; bloomWidth = blevel.Viewport.width; bloomHeight = blevel.Viewport.height; } + + lastWidth = width; + lastHeight = height; } -void PPBloom::UpdateSteps() +void PPBloom::RenderBloom(PPRenderState *renderstate, int sceneWidth, int sceneHeight, int fixedcm) { - UpdateBlurSteps(); - // Only bloom things if enabled and no special fixed light mode is active - if (!gl_bloom || hw_postprocess.fixedcm != CM_DEFAULT || gl_ssao_debug || hw_postprocess.SceneWidth <= 0 || hw_postprocess.SceneHeight <= 0) + if (!gl_bloom || fixedcm != CM_DEFAULT || gl_ssao_debug || sceneWidth <= 0 || sceneHeight <= 0) { - hw_postprocess.Effects["BloomScene"] = {}; return; } - TArray steps; - PPStep step; + UpdateTextures(sceneWidth, sceneHeight); ExtractUniforms extractUniforms; extractUniforms.Scale = screen->SceneScale(); @@ -88,14 +54,15 @@ void PPBloom::UpdateSteps() auto &level0 = levels[0]; // Extract blooming pixels from scene texture: - step.ShaderName = "BloomExtract"; - step.Uniforms.Set(extractUniforms); - step.Viewport = level0.Viewport; - step.SetInputCurrent(0, PPFilterMode::Linear); - step.SetInputTexture(1, "Exposure.CameraTexture"); - step.SetOutputTexture(level0.VTexture); - step.SetNoBlend(); - steps.Push(step); + renderstate->Clear(); + renderstate->Shader = &BloomExtract; + renderstate->Uniforms.Set(extractUniforms); + renderstate->Viewport = level0.Viewport; + renderstate->SetInputCurrent(0, PPFilterMode::Linear); + renderstate->SetInputTexture(1, &hw_postprocess.exposure.CameraTexture); + renderstate->SetOutputTexture(&level0.VTexture); + renderstate->SetNoBlend(); + renderstate->Draw(); const float blurAmount = gl_bloom_amount; BlurUniforms blurUniforms; @@ -107,17 +74,18 @@ void PPBloom::UpdateSteps() auto &blevel = levels[i]; auto &next = levels[i + 1]; - steps.Push(BlurStep(blurUniforms, blevel.VTexture, blevel.HTexture, blevel.Viewport, false)); - steps.Push(BlurStep(blurUniforms, blevel.HTexture, blevel.VTexture, blevel.Viewport, true)); + BlurStep(renderstate, blurUniforms, blevel.VTexture, blevel.HTexture, blevel.Viewport, false); + BlurStep(renderstate, blurUniforms, blevel.HTexture, blevel.VTexture, blevel.Viewport, true); // Linear downscale: - step.ShaderName = "BloomCombine"; - step.Uniforms.Clear(); - step.Viewport = next.Viewport; - step.SetInputTexture(0, blevel.VTexture, PPFilterMode::Linear); - step.SetOutputTexture(next.VTexture); - step.SetNoBlend(); - steps.Push(step); + renderstate->Clear(); + renderstate->Shader = &BloomCombine; + renderstate->Uniforms.Clear(); + renderstate->Viewport = next.Viewport; + renderstate->SetInputTexture(0, &blevel.VTexture, PPFilterMode::Linear); + renderstate->SetOutputTexture(&next.VTexture); + renderstate->SetNoBlend(); + renderstate->Draw(); } // Blur and upscale: @@ -126,66 +94,69 @@ void PPBloom::UpdateSteps() auto &blevel = levels[i]; auto &next = levels[i - 1]; - steps.Push(BlurStep(blurUniforms, blevel.VTexture, blevel.HTexture, blevel.Viewport, false)); - steps.Push(BlurStep(blurUniforms, blevel.HTexture, blevel.VTexture, blevel.Viewport, true)); + BlurStep(renderstate, blurUniforms, blevel.VTexture, blevel.HTexture, blevel.Viewport, false); + BlurStep(renderstate, blurUniforms, blevel.HTexture, blevel.VTexture, blevel.Viewport, true); // Linear upscale: - step.ShaderName = "BloomCombine"; - step.Uniforms.Clear(); - step.Viewport = next.Viewport; - step.SetInputTexture(0, blevel.VTexture, PPFilterMode::Linear); - step.SetOutputTexture(next.VTexture); - step.SetNoBlend(); - steps.Push(step); + renderstate->Clear(); + renderstate->Shader = &BloomCombine; + renderstate->Uniforms.Clear(); + renderstate->Viewport = next.Viewport; + renderstate->SetInputTexture(0, &blevel.VTexture, PPFilterMode::Linear); + renderstate->SetOutputTexture(&next.VTexture); + renderstate->SetNoBlend(); + renderstate->Draw(); } - steps.Push(BlurStep(blurUniforms, level0.VTexture, level0.HTexture, level0.Viewport, false)); - steps.Push(BlurStep(blurUniforms, level0.HTexture, level0.VTexture, level0.Viewport, true)); + BlurStep(renderstate, blurUniforms, level0.VTexture, level0.HTexture, level0.Viewport, false); + BlurStep(renderstate, blurUniforms, level0.HTexture, level0.VTexture, level0.Viewport, true); // Add bloom back to scene texture: - step.ShaderName = "BloomCombine"; - step.Uniforms.Clear(); - step.Viewport = screen->mSceneViewport; - step.SetInputTexture(0, level0.VTexture, PPFilterMode::Linear); - step.SetOutputCurrent(); - step.SetAdditiveBlend(); - steps.Push(step); - - hw_postprocess.Effects["BloomScene"] = steps; + renderstate->Clear(); + renderstate->Shader = &BloomCombine; + renderstate->Uniforms.Clear(); + renderstate->Viewport = screen->mSceneViewport; + renderstate->SetInputTexture(0, &level0.VTexture, PPFilterMode::Linear); + renderstate->SetOutputCurrent(); + renderstate->SetAdditiveBlend(); + renderstate->Draw(); } -void PPBloom::UpdateBlurSteps() +void PPBloom::RenderBlur(PPRenderState *renderstate, int sceneWidth, int sceneHeight, float gameinfobluramount) { + // No scene, no blur! + if (sceneWidth <= 0 || sceneHeight <= 0) + return; + + UpdateTextures(sceneWidth, sceneHeight); + // first, respect the CVar float blurAmount = gl_menu_blur; // if CVar is negative, use the gameinfo entry if (gl_menu_blur < 0) - blurAmount = hw_postprocess.gameinfobluramount; + blurAmount = gameinfobluramount; // if blurAmount == 0 or somehow still returns negative, exit to prevent a crash, clearly we don't want this if (blurAmount <= 0.0) { - hw_postprocess.Effects["BlurScene"] = {}; return; } - TArray steps; - PPStep step; - int numLevels = 3; assert(numLevels <= NumBloomLevels); - const auto &level0 = levels[0]; + auto &level0 = levels[0]; // Grab the area we want to bloom: - step.ShaderName = "BloomCombine"; - step.Uniforms.Clear(); - step.Viewport = level0.Viewport; - step.SetInputCurrent(0, PPFilterMode::Linear); - step.SetOutputTexture(level0.VTexture); - step.SetNoBlend(); - steps.Push(step); + renderstate->Clear(); + renderstate->Shader = &BloomCombine; + renderstate->Uniforms.Clear(); + renderstate->Viewport = level0.Viewport; + renderstate->SetInputCurrent(0, PPFilterMode::Linear); + renderstate->SetOutputTexture(&level0.VTexture); + renderstate->SetNoBlend(); + renderstate->Draw(); BlurUniforms blurUniforms; ComputeBlurSamples(7, blurAmount, blurUniforms.SampleWeights); @@ -196,17 +167,18 @@ void PPBloom::UpdateBlurSteps() auto &blevel = levels[i]; auto &next = levels[i + 1]; - steps.Push(BlurStep(blurUniforms, blevel.VTexture, blevel.HTexture, blevel.Viewport, false)); - steps.Push(BlurStep(blurUniforms, blevel.HTexture, blevel.VTexture, blevel.Viewport, true)); + BlurStep(renderstate, blurUniforms, blevel.VTexture, blevel.HTexture, blevel.Viewport, false); + BlurStep(renderstate, blurUniforms, blevel.HTexture, blevel.VTexture, blevel.Viewport, true); // Linear downscale: - step.ShaderName = "BloomCombine"; - step.Uniforms.Clear(); - step.Viewport = next.Viewport; - step.SetInputTexture(0, blevel.VTexture, PPFilterMode::Linear); - step.SetOutputTexture(next.VTexture); - step.SetNoBlend(); - steps.Push(step); + renderstate->Clear(); + renderstate->Shader = &BloomCombine; + renderstate->Uniforms.Clear(); + renderstate->Viewport = next.Viewport; + renderstate->SetInputTexture(0, &blevel.VTexture, PPFilterMode::Linear); + renderstate->SetOutputTexture(&next.VTexture); + renderstate->SetNoBlend(); + renderstate->Draw(); } // Blur and upscale: @@ -215,44 +187,44 @@ void PPBloom::UpdateBlurSteps() auto &blevel = levels[i]; auto &next = levels[i - 1]; - steps.Push(BlurStep(blurUniforms, blevel.VTexture, blevel.HTexture, blevel.Viewport, false)); - steps.Push(BlurStep(blurUniforms, blevel.HTexture, blevel.VTexture, blevel.Viewport, true)); + BlurStep(renderstate, blurUniforms, blevel.VTexture, blevel.HTexture, blevel.Viewport, false); + BlurStep(renderstate, blurUniforms, blevel.HTexture, blevel.VTexture, blevel.Viewport, true); // Linear upscale: - step.ShaderName = "BloomCombine"; - step.Uniforms.Clear(); - step.Viewport = next.Viewport; - step.SetInputTexture(0, blevel.VTexture, PPFilterMode::Linear); - step.SetOutputTexture(next.VTexture); - step.SetNoBlend(); - steps.Push(step); + renderstate->Clear(); + renderstate->Shader = &BloomCombine; + renderstate->Uniforms.Clear(); + renderstate->Viewport = next.Viewport; + renderstate->SetInputTexture(0, &blevel.VTexture, PPFilterMode::Linear); + renderstate->SetOutputTexture(&next.VTexture); + renderstate->SetNoBlend(); + renderstate->Draw(); } - steps.Push(BlurStep(blurUniforms, level0.VTexture, level0.HTexture, level0.Viewport, false)); - steps.Push(BlurStep(blurUniforms, level0.HTexture, level0.VTexture, level0.Viewport, true)); + BlurStep(renderstate, blurUniforms, level0.VTexture, level0.HTexture, level0.Viewport, false); + BlurStep(renderstate, blurUniforms, level0.HTexture, level0.VTexture, level0.Viewport, true); // Copy blur back to scene texture: - step.ShaderName = "BloomCombine"; - step.Uniforms.Clear(); - step.Viewport = screen->mScreenViewport; - step.SetInputTexture(0, level0.VTexture, PPFilterMode::Linear); - step.SetOutputCurrent(); - step.SetNoBlend(); - steps.Push(step); - - hw_postprocess.Effects["BlurScene"] = steps; + renderstate->Clear(); + renderstate->Shader = &BloomCombine; + renderstate->Uniforms.Clear(); + renderstate->Viewport = screen->mScreenViewport; + renderstate->SetInputTexture(0, &level0.VTexture, PPFilterMode::Linear); + renderstate->SetOutputCurrent(); + renderstate->SetNoBlend(); + renderstate->Draw(); } -PPStep PPBloom::BlurStep(const BlurUniforms &blurUniforms, PPTextureName input, PPTextureName output, PPViewport viewport, bool vertical) +void PPBloom::BlurStep(PPRenderState *renderstate, const BlurUniforms &blurUniforms, PPTexture &input, PPTexture &output, PPViewport viewport, bool vertical) { - PPStep step; - step.ShaderName = vertical ? "BlurVertical" : "BlurHorizontal"; - step.Uniforms.Set(blurUniforms); - step.Viewport = viewport; - step.SetInputTexture(0, input); - step.SetOutputTexture(output); - step.SetNoBlend(); - return step; + renderstate->Clear(); + renderstate->Shader = vertical ? &BlurVertical : &BlurHorizontal; + renderstate->Uniforms.Set(blurUniforms); + renderstate->Viewport = viewport; + renderstate->SetInputTexture(0, &input); + renderstate->SetOutputTexture(&output); + renderstate->SetNoBlend(); + renderstate->Draw(); } float PPBloom::ComputeBlurGaussian(float n, float theta) // theta = Blur Amount @@ -284,16 +256,10 @@ void PPBloom::ComputeBlurSamples(int sampleCount, float blurAmount, float *sampl ///////////////////////////////////////////////////////////////////////////// -void PPLensDistort::DeclareShaders() -{ - hw_postprocess.Shaders["Lens"] = { "shaders/glsl/lensdistortion.fp", "", LensUniforms::Desc() }; -} - -void PPLensDistort::UpdateSteps() +void PPLensDistort::Render(PPRenderState *renderstate) { if (gl_lens == 0) { - hw_postprocess.Effects["LensDistortScene"] = {}; return; } @@ -328,59 +294,43 @@ void PPLensDistort::UpdateSteps() uniforms.LensDistortionCoefficient = k; uniforms.CubicDistortionValue = kcube; - TArray steps; - - PPStep step; - step.ShaderName = "Lens"; - step.Uniforms.Set(uniforms); - step.Viewport = screen->mScreenViewport; - step.SetInputCurrent(0, PPFilterMode::Linear); - step.SetOutputNext(); - step.SetNoBlend(); - steps.Push(step); - - hw_postprocess.Effects["LensDistortScene"] = steps; + renderstate->Clear(); + renderstate->Shader = &Lens; + renderstate->Uniforms.Set(uniforms); + renderstate->Viewport = screen->mScreenViewport; + renderstate->SetInputCurrent(0, PPFilterMode::Linear); + renderstate->SetOutputNext(); + renderstate->SetNoBlend(); + renderstate->Draw(); } ///////////////////////////////////////////////////////////////////////////// -void PPFXAA::DeclareShaders() -{ - hw_postprocess.Shaders["FXAALuma"] = { "shaders/glsl/fxaa.fp", "#define FXAA_LUMA_PASS\n", {} }; - hw_postprocess.Shaders["FXAA"] = { "shaders/glsl/fxaa.fp", GetDefines(), FXAAUniforms::Desc(), GetMaxVersion() }; -} - -void PPFXAA::UpdateSteps() +void PPFXAA::Render(PPRenderState *renderstate) { if (0 == gl_fxaa) { - hw_postprocess.Effects["ApplyFXAA"] = {}; return; } + CreateShaders(); + FXAAUniforms uniforms; uniforms.ReciprocalResolution = { 1.0f / screen->mScreenViewport.width, 1.0f / screen->mScreenViewport.height }; - TArray steps; + renderstate->Clear(); + renderstate->Shader = &FXAALuma; + renderstate->Uniforms.Clear(); + renderstate->Viewport = screen->mScreenViewport; + renderstate->SetInputCurrent(0, PPFilterMode::Nearest); + renderstate->SetOutputNext(); + renderstate->SetNoBlend(); + renderstate->Draw(); - PPStep step; - step.ShaderName = "FXAALuma"; - step.Uniforms.Clear(); - step.Viewport = screen->mScreenViewport; - step.SetInputCurrent(0, PPFilterMode::Nearest); - step.SetOutputNext(); - step.SetNoBlend(); - steps.Push(step); - - step.ShaderName = "FXAA"; - step.Uniforms.Set(uniforms); - step.Viewport = screen->mScreenViewport; - step.SetInputCurrent(0, PPFilterMode::Linear); - step.SetOutputNext(); - step.SetNoBlend(); - steps.Push(step); - - hw_postprocess.Effects["ApplyFXAA"] = steps; + renderstate->Shader = &FXAA; + renderstate->Uniforms.Set(uniforms); + renderstate->SetInputCurrent(0, PPFilterMode::Linear); + renderstate->Draw(); } int PPFXAA::GetMaxVersion() @@ -388,6 +338,16 @@ int PPFXAA::GetMaxVersion() return screen->glslversion >= 4.f ? 400 : 330; } +void PPFXAA::CreateShaders() +{ + if (LastQuality == gl_fxaa) + return; + + FXAALuma = { "shaders/glsl/fxaa.fp", "#define FXAA_LUMA_PASS\n", {} }; + FXAA = { "shaders/glsl/fxaa.fp", GetDefines(), FXAAUniforms::Desc(), GetMaxVersion() }; + LastQuality = gl_fxaa; +} + FString PPFXAA::GetDefines() { int quality; @@ -417,61 +377,14 @@ FString PPFXAA::GetDefines() ///////////////////////////////////////////////////////////////////////////// -void PPCameraExposure::DeclareShaders() -{ - hw_postprocess.Shaders["ExposureExtract"] = { "shaders/glsl/exposureextract.fp", "", ExposureExtractUniforms::Desc() }; - hw_postprocess.Shaders["ExposureAverage"] = { "shaders/glsl/exposureaverage.fp", "", {}, 400 }; - hw_postprocess.Shaders["ExposureCombine"] = { "shaders/glsl/exposurecombine.fp", "", ExposureCombineUniforms::Desc() }; -} - -void PPCameraExposure::UpdateTextures() -{ - int width = hw_postprocess.SceneWidth; - int height = hw_postprocess.SceneHeight; - - if (ExposureLevels.Size() > 0 && ExposureLevels[0].Viewport.width == width && ExposureLevels[0].Viewport.height == height) - { - return; - } - - ExposureLevels.Clear(); - - int i = 0; - do - { - width = MAX(width / 2, 1); - height = MAX(height / 2, 1); - - PPExposureLevel blevel; - blevel.Viewport.left = 0; - blevel.Viewport.top = 0; - blevel.Viewport.width = width; - blevel.Viewport.height = height; - blevel.Texture.Format("Exposure.Level.%d", i); - ExposureLevels.Push(blevel); - - PPTextureDesc texture = { blevel.Viewport.width, blevel.Viewport.height, PixelFormat::R32f }; - hw_postprocess.Textures[blevel.Texture] = texture; - - i++; - - } while (width > 1 || height > 1); - - hw_postprocess.Textures["Exposure.CameraTexture"] = { 1, 1, PixelFormat::R32f }; - - FirstExposureFrame = true; -} - -void PPCameraExposure::UpdateSteps() +void PPCameraExposure::Render(PPRenderState *renderstate, int sceneWidth, int sceneHeight) { if (!gl_bloom) { - hw_postprocess.Effects["UpdateCameraExposure"] = {}; return; } - TArray steps; - PPStep step; + UpdateTextures(sceneWidth, sceneHeight); ExposureExtractUniforms extractUniforms; extractUniforms.Scale = screen->SceneScale(); @@ -486,63 +399,84 @@ void PPCameraExposure::UpdateSteps() auto &level0 = ExposureLevels[0]; // Extract light blevel from scene texture: - step.ShaderName = "ExposureExtract"; - step.Uniforms.Set(extractUniforms); - step.Viewport = level0.Viewport; - step.SetInputCurrent(0, PPFilterMode::Linear); - step.SetOutputTexture(level0.Texture); - step.SetNoBlend(); - steps.Push(step); + renderstate->Clear(); + renderstate->Shader = &ExposureExtract; + renderstate->Uniforms.Set(extractUniforms); + renderstate->Viewport = level0.Viewport; + renderstate->SetInputCurrent(0, PPFilterMode::Linear); + renderstate->SetOutputTexture(&level0.Texture); + renderstate->SetNoBlend(); + renderstate->Draw(); // Find the average value: - for (unsigned int i = 0; i + 1 < ExposureLevels.Size(); i++) + for (size_t i = 0; i + 1 < ExposureLevels.size(); i++) { auto &blevel = ExposureLevels[i]; auto &next = ExposureLevels[i + 1]; - step.ShaderName = "ExposureAverage"; - step.Uniforms.Clear(); - step.Viewport = next.Viewport; - step.SetInputTexture(0, blevel.Texture, PPFilterMode::Linear); - step.SetOutputTexture(next.Texture); - step.SetNoBlend(); - steps.Push(step); + renderstate->Shader = &ExposureAverage; + renderstate->Uniforms.Clear(); + renderstate->Viewport = next.Viewport; + renderstate->SetInputTexture(0, &blevel.Texture, PPFilterMode::Linear); + renderstate->SetOutputTexture(&next.Texture); + renderstate->SetNoBlend(); + renderstate->Draw(); } // Combine average value with current camera exposure: - step.ShaderName = "ExposureCombine"; - step.Uniforms.Set(combineUniforms); - step.Viewport.left = 0; - step.Viewport.top = 0; - step.Viewport.width = 1; - step.Viewport.height = 1; - step.SetInputTexture(0, ExposureLevels.Last().Texture, PPFilterMode::Linear); - step.SetOutputTexture("Exposure.CameraTexture"); + renderstate->Shader = &ExposureCombine; + renderstate->Uniforms.Set(combineUniforms); + renderstate->Viewport.left = 0; + renderstate->Viewport.top = 0; + renderstate->Viewport.width = 1; + renderstate->Viewport.height = 1; + renderstate->SetInputTexture(0, &ExposureLevels.back().Texture, PPFilterMode::Linear); + renderstate->SetOutputTexture(&CameraTexture); if (!FirstExposureFrame) - step.SetAlphaBlend(); + renderstate->SetAlphaBlend(); else - step.SetNoBlend(); - steps.Push(step); + renderstate->SetNoBlend(); + renderstate->Draw(); FirstExposureFrame = false; +} - hw_postprocess.Effects["UpdateCameraExposure"] = steps; +void PPCameraExposure::UpdateTextures(int width, int height) +{ + if (ExposureLevels.size() > 0 && ExposureLevels[0].Viewport.width == width && ExposureLevels[0].Viewport.height == height) + { + return; + } + + ExposureLevels.clear(); + + int i = 0; + do + { + width = MAX(width / 2, 1); + height = MAX(height / 2, 1); + + PPExposureLevel blevel; + blevel.Viewport.left = 0; + blevel.Viewport.top = 0; + blevel.Viewport.width = width; + blevel.Viewport.height = height; + blevel.Texture = { blevel.Viewport.width, blevel.Viewport.height, PixelFormat::R32f }; + ExposureLevels.push_back(std::move(blevel)); + + i++; + + } while (width > 1 || height > 1); + + FirstExposureFrame = true; } ///////////////////////////////////////////////////////////////////////////// -void PPColormap::DeclareShaders() +void PPColormap::Render(PPRenderState *renderstate, int fixedcm) { - hw_postprocess.Shaders["Colormap"] = { "shaders/glsl/colormap.fp", "", ColormapUniforms::Desc() }; -} - -void PPColormap::UpdateSteps() -{ - int fixedcm = hw_postprocess.fixedcm; - if (fixedcm < CM_FIRSTSPECIALCOLORMAP || fixedcm >= CM_MAXCOLORMAP) { - hw_postprocess.Effects["ColormapScene"] = {}; return; } @@ -554,99 +488,114 @@ void PPColormap::UpdateSteps() uniforms.MapStart = { scm->ColorizeStart[0], scm->ColorizeStart[1], scm->ColorizeStart[2], 0.f }; uniforms.MapRange = m; - PPStep step; - step.ShaderName = "Colormap"; - step.Uniforms.Set(uniforms); - step.Viewport = screen->mScreenViewport; - step.SetInputCurrent(0); - step.SetOutputNext(); - step.SetNoBlend(); - - TArray steps; - steps.Push(step); - hw_postprocess.Effects["ColormapScene"] = steps; + renderstate->Clear(); + renderstate->Shader = &Colormap; + renderstate->Uniforms.Set(uniforms); + renderstate->Viewport = screen->mScreenViewport; + renderstate->SetInputCurrent(0); + renderstate->SetOutputNext(); + renderstate->SetNoBlend(); + renderstate->Draw(); } ///////////////////////////////////////////////////////////////////////////// -void PPTonemap::DeclareShaders() -{ - hw_postprocess.Shaders["Tonemap.Linear"] = { "shaders/glsl/tonemap.fp", "#define LINEAR\n", {} }; - hw_postprocess.Shaders["Tonemap.Reinhard"] = { "shaders/glsl/tonemap.fp", "#define REINHARD\n", {} }; - hw_postprocess.Shaders["Tonemap.HejlDawson"] = { "shaders/glsl/tonemap.fp", "#define HEJLDAWSON\n", {} }; - hw_postprocess.Shaders["Tonemap.Uncharted2"] = { "shaders/glsl/tonemap.fp", "#define UNCHARTED2\n", {} }; - hw_postprocess.Shaders["Tonemap.Palette"] = { "shaders/glsl/tonemap.fp", "#define PALETTE\n", {} }; -} - void PPTonemap::UpdateTextures() { - if (gl_tonemap == Palette) + if (gl_tonemap == Palette && !PaletteTexture.Data) { - if (!hw_postprocess.Textures.CheckKey("Tonemap.Palette")) - { - std::shared_ptr data(new uint32_t[512 * 512], [](void *p) { delete[](uint32_t*)p; }); + std::shared_ptr data(new uint32_t[512 * 512], [](void *p) { delete[](uint32_t*)p; }); - uint8_t *lut = (uint8_t *)data.get(); - for (int r = 0; r < 64; r++) + uint8_t *lut = (uint8_t *)data.get(); + for (int r = 0; r < 64; r++) + { + for (int g = 0; g < 64; g++) { - for (int g = 0; g < 64; g++) + for (int b = 0; b < 64; b++) { - for (int b = 0; b < 64; b++) - { - PalEntry color = GPalette.BaseColors[(uint8_t)PTM_BestColor((uint32_t *)GPalette.BaseColors, (r << 2) | (r >> 4), (g << 2) | (g >> 4), (b << 2) | (b >> 4), - gl_paltonemap_reverselookup, gl_paltonemap_powtable, 0, 256)]; - int index = ((r * 64 + g) * 64 + b) * 4; - lut[index] = color.r; - lut[index + 1] = color.g; - lut[index + 2] = color.b; - lut[index + 3] = 255; - } + PalEntry color = GPalette.BaseColors[(uint8_t)PTM_BestColor((uint32_t *)GPalette.BaseColors, (r << 2) | (r >> 4), (g << 2) | (g >> 4), (b << 2) | (b >> 4), + gl_paltonemap_reverselookup, gl_paltonemap_powtable, 0, 256)]; + int index = ((r * 64 + g) * 64 + b) * 4; + lut[index] = color.r; + lut[index + 1] = color.g; + lut[index + 2] = color.b; + lut[index + 3] = 255; } } - - hw_postprocess.Textures["Tonemap.Palette"] = { 512, 512, PixelFormat::Rgba8, data }; } + + PaletteTexture = { 512, 512, PixelFormat::Rgba8, data }; } } -void PPTonemap::UpdateSteps() +void PPTonemap::Render(PPRenderState *renderstate) { if (gl_tonemap == 0) { - hw_postprocess.Effects["TonemapScene"] = {}; return; } - PPShaderName shader; + UpdateTextures(); + + PPShader *shader = nullptr; switch (gl_tonemap) { default: - case Linear: shader = "Tonemap.Linear"; break; - case Reinhard: shader = "Tonemap.Reinhard"; break; - case HejlDawson: shader = "Tonemap.HejlDawson"; break; - case Uncharted2: shader = "Tonemap.Uncharted2"; break; - case Palette: shader = "Tonemap.Palette"; break; + case Linear: shader = &LinearShader; break; + case Reinhard: shader = &ReinhardShader; break; + case HejlDawson: shader = &HejlDawsonShader; break; + case Uncharted2: shader = &Uncharted2Shader; break; + case Palette: shader = &PaletteShader; break; } - PPStep step; - step.ShaderName = shader; - step.Viewport = screen->mScreenViewport; - step.SetInputCurrent(0); + renderstate->Clear(); + renderstate->Shader = shader; + renderstate->Viewport = screen->mScreenViewport; + renderstate->SetInputCurrent(0); if (gl_tonemap == Palette) - step.SetInputTexture(1, "Tonemap.Palette"); - step.SetOutputNext(); - step.SetNoBlend(); - - TArray steps; - steps.Push(step); - hw_postprocess.Effects["TonemapScene"] = steps; + renderstate->SetInputTexture(1, &PaletteTexture); + renderstate->SetOutputNext(); + renderstate->SetNoBlend(); + renderstate->Draw(); } - ///////////////////////////////////////////////////////////////////////////// -void PPAmbientOcclusion::DeclareShaders() +PPAmbientOcclusion::PPAmbientOcclusion() { + // Must match quality enum in PPAmbientOcclusion::DeclareShaders + double numDirections[NumAmbientRandomTextures] = { 2.0, 4.0, 8.0 }; + + std::mt19937 generator(1337); + std::uniform_real_distribution distribution(0.0, 1.0); + for (int quality = 0; quality < NumAmbientRandomTextures; quality++) + { + std::shared_ptr data(new int16_t[16 * 4], [](void *p) { delete[](int16_t*)p; }); + int16_t *randomValues = (int16_t *)data.get(); + + for (int i = 0; i < 16; i++) + { + double angle = 2.0 * M_PI * distribution(generator) / numDirections[quality]; + double x = cos(angle); + double y = sin(angle); + double z = distribution(generator); + double w = distribution(generator); + + randomValues[i * 4 + 0] = (int16_t)clamp(x * 32767.0, -32768.0, 32767.0); + randomValues[i * 4 + 1] = (int16_t)clamp(y * 32767.0, -32768.0, 32767.0); + randomValues[i * 4 + 2] = (int16_t)clamp(z * 32767.0, -32768.0, 32767.0); + randomValues[i * 4 + 3] = (int16_t)clamp(w * 32767.0, -32768.0, 32767.0); + } + + AmbientRandomTexture[quality] = { 4, 4, PixelFormat::Rgba16_snorm, data }; + } +} + +void PPAmbientOcclusion::CreateShaders() +{ + if (gl_ssao == LastQuality) + return; + // Must match quality values in PPAmbientOcclusion::UpdateTextures int numDirections, numSteps; switch (gl_ssao) @@ -665,83 +614,52 @@ void PPAmbientOcclusion::DeclareShaders() #define NUM_STEPS %d.0 )", numDirections, numSteps); - hw_postprocess.Shaders["SSAO.LinearDepth"] = { "shaders/glsl/lineardepth.fp", "", LinearDepthUniforms::Desc() }; - hw_postprocess.Shaders["SSAO.LinearDepthMS"] = { "shaders/glsl/lineardepth.fp", "#define MULTISAMPLE\n", LinearDepthUniforms::Desc() }; - hw_postprocess.Shaders["SSAO.AmbientOcclude"] = { "shaders/glsl/ssao.fp", defines, SSAOUniforms::Desc() }; - hw_postprocess.Shaders["SSAO.AmbientOccludeMS"] = { "shaders/glsl/ssao.fp", defines + "\n#define MULTISAMPLE\n", SSAOUniforms::Desc() }; - hw_postprocess.Shaders["SSAO.BlurVertical"] = { "shaders/glsl/depthblur.fp", "#define BLUR_VERTICAL\n", DepthBlurUniforms::Desc() }; - hw_postprocess.Shaders["SSAO.BlurHorizontal"] = { "shaders/glsl/depthblur.fp", "#define BLUR_HORIZONTAL\n", DepthBlurUniforms::Desc() }; - hw_postprocess.Shaders["SSAO.Combine"] = { "shaders/glsl/ssaocombine.fp", "", AmbientCombineUniforms::Desc() }; - hw_postprocess.Shaders["SSAO.CombineMS"] = { "shaders/glsl/ssaocombine.fp", "#define MULTISAMPLE\n", AmbientCombineUniforms::Desc() }; + LinearDepth = { "shaders/glsl/lineardepth.fp", "", LinearDepthUniforms::Desc() }; + LinearDepthMS = { "shaders/glsl/lineardepth.fp", "#define MULTISAMPLE\n", LinearDepthUniforms::Desc() }; + AmbientOcclude = { "shaders/glsl/ssao.fp", defines, SSAOUniforms::Desc() }; + AmbientOccludeMS = { "shaders/glsl/ssao.fp", defines + "\n#define MULTISAMPLE\n", SSAOUniforms::Desc() }; + BlurVertical = { "shaders/glsl/depthblur.fp", "#define BLUR_VERTICAL\n", DepthBlurUniforms::Desc() }; + BlurHorizontal = { "shaders/glsl/depthblur.fp", "#define BLUR_HORIZONTAL\n", DepthBlurUniforms::Desc() }; + Combine = { "shaders/glsl/ssaocombine.fp", "", AmbientCombineUniforms::Desc() }; + CombineMS = { "shaders/glsl/ssaocombine.fp", "#define MULTISAMPLE\n", AmbientCombineUniforms::Desc() }; + + LastQuality = gl_ssao; } -void PPAmbientOcclusion::UpdateTextures() +void PPAmbientOcclusion::UpdateTextures(int width, int height) { - int width = hw_postprocess.SceneWidth; - int height = hw_postprocess.SceneHeight; - - if (width <= 0 || height <= 0) + if ((width <= 0 || height <= 0) || (width == LastWidth && height == LastHeight)) return; AmbientWidth = (width + 1) / 2; AmbientHeight = (height + 1) / 2; - hw_postprocess.Textures["SSAO.LinearDepth"] = { AmbientWidth, AmbientHeight, PixelFormat::R32f }; - hw_postprocess.Textures["SSAO.Ambient0"] = { AmbientWidth, AmbientHeight, PixelFormat::Rg16f }; - hw_postprocess.Textures["SSAO.Ambient1"] = { AmbientWidth, AmbientHeight, PixelFormat::Rg16f }; + LinearDepthTexture = { AmbientWidth, AmbientHeight, PixelFormat::R32f }; + Ambient0 = { AmbientWidth, AmbientHeight, PixelFormat::Rg16f }; + Ambient1 = { AmbientWidth, AmbientHeight, PixelFormat::Rg16f }; - // We only need to create the random texture once - if (!hw_postprocess.Textures.CheckKey("SSAO.Random0")) - { - // Must match quality enum in PPAmbientOcclusion::DeclareShaders - double numDirections[NumAmbientRandomTextures] = { 2.0, 4.0, 8.0 }; - - std::mt19937 generator(1337); - std::uniform_real_distribution distribution(0.0, 1.0); - for (int quality = 0; quality < NumAmbientRandomTextures; quality++) - { - std::shared_ptr data(new int16_t[16 * 4], [](void *p) { delete[](int16_t*)p; }); - int16_t *randomValues = (int16_t *)data.get(); - - for (int i = 0; i < 16; i++) - { - double angle = 2.0 * M_PI * distribution(generator) / numDirections[quality]; - double x = cos(angle); - double y = sin(angle); - double z = distribution(generator); - double w = distribution(generator); - - randomValues[i * 4 + 0] = (int16_t)clamp(x * 32767.0, -32768.0, 32767.0); - randomValues[i * 4 + 1] = (int16_t)clamp(y * 32767.0, -32768.0, 32767.0); - randomValues[i * 4 + 2] = (int16_t)clamp(z * 32767.0, -32768.0, 32767.0); - randomValues[i * 4 + 3] = (int16_t)clamp(w * 32767.0, -32768.0, 32767.0); - } - - FString name; - name.Format("SSAO.Random%d", quality); - - hw_postprocess.Textures[name] = { 4, 4, PixelFormat::Rgba16_snorm, data }; - AmbientRandomTexture[quality] = name; - } - } + LastWidth = width; + LastHeight = height; } -void PPAmbientOcclusion::UpdateSteps() +void PPAmbientOcclusion::Render(PPRenderState *renderstate, float m5, int sceneWidth, int sceneHeight) { - if (gl_ssao == 0 || hw_postprocess.SceneWidth == 0 || hw_postprocess.SceneHeight == 0) + if (gl_ssao == 0 || sceneWidth == 0 || sceneHeight == 0) { - hw_postprocess.Effects["AmbientOccludeScene"] = {}; return; } + CreateShaders(); + UpdateTextures(sceneWidth, sceneHeight); + float bias = gl_ssao_bias; float aoRadius = gl_ssao_radius; const float blurAmount = gl_ssao_blur; float aoStrength = gl_ssao_strength; //float tanHalfFovy = tan(fovy * (M_PI / 360.0f)); - float tanHalfFovy = 1.0f / hw_postprocess.m5; - float invFocalLenX = tanHalfFovy * (hw_postprocess.SceneWidth / (float)hw_postprocess.SceneHeight); + float tanHalfFovy = 1.0f / m5; + float invFocalLenX = tanHalfFovy * (sceneWidth / (float)sceneHeight); float invFocalLenY = tanHalfFovy; float nDotVBias = clamp(bias, 0.0f, 1.0f); float r2 = aoRadius * aoRadius; @@ -791,134 +709,96 @@ void PPAmbientOcclusion::UpdateSteps() ambientViewport.width = AmbientWidth; ambientViewport.height = AmbientHeight; - TArray steps; - // Calculate linear depth values - { - PPStep step; - step.ShaderName = gl_multisample > 1 ? "SSAO.LinearDepthMS" : "SSAO.LinearDepth"; - step.Uniforms.Set(linearUniforms); - step.Viewport = ambientViewport; - step.SetInputSceneDepth(0); - step.SetInputSceneColor(1); - step.SetOutputTexture("SSAO.LinearDepth"); - step.SetNoBlend(); - steps.Push(step); - } + renderstate->Clear(); + renderstate->Shader = gl_multisample > 1 ? &LinearDepthMS : &LinearDepth; + renderstate->Uniforms.Set(linearUniforms); + renderstate->Viewport = ambientViewport; + renderstate->SetInputSceneDepth(0); + renderstate->SetInputSceneColor(1); + renderstate->SetOutputTexture(&LinearDepthTexture); + renderstate->SetNoBlend(); + renderstate->Draw(); // Apply ambient occlusion - { - PPStep step; - step.ShaderName = gl_multisample > 1 ? "SSAO.AmbientOccludeMS" : "SSAO.AmbientOcclude"; - step.Uniforms.Set(ssaoUniforms); - step.Viewport = ambientViewport; - step.SetInputTexture(0, "SSAO.LinearDepth"); - step.SetInputSceneNormal(1); - step.SetInputTexture(2, AmbientRandomTexture[randomTexture], PPFilterMode::Nearest, PPWrapMode::Repeat); - step.SetOutputTexture("SSAO.Ambient0"); - step.SetNoBlend(); - steps.Push(step); - } + renderstate->Clear(); + renderstate->Shader = gl_multisample > 1 ? &AmbientOccludeMS : &AmbientOcclude; + renderstate->Uniforms.Set(ssaoUniforms); + renderstate->Viewport = ambientViewport; + renderstate->SetInputTexture(0, &LinearDepthTexture); + renderstate->SetInputSceneNormal(1); + renderstate->SetInputTexture(2, &AmbientRandomTexture[randomTexture], PPFilterMode::Nearest, PPWrapMode::Repeat); + renderstate->SetOutputTexture(&Ambient0); + renderstate->SetNoBlend(); + renderstate->Draw(); // Blur SSAO texture if (gl_ssao_debug < 2) { - PPStep step; - step.ShaderName = "SSAO.BlurHorizontal"; - step.Uniforms.Set(blurUniforms); - step.Viewport = ambientViewport; - step.SetInputTexture(0, "SSAO.Ambient0"); - step.SetOutputTexture("SSAO.Ambient1"); - step.SetNoBlend(); - steps.Push(step); + renderstate->Clear(); + renderstate->Shader = &BlurHorizontal; + renderstate->Uniforms.Set(blurUniforms); + renderstate->Viewport = ambientViewport; + renderstate->SetInputTexture(0, &Ambient0); + renderstate->SetOutputTexture(&Ambient1); + renderstate->SetNoBlend(); + renderstate->Draw(); - step.ShaderName = "SSAO.BlurVertical"; - step.SetInputTexture(0, "SSAO.Ambient1"); - step.SetOutputTexture("SSAO.Ambient0"); - steps.Push(step); + renderstate->Shader = &BlurVertical; + renderstate->SetInputTexture(0, &Ambient1); + renderstate->SetOutputTexture(&Ambient0); + renderstate->Draw(); } // Add SSAO back to scene texture: - { - PPStep step; - step.ShaderName = gl_multisample > 1 ? "SSAO.CombineMS" : "SSAO.Combine"; - step.Uniforms.Set(combineUniforms); - step.Viewport = screen->mSceneViewport; - step.SetInputTexture(0, "SSAO.Ambient0", PPFilterMode::Linear); - step.SetInputSceneFog(1); - step.SetOutputSceneColor(); - if (gl_ssao_debug != 0) - step.SetNoBlend(); - else - step.SetAlphaBlend(); - steps.Push(step); - } - - hw_postprocess.Effects["AmbientOccludeScene"] = steps; + renderstate->Clear(); + renderstate->Shader = gl_multisample > 1 ? &CombineMS : &Combine; + renderstate->Uniforms.Set(combineUniforms); + renderstate->Viewport = screen->mSceneViewport; + renderstate->SetInputTexture(0, &Ambient0, PPFilterMode::Linear); + renderstate->SetInputSceneFog(1); + renderstate->SetOutputSceneColor(); + if (gl_ssao_debug != 0) + renderstate->SetNoBlend(); + else + renderstate->SetAlphaBlend(); + renderstate->Draw(); } ///////////////////////////////////////////////////////////////////////////// -void PPPresent::DeclareShaders() +PPPresent::PPPresent() { - hw_postprocess.Shaders["Present"] = { "shaders/glsl/present.fp", "", PresentUniforms::Desc() }; - hw_postprocess.Shaders["Present.Checker3D"] = { "shaders/glsl/present_checker3d.fp", "", PresentUniforms::Desc() }; - hw_postprocess.Shaders["Present.Column3D"] = { "shaders/glsl/present_column3d.fp", "", PresentUniforms::Desc() }; - hw_postprocess.Shaders["Present.Row3D"] = { "shaders/glsl/present_row3d.fp", "", PresentUniforms::Desc() }; -} - -void PPPresent::UpdateTextures() -{ - auto &tex = hw_postprocess.Textures["PresentDither"]; - if (!tex.Data) + static const float data[64] = { - static const float data[64] = - { - .0078125, .2578125, .1328125, .3828125, .0234375, .2734375, .1484375, .3984375, - .7578125, .5078125, .8828125, .6328125, .7734375, .5234375, .8984375, .6484375, - .0703125, .3203125, .1953125, .4453125, .0859375, .3359375, .2109375, .4609375, - .8203125, .5703125, .9453125, .6953125, .8359375, .5859375, .9609375, .7109375, - .0390625, .2890625, .1640625, .4140625, .0546875, .3046875, .1796875, .4296875, - .7890625, .5390625, .9140625, .6640625, .8046875, .5546875, .9296875, .6796875, - .1015625, .3515625, .2265625, .4765625, .1171875, .3671875, .2421875, .4921875, - .8515625, .6015625, .9765625, .7265625, .8671875, .6171875, .9921875, .7421875, - }; + .0078125, .2578125, .1328125, .3828125, .0234375, .2734375, .1484375, .3984375, + .7578125, .5078125, .8828125, .6328125, .7734375, .5234375, .8984375, .6484375, + .0703125, .3203125, .1953125, .4453125, .0859375, .3359375, .2109375, .4609375, + .8203125, .5703125, .9453125, .6953125, .8359375, .5859375, .9609375, .7109375, + .0390625, .2890625, .1640625, .4140625, .0546875, .3046875, .1796875, .4296875, + .7890625, .5390625, .9140625, .6640625, .8046875, .5546875, .9296875, .6796875, + .1015625, .3515625, .2265625, .4765625, .1171875, .3671875, .2421875, .4921875, + .8515625, .6015625, .9765625, .7265625, .8671875, .6171875, .9921875, .7421875, + }; - std::shared_ptr pixels(new float[64], [](void *p) { delete[](float*)p; }); - memcpy(pixels.get(), data, 64 * sizeof(float)); - tex = { 8, 8, PixelFormat::R32f, pixels }; - } -} - -void PPPresent::UpdateSteps() -{ + std::shared_ptr pixels(new float[64], [](void *p) { delete[](float*)p; }); + memcpy(pixels.get(), data, 64 * sizeof(float)); + Dither = { 8, 8, PixelFormat::R32f, pixels }; } ///////////////////////////////////////////////////////////////////////////// -void PPShadowMap::DeclareShaders() -{ - hw_postprocess.Shaders["ShadowMap"] = { "shaders/glsl/shadowmap.fp", "", ShadowMapUniforms::Desc() }; -} - -void PPShadowMap::UpdateTextures() -{ -} - -void PPShadowMap::UpdateSteps() +void PPShadowMap::Update(PPRenderState *renderstate) { 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 steps; - steps.Push(step); - hw_postprocess.Effects["UpdateShadowMap"] = steps; + renderstate->Clear(); + renderstate->Shader = &ShadowMap; + renderstate->Uniforms.Set(uniforms); + renderstate->Viewport = { 0, 0, gl_shadowmap_quality, 1024 }; + renderstate->SetShadowMapBuffers(true); + renderstate->SetOutputShadowMap(); + renderstate->SetNoBlend(); + renderstate->Draw(); } diff --git a/src/rendering/hwrenderer/postprocessing/hw_postprocess.h b/src/rendering/hwrenderer/postprocessing/hw_postprocess.h index 1e2dd28c39..9b1df90afa 100644 --- a/src/rendering/hwrenderer/postprocessing/hw_postprocess.h +++ b/src/rendering/hwrenderer/postprocessing/hw_postprocess.h @@ -3,12 +3,12 @@ #include "hwrenderer/data/shaderuniforms.h" #include -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 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(); + 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 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 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 data = {}) : Width(width), Height(height), Format(format), Data(data) { } + + void ResetBackend() override { Backend.reset(); } int Width; int Height; PixelFormat Format; std::shared_ptr Data; + + std::unique_ptr 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 &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 Uniforms; int Version = 330; + + std::unique_ptr 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> Effects; - TMap Textures; - TMap Shaders; - - TArray 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 ExposureLevels; + void UpdateTextures(int width, int height); + + std::vector 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; diff --git a/src/rendering/vulkan/renderer/vk_postprocess.cpp b/src/rendering/vulkan/renderer/vk_postprocess.cpp index 8cba3793fb..12ff156394 100644 --- a/src/rendering/vulkan/renderer/vk_postprocess.cpp +++ b/src/rendering/vulkan/renderer/vk_postprocess.cpp @@ -40,18 +40,22 @@ void VkPostprocess::SetActiveRenderTarget() void VkPostprocess::PostProcessScene(int fixedcm, const std::function &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 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::Iterator it(hw_postprocess.Textures); - TMap::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, ®ion); - 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, ®ion); - - 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::Iterator it(hw_postprocess.Shaders); - TMap::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 &textures, bool bindShadowMapBuffers) +VulkanDescriptorSet *VkPPRenderState::GetInput(VkPPRenderPassSetup *passSetup, const TArray &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(shader); + return static_cast(shader->Backend.get()); } -void VkPostprocess::NextEye(int eyeCount) +VkPPTexture *VkPPRenderState::GetVkTexture(PPTexture *texture) { + if (!texture->Backend) + texture->Backend = std::make_unique(texture); + return static_cast(texture->Backend.get()); } ///////////////////////////////////////////////////////////////////////////// diff --git a/src/rendering/vulkan/renderer/vk_postprocess.h b/src/rendering/vulkan/renderer/vk_postprocess.h index 7cb009e583..2ba858ccbf 100644 --- a/src/rendering/vulkan/renderer/vk_postprocess.h +++ b/src/rendering/vulkan/renderer/vk_postprocess.h @@ -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 &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> mTextures; - std::map> mShaders; std::array, 16> mSamplers; std::map> mRenderPassSetup; std::unique_ptr mDescriptorPool; std::vector> mFrameDescriptorSets; int mCurrentPipelineImage = 0; + + friend class VkPPRenderState; }; -class VkPPShader +class VkPPShader : public PPShaderBackend { public: + VkPPShader(PPShader *shader); + std::unique_ptr VertexShader; std::unique_ptr 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 Image; std::unique_ptr View; std::unique_ptr 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 &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); +}; diff --git a/src/rendering/vulkan/system/vk_framebuffer.cpp b/src/rendering/vulkan/system/vk_framebuffer.cpp index b1eb24fdcc..61f083ab77 100644 --- a/src/rendering/vulkan/system/vk_framebuffer.cpp +++ b/src/rendering/vulkan/system/vk_framebuffer.cpp @@ -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;