From 490dd612b3d662b4f190f34dc37e4367fddedc61 Mon Sep 17 00:00:00 2001 From: Magnus Norddahl Date: Wed, 5 Oct 2016 03:56:58 +0200 Subject: [PATCH 1/4] Keep using render buffers when ssao is off, for better performance --- src/gl/renderer/gl_renderbuffers.cpp | 91 ++++++++++++++++++++-------- src/gl/renderer/gl_renderbuffers.h | 4 +- 2 files changed, 70 insertions(+), 25 deletions(-) diff --git a/src/gl/renderer/gl_renderbuffers.cpp b/src/gl/renderer/gl_renderbuffers.cpp index 54d597c4d..9915b024c 100644 --- a/src/gl/renderer/gl_renderbuffers.cpp +++ b/src/gl/renderer/gl_renderbuffers.cpp @@ -83,9 +83,18 @@ void FGLRenderBuffers::ClearScene() { DeleteFrameBuffer(mSceneFB); DeleteFrameBuffer(mSceneDataFB); - DeleteTexture(mSceneMultisample); - DeleteTexture(mSceneData); - DeleteTexture(mSceneDepthStencil); + if (mSceneUsesTextures) + { + DeleteTexture(mSceneMultisample); + DeleteTexture(mSceneData); + DeleteTexture(mSceneDepthStencil); + } + else + { + DeleteRenderBuffer(mSceneMultisample); + DeleteRenderBuffer(mSceneData); + DeleteRenderBuffer(mSceneDepthStencil); + } } void FGLRenderBuffers::ClearPipeline() @@ -188,6 +197,7 @@ bool FGLRenderBuffers::Setup(int width, int height, int sceneWidth, int sceneHei I_FatalError("Requested invalid render buffer sizes: screen = %dx%d", width, height); int samples = clamp((int)gl_multisample, 0, mMaxSamples); + bool needsSceneTextures = (gl_ssao != 0); GLint activeTex; GLint textureBinding; @@ -195,19 +205,16 @@ bool FGLRenderBuffers::Setup(int width, int height, int sceneWidth, int sceneHei glActiveTexture(GL_TEXTURE0); glGetIntegerv(GL_TEXTURE_BINDING_2D, &textureBinding); - if (width == mWidth && height == mHeight && mSamples != samples) - { - CreateScene(mWidth, mHeight, samples); - mSamples = samples; - } - else if (width != mWidth || height != mHeight) - { + if (width != mWidth || height != mHeight) CreatePipeline(width, height); - CreateScene(width, height, samples); - mWidth = width; - mHeight = height; - mSamples = samples; - } + + if (width != mWidth || height != mHeight || mSamples != samples || mSceneUsesTextures != needsSceneTextures) + CreateScene(width, height, samples, needsSceneTextures); + + mWidth = width; + mHeight = height; + mSamples = samples; + mSceneUsesTextures = needsSceneTextures; // Bloom bluring buffers need to match the scene to avoid bloom bleeding artifacts if (mSceneWidth != sceneWidth || mSceneHeight != sceneHeight) @@ -247,24 +254,44 @@ bool FGLRenderBuffers::Setup(int width, int height, int sceneWidth, int sceneHei // //========================================================================== -void FGLRenderBuffers::CreateScene(int width, int height, int samples) +void FGLRenderBuffers::CreateScene(int width, int height, int samples, bool needsSceneTextures) { ClearScene(); if (samples > 1) { - mSceneMultisample = Create2DMultisampleTexture("SceneMultisample", GL_RGBA16F, width, height, samples, false); - mSceneDepthStencil = Create2DMultisampleTexture("SceneDepthStencil", GL_DEPTH24_STENCIL8, width, height, samples, false); - mSceneData = Create2DMultisampleTexture("SceneSSAOData", GL_RGBA8, width, height, samples, false); + if (needsSceneTextures) + { + mSceneMultisample = Create2DMultisampleTexture("SceneMultisample", GL_RGBA16F, width, height, samples, false); + mSceneDepthStencil = Create2DMultisampleTexture("SceneDepthStencil", GL_DEPTH24_STENCIL8, width, height, samples, false); + mSceneData = Create2DMultisampleTexture("SceneSSAOData", GL_RGBA8, width, height, samples, false); + mSceneFB = CreateFrameBuffer("SceneFB", mSceneMultisample, 0, mSceneDepthStencil, true); + mSceneDataFB = CreateFrameBuffer("SSAOSceneFB", mSceneMultisample, mSceneData, mSceneDepthStencil, true); + } + else + { + mSceneMultisample = CreateRenderBuffer("SceneMultisample", GL_RGBA16F, width, height, samples); + mSceneDepthStencil = CreateRenderBuffer("SceneDepthStencil", GL_DEPTH24_STENCIL8, width, height, samples); + mSceneFB = CreateFrameBuffer("SceneFB", mSceneMultisample, mSceneDepthStencil, true); + mSceneDataFB = CreateFrameBuffer("SSAOSceneFB", mSceneMultisample, mSceneDepthStencil, true); + } } else { - mSceneDepthStencil = Create2DTexture("SceneDepthStencil", GL_DEPTH24_STENCIL8, width, height); - mSceneData = Create2DTexture("SceneSSAOData", GL_RGBA8, width, height); + if (needsSceneTextures) + { + mSceneDepthStencil = Create2DTexture("SceneDepthStencil", GL_DEPTH24_STENCIL8, width, height); + mSceneData = Create2DTexture("SceneSSAOData", GL_RGBA8, width, height); + mSceneFB = CreateFrameBuffer("SceneFB", mPipelineTexture[0], 0, mSceneDepthStencil, false); + mSceneDataFB = CreateFrameBuffer("SSAOSceneFB", mPipelineTexture[0], mSceneData, mSceneDepthStencil, false); + } + else + { + mSceneDepthStencil = CreateRenderBuffer("SceneDepthStencil", GL_DEPTH24_STENCIL8, width, height); + mSceneFB = CreateFrameBuffer("SceneFB", mPipelineTexture[0], mSceneDepthStencil, false); + mSceneDataFB = CreateFrameBuffer("SSAOSceneFB", mPipelineTexture[0], mSceneDepthStencil, false); + } } - - mSceneFB = CreateFrameBuffer("SceneFB", samples > 1 ? mSceneMultisample : mPipelineTexture[0], 0, mSceneDepthStencil, samples > 1); - mSceneDataFB = CreateFrameBuffer("SSAOSceneFB", samples > 1 ? mSceneMultisample : mPipelineTexture[0], mSceneData, mSceneDepthStencil, samples > 1); } //========================================================================== @@ -517,6 +544,22 @@ GLuint FGLRenderBuffers::CreateFrameBuffer(const FString &name, GLuint colorbuff return handle; } +GLuint FGLRenderBuffers::CreateFrameBuffer(const FString &name, GLuint colorbuffer, GLuint depthstencil, bool colorIsARenderBuffer) +{ + GLuint handle = 0; + glGenFramebuffers(1, &handle); + glBindFramebuffer(GL_FRAMEBUFFER, handle); + FGLDebug::LabelObject(GL_FRAMEBUFFER, handle, name); + if (colorIsARenderBuffer) + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, colorbuffer); + else + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, colorbuffer, 0); + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, depthstencil); + if (CheckFrameBufferCompleteness()) + ClearFrameBuffer(true, true); + return handle; +} + GLuint FGLRenderBuffers::CreateFrameBuffer(const FString &name, GLuint colorbuffer0, GLuint colorbuffer1, GLuint depthstencil, bool multisample) { GLuint handle = 0; diff --git a/src/gl/renderer/gl_renderbuffers.h b/src/gl/renderer/gl_renderbuffers.h index 2ca58149f..3fcc2c07b 100644 --- a/src/gl/renderer/gl_renderbuffers.h +++ b/src/gl/renderer/gl_renderbuffers.h @@ -81,7 +81,7 @@ private: void ClearBloom(); void ClearExposureLevels(); void ClearAmbientOcclusion(); - void CreateScene(int width, int height, int samples); + void CreateScene(int width, int height, int samples, bool needsSceneTextures); void CreatePipeline(int width, int height); void CreateBloom(int width, int height); void CreateExposureLevels(int width, int height); @@ -92,6 +92,7 @@ private: GLuint CreateRenderBuffer(const FString &name, GLuint format, int width, int height); GLuint CreateRenderBuffer(const FString &name, GLuint format, int samples, int width, int height); GLuint CreateFrameBuffer(const FString &name, GLuint colorbuffer); + GLuint CreateFrameBuffer(const FString &name, GLuint colorbuffer, GLuint depthstencil, bool colorIsARenderBuffer); GLuint CreateFrameBuffer(const FString &name, GLuint colorbuffer0, GLuint colorbuffer1, GLuint depthstencil, bool multisample); bool CheckFrameBufferCompleteness(); void ClearFrameBuffer(bool stencil, bool depth); @@ -115,6 +116,7 @@ private: GLuint mSceneData = 0; GLuint mSceneFB = 0; GLuint mSceneDataFB = 0; + bool mSceneUsesTextures = false; // Effect/HUD buffers GLuint mPipelineTexture[NumPipelineTextures]; From 00e72028efd9145eb54704fa974c57d2034b7cec Mon Sep 17 00:00:00 2001 From: Magnus Norddahl Date: Wed, 5 Oct 2016 07:57:27 +0200 Subject: [PATCH 2/4] Add another gbuffer with normal data and make ssao pass use it --- src/gl/renderer/gl_postprocess.cpp | 58 ++++++----- src/gl/renderer/gl_postprocessstate.cpp | 55 +++++----- src/gl/renderer/gl_postprocessstate.h | 7 +- src/gl/renderer/gl_renderbuffers.cpp | 54 +++++++--- src/gl/renderer/gl_renderbuffers.h | 8 +- src/gl/scene/gl_scene.cpp | 8 +- src/gl/shaders/gl_ambientshader.cpp | 121 +++++++++++++--------- src/gl/shaders/gl_ambientshader.h | 45 ++++---- src/gl/shaders/gl_shader.cpp | 3 +- src/gl/system/gl_cvars.h | 2 +- wadsrc/static/shaders/glsl/main.fp | 6 +- wadsrc/static/shaders/glsl/ssao.fp | 23 +++- wadsrc/static/shaders/glsl/ssaocombine.fp | 12 +-- 13 files changed, 241 insertions(+), 161 deletions(-) diff --git a/src/gl/renderer/gl_postprocess.cpp b/src/gl/renderer/gl_postprocess.cpp index fde8da353..ac5a6336d 100644 --- a/src/gl/renderer/gl_postprocess.cpp +++ b/src/gl/renderer/gl_postprocess.cpp @@ -121,7 +121,7 @@ CUSTOM_CVAR(Int, gl_ssao_portals, 0, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) } CVAR(Float, gl_ssao_strength, 0.7, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) -CVAR(Bool, gl_ssao_debug, false, 0) +CVAR(Int, gl_ssao_debug, 0, 0) CVAR(Float, gl_ssao_bias, 0.5f, 0) CVAR(Float, gl_ssao_radius, 100.0f, 0) CUSTOM_CVAR(Float, gl_ssao_blur_amount, 4.0f, 0) @@ -162,13 +162,12 @@ void FGLRenderer::AmbientOccludeScene() FGLDebug::PushGroup("AmbientOccludeScene"); FGLPostProcessState savedState; - savedState.SaveTextureBinding1(); + savedState.SaveTextureBindings(3); float bias = gl_ssao_bias; float aoRadius = gl_ssao_radius; const float blurAmount = gl_ssao_blur_amount; float aoStrength = gl_ssao_strength; - bool multisample = gl_multisample > 1; //float tanHalfFovy = tan(fovy * (M_PI / 360.0f)); float tanHalfFovy = 1.0f / gl_RenderState.mProjectionMatrix.get()[5]; @@ -189,16 +188,16 @@ void FGLRenderer::AmbientOccludeScene() glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glActiveTexture(GL_TEXTURE0); - mLinearDepthShader->Bind(multisample); - mLinearDepthShader->DepthTexture[multisample].Set(0); - mLinearDepthShader->ColorTexture[multisample].Set(1); - if (multisample) mLinearDepthShader->SampleCount[multisample].Set(gl_multisample); - mLinearDepthShader->LinearizeDepthA[multisample].Set(1.0f / GetZFar() - 1.0f / GetZNear()); - mLinearDepthShader->LinearizeDepthB[multisample].Set(MAX(1.0f / GetZNear(), 1.e-8f)); - mLinearDepthShader->InverseDepthRangeA[multisample].Set(1.0f); - mLinearDepthShader->InverseDepthRangeB[multisample].Set(0.0f); - mLinearDepthShader->Scale[multisample].Set(mBuffers->AmbientWidth * 2.0f / (float)mScreenViewport.width, mBuffers->AmbientHeight * 2.0f / (float)mScreenViewport.height); - mLinearDepthShader->Offset[multisample].Set(mSceneViewport.left / (float)mScreenViewport.width, mSceneViewport.top / (float)mScreenViewport.height); + mLinearDepthShader->Bind(); + mLinearDepthShader->DepthTexture.Set(0); + mLinearDepthShader->ColorTexture.Set(1); + if (gl_multisample > 1) mLinearDepthShader->SampleCount.Set(gl_multisample); + mLinearDepthShader->LinearizeDepthA.Set(1.0f / GetZFar() - 1.0f / GetZNear()); + mLinearDepthShader->LinearizeDepthB.Set(MAX(1.0f / GetZNear(), 1.e-8f)); + mLinearDepthShader->InverseDepthRangeA.Set(1.0f); + mLinearDepthShader->InverseDepthRangeB.Set(0.0f); + mLinearDepthShader->Scale.Set(mBuffers->AmbientWidth * 2.0f / (float)mScreenViewport.width, mBuffers->AmbientHeight * 2.0f / (float)mScreenViewport.height); + mLinearDepthShader->Offset.Set(mSceneViewport.left / (float)mScreenViewport.width, mSceneViewport.top / (float)mScreenViewport.height); RenderScreenQuad(); // Apply ambient occlusion @@ -212,10 +211,14 @@ void FGLRenderer::AmbientOccludeScene() glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); + mBuffers->BindSceneNormalTexture(2); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glActiveTexture(GL_TEXTURE0); mSSAOShader->Bind(); mSSAOShader->DepthTexture.Set(0); mSSAOShader->RandomTexture.Set(1); + mSSAOShader->NormalTexture.Set(2); mSSAOShader->UVToViewA.Set(2.0f * invFocalLenX, -2.0f * invFocalLenY); mSSAOShader->UVToViewB.Set(-invFocalLenX, invFocalLenY); mSSAOShader->InvFullResolution.Set(1.0f / mBuffers->AmbientWidth, 1.0f / mBuffers->AmbientHeight); @@ -246,26 +249,29 @@ void FGLRenderer::AmbientOccludeScene() // Add SSAO back to scene texture: mBuffers->BindSceneFB(false); - GLenum buffers[] = { GL_COLOR_ATTACHMENT0 }; - glDrawBuffers(1, buffers); glViewport(mSceneViewport.left, mSceneViewport.top, mSceneViewport.width, mSceneViewport.height); glEnable(GL_BLEND); glBlendEquation(GL_FUNC_ADD); - if (gl_ssao_debug) + if (gl_ssao_debug > 1) glBlendFunc(GL_ONE, GL_ZERO); else glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + if (gl_ssao_debug == 1) + { + glClearColor(1.0f, 1.0f, 1.0f, 1.0f); + glClear(GL_COLOR_BUFFER_BIT); + } glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, mBuffers->AmbientTexture1); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - mBuffers->BindSceneDataTexture(1); - mSSAOCombineShader->Bind(multisample); - mSSAOCombineShader->AODepthTexture[multisample].Set(0); - mSSAOCombineShader->SceneDataTexture[multisample].Set(1); - if (multisample) mSSAOCombineShader->SampleCount[multisample].Set(gl_multisample); - mSSAOCombineShader->Scale[multisample].Set(mBuffers->AmbientWidth * 2.0f / (float)mScreenViewport.width, mBuffers->AmbientHeight * 2.0f / (float)mScreenViewport.height); - mSSAOCombineShader->Offset[multisample].Set(mSceneViewport.left / (float)mScreenViewport.width, mSceneViewport.top / (float)mScreenViewport.height); + mBuffers->BindSceneFogTexture(1); + mSSAOCombineShader->Bind(); + mSSAOCombineShader->AODepthTexture.Set(0); + mSSAOCombineShader->SceneFogTexture.Set(1); + if (gl_multisample > 1) mSSAOCombineShader->SampleCount.Set(gl_multisample); + mSSAOCombineShader->Scale.Set(mBuffers->AmbientWidth * 2.0f / (float)mScreenViewport.width, mBuffers->AmbientHeight * 2.0f / (float)mScreenViewport.height); + mSSAOCombineShader->Offset.Set(mSceneViewport.left / (float)mScreenViewport.width, mSceneViewport.top / (float)mScreenViewport.height); RenderScreenQuad(); FGLDebug::PopGroup(); @@ -285,7 +291,7 @@ void FGLRenderer::UpdateCameraExposure() FGLDebug::PushGroup("UpdateCameraExposure"); FGLPostProcessState savedState; - savedState.SaveTextureBinding1(); + savedState.SaveTextureBindings(2); // Extract light level from scene texture: const auto &level0 = mBuffers->ExposureLevels[0]; @@ -358,7 +364,7 @@ void FGLRenderer::BloomScene() FGLDebug::PushGroup("BloomScene"); FGLPostProcessState savedState; - savedState.SaveTextureBinding1(); + savedState.SaveTextureBindings(2); const float blurAmount = gl_bloom_amount; int sampleCount = gl_bloom_kernel_size; @@ -461,7 +467,7 @@ void FGLRenderer::TonemapScene() } else { - savedState.SaveTextureBinding1(); + savedState.SaveTextureBindings(2); glActiveTexture(GL_TEXTURE1); glBindTexture(GL_TEXTURE_2D, mBuffers->ExposureTexture); glActiveTexture(GL_TEXTURE0); diff --git a/src/gl/renderer/gl_postprocessstate.cpp b/src/gl/renderer/gl_postprocessstate.cpp index 57b7862f5..fead1435a 100644 --- a/src/gl/renderer/gl_postprocessstate.cpp +++ b/src/gl/renderer/gl_postprocessstate.cpp @@ -45,17 +45,7 @@ FGLPostProcessState::FGLPostProcessState() { glGetIntegerv(GL_ACTIVE_TEXTURE, &activeTex); glActiveTexture(GL_TEXTURE0); - glGetIntegerv(GL_TEXTURE_BINDING_2D, &textureBinding[0]); - glBindTexture(GL_TEXTURE_2D, 0); - if (gl.flags & RFL_SAMPLER_OBJECTS) - { - glGetIntegerv(GL_SAMPLER_BINDING, &samplerBinding[0]); - glBindSampler(0, 0); - glActiveTexture(GL_TEXTURE0 + 1); - glGetIntegerv(GL_SAMPLER_BINDING, &samplerBinding[1]); - glBindSampler(1, 0); - glActiveTexture(GL_TEXTURE0); - } + SaveTextureBindings(1); glGetBooleanv(GL_BLEND, &blendEnabled); glGetBooleanv(GL_SCISSOR_TEST, &scissorEnabled); @@ -75,12 +65,26 @@ FGLPostProcessState::FGLPostProcessState() glDisable(GL_BLEND); } -void FGLPostProcessState::SaveTextureBinding1() +void FGLPostProcessState::SaveTextureBindings(unsigned int numUnits) { - glActiveTexture(GL_TEXTURE1); - glGetIntegerv(GL_TEXTURE_BINDING_2D, &textureBinding[1]); - glBindTexture(GL_TEXTURE_2D, 0); - textureBinding1Saved = true; + while (textureBinding.Size() < numUnits) + { + unsigned int i = textureBinding.Size(); + + GLint texture; + glActiveTexture(GL_TEXTURE0 + i); + glGetIntegerv(GL_TEXTURE_BINDING_2D, &texture); + glBindTexture(GL_TEXTURE_2D, 0); + textureBinding.Push(texture); + + if (gl.flags & RFL_SAMPLER_OBJECTS) + { + GLint sampler; + glGetIntegerv(GL_SAMPLER_BINDING, &sampler); + glBindSampler(i, 0); + samplerBinding.Push(sampler); + } + } glActiveTexture(GL_TEXTURE0); } @@ -117,25 +121,22 @@ FGLPostProcessState::~FGLPostProcessState() glUseProgram(currentProgram); - if (textureBinding1Saved) + // Fully unbind to avoid incomplete texture warnings from Nvidia's driver when gl_debug_level 4 is active + for (unsigned int i = 0; i < textureBinding.Size(); i++) { - glActiveTexture(GL_TEXTURE1); + glActiveTexture(GL_TEXTURE0 + i); glBindTexture(GL_TEXTURE_2D, 0); } - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, 0); - if (gl.flags & RFL_SAMPLER_OBJECTS) + for (unsigned int i = 0; i < samplerBinding.Size(); i++) { - glBindSampler(0, samplerBinding[0]); - glBindSampler(1, samplerBinding[1]); + glBindSampler(i, samplerBinding[i]); } - glBindTexture(GL_TEXTURE_2D, textureBinding[0]); - if (textureBinding1Saved) + for (unsigned int i = 0; i < textureBinding.Size(); i++) { - glActiveTexture(GL_TEXTURE1); - glBindTexture(GL_TEXTURE_2D, textureBinding[1]); + glActiveTexture(GL_TEXTURE0 + i); + glBindTexture(GL_TEXTURE_2D, textureBinding[i]); } glActiveTexture(activeTex); diff --git a/src/gl/renderer/gl_postprocessstate.h b/src/gl/renderer/gl_postprocessstate.h index bf53aa7de..795a7d4ba 100644 --- a/src/gl/renderer/gl_postprocessstate.h +++ b/src/gl/renderer/gl_postprocessstate.h @@ -14,15 +14,15 @@ public: FGLPostProcessState(); ~FGLPostProcessState(); - void SaveTextureBinding1(); + void SaveTextureBindings(unsigned int numUnits); private: FGLPostProcessState(const FGLPostProcessState &) = delete; FGLPostProcessState &operator=(const FGLPostProcessState &) = delete; GLint activeTex; - GLint textureBinding[2]; - GLint samplerBinding[2]; + TArray textureBinding; + TArray samplerBinding; GLboolean blendEnabled; GLboolean scissorEnabled; GLboolean depthEnabled; @@ -34,7 +34,6 @@ private: GLint blendSrcAlpha; GLint blendDestRgb; GLint blendDestAlpha; - bool textureBinding1Saved = false; }; #endif diff --git a/src/gl/renderer/gl_renderbuffers.cpp b/src/gl/renderer/gl_renderbuffers.cpp index 9915b024c..1a1509d7a 100644 --- a/src/gl/renderer/gl_renderbuffers.cpp +++ b/src/gl/renderer/gl_renderbuffers.cpp @@ -86,13 +86,15 @@ void FGLRenderBuffers::ClearScene() if (mSceneUsesTextures) { DeleteTexture(mSceneMultisample); - DeleteTexture(mSceneData); + DeleteTexture(mSceneFog); + DeleteTexture(mSceneNormal); DeleteTexture(mSceneDepthStencil); } else { DeleteRenderBuffer(mSceneMultisample); - DeleteRenderBuffer(mSceneData); + DeleteRenderBuffer(mSceneFog); + DeleteRenderBuffer(mSceneNormal); DeleteRenderBuffer(mSceneDepthStencil); } } @@ -264,16 +266,17 @@ void FGLRenderBuffers::CreateScene(int width, int height, int samples, bool need { mSceneMultisample = Create2DMultisampleTexture("SceneMultisample", GL_RGBA16F, width, height, samples, false); mSceneDepthStencil = Create2DMultisampleTexture("SceneDepthStencil", GL_DEPTH24_STENCIL8, width, height, samples, false); - mSceneData = Create2DMultisampleTexture("SceneSSAOData", GL_RGBA8, width, height, samples, false); - mSceneFB = CreateFrameBuffer("SceneFB", mSceneMultisample, 0, mSceneDepthStencil, true); - mSceneDataFB = CreateFrameBuffer("SSAOSceneFB", mSceneMultisample, mSceneData, mSceneDepthStencil, true); + mSceneFog = Create2DMultisampleTexture("SceneFog", GL_RGBA8, width, height, samples, false); + mSceneNormal = Create2DMultisampleTexture("SceneNormal", GL_RGB10_A2, width, height, samples, false); + mSceneFB = CreateFrameBuffer("SceneFB", mSceneMultisample, 0, 0, mSceneDepthStencil, true); + mSceneDataFB = CreateFrameBuffer("SceneGBufferFB", mSceneMultisample, mSceneFog, mSceneNormal, mSceneDepthStencil, true); } else { mSceneMultisample = CreateRenderBuffer("SceneMultisample", GL_RGBA16F, width, height, samples); mSceneDepthStencil = CreateRenderBuffer("SceneDepthStencil", GL_DEPTH24_STENCIL8, width, height, samples); mSceneFB = CreateFrameBuffer("SceneFB", mSceneMultisample, mSceneDepthStencil, true); - mSceneDataFB = CreateFrameBuffer("SSAOSceneFB", mSceneMultisample, mSceneDepthStencil, true); + mSceneDataFB = CreateFrameBuffer("SceneGBufferFB", mSceneMultisample, mSceneDepthStencil, true); } } else @@ -281,15 +284,16 @@ void FGLRenderBuffers::CreateScene(int width, int height, int samples, bool need if (needsSceneTextures) { mSceneDepthStencil = Create2DTexture("SceneDepthStencil", GL_DEPTH24_STENCIL8, width, height); - mSceneData = Create2DTexture("SceneSSAOData", GL_RGBA8, width, height); - mSceneFB = CreateFrameBuffer("SceneFB", mPipelineTexture[0], 0, mSceneDepthStencil, false); - mSceneDataFB = CreateFrameBuffer("SSAOSceneFB", mPipelineTexture[0], mSceneData, mSceneDepthStencil, false); + mSceneFog = Create2DTexture("SceneFog", GL_RGBA8, width, height); + mSceneNormal = Create2DTexture("SceneNormal", GL_RGB10_A2, width, height); + mSceneFB = CreateFrameBuffer("SceneFB", mPipelineTexture[0], 0, 0, mSceneDepthStencil, false); + mSceneDataFB = CreateFrameBuffer("SceneGBufferFB", mPipelineTexture[0], mSceneFog, mSceneNormal, mSceneDepthStencil, false); } else { mSceneDepthStencil = CreateRenderBuffer("SceneDepthStencil", GL_DEPTH24_STENCIL8, width, height); mSceneFB = CreateFrameBuffer("SceneFB", mPipelineTexture[0], mSceneDepthStencil, false); - mSceneDataFB = CreateFrameBuffer("SSAOSceneFB", mPipelineTexture[0], mSceneDepthStencil, false); + mSceneDataFB = CreateFrameBuffer("SceneGBufferFB", mPipelineTexture[0], mSceneDepthStencil, false); } } } @@ -471,6 +475,7 @@ GLuint FGLRenderBuffers::Create2DTexture(const FString &name, GLuint format, int case GL_RGBA32F: dataformat = GL_RGBA; datatype = GL_FLOAT; break; case GL_R32F: dataformat = GL_RED; datatype = GL_FLOAT; break; case GL_RG32F: dataformat = GL_RG; datatype = GL_FLOAT; break; + case GL_RGB10_A2: dataformat = GL_RGBA; datatype = GL_UNSIGNED_INT_10_10_10_2; break; case GL_DEPTH_COMPONENT24: dataformat = GL_DEPTH_COMPONENT; datatype = GL_FLOAT; break; case GL_STENCIL_INDEX8: dataformat = GL_STENCIL_INDEX; datatype = GL_INT; break; case GL_DEPTH24_STENCIL8: dataformat = GL_DEPTH_STENCIL; datatype = GL_UNSIGNED_INT_24_8; break; @@ -560,7 +565,7 @@ GLuint FGLRenderBuffers::CreateFrameBuffer(const FString &name, GLuint colorbuff return handle; } -GLuint FGLRenderBuffers::CreateFrameBuffer(const FString &name, GLuint colorbuffer0, GLuint colorbuffer1, GLuint depthstencil, bool multisample) +GLuint FGLRenderBuffers::CreateFrameBuffer(const FString &name, GLuint colorbuffer0, GLuint colorbuffer1, GLuint colorbuffer2, GLuint depthstencil, bool multisample) { GLuint handle = 0; glGenFramebuffers(1, &handle); @@ -571,6 +576,8 @@ GLuint FGLRenderBuffers::CreateFrameBuffer(const FString &name, GLuint colorbuff glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D_MULTISAMPLE, colorbuffer0, 0); if (colorbuffer1 != 0) glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D_MULTISAMPLE, colorbuffer1, 0); + if (colorbuffer2 != 0) + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT2, GL_TEXTURE_2D_MULTISAMPLE, colorbuffer2, 0); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D_MULTISAMPLE, depthstencil, 0); } else @@ -578,6 +585,8 @@ GLuint FGLRenderBuffers::CreateFrameBuffer(const FString &name, GLuint colorbuff glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, colorbuffer0, 0); if (colorbuffer1 != 0) glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, colorbuffer1, 0); + if (colorbuffer2 != 0) + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT2, GL_TEXTURE_2D, colorbuffer2, 0); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, depthstencil, 0); } if (CheckFrameBufferCompleteness()) @@ -742,17 +751,32 @@ void FGLRenderBuffers::BindSceneColorTexture(int index) //========================================================================== // -// Binds the scene data texture to the specified texture unit +// Binds the scene fog data texture to the specified texture unit // //========================================================================== -void FGLRenderBuffers::BindSceneDataTexture(int index) +void FGLRenderBuffers::BindSceneFogTexture(int index) { glActiveTexture(GL_TEXTURE0 + index); if (mSamples > 1) - glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, mSceneData); + glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, mSceneFog); else - glBindTexture(GL_TEXTURE_2D, mSceneData); + glBindTexture(GL_TEXTURE_2D, mSceneFog); +} + +//========================================================================== +// +// Binds the scene normal data texture to the specified texture unit +// +//========================================================================== + +void FGLRenderBuffers::BindSceneNormalTexture(int index) +{ + glActiveTexture(GL_TEXTURE0 + index); + if (mSamples > 1) + glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, mSceneNormal); + else + glBindTexture(GL_TEXTURE_2D, mSceneNormal); } //========================================================================== diff --git a/src/gl/renderer/gl_renderbuffers.h b/src/gl/renderer/gl_renderbuffers.h index 3fcc2c07b..9508f7009 100644 --- a/src/gl/renderer/gl_renderbuffers.h +++ b/src/gl/renderer/gl_renderbuffers.h @@ -34,7 +34,8 @@ public: void BindSceneFB(bool sceneData); void BindSceneColorTexture(int index); - void BindSceneDataTexture(int index); + void BindSceneFogTexture(int index); + void BindSceneNormalTexture(int index); void BindSceneDepthTexture(int index); void BlitSceneToTexture(); @@ -93,7 +94,7 @@ private: GLuint CreateRenderBuffer(const FString &name, GLuint format, int samples, int width, int height); GLuint CreateFrameBuffer(const FString &name, GLuint colorbuffer); GLuint CreateFrameBuffer(const FString &name, GLuint colorbuffer, GLuint depthstencil, bool colorIsARenderBuffer); - GLuint CreateFrameBuffer(const FString &name, GLuint colorbuffer0, GLuint colorbuffer1, GLuint depthstencil, bool multisample); + GLuint CreateFrameBuffer(const FString &name, GLuint colorbuffer0, GLuint colorbuffer1, GLuint colorbuffer2, GLuint depthstencil, bool multisample); bool CheckFrameBufferCompleteness(); void ClearFrameBuffer(bool stencil, bool depth); void DeleteTexture(GLuint &handle); @@ -113,7 +114,8 @@ private: // Buffers for the scene GLuint mSceneMultisample = 0; GLuint mSceneDepthStencil = 0; - GLuint mSceneData = 0; + GLuint mSceneFog = 0; + GLuint mSceneNormal = 0; GLuint mSceneFB = 0; GLuint mSceneDataFB = 0; bool mSceneUsesTextures = false; diff --git a/src/gl/scene/gl_scene.cpp b/src/gl/scene/gl_scene.cpp index b6120f940..13b210d91 100644 --- a/src/gl/scene/gl_scene.cpp +++ b/src/gl/scene/gl_scene.cpp @@ -160,8 +160,8 @@ void FGLRenderer::Set3DViewport(bool mainview) { bool useSSAO = (gl_ssao != 0); mBuffers->BindSceneFB(useSSAO); - GLenum buffers[] = { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1 }; - glDrawBuffers(useSSAO ? 2 : 1, buffers); + GLenum buffers[] = { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1, GL_COLOR_ATTACHMENT2 }; + glDrawBuffers(useSSAO ? 3 : 1, buffers); gl_RenderState.SetPassType(useSSAO ? GBUFFER_PASS : NORMAL_PASS); gl_RenderState.Apply(); } @@ -507,8 +507,8 @@ void FGLRenderer::DrawScene(int drawmode) // If SSAO is active, switch to gbuffer shaders and use the framebuffer with gbuffers if (applySSAO) { - GLenum buffers[] = { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1 }; - glDrawBuffers(2, buffers); + GLenum buffers[] = { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1, GL_COLOR_ATTACHMENT2 }; + glDrawBuffers(3, buffers); gl_RenderState.SetPassType(GBUFFER_PASS); gl_RenderState.Apply(); gl_RenderState.ApplyMatrices(); diff --git a/src/gl/shaders/gl_ambientshader.cpp b/src/gl/shaders/gl_ambientshader.cpp index 43adb5c0e..6348d24cd 100644 --- a/src/gl/shaders/gl_ambientshader.cpp +++ b/src/gl/shaders/gl_ambientshader.cpp @@ -31,54 +31,65 @@ #include "gl/system/gl_cvars.h" #include "gl/shaders/gl_ambientshader.h" -void FLinearDepthShader::Bind(bool multisample) +void FLinearDepthShader::Bind() { - auto &shader = mShader[multisample]; - if (!shader) + bool multisample = (gl_multisample > 1); + if (mMultisample != multisample) + mShader.reset(); + + if (!mShader) { - shader.Compile(FShaderProgram::Vertex, "shaders/glsl/screenquad.vp", "", 330); - shader.Compile(FShaderProgram::Fragment, "shaders/glsl/lineardepth.fp", multisample ? "#define MULTISAMPLE\n" : "", 330); - shader.SetFragDataLocation(0, "FragColor"); - shader.Link("shaders/glsl/lineardepth"); - shader.SetAttribLocation(0, "PositionInProjection"); - DepthTexture[multisample].Init(shader, "DepthTexture"); - ColorTexture[multisample].Init(shader, "ColorTexture"); - SampleCount[multisample].Init(shader, "SampleCount"); - LinearizeDepthA[multisample].Init(shader, "LinearizeDepthA"); - LinearizeDepthB[multisample].Init(shader, "LinearizeDepthB"); - InverseDepthRangeA[multisample].Init(shader, "InverseDepthRangeA"); - InverseDepthRangeB[multisample].Init(shader, "InverseDepthRangeB"); - Scale[multisample].Init(shader, "Scale"); - Offset[multisample].Init(shader, "Offset"); + mShader = std::make_unique(); + mShader->Compile(FShaderProgram::Vertex, "shaders/glsl/screenquad.vp", "", 330); + mShader->Compile(FShaderProgram::Fragment, "shaders/glsl/lineardepth.fp", multisample ? "#define MULTISAMPLE\n" : "", 330); + mShader->SetFragDataLocation(0, "FragColor"); + mShader->Link("shaders/glsl/lineardepth"); + mShader->SetAttribLocation(0, "PositionInProjection"); + DepthTexture.Init(*mShader, "DepthTexture"); + ColorTexture.Init(*mShader, "ColorTexture"); + SampleCount.Init(*mShader, "SampleCount"); + LinearizeDepthA.Init(*mShader, "LinearizeDepthA"); + LinearizeDepthB.Init(*mShader, "LinearizeDepthB"); + InverseDepthRangeA.Init(*mShader, "InverseDepthRangeA"); + InverseDepthRangeB.Init(*mShader, "InverseDepthRangeB"); + Scale.Init(*mShader, "Scale"); + Offset.Init(*mShader, "Offset"); + mMultisample = multisample; } - shader.Bind(); + mShader->Bind(); } void FSSAOShader::Bind() { - auto &shader = mShader[gl_ssao]; - if (!shader) + bool multisample = (gl_multisample > 1); + if (mCurrentQuality != gl_ssao || mMultisample != multisample) + mShader.reset(); + + if (!mShader) { - shader.Compile(FShaderProgram::Vertex, "shaders/glsl/screenquad.vp", "", 330); - shader.Compile(FShaderProgram::Fragment, "shaders/glsl/ssao.fp", GetDefines(gl_ssao), 330); - shader.SetFragDataLocation(0, "FragColor"); - shader.Link("shaders/glsl/ssao"); - shader.SetAttribLocation(0, "PositionInProjection"); - DepthTexture.Init(shader, "DepthTexture"); - RandomTexture.Init(shader, "RandomTexture"); - UVToViewA.Init(shader, "UVToViewA"); - UVToViewB.Init(shader, "UVToViewB"); - InvFullResolution.Init(shader, "InvFullResolution"); - NDotVBias.Init(shader, "NDotVBias"); - NegInvR2.Init(shader, "NegInvR2"); - RadiusToScreen.Init(shader, "RadiusToScreen"); - AOMultiplier.Init(shader, "AOMultiplier"); - AOStrength.Init(shader, "AOStrength"); + mShader = std::make_unique(); + mShader->Compile(FShaderProgram::Vertex, "shaders/glsl/screenquad.vp", "", 330); + mShader->Compile(FShaderProgram::Fragment, "shaders/glsl/ssao.fp", GetDefines(gl_ssao, multisample), 330); + mShader->SetFragDataLocation(0, "FragColor"); + mShader->Link("shaders/glsl/ssao"); + mShader->SetAttribLocation(0, "PositionInProjection"); + DepthTexture.Init(*mShader, "DepthTexture"); + NormalTexture.Init(*mShader, "NormalTexture"); + RandomTexture.Init(*mShader, "RandomTexture"); + UVToViewA.Init(*mShader, "UVToViewA"); + UVToViewB.Init(*mShader, "UVToViewB"); + InvFullResolution.Init(*mShader, "InvFullResolution"); + NDotVBias.Init(*mShader, "NDotVBias"); + NegInvR2.Init(*mShader, "NegInvR2"); + RadiusToScreen.Init(*mShader, "RadiusToScreen"); + AOMultiplier.Init(*mShader, "AOMultiplier"); + AOStrength.Init(*mShader, "AOStrength"); + mMultisample = multisample; } - shader.Bind(); + mShader->Bind(); } -FString FSSAOShader::GetDefines(int mode) +FString FSSAOShader::GetDefines(int mode, bool multisample) { int numDirections, numSteps; switch (gl_ssao) @@ -96,6 +107,9 @@ FString FSSAOShader::GetDefines(int mode) #define NUM_DIRECTIONS %d.0 #define NUM_STEPS %d.0 )", numDirections, numSteps); + + if (multisample) + defines += "\n#define MULTISAMPLE\n"; return defines; } @@ -117,21 +131,26 @@ void FDepthBlurShader::Bind(bool vertical) shader.Bind(); } -void FSSAOCombineShader::Bind(bool multisample) +void FSSAOCombineShader::Bind() { - auto &shader = mShader[multisample]; - if (!shader) + bool multisample = (gl_multisample > 1); + if (mMultisample != multisample) + mShader.reset(); + + if (!mShader) { - shader.Compile(FShaderProgram::Vertex, "shaders/glsl/screenquad.vp", "", 330); - shader.Compile(FShaderProgram::Fragment, "shaders/glsl/ssaocombine.fp", multisample ? "#define MULTISAMPLE\n" : "", 330); - shader.SetFragDataLocation(0, "FragColor"); - shader.Link("shaders/glsl/ssaocombine"); - shader.SetAttribLocation(0, "PositionInProjection"); - AODepthTexture[multisample].Init(shader, "AODepthTexture"); - SceneDataTexture[multisample].Init(shader, "SceneDataTexture"); - SampleCount[multisample].Init(shader, "SampleCount"); - Scale[multisample].Init(shader, "Scale"); - Offset[multisample].Init(shader, "Offset"); + mShader = std::make_unique(); + mShader->Compile(FShaderProgram::Vertex, "shaders/glsl/screenquad.vp", "", 330); + mShader->Compile(FShaderProgram::Fragment, "shaders/glsl/ssaocombine.fp", multisample ? "#define MULTISAMPLE\n" : "", 330); + mShader->SetFragDataLocation(0, "FragColor"); + mShader->Link("shaders/glsl/ssaocombine"); + mShader->SetAttribLocation(0, "PositionInProjection"); + AODepthTexture.Init(*mShader, "AODepthTexture"); + SceneFogTexture.Init(*mShader, "SceneFogTexture"); + SampleCount.Init(*mShader, "SampleCount"); + Scale.Init(*mShader, "Scale"); + Offset.Init(*mShader, "Offset"); + mMultisample = multisample; } - shader.Bind(); + mShader->Bind(); } diff --git a/src/gl/shaders/gl_ambientshader.h b/src/gl/shaders/gl_ambientshader.h index 704729b24..5c68892c3 100644 --- a/src/gl/shaders/gl_ambientshader.h +++ b/src/gl/shaders/gl_ambientshader.h @@ -6,20 +6,21 @@ class FLinearDepthShader { public: - void Bind(bool multisample); + void Bind(); - FBufferedUniformSampler DepthTexture[2]; - FBufferedUniformSampler ColorTexture[2]; - FBufferedUniform1i SampleCount[2]; - FBufferedUniform1f LinearizeDepthA[2]; - FBufferedUniform1f LinearizeDepthB[2]; - FBufferedUniform1f InverseDepthRangeA[2]; - FBufferedUniform1f InverseDepthRangeB[2]; - FBufferedUniform2f Scale[2]; - FBufferedUniform2f Offset[2]; + FBufferedUniformSampler DepthTexture; + FBufferedUniformSampler ColorTexture; + FBufferedUniform1i SampleCount; + FBufferedUniform1f LinearizeDepthA; + FBufferedUniform1f LinearizeDepthB; + FBufferedUniform1f InverseDepthRangeA; + FBufferedUniform1f InverseDepthRangeB; + FBufferedUniform2f Scale; + FBufferedUniform2f Offset; private: - FShaderProgram mShader[2]; + std::unique_ptr mShader; + bool mMultisample = false; }; class FSSAOShader @@ -28,6 +29,7 @@ public: void Bind(); FBufferedUniformSampler DepthTexture; + FBufferedUniformSampler NormalTexture; FBufferedUniformSampler RandomTexture; FBufferedUniform2f UVToViewA; FBufferedUniform2f UVToViewB; @@ -48,9 +50,11 @@ private: NumQualityModes }; - FString GetDefines(int mode); + FString GetDefines(int mode, bool multisample); - FShaderProgram mShader[NumQualityModes]; + std::unique_ptr mShader; + Quality mCurrentQuality = Off; + bool mMultisample = false; }; class FDepthBlurShader @@ -70,16 +74,17 @@ private: class FSSAOCombineShader { public: - void Bind(bool multisample); + void Bind(); - FBufferedUniformSampler AODepthTexture[2]; - FBufferedUniformSampler SceneDataTexture[2]; - FBufferedUniform1i SampleCount[2]; - FBufferedUniform2f Scale[2]; - FBufferedUniform2f Offset[2]; + FBufferedUniformSampler AODepthTexture; + FBufferedUniformSampler SceneFogTexture; + FBufferedUniform1i SampleCount; + FBufferedUniform2f Scale; + FBufferedUniform2f Offset; private: - FShaderProgram mShader[2]; + std::unique_ptr mShader; + bool mMultisample = false; }; #endif \ No newline at end of file diff --git a/src/gl/shaders/gl_shader.cpp b/src/gl/shaders/gl_shader.cpp index 9cbd69ce2..b7d8335f8 100644 --- a/src/gl/shaders/gl_shader.cpp +++ b/src/gl/shaders/gl_shader.cpp @@ -182,7 +182,8 @@ bool FShader::Load(const char * name, const char * vert_prog_lump, const char * glBindAttribLocation(hShader, VATTR_NORMAL, "aNormal"); glBindFragDataLocation(hShader, 0, "FragColor"); - glBindFragDataLocation(hShader, 1, "FragData"); + glBindFragDataLocation(hShader, 1, "FragFog"); + glBindFragDataLocation(hShader, 2, "FragNormal"); glLinkProgram(hShader); diff --git a/src/gl/system/gl_cvars.h b/src/gl/system/gl_cvars.h index 836787117..3b425d261 100644 --- a/src/gl/system/gl_cvars.h +++ b/src/gl/system/gl_cvars.h @@ -53,7 +53,7 @@ EXTERN_CVAR(Float, gl_lens_chromatic) EXTERN_CVAR(Int, gl_ssao) EXTERN_CVAR(Int, gl_ssao_portals) EXTERN_CVAR(Float, gl_ssao_strength) -EXTERN_CVAR(Bool, gl_ssao_debug) +EXTERN_CVAR(Int, gl_ssao_debug) EXTERN_CVAR(Float, gl_ssao_bias) EXTERN_CVAR(Float, gl_ssao_radius) EXTERN_CVAR(Float, gl_ssao_blur_amount) diff --git a/wadsrc/static/shaders/glsl/main.fp b/wadsrc/static/shaders/glsl/main.fp index 1f270728d..e26b2fd4a 100644 --- a/wadsrc/static/shaders/glsl/main.fp +++ b/wadsrc/static/shaders/glsl/main.fp @@ -8,7 +8,8 @@ in vec4 vColor; out vec4 FragColor; #ifdef GBUFFER_PASS -out vec4 FragData; +out vec4 FragFog; +out vec4 FragNormal; #endif #ifdef SHADER_STORAGE_LIGHTS @@ -408,7 +409,8 @@ void main() } FragColor = frag; #ifdef GBUFFER_PASS - FragData = vec4(AmbientOcclusionColor(), 1.0); + FragFog = vec4(AmbientOcclusionColor(), 1.0); + FragNormal = vec4(vEyeNormal.xyz * 0.5 + 0.5, 1.0); #endif } diff --git a/wadsrc/static/shaders/glsl/ssao.fp b/wadsrc/static/shaders/glsl/ssao.fp index e0d972c57..758f7dbaa 100644 --- a/wadsrc/static/shaders/glsl/ssao.fp +++ b/wadsrc/static/shaders/glsl/ssao.fp @@ -15,6 +15,12 @@ uniform float AOStrength; uniform sampler2D DepthTexture; +#if defined(MULTISAMPLE) +uniform sampler2DMS NormalTexture; +#else +uniform sampler2D NormalTexture; +#endif + #if defined(USE_RANDOM_TEXTURE) uniform sampler2D RandomTexture; #endif @@ -28,6 +34,20 @@ vec3 FetchViewPos(vec2 uv) return vec3((UVToViewA * uv + UVToViewB) * z, z); } +#if defined(MULTISAMPLE) +vec3 FetchNormal(vec2 uv) +{ + ivec2 texSize = textureSize(NormalTexture); + ivec2 ipos = ivec2(uv * vec2(texSize)); + return normalize(texelFetch(NormalTexture, ipos, 0).xyz * 2.0 - 1.0); +} +#else +vec3 FetchNormal(vec2 uv) +{ + return normalize(texture(NormalTexture, uv).xyz * 2.0 - 1.0); +} +#endif + vec3 MinDiff(vec3 p, vec3 pr, vec3 pl) { vec3 v1 = pr - p; @@ -106,7 +126,8 @@ float ComputeAO(vec3 viewPosition, vec3 viewNormal) void main() { vec3 viewPosition = FetchViewPos(TexCoord); - vec3 viewNormal = ReconstructNormal(viewPosition); + //vec3 viewNormal = ReconstructNormal(viewPosition); + vec3 viewNormal = FetchNormal(TexCoord); float occlusion = ComputeAO(viewPosition, viewNormal) * AOStrength + (1.0 - AOStrength); FragColor = vec4(occlusion, viewPosition.z, 0.0, 1.0); } diff --git a/wadsrc/static/shaders/glsl/ssaocombine.fp b/wadsrc/static/shaders/glsl/ssaocombine.fp index 7cd096276..377516587 100644 --- a/wadsrc/static/shaders/glsl/ssaocombine.fp +++ b/wadsrc/static/shaders/glsl/ssaocombine.fp @@ -5,10 +5,10 @@ out vec4 FragColor; uniform sampler2D AODepthTexture; #if defined(MULTISAMPLE) -uniform sampler2DMS SceneDataTexture; +uniform sampler2DMS SceneFogTexture; uniform int SampleCount; #else -uniform sampler2D SceneDataTexture; +uniform sampler2D SceneFogTexture; #endif uniform vec2 Scale; @@ -18,19 +18,19 @@ void main() { vec2 uv = Offset + TexCoord * Scale; #if defined(MULTISAMPLE) - ivec2 texSize = textureSize(SceneDataTexture); + ivec2 texSize = textureSize(SceneFogTexture); #else - ivec2 texSize = textureSize(SceneDataTexture, 0); + ivec2 texSize = textureSize(SceneFogTexture, 0); #endif ivec2 ipos = ivec2(max(floor(uv * vec2(texSize) - 0.75), vec2(0.0))); #if defined(MULTISAMPLE) vec3 fogColor = vec3(0.0); for (int i = 0; i < SampleCount; i++) - fogColor += texelFetch(SceneDataTexture, ipos, i).rgb; + fogColor += texelFetch(SceneFogTexture, ipos, i).rgb; fogColor /= float(SampleCount); #else - vec3 fogColor = texelFetch(SceneDataTexture, ipos, 0).rgb; + vec3 fogColor = texelFetch(SceneFogTexture, ipos, 0).rgb; #endif float attenutation = texture(AODepthTexture, TexCoord).x; From bb79dcb6349c694e441a875b5ff015de127da065 Mon Sep 17 00:00:00 2001 From: Magnus Norddahl Date: Thu, 6 Oct 2016 07:36:49 +0200 Subject: [PATCH 3/4] SSAO math bug fixes --- src/gl/renderer/gl_postprocess.cpp | 65 +++++++++++++---------- src/gl/renderer/gl_renderbuffers.cpp | 44 +++++++++------ src/gl/renderer/gl_renderbuffers.h | 3 +- src/gl/shaders/gl_ambientshader.cpp | 3 ++ src/gl/shaders/gl_ambientshader.h | 2 + wadsrc/static/shaders/glsl/depthblur.fp | 2 +- wadsrc/static/shaders/glsl/lineardepth.fp | 33 ++++++++---- wadsrc/static/shaders/glsl/ssao.fp | 56 ++++++++++--------- 8 files changed, 125 insertions(+), 83 deletions(-) diff --git a/src/gl/renderer/gl_postprocess.cpp b/src/gl/renderer/gl_postprocess.cpp index ac5a6336d..97e2c3be9 100644 --- a/src/gl/renderer/gl_postprocess.cpp +++ b/src/gl/renderer/gl_postprocess.cpp @@ -124,7 +124,7 @@ CVAR(Float, gl_ssao_strength, 0.7, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) CVAR(Int, gl_ssao_debug, 0, 0) CVAR(Float, gl_ssao_bias, 0.5f, 0) CVAR(Float, gl_ssao_radius, 100.0f, 0) -CUSTOM_CVAR(Float, gl_ssao_blur_amount, 4.0f, 0) +CUSTOM_CVAR(Float, gl_ssao_blur_amount, 16.0f, 0) { if (self < 0.1f) self = 0.1f; } @@ -178,6 +178,13 @@ void FGLRenderer::AmbientOccludeScene() float blurSharpness = 1.0f / blurAmount; + float sceneScaleX = mSceneViewport.width / (float)mScreenViewport.width; + float sceneScaleY = mSceneViewport.height / (float)mScreenViewport.height; + float sceneOffsetX = mSceneViewport.left / (float)mScreenViewport.width; + float sceneOffsetY = mSceneViewport.top / (float)mScreenViewport.height; + + int randomTexture = clamp(gl_ssao - 1, 0, FGLRenderBuffers::NumAmbientRandomTextures - 1); + // Calculate linear depth values glBindFramebuffer(GL_FRAMEBUFFER, mBuffers->AmbientFB0); glViewport(0, 0, mBuffers->AmbientWidth, mBuffers->AmbientHeight); @@ -196,8 +203,8 @@ void FGLRenderer::AmbientOccludeScene() mLinearDepthShader->LinearizeDepthB.Set(MAX(1.0f / GetZNear(), 1.e-8f)); mLinearDepthShader->InverseDepthRangeA.Set(1.0f); mLinearDepthShader->InverseDepthRangeB.Set(0.0f); - mLinearDepthShader->Scale.Set(mBuffers->AmbientWidth * 2.0f / (float)mScreenViewport.width, mBuffers->AmbientHeight * 2.0f / (float)mScreenViewport.height); - mLinearDepthShader->Offset.Set(mSceneViewport.left / (float)mScreenViewport.width, mSceneViewport.top / (float)mScreenViewport.height); + mLinearDepthShader->Scale.Set(sceneScaleX, sceneScaleY); + mLinearDepthShader->Offset.Set(sceneOffsetX, sceneOffsetY); RenderScreenQuad(); // Apply ambient occlusion @@ -206,7 +213,7 @@ void FGLRenderer::AmbientOccludeScene() glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glActiveTexture(GL_TEXTURE1); - glBindTexture(GL_TEXTURE_2D, mBuffers->AmbientRandomTexture); + glBindTexture(GL_TEXTURE_2D, mBuffers->AmbientRandomTexture[randomTexture]); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); @@ -219,44 +226,46 @@ void FGLRenderer::AmbientOccludeScene() mSSAOShader->DepthTexture.Set(0); mSSAOShader->RandomTexture.Set(1); mSSAOShader->NormalTexture.Set(2); - mSSAOShader->UVToViewA.Set(2.0f * invFocalLenX, -2.0f * invFocalLenY); - mSSAOShader->UVToViewB.Set(-invFocalLenX, invFocalLenY); + mSSAOShader->UVToViewA.Set(2.0f * invFocalLenX, 2.0f * invFocalLenY); + mSSAOShader->UVToViewB.Set(-invFocalLenX, -invFocalLenY); mSSAOShader->InvFullResolution.Set(1.0f / mBuffers->AmbientWidth, 1.0f / mBuffers->AmbientHeight); mSSAOShader->NDotVBias.Set(nDotVBias); mSSAOShader->NegInvR2.Set(-1.0f / r2); mSSAOShader->RadiusToScreen.Set(aoRadius * 0.5 / tanHalfFovy * mBuffers->AmbientHeight); mSSAOShader->AOMultiplier.Set(1.0f / (1.0f - nDotVBias)); mSSAOShader->AOStrength.Set(aoStrength); + mSSAOShader->Scale.Set(sceneScaleX, sceneScaleY); + mSSAOShader->Offset.Set(sceneOffsetX, sceneOffsetY); RenderScreenQuad(); // Blur SSAO texture - glBindFramebuffer(GL_FRAMEBUFFER, mBuffers->AmbientFB0); - glBindTexture(GL_TEXTURE_2D, mBuffers->AmbientTexture1); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - mDepthBlurShader->Bind(false); - mDepthBlurShader->BlurSharpness[false].Set(blurSharpness); - mDepthBlurShader->InvFullResolution[false].Set(1.0f / mBuffers->AmbientWidth, 1.0f / mBuffers->AmbientHeight); - RenderScreenQuad(); + if (gl_ssao_debug < 2) + { + glBindFramebuffer(GL_FRAMEBUFFER, mBuffers->AmbientFB0); + glBindTexture(GL_TEXTURE_2D, mBuffers->AmbientTexture1); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + mDepthBlurShader->Bind(false); + mDepthBlurShader->BlurSharpness[false].Set(blurSharpness); + mDepthBlurShader->InvFullResolution[false].Set(1.0f / mBuffers->AmbientWidth, 1.0f / mBuffers->AmbientHeight); + RenderScreenQuad(); - glBindFramebuffer(GL_FRAMEBUFFER, mBuffers->AmbientFB1); - glBindTexture(GL_TEXTURE_2D, mBuffers->AmbientTexture0); - mDepthBlurShader->Bind(true); - mDepthBlurShader->BlurSharpness[true].Set(blurSharpness); - mDepthBlurShader->InvFullResolution[true].Set(1.0f / mBuffers->AmbientWidth, 1.0f / mBuffers->AmbientHeight); - mDepthBlurShader->PowExponent[true].Set(1.8f); - RenderScreenQuad(); + glBindFramebuffer(GL_FRAMEBUFFER, mBuffers->AmbientFB1); + glBindTexture(GL_TEXTURE_2D, mBuffers->AmbientTexture0); + mDepthBlurShader->Bind(true); + mDepthBlurShader->BlurSharpness[true].Set(blurSharpness); + mDepthBlurShader->InvFullResolution[true].Set(1.0f / mBuffers->AmbientWidth, 1.0f / mBuffers->AmbientHeight); + mDepthBlurShader->PowExponent[true].Set(1.8f); + RenderScreenQuad(); + } // Add SSAO back to scene texture: mBuffers->BindSceneFB(false); glViewport(mSceneViewport.left, mSceneViewport.top, mSceneViewport.width, mSceneViewport.height); glEnable(GL_BLEND); glBlendEquation(GL_FUNC_ADD); - if (gl_ssao_debug > 1) - glBlendFunc(GL_ONE, GL_ZERO); - else - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - if (gl_ssao_debug == 1) + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + if (gl_ssao_debug != 0) { glClearColor(1.0f, 1.0f, 1.0f, 1.0f); glClear(GL_COLOR_BUFFER_BIT); @@ -270,8 +279,8 @@ void FGLRenderer::AmbientOccludeScene() mSSAOCombineShader->AODepthTexture.Set(0); mSSAOCombineShader->SceneFogTexture.Set(1); if (gl_multisample > 1) mSSAOCombineShader->SampleCount.Set(gl_multisample); - mSSAOCombineShader->Scale.Set(mBuffers->AmbientWidth * 2.0f / (float)mScreenViewport.width, mBuffers->AmbientHeight * 2.0f / (float)mScreenViewport.height); - mSSAOCombineShader->Offset.Set(mSceneViewport.left / (float)mScreenViewport.width, mSceneViewport.top / (float)mScreenViewport.height); + mSSAOCombineShader->Scale.Set(sceneScaleX, sceneScaleY); + mSSAOCombineShader->Offset.Set(sceneOffsetX, sceneOffsetY); RenderScreenQuad(); FGLDebug::PopGroup(); diff --git a/src/gl/renderer/gl_renderbuffers.cpp b/src/gl/renderer/gl_renderbuffers.cpp index 1a1509d7a..a24596562 100644 --- a/src/gl/renderer/gl_renderbuffers.cpp +++ b/src/gl/renderer/gl_renderbuffers.cpp @@ -59,6 +59,11 @@ FGLRenderBuffers::FGLRenderBuffers() mPipelineFB[i] = 0; } + for (int i = 0; i < NumAmbientRandomTextures; i++) + { + AmbientRandomTexture[i] = 0; + } + glGetIntegerv(GL_FRAMEBUFFER_BINDING, (GLint*)&mOutputFB); glGetIntegerv(GL_MAX_SAMPLES, &mMaxSamples); } @@ -151,7 +156,8 @@ void FGLRenderBuffers::ClearAmbientOcclusion() DeleteFrameBuffer(AmbientFB1); DeleteTexture(AmbientTexture0); DeleteTexture(AmbientTexture1); - DeleteTexture(AmbientRandomTexture); + for (int i = 0; i < NumAmbientRandomTextures; i++) + DeleteTexture(AmbientRandomTexture[i]); } void FGLRenderBuffers::DeleteTexture(GLuint &handle) @@ -368,25 +374,31 @@ void FGLRenderBuffers::CreateAmbientOcclusion(int width, int height) AmbientFB0 = CreateFrameBuffer("AmbientFB0", AmbientTexture0); AmbientFB1 = CreateFrameBuffer("AmbientFB1", AmbientTexture1); - int16_t randomValues[16 * 4]; + // Must match quality enum in FSSAOShader::GetDefines + double numDirections[NumAmbientRandomTextures] = { 2.0, 4.0, 8.0 }; + std::mt19937 generator(1337); - std::uniform_real_distribution distribution(-1.0, 1.0); - for (int i = 0; i < 16; i++) + std::uniform_real_distribution distribution(0.0, 1.0); + for (int quality = 0; quality < NumAmbientRandomTextures; quality++) { - double num_directions = 8.0; // Must be same as the define in ssao.fp - double angle = 2.0 * M_PI * distribution(generator) / num_directions; - double x = cos(angle); - double y = sin(angle); - double z = distribution(generator); - double w = distribution(generator); + int16_t randomValues[16 * 4]; - 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); + 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] = Create2DTexture("AmbientRandomTexture", GL_RGBA16_SNORM, 4, 4, randomValues); } - - AmbientRandomTexture = Create2DTexture("AmbientRandomTexture", GL_RGBA16_SNORM, 4, 4, randomValues); } //========================================================================== diff --git a/src/gl/renderer/gl_renderbuffers.h b/src/gl/renderer/gl_renderbuffers.h index 9508f7009..d593b0248 100644 --- a/src/gl/renderer/gl_renderbuffers.h +++ b/src/gl/renderer/gl_renderbuffers.h @@ -65,7 +65,8 @@ public: GLuint AmbientFB1 = 0; int AmbientWidth = 0; int AmbientHeight = 0; - GLuint AmbientRandomTexture = 0; + enum { NumAmbientRandomTextures = 3 }; + GLuint AmbientRandomTexture[NumAmbientRandomTextures]; static bool IsEnabled(); diff --git a/src/gl/shaders/gl_ambientshader.cpp b/src/gl/shaders/gl_ambientshader.cpp index 6348d24cd..0d08e1258 100644 --- a/src/gl/shaders/gl_ambientshader.cpp +++ b/src/gl/shaders/gl_ambientshader.cpp @@ -84,6 +84,8 @@ void FSSAOShader::Bind() RadiusToScreen.Init(*mShader, "RadiusToScreen"); AOMultiplier.Init(*mShader, "AOMultiplier"); AOStrength.Init(*mShader, "AOStrength"); + Scale.Init(*mShader, "Scale"); + Offset.Init(*mShader, "Offset"); mMultisample = multisample; } mShader->Bind(); @@ -91,6 +93,7 @@ void FSSAOShader::Bind() FString FSSAOShader::GetDefines(int mode, bool multisample) { + // Must match quality values in FGLRenderBuffers::CreateAmbientOcclusion int numDirections, numSteps; switch (gl_ssao) { diff --git a/src/gl/shaders/gl_ambientshader.h b/src/gl/shaders/gl_ambientshader.h index 5c68892c3..95dfd6bac 100644 --- a/src/gl/shaders/gl_ambientshader.h +++ b/src/gl/shaders/gl_ambientshader.h @@ -39,6 +39,8 @@ public: FBufferedUniform1f RadiusToScreen; FBufferedUniform1f AOMultiplier; FBufferedUniform1f AOStrength; + FBufferedUniform2f Scale; + FBufferedUniform2f Offset; private: enum Quality diff --git a/wadsrc/static/shaders/glsl/depthblur.fp b/wadsrc/static/shaders/glsl/depthblur.fp index c4f4438d3..7e3dad074 100644 --- a/wadsrc/static/shaders/glsl/depthblur.fp +++ b/wadsrc/static/shaders/glsl/depthblur.fp @@ -7,7 +7,7 @@ uniform float BlurSharpness; uniform vec2 InvFullResolution; uniform float PowExponent; -#define KERNEL_RADIUS 7.0 +#define KERNEL_RADIUS 3.0 float CrossBilateralWeight(float r, float sampleDepth, float centerDepth) { diff --git a/wadsrc/static/shaders/glsl/lineardepth.fp b/wadsrc/static/shaders/glsl/lineardepth.fp index 558738bd9..fa71c9de0 100644 --- a/wadsrc/static/shaders/glsl/lineardepth.fp +++ b/wadsrc/static/shaders/glsl/lineardepth.fp @@ -18,6 +18,12 @@ uniform float InverseDepthRangeB; uniform vec2 Scale; uniform vec2 Offset; +float normalizeDepth(float depth) +{ + float normalizedDepth = clamp(InverseDepthRangeA * depth + InverseDepthRangeB, 0.0, 1.0); + return 1.0 / (normalizedDepth * LinearizeDepthA + LinearizeDepthB); +} + void main() { vec2 uv = Offset + TexCoord * Scale; @@ -28,19 +34,24 @@ void main() ivec2 texSize = textureSize(DepthTexture, 0); #endif - // Use floor here because as we downscale the sampling error has to remain uniform to prevent - // noise in the depth values. - ivec2 ipos = ivec2(max(floor(uv * vec2(texSize) - 0.75), vec2(0.0))); + ivec2 ipos = ivec2(max(uv * vec2(texSize), vec2(0.0))); #if defined(MULTISAMPLE) - float depth = 0.0; - for (int i = 0; i < SampleCount; i++) - depth += texelFetch(ColorTexture, ipos, i).a != 0.0 ? texelFetch(DepthTexture, ipos, i).x : 1.0; - depth /= float(SampleCount); + float depth = normalizeDepth(texelFetch(ColorTexture, ipos, 0).a != 0.0 ? texelFetch(DepthTexture, ipos, 0).x : 1.0); + float sampleIndex = 0.0; + for (int i = 1; i < SampleCount; i++) + { + float hardwareDepth = texelFetch(ColorTexture, ipos, i).a != 0.0 ? texelFetch(DepthTexture, ipos, i).x : 1.0; + float sampleDepth = normalizeDepth(hardwareDepth); + if (sampleDepth < depth) + { + depth = sampleDepth; + sampleIndex = float(i); + } + } + FragColor = vec4(depth, sampleIndex, 0.0, 1.0); #else - float depth = texelFetch(ColorTexture, ipos, 0).a != 0.0 ? texelFetch(DepthTexture, ipos, 0).x : 1.0; + float depth = normalizeDepth(texelFetch(ColorTexture, ipos, 0).a != 0.0 ? texelFetch(DepthTexture, ipos, 0).x : 1.0); + FragColor = vec4(depth, 0.0, 0.0, 1.0); #endif - - float normalizedDepth = clamp(InverseDepthRangeA * depth + InverseDepthRangeB, 0.0, 1.0); - FragColor = vec4(1.0 / (normalizedDepth * LinearizeDepthA + LinearizeDepthB), 0.0, 0.0, 1.0); } diff --git a/wadsrc/static/shaders/glsl/ssao.fp b/wadsrc/static/shaders/glsl/ssao.fp index 758f7dbaa..f895ddc25 100644 --- a/wadsrc/static/shaders/glsl/ssao.fp +++ b/wadsrc/static/shaders/glsl/ssao.fp @@ -13,6 +13,9 @@ uniform float AOMultiplier; uniform float AOStrength; +uniform vec2 Scale; +uniform vec2 Offset; + uniform sampler2D DepthTexture; #if defined(MULTISAMPLE) @@ -27,42 +30,42 @@ uniform sampler2D RandomTexture; #define PI 3.14159265358979323846 -// Calculate eye space position for the specified texture coordinate -vec3 FetchViewPos(vec2 uv) +// Calculate eye space position for the specified texture coordinate and depth +vec3 FetchViewPos(vec2 uv, float z) { - float z = texture(DepthTexture, uv).x; return vec3((UVToViewA * uv + UVToViewB) * z, z); } #if defined(MULTISAMPLE) -vec3 FetchNormal(vec2 uv) +vec3 SampleNormal(vec2 uv, float samplerIndex) { ivec2 texSize = textureSize(NormalTexture); ivec2 ipos = ivec2(uv * vec2(texSize)); - return normalize(texelFetch(NormalTexture, ipos, 0).xyz * 2.0 - 1.0); + return texelFetch(NormalTexture, ipos, int(samplerIndex)).xyz * 2.0 - 1.0; } #else -vec3 FetchNormal(vec2 uv) +vec3 SampleNormal(vec2 uv, float samplerIndex) { - return normalize(texture(NormalTexture, uv).xyz * 2.0 - 1.0); + ivec2 texSize = textureSize(NormalTexture, 0); + ivec2 ipos = ivec2(uv * vec2(texSize)); + return texelFetch(NormalTexture, ipos, 0).xyz * 2.0 - 1.0; } #endif -vec3 MinDiff(vec3 p, vec3 pr, vec3 pl) +// Look up the eye space normal for the specified texture coordinate +vec3 FetchNormal(vec2 uv, float samplerIndex) { - vec3 v1 = pr - p; - vec3 v2 = p - pl; - return (dot(v1, v1) < dot(v2, v2)) ? v1 : v2; -} - -// Reconstruct eye space normal from nearest neighbors -vec3 ReconstructNormal(vec3 p) -{ - vec3 pr = FetchViewPos(TexCoord + vec2(InvFullResolution.x, 0)); - vec3 pl = FetchViewPos(TexCoord + vec2(-InvFullResolution.x, 0)); - vec3 pt = FetchViewPos(TexCoord + vec2(0, InvFullResolution.y)); - vec3 pb = FetchViewPos(TexCoord + vec2(0, -InvFullResolution.y)); - return normalize(cross(MinDiff(p, pr, pl), MinDiff(p, pt, pb))); + vec3 normal = SampleNormal(Offset + uv * Scale, samplerIndex); + if (length(normal) > 0.1) + { + normal = normalize(normal); + normal.z = -normal.z; + return normal; + } + else + { + return vec3(0.0); + } } // Compute normalized 2D direction @@ -113,7 +116,7 @@ float ComputeAO(vec3 viewPosition, vec3 viewNormal) for (float StepIndex = 0.0; StepIndex < NUM_STEPS; ++StepIndex) { vec2 sampleUV = round(rayPixels * direction) * InvFullResolution + TexCoord; - vec3 samplePos = FetchViewPos(sampleUV); + vec3 samplePos = FetchViewPos(sampleUV, texture(DepthTexture, sampleUV).x); ao += ComputeSampleAO(viewPosition, viewNormal, samplePos); rayPixels += stepSizePixels; } @@ -125,9 +128,10 @@ float ComputeAO(vec3 viewPosition, vec3 viewNormal) void main() { - vec3 viewPosition = FetchViewPos(TexCoord); - //vec3 viewNormal = ReconstructNormal(viewPosition); - vec3 viewNormal = FetchNormal(TexCoord); - float occlusion = ComputeAO(viewPosition, viewNormal) * AOStrength + (1.0 - AOStrength); + vec2 depthData = texture(DepthTexture, TexCoord).xy; + vec3 viewPosition = FetchViewPos(TexCoord, depthData.x); + vec3 viewNormal = FetchNormal(TexCoord, depthData.y); + float occlusion = viewNormal != vec3(0.0) ? ComputeAO(viewPosition, viewNormal) * AOStrength + (1.0 - AOStrength) : 1.0; + FragColor = vec4(occlusion, viewPosition.z, 0.0, 1.0); } From 1b7c42f45f9c9bf524d065505a758c023560a172 Mon Sep 17 00:00:00 2001 From: Magnus Norddahl Date: Sun, 9 Oct 2016 06:17:48 +0200 Subject: [PATCH 4/4] Multisampling ssao bug fixes and split linear depth to its own buffer --- src/gl/renderer/gl_postprocess.cpp | 22 ++++++++++++------- src/gl/renderer/gl_renderbuffers.cpp | 26 ++++++++++++++--------- src/gl/renderer/gl_renderbuffers.h | 4 +++- src/gl/shaders/gl_ambientshader.cpp | 3 ++- src/gl/shaders/gl_ambientshader.h | 3 ++- wadsrc/static/shaders/glsl/lineardepth.fp | 19 ++++------------- wadsrc/static/shaders/glsl/ssao.fp | 23 ++++++++++---------- wadsrc/static/shaders/glsl/ssaocombine.fp | 3 ++- 8 files changed, 55 insertions(+), 48 deletions(-) diff --git a/src/gl/renderer/gl_postprocess.cpp b/src/gl/renderer/gl_postprocess.cpp index 97e2c3be9..dd8bccc8b 100644 --- a/src/gl/renderer/gl_postprocess.cpp +++ b/src/gl/renderer/gl_postprocess.cpp @@ -122,9 +122,14 @@ CUSTOM_CVAR(Int, gl_ssao_portals, 0, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) CVAR(Float, gl_ssao_strength, 0.7, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) CVAR(Int, gl_ssao_debug, 0, 0) -CVAR(Float, gl_ssao_bias, 0.5f, 0) -CVAR(Float, gl_ssao_radius, 100.0f, 0) -CUSTOM_CVAR(Float, gl_ssao_blur_amount, 16.0f, 0) +CVAR(Float, gl_ssao_bias, 0.2f, 0) +CVAR(Float, gl_ssao_radius, 80.0f, 0) +CUSTOM_CVAR(Float, gl_ssao_blur, 16.0f, 0) +{ + if (self < 0.1f) self = 0.1f; +} + +CUSTOM_CVAR(Float, gl_ssao_exponent, 1.8f, 0) { if (self < 0.1f) self = 0.1f; } @@ -166,7 +171,7 @@ void FGLRenderer::AmbientOccludeScene() float bias = gl_ssao_bias; float aoRadius = gl_ssao_radius; - const float blurAmount = gl_ssao_blur_amount; + const float blurAmount = gl_ssao_blur; float aoStrength = gl_ssao_strength; //float tanHalfFovy = tan(fovy * (M_PI / 360.0f)); @@ -186,7 +191,7 @@ void FGLRenderer::AmbientOccludeScene() int randomTexture = clamp(gl_ssao - 1, 0, FGLRenderBuffers::NumAmbientRandomTextures - 1); // Calculate linear depth values - glBindFramebuffer(GL_FRAMEBUFFER, mBuffers->AmbientFB0); + glBindFramebuffer(GL_FRAMEBUFFER, mBuffers->LinearDepthFB); glViewport(0, 0, mBuffers->AmbientWidth, mBuffers->AmbientHeight); mBuffers->BindSceneDepthTexture(0); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); @@ -198,7 +203,7 @@ void FGLRenderer::AmbientOccludeScene() mLinearDepthShader->Bind(); mLinearDepthShader->DepthTexture.Set(0); mLinearDepthShader->ColorTexture.Set(1); - if (gl_multisample > 1) mLinearDepthShader->SampleCount.Set(gl_multisample); + if (gl_multisample > 1) mLinearDepthShader->SampleIndex.Set(0); mLinearDepthShader->LinearizeDepthA.Set(1.0f / GetZFar() - 1.0f / GetZNear()); mLinearDepthShader->LinearizeDepthB.Set(MAX(1.0f / GetZNear(), 1.e-8f)); mLinearDepthShader->InverseDepthRangeA.Set(1.0f); @@ -209,7 +214,7 @@ void FGLRenderer::AmbientOccludeScene() // Apply ambient occlusion glBindFramebuffer(GL_FRAMEBUFFER, mBuffers->AmbientFB1); - glBindTexture(GL_TEXTURE_2D, mBuffers->AmbientTexture0); + glBindTexture(GL_TEXTURE_2D, mBuffers->LinearDepthTexture); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glActiveTexture(GL_TEXTURE1); @@ -226,6 +231,7 @@ void FGLRenderer::AmbientOccludeScene() mSSAOShader->DepthTexture.Set(0); mSSAOShader->RandomTexture.Set(1); mSSAOShader->NormalTexture.Set(2); + if (gl_multisample > 1) mSSAOShader->SampleIndex.Set(0); mSSAOShader->UVToViewA.Set(2.0f * invFocalLenX, 2.0f * invFocalLenY); mSSAOShader->UVToViewB.Set(-invFocalLenX, -invFocalLenY); mSSAOShader->InvFullResolution.Set(1.0f / mBuffers->AmbientWidth, 1.0f / mBuffers->AmbientHeight); @@ -255,7 +261,7 @@ void FGLRenderer::AmbientOccludeScene() mDepthBlurShader->Bind(true); mDepthBlurShader->BlurSharpness[true].Set(blurSharpness); mDepthBlurShader->InvFullResolution[true].Set(1.0f / mBuffers->AmbientWidth, 1.0f / mBuffers->AmbientHeight); - mDepthBlurShader->PowExponent[true].Set(1.8f); + mDepthBlurShader->PowExponent[true].Set(gl_ssao_exponent); RenderScreenQuad(); } diff --git a/src/gl/renderer/gl_renderbuffers.cpp b/src/gl/renderer/gl_renderbuffers.cpp index a24596562..b14ee9852 100644 --- a/src/gl/renderer/gl_renderbuffers.cpp +++ b/src/gl/renderer/gl_renderbuffers.cpp @@ -152,8 +152,10 @@ void FGLRenderBuffers::ClearEyeBuffers() void FGLRenderBuffers::ClearAmbientOcclusion() { + DeleteFrameBuffer(LinearDepthFB); DeleteFrameBuffer(AmbientFB0); DeleteFrameBuffer(AmbientFB1); + DeleteTexture(LinearDepthTexture); DeleteTexture(AmbientTexture0); DeleteTexture(AmbientTexture1); for (int i = 0; i < NumAmbientRandomTextures; i++) @@ -336,13 +338,13 @@ void FGLRenderBuffers::CreateBloom(int width, int height) if (width <= 0 || height <= 0) return; - int bloomWidth = MAX(width / 2, 1); - int bloomHeight = MAX(height / 2, 1); + int bloomWidth = (width + 1) / 2; + int bloomHeight = (height + 1) / 2; for (int i = 0; i < NumBloomLevels; i++) { auto &level = BloomLevels[i]; - level.Width = MAX(bloomWidth / 2, 1); - level.Height = MAX(bloomHeight / 2, 1); + level.Width = (bloomWidth + 1) / 2; + level.Height = (bloomHeight + 1) / 2; level.VTexture = Create2DTexture("Bloom.VTexture", GL_RGBA16F, level.Width, level.Height); level.HTexture = Create2DTexture("Bloom.HTexture", GL_RGBA16F, level.Width, level.Height); @@ -367,10 +369,12 @@ void FGLRenderBuffers::CreateAmbientOcclusion(int width, int height) if (width <= 0 || height <= 0) return; - AmbientWidth = width / 2; - AmbientHeight = height / 2; - AmbientTexture0 = Create2DTexture("AmbientTexture0", GL_RG32F, AmbientWidth, AmbientHeight); - AmbientTexture1 = Create2DTexture("AmbientTexture1", GL_RG32F, AmbientWidth, AmbientHeight); + AmbientWidth = (width + 1) / 2; + AmbientHeight = (height + 1) / 2; + LinearDepthTexture = Create2DTexture("LinearDepthTexture", GL_R32F, AmbientWidth, AmbientHeight); + AmbientTexture0 = Create2DTexture("AmbientTexture0", GL_RG16F, AmbientWidth, AmbientHeight); + AmbientTexture1 = Create2DTexture("AmbientTexture1", GL_RG16F, AmbientWidth, AmbientHeight); + LinearDepthFB = CreateFrameBuffer("LinearDepthFB", LinearDepthTexture); AmbientFB0 = CreateFrameBuffer("AmbientFB0", AmbientTexture0); AmbientFB1 = CreateFrameBuffer("AmbientFB1", AmbientTexture1); @@ -485,13 +489,15 @@ GLuint FGLRenderBuffers::Create2DTexture(const FString &name, GLuint format, int case GL_RGBA16: dataformat = GL_RGBA; datatype = GL_UNSIGNED_SHORT; break; case GL_RGBA16F: dataformat = GL_RGBA; datatype = GL_FLOAT; break; case GL_RGBA32F: dataformat = GL_RGBA; datatype = GL_FLOAT; break; + case GL_RGBA16_SNORM: dataformat = GL_RGBA; datatype = GL_SHORT; break; case GL_R32F: dataformat = GL_RED; datatype = GL_FLOAT; break; + case GL_R16F: dataformat = GL_RED; datatype = GL_FLOAT; break; case GL_RG32F: dataformat = GL_RG; datatype = GL_FLOAT; break; + case GL_RG16F: dataformat = GL_RG; datatype = GL_FLOAT; break; case GL_RGB10_A2: dataformat = GL_RGBA; datatype = GL_UNSIGNED_INT_10_10_10_2; break; case GL_DEPTH_COMPONENT24: dataformat = GL_DEPTH_COMPONENT; datatype = GL_FLOAT; break; case GL_STENCIL_INDEX8: dataformat = GL_STENCIL_INDEX; datatype = GL_INT; break; case GL_DEPTH24_STENCIL8: dataformat = GL_DEPTH_STENCIL; datatype = GL_UNSIGNED_INT_24_8; break; - case GL_RGBA16_SNORM: dataformat = GL_RGBA; datatype = GL_SHORT; break; default: I_FatalError("Unknown format passed to FGLRenderBuffers.Create2DTexture"); } @@ -530,7 +536,7 @@ GLuint FGLRenderBuffers::CreateRenderBuffer(const FString &name, GLuint format, return handle; } -GLuint FGLRenderBuffers::CreateRenderBuffer(const FString &name, GLuint format, int samples, int width, int height) +GLuint FGLRenderBuffers::CreateRenderBuffer(const FString &name, GLuint format, int width, int height, int samples) { if (samples <= 1) return CreateRenderBuffer(name, format, width, height); diff --git a/src/gl/renderer/gl_renderbuffers.h b/src/gl/renderer/gl_renderbuffers.h index d593b0248..efa61f3e2 100644 --- a/src/gl/renderer/gl_renderbuffers.h +++ b/src/gl/renderer/gl_renderbuffers.h @@ -59,6 +59,8 @@ public: bool FirstExposureFrame = true; // Ambient occlusion buffers + GLuint LinearDepthTexture = 0; + GLuint LinearDepthFB = 0; GLuint AmbientTexture0 = 0; GLuint AmbientTexture1 = 0; GLuint AmbientFB0 = 0; @@ -92,7 +94,7 @@ private: GLuint Create2DTexture(const FString &name, GLuint format, int width, int height, const void *data = nullptr); GLuint Create2DMultisampleTexture(const FString &name, GLuint format, int width, int height, int samples, bool fixedSampleLocations); GLuint CreateRenderBuffer(const FString &name, GLuint format, int width, int height); - GLuint CreateRenderBuffer(const FString &name, GLuint format, int samples, int width, int height); + GLuint CreateRenderBuffer(const FString &name, GLuint format, int width, int height, int samples); GLuint CreateFrameBuffer(const FString &name, GLuint colorbuffer); GLuint CreateFrameBuffer(const FString &name, GLuint colorbuffer, GLuint depthstencil, bool colorIsARenderBuffer); GLuint CreateFrameBuffer(const FString &name, GLuint colorbuffer0, GLuint colorbuffer1, GLuint colorbuffer2, GLuint depthstencil, bool multisample); diff --git a/src/gl/shaders/gl_ambientshader.cpp b/src/gl/shaders/gl_ambientshader.cpp index 0d08e1258..effde2496 100644 --- a/src/gl/shaders/gl_ambientshader.cpp +++ b/src/gl/shaders/gl_ambientshader.cpp @@ -47,7 +47,7 @@ void FLinearDepthShader::Bind() mShader->SetAttribLocation(0, "PositionInProjection"); DepthTexture.Init(*mShader, "DepthTexture"); ColorTexture.Init(*mShader, "ColorTexture"); - SampleCount.Init(*mShader, "SampleCount"); + SampleIndex.Init(*mShader, "SampleIndex"); LinearizeDepthA.Init(*mShader, "LinearizeDepthA"); LinearizeDepthB.Init(*mShader, "LinearizeDepthB"); InverseDepthRangeA.Init(*mShader, "InverseDepthRangeA"); @@ -86,6 +86,7 @@ void FSSAOShader::Bind() AOStrength.Init(*mShader, "AOStrength"); Scale.Init(*mShader, "Scale"); Offset.Init(*mShader, "Offset"); + SampleIndex.Init(*mShader, "SampleIndex"); mMultisample = multisample; } mShader->Bind(); diff --git a/src/gl/shaders/gl_ambientshader.h b/src/gl/shaders/gl_ambientshader.h index 95dfd6bac..d3310c3d6 100644 --- a/src/gl/shaders/gl_ambientshader.h +++ b/src/gl/shaders/gl_ambientshader.h @@ -10,7 +10,7 @@ public: FBufferedUniformSampler DepthTexture; FBufferedUniformSampler ColorTexture; - FBufferedUniform1i SampleCount; + FBufferedUniform1i SampleIndex; FBufferedUniform1f LinearizeDepthA; FBufferedUniform1f LinearizeDepthB; FBufferedUniform1f InverseDepthRangeA; @@ -41,6 +41,7 @@ public: FBufferedUniform1f AOStrength; FBufferedUniform2f Scale; FBufferedUniform2f Offset; + FBufferedUniform1i SampleIndex; private: enum Quality diff --git a/wadsrc/static/shaders/glsl/lineardepth.fp b/wadsrc/static/shaders/glsl/lineardepth.fp index fa71c9de0..3e2b3eb95 100644 --- a/wadsrc/static/shaders/glsl/lineardepth.fp +++ b/wadsrc/static/shaders/glsl/lineardepth.fp @@ -5,7 +5,7 @@ out vec4 FragColor; #if defined(MULTISAMPLE) uniform sampler2DMS DepthTexture; uniform sampler2DMS ColorTexture; -uniform int SampleCount; +uniform int SampleIndex; #else uniform sampler2D DepthTexture; uniform sampler2D ColorTexture; @@ -37,21 +37,10 @@ void main() ivec2 ipos = ivec2(max(uv * vec2(texSize), vec2(0.0))); #if defined(MULTISAMPLE) - float depth = normalizeDepth(texelFetch(ColorTexture, ipos, 0).a != 0.0 ? texelFetch(DepthTexture, ipos, 0).x : 1.0); - float sampleIndex = 0.0; - for (int i = 1; i < SampleCount; i++) - { - float hardwareDepth = texelFetch(ColorTexture, ipos, i).a != 0.0 ? texelFetch(DepthTexture, ipos, i).x : 1.0; - float sampleDepth = normalizeDepth(hardwareDepth); - if (sampleDepth < depth) - { - depth = sampleDepth; - sampleIndex = float(i); - } - } - FragColor = vec4(depth, sampleIndex, 0.0, 1.0); + float depth = normalizeDepth(texelFetch(ColorTexture, ipos, SampleIndex).a != 0.0 ? texelFetch(DepthTexture, ipos, SampleIndex).x : 1.0); #else float depth = normalizeDepth(texelFetch(ColorTexture, ipos, 0).a != 0.0 ? texelFetch(DepthTexture, ipos, 0).x : 1.0); - FragColor = vec4(depth, 0.0, 0.0, 1.0); #endif + + FragColor = vec4(depth, 0.0, 0.0, 1.0); } diff --git a/wadsrc/static/shaders/glsl/ssao.fp b/wadsrc/static/shaders/glsl/ssao.fp index f895ddc25..3b2db6005 100644 --- a/wadsrc/static/shaders/glsl/ssao.fp +++ b/wadsrc/static/shaders/glsl/ssao.fp @@ -20,6 +20,7 @@ uniform sampler2D DepthTexture; #if defined(MULTISAMPLE) uniform sampler2DMS NormalTexture; +uniform int SampleIndex; #else uniform sampler2D NormalTexture; #endif @@ -30,21 +31,22 @@ uniform sampler2D RandomTexture; #define PI 3.14159265358979323846 -// Calculate eye space position for the specified texture coordinate and depth -vec3 FetchViewPos(vec2 uv, float z) +// Calculate eye space position for the specified texture coordinate +vec3 FetchViewPos(vec2 uv) { + float z = texture(DepthTexture, uv).x; return vec3((UVToViewA * uv + UVToViewB) * z, z); } #if defined(MULTISAMPLE) -vec3 SampleNormal(vec2 uv, float samplerIndex) +vec3 SampleNormal(vec2 uv) { ivec2 texSize = textureSize(NormalTexture); ivec2 ipos = ivec2(uv * vec2(texSize)); - return texelFetch(NormalTexture, ipos, int(samplerIndex)).xyz * 2.0 - 1.0; + return texelFetch(NormalTexture, ipos, SampleIndex).xyz * 2.0 - 1.0; } #else -vec3 SampleNormal(vec2 uv, float samplerIndex) +vec3 SampleNormal(vec2 uv) { ivec2 texSize = textureSize(NormalTexture, 0); ivec2 ipos = ivec2(uv * vec2(texSize)); @@ -53,9 +55,9 @@ vec3 SampleNormal(vec2 uv, float samplerIndex) #endif // Look up the eye space normal for the specified texture coordinate -vec3 FetchNormal(vec2 uv, float samplerIndex) +vec3 FetchNormal(vec2 uv) { - vec3 normal = SampleNormal(Offset + uv * Scale, samplerIndex); + vec3 normal = SampleNormal(Offset + uv * Scale); if (length(normal) > 0.1) { normal = normalize(normal); @@ -116,7 +118,7 @@ float ComputeAO(vec3 viewPosition, vec3 viewNormal) for (float StepIndex = 0.0; StepIndex < NUM_STEPS; ++StepIndex) { vec2 sampleUV = round(rayPixels * direction) * InvFullResolution + TexCoord; - vec3 samplePos = FetchViewPos(sampleUV, texture(DepthTexture, sampleUV).x); + vec3 samplePos = FetchViewPos(sampleUV); ao += ComputeSampleAO(viewPosition, viewNormal, samplePos); rayPixels += stepSizePixels; } @@ -128,9 +130,8 @@ float ComputeAO(vec3 viewPosition, vec3 viewNormal) void main() { - vec2 depthData = texture(DepthTexture, TexCoord).xy; - vec3 viewPosition = FetchViewPos(TexCoord, depthData.x); - vec3 viewNormal = FetchNormal(TexCoord, depthData.y); + vec3 viewPosition = FetchViewPos(TexCoord); + vec3 viewNormal = FetchNormal(TexCoord); float occlusion = viewNormal != vec3(0.0) ? ComputeAO(viewPosition, viewNormal) * AOStrength + (1.0 - AOStrength) : 1.0; FragColor = vec4(occlusion, viewPosition.z, 0.0, 1.0); diff --git a/wadsrc/static/shaders/glsl/ssaocombine.fp b/wadsrc/static/shaders/glsl/ssaocombine.fp index 377516587..4ca64421b 100644 --- a/wadsrc/static/shaders/glsl/ssaocombine.fp +++ b/wadsrc/static/shaders/glsl/ssaocombine.fp @@ -17,12 +17,13 @@ uniform vec2 Offset; void main() { vec2 uv = Offset + TexCoord * Scale; + #if defined(MULTISAMPLE) ivec2 texSize = textureSize(SceneFogTexture); #else ivec2 texSize = textureSize(SceneFogTexture, 0); #endif - ivec2 ipos = ivec2(max(floor(uv * vec2(texSize) - 0.75), vec2(0.0))); + ivec2 ipos = ivec2(uv * vec2(texSize)); #if defined(MULTISAMPLE) vec3 fogColor = vec3(0.0);