diff --git a/src/gl/renderer/gl_postprocess.cpp b/src/gl/renderer/gl_postprocess.cpp index 06ac1cae36..2b683969ca 100644 --- a/src/gl/renderer/gl_postprocess.cpp +++ b/src/gl/renderer/gl_postprocess.cpp @@ -275,6 +275,48 @@ void FGLRenderer::UpdateCameraExposure() // //----------------------------------------------------------------------------- +static float ComputeBlurGaussian(float n, float theta) // theta = Blur Amount +{ + return (float)((1.0f / sqrtf(2 * (float)M_PI * theta)) * expf(-(n * n) / (2.0f * theta * theta))); +} + +static void ComputeBlurSamples(int sampleCount, float blurAmount, float *sampleWeights) +{ + sampleWeights[0] = ComputeBlurGaussian(0, blurAmount); + + float totalWeights = sampleWeights[0]; + + for (int i = 0; i < sampleCount / 2; i++) + { + float weight = ComputeBlurGaussian(i + 1.0f, blurAmount); + + sampleWeights[i * 2 + 1] = weight; + sampleWeights[i * 2 + 2] = weight; + + totalWeights += weight * 2; + } + + for (int i = 0; i < sampleCount; i++) + { + sampleWeights[i] /= totalWeights; + } +} + +static void RenderBlur(FGLRenderer *renderer, float blurAmount, PPTexture input, PPFrameBuffer output, int width, int height, bool vertical) +{ + ComputeBlurSamples(7, blurAmount, renderer->mBlurShader->Uniforms[vertical]->SampleWeights); + + renderer->mBlurShader->Bind(vertical); + renderer->mBlurShader->SourceTexture[vertical].Set(0); + renderer->mBlurShader->Uniforms[vertical].Set(POSTPROCESS_BINDINGPOINT); + + input.Bind(0); + output.Bind(); + glViewport(0, 0, width, height); + glDisable(GL_BLEND); + renderer->RenderScreenQuad(); +} + void FGLRenderer::BloomScene(int fixedcm) { // Only bloom things if enabled and no special fixed light mode is active @@ -287,7 +329,6 @@ void FGLRenderer::BloomScene(int fixedcm) savedState.SaveTextureBindings(2); const float blurAmount = gl_bloom_amount; - int sampleCount = gl_bloom_kernel_size; auto &level0 = mBuffers->BloomLevels[0]; @@ -312,8 +353,8 @@ void FGLRenderer::BloomScene(int fixedcm) { auto &level = mBuffers->BloomLevels[i]; auto &next = mBuffers->BloomLevels[i + 1]; - mBlurShader->BlurHorizontal(this, blurAmount, sampleCount, level.VTexture, level.HFramebuffer, level.Width, level.Height); - mBlurShader->BlurVertical(this, blurAmount, sampleCount, level.HTexture, next.VFramebuffer, next.Width, next.Height); + RenderBlur(this, blurAmount, level.VTexture, level.HFramebuffer, level.Width, level.Height, false); + RenderBlur(this, blurAmount, level.HTexture, next.VFramebuffer, next.Width, next.Height, true); } // Blur and upscale: @@ -322,8 +363,8 @@ void FGLRenderer::BloomScene(int fixedcm) auto &level = mBuffers->BloomLevels[i]; auto &next = mBuffers->BloomLevels[i - 1]; - mBlurShader->BlurHorizontal(this, blurAmount, sampleCount, level.VTexture, level.HFramebuffer, level.Width, level.Height); - mBlurShader->BlurVertical(this, blurAmount, sampleCount, level.HTexture, level.VFramebuffer, level.Width, level.Height); + RenderBlur(this, blurAmount, level.VTexture, level.HFramebuffer, level.Width, level.Height, false); + RenderBlur(this, blurAmount, level.HTexture, level.VFramebuffer, level.Width, level.Height, true); // Linear upscale: next.VFramebuffer.Bind(); @@ -334,8 +375,8 @@ void FGLRenderer::BloomScene(int fixedcm) RenderScreenQuad(); } - mBlurShader->BlurHorizontal(this, blurAmount, sampleCount, level0.VTexture, level0.HFramebuffer, level0.Width, level0.Height); - mBlurShader->BlurVertical(this, blurAmount, sampleCount, level0.HTexture, level0.VFramebuffer, level0.Width, level0.Height); + RenderBlur(this, blurAmount, level0.VTexture, level0.HFramebuffer, level0.Width, level0.Height, false); + RenderBlur(this, blurAmount, level0.HTexture, level0.VFramebuffer, level0.Width, level0.Height, true); // Add bloom back to scene texture: mBuffers->BindCurrentFB(); @@ -376,7 +417,6 @@ void FGLRenderer::BlurScene(float gameinfobluramount) FGLPostProcessState savedState; savedState.SaveTextureBindings(2); - int sampleCount = 9; int numLevels = 3; // Must be 4 or less (since FGLRenderBuffers::NumBloomLevels is 4 and we are using its buffers). assert(numLevels <= FGLRenderBuffers::NumBloomLevels); @@ -392,8 +432,8 @@ void FGLRenderer::BlurScene(float gameinfobluramount) { auto &level = mBuffers->BloomLevels[i]; auto &next = mBuffers->BloomLevels[i + 1]; - mBlurShader->BlurHorizontal(this, blurAmount, sampleCount, level.VTexture, level.HFramebuffer, level.Width, level.Height); - mBlurShader->BlurVertical(this, blurAmount, sampleCount, level.HTexture, next.VFramebuffer, next.Width, next.Height); + RenderBlur(this, blurAmount, level.VTexture, level.HFramebuffer, level.Width, level.Height, false); + RenderBlur(this, blurAmount, level.HTexture, next.VFramebuffer, next.Width, next.Height, true); } // Blur and upscale: @@ -402,8 +442,8 @@ void FGLRenderer::BlurScene(float gameinfobluramount) auto &level = mBuffers->BloomLevels[i]; auto &next = mBuffers->BloomLevels[i - 1]; - mBlurShader->BlurHorizontal(this, blurAmount, sampleCount, level.VTexture, level.HFramebuffer, level.Width, level.Height); - mBlurShader->BlurVertical(this, blurAmount, sampleCount, level.HTexture, level.VFramebuffer, level.Width, level.Height); + RenderBlur(this, blurAmount, level.VTexture, level.HFramebuffer, level.Width, level.Height, false); + RenderBlur(this, blurAmount, level.HTexture, level.VFramebuffer, level.Width, level.Height, true); // Linear upscale: next.VFramebuffer.Bind(); @@ -414,8 +454,8 @@ void FGLRenderer::BlurScene(float gameinfobluramount) RenderScreenQuad(); } - mBlurShader->BlurHorizontal(this, blurAmount, sampleCount, level0.VTexture, level0.HFramebuffer, level0.Width, level0.Height); - mBlurShader->BlurVertical(this, blurAmount, sampleCount, level0.HTexture, level0.VFramebuffer, level0.Width, level0.Height); + RenderBlur(this, blurAmount, level0.VTexture, level0.HFramebuffer, level0.Width, level0.Height, false); + RenderBlur(this, blurAmount, level0.HTexture, level0.VFramebuffer, level0.Width, level0.Height, true); // Copy blur back to scene texture: mBuffers->BlitLinear(level0.VFramebuffer, mBuffers->GetCurrentFB(), 0, 0, level0.Width, level0.Height, viewport.left, viewport.top, viewport.width, viewport.height); diff --git a/src/gl/shaders/gl_blurshader.cpp b/src/gl/shaders/gl_blurshader.cpp index a581d531ec..31e54a90ae 100644 --- a/src/gl/shaders/gl_blurshader.cpp +++ b/src/gl/shaders/gl_blurshader.cpp @@ -32,206 +32,25 @@ #include "gl/renderer/gl_renderer.h" #include "gl/renderer/gl_renderbuffers.h" -//========================================================================== -// -// Performs a vertical gaussian blur pass -// -//========================================================================== - -void FBlurShader::BlurVertical(FGLRenderer *renderer, float blurAmount, int sampleCount, PPTexture inputTexture, PPFrameBuffer outputFrameBuffer, int width, int height) +void FBlurShader::Bind(bool vertical) { - Blur(renderer, blurAmount, sampleCount, inputTexture, outputFrameBuffer, width, height, true); -} - -//========================================================================== -// -// Performs a horizontal gaussian blur pass -// -//========================================================================== - -void FBlurShader::BlurHorizontal(FGLRenderer *renderer, float blurAmount, int sampleCount, PPTexture inputTexture, PPFrameBuffer outputFrameBuffer, int width, int height) -{ - Blur(renderer, blurAmount, sampleCount, inputTexture, outputFrameBuffer, width, height, false); -} - -//========================================================================== -// -// Helper for BlurVertical and BlurHorizontal. Executes the actual pass -// -//========================================================================== - -void FBlurShader::Blur(FGLRenderer *renderer, float blurAmount, int sampleCount, PPTexture inputTexture, PPFrameBuffer outputFrameBuffer, int width, int height, bool vertical) -{ - BlurSetup *setup = GetSetup(blurAmount, sampleCount); - if (vertical) - setup->VerticalShader->Bind(); - else - setup->HorizontalShader->Bind(); - - inputTexture.Bind(0); - - outputFrameBuffer.Bind(); - glViewport(0, 0, width, height); - glDisable(GL_BLEND); - - renderer->RenderScreenQuad(); -} - -//========================================================================== -// -// Compiles the blur shaders needed for the specified blur amount and -// kernel size -// -//========================================================================== - -FBlurShader::BlurSetup *FBlurShader::GetSetup(float blurAmount, int sampleCount) -{ - for (size_t mBlurSetupIndex = 0; mBlurSetupIndex < mBlurSetups.Size(); mBlurSetupIndex++) + if (!mShader[vertical]) { - if (mBlurSetups[mBlurSetupIndex].blurAmount == blurAmount && mBlurSetups[mBlurSetupIndex].sampleCount == sampleCount) - { - return &mBlurSetups[mBlurSetupIndex]; - } - } - - BlurSetup blurSetup(blurAmount, sampleCount); - - FString vertexCode = VertexShaderCode(); - FString horizontalCode = FragmentShaderCode(blurAmount, sampleCount, false); - FString verticalCode = FragmentShaderCode(blurAmount, sampleCount, true); - - blurSetup.VerticalShader = std::make_shared(); - blurSetup.VerticalShader->Compile(FShaderProgram::Vertex, "vertical blur vertex shader", vertexCode, "", 330); - blurSetup.VerticalShader->Compile(FShaderProgram::Fragment, "vertical blur fragment shader", verticalCode, "", 330); - blurSetup.VerticalShader->SetFragDataLocation(0, "FragColor"); - blurSetup.VerticalShader->SetAttribLocation(0, "PositionInProjection"); - blurSetup.VerticalShader->Link("vertical blur"); - blurSetup.VerticalShader->Bind(); - glUniform1i(glGetUniformLocation(*blurSetup.VerticalShader.get(), "SourceTexture"), 0); - - blurSetup.HorizontalShader = std::make_shared(); - blurSetup.HorizontalShader->Compile(FShaderProgram::Vertex, "horizontal blur vertex shader", vertexCode, "", 330); - blurSetup.HorizontalShader->Compile(FShaderProgram::Fragment, "horizontal blur fragment shader", horizontalCode, "", 330); - blurSetup.HorizontalShader->SetFragDataLocation(0, "FragColor"); - blurSetup.HorizontalShader->SetAttribLocation(0, "PositionInProjection"); - blurSetup.HorizontalShader->Link("horizontal blur"); - blurSetup.HorizontalShader->Bind(); - glUniform1i(glGetUniformLocation(*blurSetup.HorizontalShader.get(), "SourceTexture"), 0); - - mBlurSetups.Push(blurSetup); - - return &mBlurSetups[mBlurSetups.Size() - 1]; -} - -//========================================================================== -// -// The vertex shader GLSL code -// -//========================================================================== - -FString FBlurShader::VertexShaderCode() -{ - return R"( - in vec4 PositionInProjection; - out vec2 TexCoord; - - void main() - { - gl_Position = PositionInProjection; - TexCoord = (gl_Position.xy + 1.0) * 0.5; - } - )"; -} - -//========================================================================== -// -// Generates the fragment shader GLSL code for a specific blur setup -// -//========================================================================== - -FString FBlurShader::FragmentShaderCode(float blurAmount, int sampleCount, bool vertical) -{ - TArray sampleWeights; - TArray sampleOffsets; - ComputeBlurSamples(sampleCount, blurAmount, sampleWeights, sampleOffsets); - - const char *fragmentShader = - R"( - in vec2 TexCoord; - uniform sampler2D SourceTexture; - out vec4 FragColor; - #if __VERSION__ < 130 - uniform float ScaleX; - uniform float ScaleY; - vec4 textureOffset(sampler2D s, vec2 texCoord, ivec2 offset) - { - return texture2D(s, texCoord + vec2(ScaleX * float(offset.x), ScaleY * float(offset.y))); - } - #endif - void main() - { - FragColor = %s; - } - )"; - - FString loopCode; - for (int i = 0; i < sampleCount; i++) - { - if (i > 0) - loopCode += " + "; - + FString prolog = Uniforms[vertical].CreateDeclaration("Uniforms", UniformBlock::Desc()); if (vertical) - loopCode.AppendFormat("\r\n\t\t\ttextureOffset(SourceTexture, TexCoord, ivec2(0, %d)) * %f", sampleOffsets[i], (double)sampleWeights[i]); + prolog += "#define BLUR_VERTICAL\n"; else - loopCode.AppendFormat("\r\n\t\t\ttextureOffset(SourceTexture, TexCoord, ivec2(%d, 0)) * %f", sampleOffsets[i], (double)sampleWeights[i]); + prolog += "#define BLUR_HORIZONTAL\n"; + + mShader[vertical].Compile(FShaderProgram::Vertex, "shaders/glsl/screenquad.vp", "", 330); + mShader[vertical].Compile(FShaderProgram::Fragment, "shaders/glsl/blur.fp", prolog, 330); + mShader[vertical].SetFragDataLocation(0, "FragColor"); + mShader[vertical].Link("shaders/glsl/blur"); + mShader[vertical].SetAttribLocation(0, "PositionInProjection"); + mShader[vertical].SetUniformBufferLocation(POSTPROCESS_BINDINGPOINT, "Uniforms"); + SourceTexture[vertical].Init(mShader[vertical], "SourceTexture"); + Uniforms[vertical].Init(); } - FString code; - code.Format(fragmentShader, loopCode.GetChars()); - return code; -} - -//========================================================================== -// -// Calculates the sample weight for a specific offset in the kernel -// -//========================================================================== - -float FBlurShader::ComputeGaussian(float n, float theta) // theta = Blur Amount -{ - return (float)((1.0f / sqrtf(2 * (float)M_PI * theta)) * expf(-(n * n) / (2.0f * theta * theta))); -} - -//========================================================================== -// -// Calculates the sample weights and offsets -// -//========================================================================== - -void FBlurShader::ComputeBlurSamples(int sampleCount, float blurAmount, TArray &sampleWeights, TArray &sampleOffsets) -{ - sampleWeights.Resize(sampleCount); - sampleOffsets.Resize(sampleCount); - - sampleWeights[0] = ComputeGaussian(0, blurAmount); - sampleOffsets[0] = 0; - - float totalWeights = sampleWeights[0]; - - for (int i = 0; i < sampleCount / 2; i++) - { - float weight = ComputeGaussian(i + 1.0f, blurAmount); - - sampleWeights[i * 2 + 1] = weight; - sampleWeights[i * 2 + 2] = weight; - sampleOffsets[i * 2 + 1] = i + 1; - sampleOffsets[i * 2 + 2] = -i - 1; - - totalWeights += weight * 2; - } - - for (int i = 0; i < sampleCount; i++) - { - sampleWeights[i] /= totalWeights; - } + mShader[vertical].Bind(); } diff --git a/src/gl/shaders/gl_blurshader.h b/src/gl/shaders/gl_blurshader.h index b143c22f19..9c03e3638d 100644 --- a/src/gl/shaders/gl_blurshader.h +++ b/src/gl/shaders/gl_blurshader.h @@ -1,5 +1,5 @@ -#ifndef __GL_BLURSHADER_H -#define __GL_BLURSHADER_H + +#pragma once #include "gl_shaderprogram.h" #include @@ -11,31 +11,32 @@ class PPTexture; class FBlurShader { public: - void BlurVertical(FGLRenderer *renderer, float blurAmount, int sampleCount, PPTexture inputTexture, PPFrameBuffer outputFrameBuffer, int width, int height); - void BlurHorizontal(FGLRenderer *renderer, float blurAmount, int sampleCount, PPTexture inputTexture, PPFrameBuffer outputFrameBuffer, int width, int height); + void Bind(bool vertical); -private: - void Blur(FGLRenderer *renderer, float blurAmount, int sampleCount, PPTexture inputTexture, PPFrameBuffer outputFrameBuffer, int width, int height, bool vertical); + FBufferedUniformSampler SourceTexture[2]; - struct BlurSetup + struct UniformBlock { - BlurSetup(float blurAmount, int sampleCount) : blurAmount(blurAmount), sampleCount(sampleCount) { } + float SampleWeights[8]; - float blurAmount; - int sampleCount; - std::shared_ptr VerticalShader; - std::shared_ptr HorizontalShader; + static std::vector Desc() + { + return + { + { "SampleWeights0", UniformType::Float, offsetof(UniformBlock, SampleWeights[0]) }, + { "SampleWeights1", UniformType::Float, offsetof(UniformBlock, SampleWeights[1]) }, + { "SampleWeights2", UniformType::Float, offsetof(UniformBlock, SampleWeights[2]) }, + { "SampleWeights3", UniformType::Float, offsetof(UniformBlock, SampleWeights[3]) }, + { "SampleWeights4", UniformType::Float, offsetof(UniformBlock, SampleWeights[4]) }, + { "SampleWeights5", UniformType::Float, offsetof(UniformBlock, SampleWeights[5]) }, + { "SampleWeights6", UniformType::Float, offsetof(UniformBlock, SampleWeights[6]) }, + { "SampleWeights7", UniformType::Float, offsetof(UniformBlock, SampleWeights[7]) }, + }; + } }; - BlurSetup *GetSetup(float blurAmount, int sampleCount); + ShaderUniforms Uniforms[2]; - FString VertexShaderCode(); - FString FragmentShaderCode(float blurAmount, int sampleCount, bool vertical); - - float ComputeGaussian(float n, float theta); - void ComputeBlurSamples(int sampleCount, float blurAmount, TArray &sample_weights, TArray &sample_offsets); - - TArray mBlurSetups; +private: + FShaderProgram mShader[2]; }; - -#endif \ No newline at end of file diff --git a/src/hwrenderer/postprocessing/hw_postprocess_cvars.cpp b/src/hwrenderer/postprocessing/hw_postprocess_cvars.cpp index d17361cf77..4f47593f47 100644 --- a/src/hwrenderer/postprocessing/hw_postprocess_cvars.cpp +++ b/src/hwrenderer/postprocessing/hw_postprocess_cvars.cpp @@ -50,12 +50,6 @@ CUSTOM_CVAR(Int, gl_tonemap, 0, CVAR_ARCHIVE) self = 0; } -CUSTOM_CVAR(Int, gl_bloom_kernel_size, 7, CVAR_ARCHIVE) -{ - if (self < 3 || self > 15 || self % 2 == 0) - self = 7; -} - CVAR(Bool, gl_lens, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) CVAR(Float, gl_lens_k, -0.12f, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) diff --git a/wadsrc/static/shaders/glsl/blur.fp b/wadsrc/static/shaders/glsl/blur.fp new file mode 100644 index 0000000000..93232e31a5 --- /dev/null +++ b/wadsrc/static/shaders/glsl/blur.fp @@ -0,0 +1,28 @@ + +in vec2 TexCoord; +out vec4 FragColor; + +uniform sampler2D SourceTexture; + +void main() +{ +#if defined(BLUR_HORIZONTAL) + FragColor = + textureOffset(SourceTexture, TexCoord, ivec2( 0, 0)) * SampleWeights0 + + textureOffset(SourceTexture, TexCoord, ivec2( 1, 0)) * SampleWeights1 + + textureOffset(SourceTexture, TexCoord, ivec2(-1, 0)) * SampleWeights2 + + textureOffset(SourceTexture, TexCoord, ivec2( 2, 0)) * SampleWeights3 + + textureOffset(SourceTexture, TexCoord, ivec2(-2, 0)) * SampleWeights4 + + textureOffset(SourceTexture, TexCoord, ivec2( 3, 0)) * SampleWeights5 + + textureOffset(SourceTexture, TexCoord, ivec2(-3, 0)) * SampleWeights6; +#else + FragColor = + textureOffset(SourceTexture, TexCoord, ivec2(0, 0)) * SampleWeights0 + + textureOffset(SourceTexture, TexCoord, ivec2(0, 1)) * SampleWeights1 + + textureOffset(SourceTexture, TexCoord, ivec2(0,-1)) * SampleWeights2 + + textureOffset(SourceTexture, TexCoord, ivec2(0, 2)) * SampleWeights3 + + textureOffset(SourceTexture, TexCoord, ivec2(0,-2)) * SampleWeights4 + + textureOffset(SourceTexture, TexCoord, ivec2(0, 3)) * SampleWeights5 + + textureOffset(SourceTexture, TexCoord, ivec2(0,-3)) * SampleWeights6; +#endif +}