From 960d4d6755db3089a8d270c009a7549a9761e76b Mon Sep 17 00:00:00 2001 From: Christopher Bruns Date: Thu, 22 Sep 2016 20:44:56 -0400 Subject: [PATCH 1/9] Create TopBottom3D mode and begin sketching RowInterleaved3D mode. --- src/CMakeLists.txt | 1 + src/gl/stereo3d/gl_interleaved3d.cpp | 71 ++++++++++++++++++++++++++++ src/gl/stereo3d/gl_interleaved3d.h | 58 +++++++++++++++++++++++ src/gl/stereo3d/gl_sidebyside3d.cpp | 38 +++++++++++++++ src/gl/stereo3d/gl_sidebyside3d.h | 8 ++++ src/gl/stereo3d/gl_stereo_cvars.cpp | 7 +++ wadsrc/static/language.enu | 2 + wadsrc/static/menudef.zz | 2 + 8 files changed, 187 insertions(+) create mode 100644 src/gl/stereo3d/gl_interleaved3d.cpp create mode 100644 src/gl/stereo3d/gl_interleaved3d.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 73dba07c4e..e768e945ff 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1116,6 +1116,7 @@ set( FASTMATH_SOURCES gl/stereo3d/gl_anaglyph.cpp gl/stereo3d/gl_quadstereo.cpp gl/stereo3d/gl_sidebyside3d.cpp + gl/stereo3d/gl_interleaved3d.cpp gl/dynlights/gl_dynlight.cpp gl/dynlights/gl_glow.cpp gl/dynlights/gl_dynlight1.cpp diff --git a/src/gl/stereo3d/gl_interleaved3d.cpp b/src/gl/stereo3d/gl_interleaved3d.cpp new file mode 100644 index 0000000000..c811e0d216 --- /dev/null +++ b/src/gl/stereo3d/gl_interleaved3d.cpp @@ -0,0 +1,71 @@ +/* +** gl_interleaved3d.cpp +** Interleaved image stereoscopic 3D modes for GZDoom +** +**--------------------------------------------------------------------------- +** Copyright 2016 Christopher Bruns +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +**--------------------------------------------------------------------------- +** +** +*/ + +#include "gl_interleaved3d.h" +#include "gl/renderer/gl_renderer.h" +#include "gl/renderer/gl_renderbuffers.h" + +namespace s3d { + +/* static */ +const RowInterleaved3D& RowInterleaved3D::getInstance(float ipd) +{ + static RowInterleaved3D instance(ipd); + return instance; +} + +void RowInterleaved3D::Present() const +{ + GLRenderer->mBuffers->BindOutputFB(); + GLRenderer->ClearBorders(); + + // Compute screen regions to use for left and right eye views + int topHeight = GLRenderer->mOutputLetterbox.height / 2; + int bottomHeight = GLRenderer->mOutputLetterbox.height - topHeight; + GL_IRECT topHalfScreen = GLRenderer->mOutputLetterbox; + topHalfScreen.height = topHeight; + GL_IRECT bottomHalfScreen = GLRenderer->mOutputLetterbox; + bottomHalfScreen.height = bottomHeight; + bottomHalfScreen.top += topHeight; + + GLRenderer->mBuffers->BindEyeTexture(0, 0); + GLRenderer->DrawPresentTexture(topHalfScreen, true); + + GLRenderer->mBuffers->BindEyeTexture(1, 0); + GLRenderer->DrawPresentTexture(bottomHalfScreen, true); +} + + +} /* namespace s3d */ diff --git a/src/gl/stereo3d/gl_interleaved3d.h b/src/gl/stereo3d/gl_interleaved3d.h new file mode 100644 index 0000000000..1f22fa356f --- /dev/null +++ b/src/gl/stereo3d/gl_interleaved3d.h @@ -0,0 +1,58 @@ +/* +** gl_interleaved3d.h +** Interleaved stereoscopic 3D modes for GZDoom +** +**--------------------------------------------------------------------------- +** Copyright 2016 Christopher Bruns +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +**--------------------------------------------------------------------------- +** +** +*/ + +#ifndef GL_INTERLEAVED3D_H_ +#define GL_INTERLEAVED3D_H_ + +#include "gl_stereo3d.h" +#include "gl_stereo_leftright.h" +#include "gl_sidebyside3d.h" +#include "gl/system/gl_system.h" +#include "gl/renderer/gl_renderstate.h" + +namespace s3d { + +class RowInterleaved3D : public TopBottom3D +{ +public: + static const RowInterleaved3D& getInstance(float ipd); + RowInterleaved3D(double ipdMeters) : TopBottom3D(ipdMeters) {} + void Present() const override; +}; + +} /* namespace s3d */ + + +#endif /* GL_INTERLEAVED3D_H_ */ diff --git a/src/gl/stereo3d/gl_sidebyside3d.cpp b/src/gl/stereo3d/gl_sidebyside3d.cpp index c6463d2c8b..d2b0cafddc 100644 --- a/src/gl/stereo3d/gl_sidebyside3d.cpp +++ b/src/gl/stereo3d/gl_sidebyside3d.cpp @@ -108,4 +108,42 @@ void SideBySideFull::AdjustPlayerSprites() const /* override */ gl_RenderState.ApplyMatrices(); } +/* static */ +const TopBottom3D& TopBottom3D::getInstance(float ipd) +{ + static TopBottom3D instance(ipd); + return instance; +} + +void TopBottom3D::Present() const +{ + GLRenderer->mBuffers->BindOutputFB(); + GLRenderer->ClearBorders(); + + // Compute screen regions to use for left and right eye views + int topHeight = GLRenderer->mOutputLetterbox.height / 2; + int bottomHeight = GLRenderer->mOutputLetterbox.height - topHeight; + GL_IRECT topHalfScreen = GLRenderer->mOutputLetterbox; + topHalfScreen.height = topHeight; + GL_IRECT bottomHalfScreen = GLRenderer->mOutputLetterbox; + bottomHalfScreen.height = bottomHeight; + bottomHalfScreen.top += topHeight; + + GLRenderer->mBuffers->BindEyeTexture(0, 0); + GLRenderer->DrawPresentTexture(topHalfScreen, true); + + GLRenderer->mBuffers->BindEyeTexture(1, 0); + GLRenderer->DrawPresentTexture(bottomHalfScreen, true); +} + +// AdjustViewports() is called from within FLGRenderer::SetOutputViewport(...) +void TopBottom3D::AdjustViewports() const +{ + // Change size of renderbuffer, and align to screen + GLRenderer->mSceneViewport.height /= 2; + GLRenderer->mSceneViewport.top /= 2; + GLRenderer->mScreenViewport.height /= 2; + GLRenderer->mScreenViewport.top /= 2; +} + } /* namespace s3d */ diff --git a/src/gl/stereo3d/gl_sidebyside3d.h b/src/gl/stereo3d/gl_sidebyside3d.h index 374f255c59..c98f748a0b 100644 --- a/src/gl/stereo3d/gl_sidebyside3d.h +++ b/src/gl/stereo3d/gl_sidebyside3d.h @@ -88,6 +88,14 @@ private: SBSFRightEyePose rightEye; }; +class TopBottom3D : public SideBySideSquished +{ +public: + static const TopBottom3D& getInstance(float ipd); + TopBottom3D(double ipdMeters) : SideBySideSquished(ipdMeters) {} + void Present() const override; + virtual void AdjustViewports() const override; +}; } /* namespace s3d */ diff --git a/src/gl/stereo3d/gl_stereo_cvars.cpp b/src/gl/stereo3d/gl_stereo_cvars.cpp index c09a7a9749..16296393d6 100644 --- a/src/gl/stereo3d/gl_stereo_cvars.cpp +++ b/src/gl/stereo3d/gl_stereo_cvars.cpp @@ -30,6 +30,7 @@ #include "gl/stereo3d/gl_anaglyph.h" #include "gl/stereo3d/gl_quadstereo.h" #include "gl/stereo3d/gl_sidebyside3d.h" +#include "gl/stereo3d/gl_interleaved3d.h" #include "gl/system/gl_cvars.h" // Set up 3D-specific console variables: @@ -100,6 +101,12 @@ const Stereo3DMode& Stereo3DMode::getCurrentMode() setCurrentMode(AmberBlue::getInstance(vr_ipd)); break; // TODO: 10: HTC Vive/OpenVR + case 11: + setCurrentMode(TopBottom3D::getInstance(vr_ipd)); + break; + case 12: + setCurrentMode(RowInterleaved3D::getInstance(vr_ipd)); + break; case 0: default: setCurrentMode(MonoView::getInstance()); diff --git a/wadsrc/static/language.enu b/wadsrc/static/language.enu index 50526a75b5..813d6b8f61 100644 --- a/wadsrc/static/language.enu +++ b/wadsrc/static/language.enu @@ -2703,6 +2703,8 @@ OPTVAL_LEFTEYE = "Left Eye"; OPTVAL_RIGHTEYE = "Right Eye"; OPTVAL_SBSFULL = "Side-by-side Full"; OPTVAL_SBSNARROW = "Side-by-side Narrow"; +OPTVAL_TOPBOTTOM = "Top/Bottom"; +OPTVAL_ROWINTERLEAVED = "Row Interleaved"; OPTVAL_QUADBUFFERED = "Quad-buffered"; OPTVAL_UNCHARTED2 = "Uncharted 2"; OPTVAL_HEJLDAWSON = "Hejl Dawson"; diff --git a/wadsrc/static/menudef.zz b/wadsrc/static/menudef.zz index 1ab4f1a6d5..6f96ea286c 100644 --- a/wadsrc/static/menudef.zz +++ b/wadsrc/static/menudef.zz @@ -169,6 +169,8 @@ OptionValue VRMode 9, "$OPTVAL_AMBERBLUE" 3, "$OPTVAL_SBSFULL" 4, "$OPTVAL_SBSNARROW" + 11, "$OPTVAL_TOPBOTTOM" + 12, "$OPTVAL_ROWINTERLEAVED" 5, "$OPTVAL_LEFTEYE" 6, "$OPTVAL_RIGHTEYE" 7, "$OPTVAL_QUADBUFFERED" From 79046580d586df604aa30be88c0d3efc1ccc7e2d Mon Sep 17 00:00:00 2001 From: Christopher Bruns Date: Tue, 27 Sep 2016 19:49:24 -0400 Subject: [PATCH 2/9] Partial implementation of row interlaced mode. --- src/gl/renderer/gl_renderbuffers.cpp | 20 ++++++++++++++++++++ src/gl/renderer/gl_renderbuffers.h | 2 ++ src/gl/stereo3d/gl_interleaved3d.cpp | 13 +++++-------- 3 files changed, 27 insertions(+), 8 deletions(-) diff --git a/src/gl/renderer/gl_renderbuffers.cpp b/src/gl/renderer/gl_renderbuffers.cpp index b2471e4b91..31fc36832f 100644 --- a/src/gl/renderer/gl_renderbuffers.cpp +++ b/src/gl/renderer/gl_renderbuffers.cpp @@ -576,6 +576,26 @@ void FGLRenderBuffers::BlitToEyeTexture(int eye) glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); } +void FGLRenderBuffers::BlitFromEyeTexture(int eye, GL_IRECT* box) +{ + glBindFramebuffer(GL_READ_FRAMEBUFFER, mEyeFBs[eye]); + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, mOutputFB); + if (box == nullptr) + box = &GLRenderer->mOutputLetterbox; + glBlitFramebuffer(0, 0, mWidth, mHeight, + box->left, box->top, box->width + box->left, box->height + box->top, + GL_COLOR_BUFFER_BIT, GL_NEAREST); + + if ((gl.flags & RFL_INVALIDATE_BUFFER) != 0) + { + GLenum attachments[2] = { GL_COLOR_ATTACHMENT0, GL_DEPTH_STENCIL_ATTACHMENT }; + glInvalidateFramebuffer(GL_READ_FRAMEBUFFER, 2, attachments); + } + + glBindFramebuffer(GL_READ_FRAMEBUFFER, 0); + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); +} + void FGLRenderBuffers::BindEyeTexture(int eye, int texunit) { CreateEyeBuffers(eye); diff --git a/src/gl/renderer/gl_renderbuffers.h b/src/gl/renderer/gl_renderbuffers.h index 4477718f4b..043cb88526 100644 --- a/src/gl/renderer/gl_renderbuffers.h +++ b/src/gl/renderer/gl_renderbuffers.h @@ -2,6 +2,7 @@ #define __GL_RENDERBUFFERS_H #include "gl/shaders/gl_shader.h" +#include "gl/renderer/gl_renderer.h" class FGLBloomTextureLevel { @@ -42,6 +43,7 @@ public: void BindOutputFB(); void BlitToEyeTexture(int eye); + void BlitFromEyeTexture(int eye, GL_IRECT* box); void BindEyeTexture(int eye, int texunit); void BindEyeFB(int eye, bool readBuffer = false); diff --git a/src/gl/stereo3d/gl_interleaved3d.cpp b/src/gl/stereo3d/gl_interleaved3d.cpp index c811e0d216..085efae51c 100644 --- a/src/gl/stereo3d/gl_interleaved3d.cpp +++ b/src/gl/stereo3d/gl_interleaved3d.cpp @@ -53,18 +53,15 @@ void RowInterleaved3D::Present() const // Compute screen regions to use for left and right eye views int topHeight = GLRenderer->mOutputLetterbox.height / 2; - int bottomHeight = GLRenderer->mOutputLetterbox.height - topHeight; GL_IRECT topHalfScreen = GLRenderer->mOutputLetterbox; topHalfScreen.height = topHeight; + topHalfScreen.top = topHeight; GL_IRECT bottomHalfScreen = GLRenderer->mOutputLetterbox; - bottomHalfScreen.height = bottomHeight; - bottomHalfScreen.top += topHeight; + bottomHalfScreen.height = topHeight; + bottomHalfScreen.top = 0; - GLRenderer->mBuffers->BindEyeTexture(0, 0); - GLRenderer->DrawPresentTexture(topHalfScreen, true); - - GLRenderer->mBuffers->BindEyeTexture(1, 0); - GLRenderer->DrawPresentTexture(bottomHalfScreen, true); + GLRenderer->mBuffers->BlitFromEyeTexture(0, &topHalfScreen); + GLRenderer->mBuffers->BlitFromEyeTexture(1, &bottomHalfScreen); } From 460b6537096062c904eed7c016871757e11957e5 Mon Sep 17 00:00:00 2001 From: Christopher Bruns Date: Sun, 2 Oct 2016 12:24:37 -0400 Subject: [PATCH 3/9] Row interlaced 3d might be working, at least in fullscreen 1920x1080 mode. --- src/CMakeLists.txt | 1 + src/gl/renderer/gl_renderer.cpp | 4 ++ src/gl/renderer/gl_renderer.h | 2 + src/gl/shaders/gl_present3dRowshader.cpp | 60 +++++++++++++++++++++ src/gl/shaders/gl_present3dRowshader.h | 51 ++++++++++++++++++ src/gl/stereo3d/gl_interleaved3d.cpp | 49 ++++++++++++++++- src/gl/stereo3d/gl_interleaved3d.h | 4 +- src/gl/stereo3d/gl_sidebyside3d.cpp | 3 +- wadsrc/static/shaders/glsl/present_row3d.fp | 36 +++++++++++++ 9 files changed, 206 insertions(+), 4 deletions(-) create mode 100644 src/gl/shaders/gl_present3dRowshader.cpp create mode 100644 src/gl/shaders/gl_present3dRowshader.h create mode 100644 wadsrc/static/shaders/glsl/present_row3d.fp diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index e768e945ff..7307e6eec4 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1125,6 +1125,7 @@ set( FASTMATH_SOURCES gl/shaders/gl_texshader.cpp gl/shaders/gl_shaderprogram.cpp gl/shaders/gl_presentshader.cpp + gl/shaders/gl_present3dRowshader.cpp gl/shaders/gl_bloomshader.cpp gl/shaders/gl_blurshader.cpp gl/shaders/gl_colormapshader.cpp diff --git a/src/gl/renderer/gl_renderer.cpp b/src/gl/renderer/gl_renderer.cpp index 42b4a8e1b8..fbfa514409 100644 --- a/src/gl/renderer/gl_renderer.cpp +++ b/src/gl/renderer/gl_renderer.cpp @@ -57,6 +57,7 @@ #include "gl/shaders/gl_colormapshader.h" #include "gl/shaders/gl_lensshader.h" #include "gl/shaders/gl_presentshader.h" +#include "gl/shaders/gl_present3dRowshader.h" #include "gl/stereo3d/gl_stereo3d.h" #include "gl/textures/gl_texture.h" #include "gl/textures/gl_translate.h" @@ -103,6 +104,7 @@ FGLRenderer::FGLRenderer(OpenGLFrameBuffer *fb) mTonemapPalette = nullptr; mBuffers = nullptr; mPresentShader = nullptr; + mPresent3dRowShader = nullptr; mBloomExtractShader = nullptr; mBloomCombineShader = nullptr; mExposureExtractShader = nullptr; @@ -132,6 +134,7 @@ void FGLRenderer::Initialize(int width, int height) mTonemapPalette = nullptr; mLensShader = new FLensShader(); mPresentShader = new FPresentShader(); + mPresent3dRowShader = new FPresent3DRowShader(); m2DDrawer = new F2DDrawer; // needed for the core profile, because someone decided it was a good idea to remove the default VAO. @@ -184,6 +187,7 @@ FGLRenderer::~FGLRenderer() } if (mBuffers) delete mBuffers; if (mPresentShader) delete mPresentShader; + if (mPresent3dRowShader) delete mPresent3dRowShader; if (mBloomExtractShader) delete mBloomExtractShader; if (mBloomCombineShader) delete mBloomCombineShader; if (mExposureExtractShader) delete mExposureExtractShader; diff --git a/src/gl/renderer/gl_renderer.h b/src/gl/renderer/gl_renderer.h index 71c52474a1..460b5685a2 100644 --- a/src/gl/renderer/gl_renderer.h +++ b/src/gl/renderer/gl_renderer.h @@ -29,6 +29,7 @@ class FTonemapShader; class FColormapShader; class FLensShader; class FPresentShader; +class FPresent3DRowShader; class F2DDrawer; class FHardwareTexture; @@ -104,6 +105,7 @@ public: FHardwareTexture *mTonemapPalette; FLensShader *mLensShader; FPresentShader *mPresentShader; + FPresent3DRowShader *mPresent3dRowShader; FTexture *gllight; FTexture *glpart2; diff --git a/src/gl/shaders/gl_present3dRowshader.cpp b/src/gl/shaders/gl_present3dRowshader.cpp new file mode 100644 index 0000000000..607e4ede60 --- /dev/null +++ b/src/gl/shaders/gl_present3dRowshader.cpp @@ -0,0 +1,60 @@ +// +//--------------------------------------------------------------------------- +// +// Copyright(C) 2016 Christopher Bruns +// All rights reserved. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this program. If not, see http://www.gnu.org/licenses/ +// +//-------------------------------------------------------------------------- +// +/* +** gl_3dRowshader.cpp +** Copy rendered texture to back buffer, possibly with gamma correction +** while interleaving rows from two independent viewpoint textures, +** representing the left-eye and right-eye views. +** +*/ + +#include "gl/system/gl_system.h" +#include "files.h" +#include "m_swap.h" +#include "v_video.h" +#include "gl/gl_functions.h" +#include "vectors.h" +#include "gl/system/gl_interface.h" +#include "gl/system/gl_framebuffer.h" +#include "gl/system/gl_cvars.h" +#include "gl/shaders/gl_present3dRowshader.h" + +void FPresent3DRowShader::Bind() +{ + if (!mShader) + { + mShader.Compile(FShaderProgram::Vertex, "shaders/glsl/screenquadscale.vp", "", 330); + mShader.Compile(FShaderProgram::Fragment, "shaders/glsl/present_row3d.fp", "", 330); + mShader.SetFragDataLocation(0, "FragColor"); + mShader.Link("shaders/glsl/presentRow3d"); + mShader.SetAttribLocation(0, "PositionInProjection"); + mShader.SetAttribLocation(1, "UV"); + LeftEyeTexture.Init(mShader, "LeftEyeTexture"); + RightEyeTexture.Init(mShader, "RightEyeTexture"); + InvGamma.Init(mShader, "InvGamma"); + Contrast.Init(mShader, "Contrast"); + Brightness.Init(mShader, "Brightness"); + Scale.Init(mShader, "UVScale"); + VerticalPixelOffset.Init(mShader, "VerticalPixelOffset"); + } + mShader.Bind(); +} diff --git a/src/gl/shaders/gl_present3dRowshader.h b/src/gl/shaders/gl_present3dRowshader.h new file mode 100644 index 0000000000..8e3bd772dc --- /dev/null +++ b/src/gl/shaders/gl_present3dRowshader.h @@ -0,0 +1,51 @@ +// +//--------------------------------------------------------------------------- +// +// Copyright(C) 2015 Christopher Bruns +// All rights reserved. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this program. If not, see http://www.gnu.org/licenses/ +// +//-------------------------------------------------------------------------- +// +/* +** gl_present3dRowshader.h +** Final composition and present shader for row-interleaved stereoscopic 3D mode +** +*/ + +#ifndef GL_PRESENT3DROWSHADER_H_ +#define GL_PRESENT3DROWSHADER_H_ + +#include "gl_shaderprogram.h" + +class FPresent3DRowShader +{ +public: + void Bind(); + + FBufferedUniformSampler LeftEyeTexture; + FBufferedUniformSampler RightEyeTexture; + FBufferedUniform1f InvGamma; + FBufferedUniform1f Contrast; + FBufferedUniform1f Brightness; + FBufferedUniform2f Scale; + FBufferedUniform1i VerticalPixelOffset; + +private: + FShaderProgram mShader; +}; + +// GL_PRESENT3DROWSHADER_H_ +#endif \ No newline at end of file diff --git a/src/gl/stereo3d/gl_interleaved3d.cpp b/src/gl/stereo3d/gl_interleaved3d.cpp index 085efae51c..28b9c373e0 100644 --- a/src/gl/stereo3d/gl_interleaved3d.cpp +++ b/src/gl/stereo3d/gl_interleaved3d.cpp @@ -36,6 +36,12 @@ #include "gl_interleaved3d.h" #include "gl/renderer/gl_renderer.h" #include "gl/renderer/gl_renderbuffers.h" +#include "gl/renderer/gl_renderer.h" +#include "gl/system/gl_framebuffer.h" +#include "gl/shaders/gl_present3dRowshader.h" + +EXTERN_CVAR(Float, vid_brightness) +EXTERN_CVAR(Float, vid_contrast) namespace s3d { @@ -46,6 +52,10 @@ const RowInterleaved3D& RowInterleaved3D::getInstance(float ipd) return instance; } +RowInterleaved3D::RowInterleaved3D(double ipdMeters) + : TopBottom3D(ipdMeters) +{} + void RowInterleaved3D::Present() const { GLRenderer->mBuffers->BindOutputFB(); @@ -60,8 +70,43 @@ void RowInterleaved3D::Present() const bottomHalfScreen.height = topHeight; bottomHalfScreen.top = 0; - GLRenderer->mBuffers->BlitFromEyeTexture(0, &topHalfScreen); - GLRenderer->mBuffers->BlitFromEyeTexture(1, &bottomHalfScreen); + // Bind each eye texture, for composition in the shader + GLRenderer->mBuffers->BindEyeTexture(0, 0); + GLRenderer->mBuffers->BindEyeTexture(1, 1); + + glActiveTexture(GL_TEXTURE0); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + + glActiveTexture(GL_TEXTURE1); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + + const GL_IRECT& box = GLRenderer->mOutputLetterbox; + glViewport(box.left, box.top, box.width, box.height); + + bool applyGamma = true; + + GLRenderer->mPresent3dRowShader->Bind(); + GLRenderer->mPresent3dRowShader->LeftEyeTexture.Set(0); + GLRenderer->mPresent3dRowShader->RightEyeTexture.Set(1); + if (!applyGamma || GLRenderer->framebuffer->IsHWGammaActive()) + { + GLRenderer->mPresent3dRowShader->InvGamma.Set(1.0f); + GLRenderer->mPresent3dRowShader->Contrast.Set(1.0f); + GLRenderer->mPresent3dRowShader->Brightness.Set(0.0f); + } + else + { + GLRenderer->mPresent3dRowShader->InvGamma.Set(1.0f / clamp(Gamma, 0.1f, 4.f)); + GLRenderer->mPresent3dRowShader->Contrast.Set(clamp(vid_contrast, 0.1f, 3.f)); + GLRenderer->mPresent3dRowShader->Brightness.Set(clamp(vid_brightness, -0.8f, 0.8f)); + } + GLRenderer->mPresent3dRowShader->Scale.Set( + GLRenderer->mScreenViewport.width / (float)GLRenderer->mBuffers->GetWidth(), + GLRenderer->mScreenViewport.height / (float)GLRenderer->mBuffers->GetHeight()); + GLRenderer->mPresent3dRowShader->VerticalPixelOffset.Set(0); // fixme: vary with window location + GLRenderer->RenderScreenQuad(); } diff --git a/src/gl/stereo3d/gl_interleaved3d.h b/src/gl/stereo3d/gl_interleaved3d.h index 1f22fa356f..30aef7d5a6 100644 --- a/src/gl/stereo3d/gl_interleaved3d.h +++ b/src/gl/stereo3d/gl_interleaved3d.h @@ -42,13 +42,15 @@ #include "gl/system/gl_system.h" #include "gl/renderer/gl_renderstate.h" +class FPresent3DRowShader; + namespace s3d { class RowInterleaved3D : public TopBottom3D { public: static const RowInterleaved3D& getInstance(float ipd); - RowInterleaved3D(double ipdMeters) : TopBottom3D(ipdMeters) {} + RowInterleaved3D(double ipdMeters); void Present() const override; }; diff --git a/src/gl/stereo3d/gl_sidebyside3d.cpp b/src/gl/stereo3d/gl_sidebyside3d.cpp index d2b0cafddc..ecb3ec1ccf 100644 --- a/src/gl/stereo3d/gl_sidebyside3d.cpp +++ b/src/gl/stereo3d/gl_sidebyside3d.cpp @@ -125,9 +125,10 @@ void TopBottom3D::Present() const int bottomHeight = GLRenderer->mOutputLetterbox.height - topHeight; GL_IRECT topHalfScreen = GLRenderer->mOutputLetterbox; topHalfScreen.height = topHeight; + topHalfScreen.top = topHeight; GL_IRECT bottomHalfScreen = GLRenderer->mOutputLetterbox; bottomHalfScreen.height = bottomHeight; - bottomHalfScreen.top += topHeight; + bottomHalfScreen.top = 0; GLRenderer->mBuffers->BindEyeTexture(0, 0); GLRenderer->DrawPresentTexture(topHalfScreen, true); diff --git a/wadsrc/static/shaders/glsl/present_row3d.fp b/wadsrc/static/shaders/glsl/present_row3d.fp new file mode 100644 index 0000000000..18bd3cd113 --- /dev/null +++ b/wadsrc/static/shaders/glsl/present_row3d.fp @@ -0,0 +1,36 @@ + +in vec2 TexCoord; +out vec4 FragColor; + +uniform sampler2D LeftEyeTexture; +uniform sampler2D RightEyeTexture; +uniform float InvGamma; +uniform float Contrast; +uniform float Brightness; +uniform int VerticalPixelOffset; // top-of-window might not be top-of-screen + +vec4 ApplyGamma(vec4 c) +{ + vec3 val = c.rgb * Contrast - (Contrast - 1.0) * 0.5; + val += Brightness * 0.5; + val = pow(max(val, vec3(0.0)), vec3(InvGamma)); + return vec4(val, c.a); +} + +void main() +{ + // NOTE we assume here that the full screen height is the sum of the left + // and right eye view heights + int screenHeightInPixels = textureSize(LeftEyeTexture, 0).y + textureSize(RightEyeTexture, 0).y; + int thisVerticalPixel = int(TexCoord.y * screenHeightInPixels + 0.5); + bool isLeftEye = (thisVerticalPixel + VerticalPixelOffset) % 2 == 0; + vec4 inputColor; + if (isLeftEye) { + inputColor = texture(LeftEyeTexture, TexCoord); + } + else { + // inputColor = vec4(0, 1, 0, 1); + inputColor = texture(RightEyeTexture, TexCoord); + } + FragColor = ApplyGamma(inputColor); +} From fcbf9342d69a04619042df12c88e857e7d41ee4e Mon Sep 17 00:00:00 2001 From: Christopher Bruns Date: Sun, 2 Oct 2016 13:11:07 -0400 Subject: [PATCH 4/9] Compute row location using gl_FragCoord. --- src/gl/shaders/gl_present3dRowshader.cpp | 1 + src/gl/shaders/gl_present3dRowshader.h | 1 + src/gl/stereo3d/gl_interleaved3d.cpp | 13 +++++-------- wadsrc/static/shaders/glsl/present_row3d.fp | 6 ++---- 4 files changed, 9 insertions(+), 12 deletions(-) diff --git a/src/gl/shaders/gl_present3dRowshader.cpp b/src/gl/shaders/gl_present3dRowshader.cpp index 607e4ede60..931278aaa5 100644 --- a/src/gl/shaders/gl_present3dRowshader.cpp +++ b/src/gl/shaders/gl_present3dRowshader.cpp @@ -54,6 +54,7 @@ void FPresent3DRowShader::Bind() Contrast.Init(mShader, "Contrast"); Brightness.Init(mShader, "Brightness"); Scale.Init(mShader, "UVScale"); + WindowHeight.Init(mShader, "WindowHeight"); VerticalPixelOffset.Init(mShader, "VerticalPixelOffset"); } mShader.Bind(); diff --git a/src/gl/shaders/gl_present3dRowshader.h b/src/gl/shaders/gl_present3dRowshader.h index 8e3bd772dc..b7f0d87b2c 100644 --- a/src/gl/shaders/gl_present3dRowshader.h +++ b/src/gl/shaders/gl_present3dRowshader.h @@ -41,6 +41,7 @@ public: FBufferedUniform1f Contrast; FBufferedUniform1f Brightness; FBufferedUniform2f Scale; + FBufferedUniform1i WindowHeight; FBufferedUniform1i VerticalPixelOffset; private: diff --git a/src/gl/stereo3d/gl_interleaved3d.cpp b/src/gl/stereo3d/gl_interleaved3d.cpp index 28b9c373e0..5e0281ee65 100644 --- a/src/gl/stereo3d/gl_interleaved3d.cpp +++ b/src/gl/stereo3d/gl_interleaved3d.cpp @@ -61,14 +61,6 @@ void RowInterleaved3D::Present() const GLRenderer->mBuffers->BindOutputFB(); GLRenderer->ClearBorders(); - // Compute screen regions to use for left and right eye views - int topHeight = GLRenderer->mOutputLetterbox.height / 2; - GL_IRECT topHalfScreen = GLRenderer->mOutputLetterbox; - topHalfScreen.height = topHeight; - topHalfScreen.top = topHeight; - GL_IRECT bottomHalfScreen = GLRenderer->mOutputLetterbox; - bottomHalfScreen.height = topHeight; - bottomHalfScreen.top = 0; // Bind each eye texture, for composition in the shader GLRenderer->mBuffers->BindEyeTexture(0, 0); @@ -90,6 +82,7 @@ void RowInterleaved3D::Present() const GLRenderer->mPresent3dRowShader->Bind(); GLRenderer->mPresent3dRowShader->LeftEyeTexture.Set(0); GLRenderer->mPresent3dRowShader->RightEyeTexture.Set(1); + if (!applyGamma || GLRenderer->framebuffer->IsHWGammaActive()) { GLRenderer->mPresent3dRowShader->InvGamma.Set(1.0f); @@ -105,7 +98,11 @@ void RowInterleaved3D::Present() const GLRenderer->mPresent3dRowShader->Scale.Set( GLRenderer->mScreenViewport.width / (float)GLRenderer->mBuffers->GetWidth(), GLRenderer->mScreenViewport.height / (float)GLRenderer->mBuffers->GetHeight()); + + GLRenderer->mPresent3dRowShader->WindowHeight.Set(0); + GLRenderer->mPresent3dRowShader->VerticalPixelOffset.Set(0); // fixme: vary with window location + GLRenderer->RenderScreenQuad(); } diff --git a/wadsrc/static/shaders/glsl/present_row3d.fp b/wadsrc/static/shaders/glsl/present_row3d.fp index 18bd3cd113..73a01539ba 100644 --- a/wadsrc/static/shaders/glsl/present_row3d.fp +++ b/wadsrc/static/shaders/glsl/present_row3d.fp @@ -7,6 +7,7 @@ uniform sampler2D RightEyeTexture; uniform float InvGamma; uniform float Contrast; uniform float Brightness; +uniform int WindowHeight; uniform int VerticalPixelOffset; // top-of-window might not be top-of-screen vec4 ApplyGamma(vec4 c) @@ -19,10 +20,7 @@ vec4 ApplyGamma(vec4 c) void main() { - // NOTE we assume here that the full screen height is the sum of the left - // and right eye view heights - int screenHeightInPixels = textureSize(LeftEyeTexture, 0).y + textureSize(RightEyeTexture, 0).y; - int thisVerticalPixel = int(TexCoord.y * screenHeightInPixels + 0.5); + int thisVerticalPixel = int(gl_FragCoord.y); bool isLeftEye = (thisVerticalPixel + VerticalPixelOffset) % 2 == 0; vec4 inputColor; if (isLeftEye) { From 576619504e63e0385e2d7500da8859980327e058 Mon Sep 17 00:00:00 2001 From: Christopher Bruns Date: Sun, 2 Oct 2016 13:12:22 -0400 Subject: [PATCH 5/9] Remove unused WindowHeight uniform. --- src/gl/shaders/gl_present3dRowshader.cpp | 1 - src/gl/shaders/gl_present3dRowshader.h | 1 - src/gl/stereo3d/gl_interleaved3d.cpp | 2 -- 3 files changed, 4 deletions(-) diff --git a/src/gl/shaders/gl_present3dRowshader.cpp b/src/gl/shaders/gl_present3dRowshader.cpp index 931278aaa5..607e4ede60 100644 --- a/src/gl/shaders/gl_present3dRowshader.cpp +++ b/src/gl/shaders/gl_present3dRowshader.cpp @@ -54,7 +54,6 @@ void FPresent3DRowShader::Bind() Contrast.Init(mShader, "Contrast"); Brightness.Init(mShader, "Brightness"); Scale.Init(mShader, "UVScale"); - WindowHeight.Init(mShader, "WindowHeight"); VerticalPixelOffset.Init(mShader, "VerticalPixelOffset"); } mShader.Bind(); diff --git a/src/gl/shaders/gl_present3dRowshader.h b/src/gl/shaders/gl_present3dRowshader.h index b7f0d87b2c..8e3bd772dc 100644 --- a/src/gl/shaders/gl_present3dRowshader.h +++ b/src/gl/shaders/gl_present3dRowshader.h @@ -41,7 +41,6 @@ public: FBufferedUniform1f Contrast; FBufferedUniform1f Brightness; FBufferedUniform2f Scale; - FBufferedUniform1i WindowHeight; FBufferedUniform1i VerticalPixelOffset; private: diff --git a/src/gl/stereo3d/gl_interleaved3d.cpp b/src/gl/stereo3d/gl_interleaved3d.cpp index 5e0281ee65..fd7a6c4c6d 100644 --- a/src/gl/stereo3d/gl_interleaved3d.cpp +++ b/src/gl/stereo3d/gl_interleaved3d.cpp @@ -99,8 +99,6 @@ void RowInterleaved3D::Present() const GLRenderer->mScreenViewport.width / (float)GLRenderer->mBuffers->GetWidth(), GLRenderer->mScreenViewport.height / (float)GLRenderer->mBuffers->GetHeight()); - GLRenderer->mPresent3dRowShader->WindowHeight.Set(0); - GLRenderer->mPresent3dRowShader->VerticalPixelOffset.Set(0); // fixme: vary with window location GLRenderer->RenderScreenQuad(); From 0240cdef18ec31b62fc53ed946d49fc775b4cacb Mon Sep 17 00:00:00 2001 From: Christopher Bruns Date: Sun, 2 Oct 2016 13:49:57 -0400 Subject: [PATCH 6/9] Modulate row interleaved stereo 3d offset with window height parity, because gl_FragCoord.y approaches zero at the bottom, not the top of the window. --- src/gl/stereo3d/gl_interleaved3d.cpp | 5 ++++- wadsrc/static/shaders/glsl/present_row3d.fp | 7 ++++--- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/gl/stereo3d/gl_interleaved3d.cpp b/src/gl/stereo3d/gl_interleaved3d.cpp index fd7a6c4c6d..225f528193 100644 --- a/src/gl/stereo3d/gl_interleaved3d.cpp +++ b/src/gl/stereo3d/gl_interleaved3d.cpp @@ -99,7 +99,10 @@ void RowInterleaved3D::Present() const GLRenderer->mScreenViewport.width / (float)GLRenderer->mBuffers->GetWidth(), GLRenderer->mScreenViewport.height / (float)GLRenderer->mBuffers->GetHeight()); - GLRenderer->mPresent3dRowShader->VerticalPixelOffset.Set(0); // fixme: vary with window location + GLRenderer->mPresent3dRowShader->VerticalPixelOffset.Set( + 0 // fixme: vary with window location + + box.height % 2 // because we want the top pixel offset, but gl_FragCoord.y is the bottom pixel offset + ); GLRenderer->RenderScreenQuad(); } diff --git a/wadsrc/static/shaders/glsl/present_row3d.fp b/wadsrc/static/shaders/glsl/present_row3d.fp index 73a01539ba..8ae72d1e07 100644 --- a/wadsrc/static/shaders/glsl/present_row3d.fp +++ b/wadsrc/static/shaders/glsl/present_row3d.fp @@ -7,7 +7,6 @@ uniform sampler2D RightEyeTexture; uniform float InvGamma; uniform float Contrast; uniform float Brightness; -uniform int WindowHeight; uniform int VerticalPixelOffset; // top-of-window might not be top-of-screen vec4 ApplyGamma(vec4 c) @@ -20,8 +19,10 @@ vec4 ApplyGamma(vec4 c) void main() { - int thisVerticalPixel = int(gl_FragCoord.y); - bool isLeftEye = (thisVerticalPixel + VerticalPixelOffset) % 2 == 0; + int thisVerticalPixel = int(gl_FragCoord.y + 1.0); // Bottom row is typically the right eye, when WindowHeight is even + bool isLeftEye = (thisVerticalPixel // because we want to alternate eye view on each row + + VerticalPixelOffset // because the window might not be aligned to the screen + ) % 2 == 0; vec4 inputColor; if (isLeftEye) { inputColor = texture(LeftEyeTexture, TexCoord); From 63b28a1d80a7d055616978de8d9f8c1c77f8dc64 Mon Sep 17 00:00:00 2001 From: Christopher Bruns Date: Sun, 2 Oct 2016 16:04:52 -0400 Subject: [PATCH 7/9] Retain stereoscopic parity after dragging window in row interleaved 3D mode. --- src/gl/stereo3d/gl_interleaved3d.cpp | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/gl/stereo3d/gl_interleaved3d.cpp b/src/gl/stereo3d/gl_interleaved3d.cpp index 225f528193..329dec9530 100644 --- a/src/gl/stereo3d/gl_interleaved3d.cpp +++ b/src/gl/stereo3d/gl_interleaved3d.cpp @@ -42,6 +42,8 @@ EXTERN_CVAR(Float, vid_brightness) EXTERN_CVAR(Float, vid_contrast) +EXTERN_CVAR(Bool, fullscreen) +EXTERN_CVAR(Int, win_y) // pixel position of top of display window namespace s3d { @@ -99,8 +101,16 @@ void RowInterleaved3D::Present() const GLRenderer->mScreenViewport.width / (float)GLRenderer->mBuffers->GetWidth(), GLRenderer->mScreenViewport.height / (float)GLRenderer->mBuffers->GetHeight()); + // Compute absolute offset from top of screen to top of current display window + // because we need screen-relative, not window-relative, scan line parity + int windowVOffset = 0; + if (! fullscreen) { + I_SaveWindowedPos(); // update win_y CVAR + windowVOffset = win_y; + } + GLRenderer->mPresent3dRowShader->VerticalPixelOffset.Set( - 0 // fixme: vary with window location + windowVOffset // fixme: vary with window location + box.height % 2 // because we want the top pixel offset, but gl_FragCoord.y is the bottom pixel offset ); From 5391216756165e0f1e66db3b141c4b4c0c9849fb Mon Sep 17 00:00:00 2001 From: Christopher Bruns Date: Sun, 2 Oct 2016 16:27:43 -0400 Subject: [PATCH 8/9] Delete unused new BlitFromEyeTexture() method I ended up not using. --- src/gl/renderer/gl_renderbuffers.cpp | 20 -------------------- src/gl/renderer/gl_renderbuffers.h | 1 - 2 files changed, 21 deletions(-) diff --git a/src/gl/renderer/gl_renderbuffers.cpp b/src/gl/renderer/gl_renderbuffers.cpp index 31fc36832f..b2471e4b91 100644 --- a/src/gl/renderer/gl_renderbuffers.cpp +++ b/src/gl/renderer/gl_renderbuffers.cpp @@ -576,26 +576,6 @@ void FGLRenderBuffers::BlitToEyeTexture(int eye) glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); } -void FGLRenderBuffers::BlitFromEyeTexture(int eye, GL_IRECT* box) -{ - glBindFramebuffer(GL_READ_FRAMEBUFFER, mEyeFBs[eye]); - glBindFramebuffer(GL_DRAW_FRAMEBUFFER, mOutputFB); - if (box == nullptr) - box = &GLRenderer->mOutputLetterbox; - glBlitFramebuffer(0, 0, mWidth, mHeight, - box->left, box->top, box->width + box->left, box->height + box->top, - GL_COLOR_BUFFER_BIT, GL_NEAREST); - - if ((gl.flags & RFL_INVALIDATE_BUFFER) != 0) - { - GLenum attachments[2] = { GL_COLOR_ATTACHMENT0, GL_DEPTH_STENCIL_ATTACHMENT }; - glInvalidateFramebuffer(GL_READ_FRAMEBUFFER, 2, attachments); - } - - glBindFramebuffer(GL_READ_FRAMEBUFFER, 0); - glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); -} - void FGLRenderBuffers::BindEyeTexture(int eye, int texunit) { CreateEyeBuffers(eye); diff --git a/src/gl/renderer/gl_renderbuffers.h b/src/gl/renderer/gl_renderbuffers.h index 043cb88526..5fe05f5ac5 100644 --- a/src/gl/renderer/gl_renderbuffers.h +++ b/src/gl/renderer/gl_renderbuffers.h @@ -43,7 +43,6 @@ public: void BindOutputFB(); void BlitToEyeTexture(int eye); - void BlitFromEyeTexture(int eye, GL_IRECT* box); void BindEyeTexture(int eye, int texunit); void BindEyeFB(int eye, bool readBuffer = false); From c68aa2b24168d6baf373edffc7f1f5b2eb18b2ca Mon Sep 17 00:00:00 2001 From: "alexey.lysiuk" Date: Sun, 25 Sep 2016 12:25:01 +0300 Subject: [PATCH 9/9] Added FXAA post-processing Implementation of Fast Approximate Anti-Aliasing is based on nVidia sample: https://github.com/NVIDIAGameWorks/GraphicsSamples/tree/master/samples/es3-kepler/FXAA --- docs/licenses/fxaa.txt | 33 ++ src/CMakeLists.txt | 1 + src/gl/renderer/gl_postprocess.cpp | 54 +++ src/gl/renderer/gl_renderer.cpp | 7 + src/gl/renderer/gl_renderer.h | 5 + src/gl/scene/gl_scene.cpp | 1 + src/gl/shaders/gl_fxaashader.cpp | 99 +++++ src/gl/shaders/gl_fxaashader.h | 66 ++++ wadsrc/static/language.enu | 7 +- wadsrc/static/menudef.zz | 10 + wadsrc/static/shaders/glsl/fxaa.fp | 615 +++++++++++++++++++++++++++++ 11 files changed, 897 insertions(+), 1 deletion(-) create mode 100644 docs/licenses/fxaa.txt create mode 100644 src/gl/shaders/gl_fxaashader.cpp create mode 100644 src/gl/shaders/gl_fxaashader.h create mode 100644 wadsrc/static/shaders/glsl/fxaa.fp diff --git a/docs/licenses/fxaa.txt b/docs/licenses/fxaa.txt new file mode 100644 index 0000000000..fbd143c1d9 --- /dev/null +++ b/docs/licenses/fxaa.txt @@ -0,0 +1,33 @@ +//---------------------------------------------------------------------------------- +// File: es3-kepler\FXAA/FXAA3_11.h +// SDK Version: v3.00 +// Email: gameworks@nvidia.com +// Site: http://developer.nvidia.com/ +// +// Copyright (c) 2014-2015, NVIDIA CORPORATION. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// * Neither the name of NVIDIA CORPORATION nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY +// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR +// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY +// OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +//---------------------------------------------------------------------------------- diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 7307e6eec4..19e5c9a0ca 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1131,6 +1131,7 @@ set( FASTMATH_SOURCES gl/shaders/gl_colormapshader.cpp gl/shaders/gl_tonemapshader.cpp gl/shaders/gl_lensshader.cpp + gl/shaders/gl_fxaashader.cpp gl/system/gl_interface.cpp gl/system/gl_framebuffer.cpp gl/system/gl_debug.cpp diff --git a/src/gl/renderer/gl_postprocess.cpp b/src/gl/renderer/gl_postprocess.cpp index 03bea6d725..52339e5870 100644 --- a/src/gl/renderer/gl_postprocess.cpp +++ b/src/gl/renderer/gl_postprocess.cpp @@ -60,6 +60,7 @@ #include "gl/shaders/gl_tonemapshader.h" #include "gl/shaders/gl_colormapshader.h" #include "gl/shaders/gl_lensshader.h" +#include "gl/shaders/gl_fxaashader.h" #include "gl/shaders/gl_presentshader.h" #include "gl/renderer/gl_2ddrawer.h" #include "gl/stereo3d/gl_stereo3d.h" @@ -98,6 +99,14 @@ CVAR(Float, gl_lens_k, -0.12f, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) CVAR(Float, gl_lens_kcube, 0.1f, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) CVAR(Float, gl_lens_chromatic, 1.12f, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) +CUSTOM_CVAR(Int, gl_fxaa, 0, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) +{ + if (self < 0 || self >= FFXAAShader::Count) + { + self = 0; + } +} + EXTERN_CVAR(Float, vid_brightness) EXTERN_CVAR(Float, vid_contrast) @@ -447,6 +456,51 @@ void FGLRenderer::LensDistortScene() FGLDebug::PopGroup(); } +//----------------------------------------------------------------------------- +// +// Apply FXAA and place the result in the HUD/2D texture +// +//----------------------------------------------------------------------------- + +void FGLRenderer::ApplyFXAA() +{ + if (0 == gl_fxaa) + { + return; + } + + FGLDebug::PushGroup("ApplyFXAA"); + + const GLfloat rpcRes[2] = + { + 1.0f / mBuffers->GetWidth(), + 1.0f / mBuffers->GetHeight() + }; + + FGLPostProcessState savedState; + + mBuffers->BindNextFB(); + mBuffers->BindCurrentTexture(0); + mFXAALumaShader->Bind(); + mFXAALumaShader->InputTexture.Set(0); + RenderScreenQuad(); + mBuffers->NextTexture(); + + mBuffers->BindNextFB(); + mBuffers->BindCurrentTexture(0); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + mFXAAShader->Bind(); + mFXAAShader->InputTexture.Set(0); + mFXAAShader->ReciprocalResolution.Set(rpcRes); + RenderScreenQuad(); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + mBuffers->NextTexture(); + + FGLDebug::PopGroup(); +} + //----------------------------------------------------------------------------- // // Copies the rendered screen to its final destination diff --git a/src/gl/renderer/gl_renderer.cpp b/src/gl/renderer/gl_renderer.cpp index fbfa514409..be1b96f150 100644 --- a/src/gl/renderer/gl_renderer.cpp +++ b/src/gl/renderer/gl_renderer.cpp @@ -56,6 +56,7 @@ #include "gl/shaders/gl_tonemapshader.h" #include "gl/shaders/gl_colormapshader.h" #include "gl/shaders/gl_lensshader.h" +#include "gl/shaders/gl_fxaashader.h" #include "gl/shaders/gl_presentshader.h" #include "gl/shaders/gl_present3dRowshader.h" #include "gl/stereo3d/gl_stereo3d.h" @@ -115,6 +116,8 @@ FGLRenderer::FGLRenderer(OpenGLFrameBuffer *fb) mTonemapPalette = nullptr; mColormapShader = nullptr; mLensShader = nullptr; + mFXAAShader = nullptr; + mFXAALumaShader = nullptr; } void gl_LoadModels(); @@ -133,6 +136,8 @@ void FGLRenderer::Initialize(int width, int height) mColormapShader = new FColormapShader(); mTonemapPalette = nullptr; mLensShader = new FLensShader(); + mFXAAShader = new FFXAAShader; + mFXAALumaShader = new FFXAALumaShader; mPresentShader = new FPresentShader(); mPresent3dRowShader = new FPresent3DRowShader(); m2DDrawer = new F2DDrawer; @@ -198,6 +203,8 @@ FGLRenderer::~FGLRenderer() if (mTonemapPalette) delete mTonemapPalette; if (mColormapShader) delete mColormapShader; if (mLensShader) delete mLensShader; + delete mFXAAShader; + delete mFXAALumaShader; } //========================================================================== diff --git a/src/gl/renderer/gl_renderer.h b/src/gl/renderer/gl_renderer.h index 460b5685a2..65e31c52f7 100644 --- a/src/gl/renderer/gl_renderer.h +++ b/src/gl/renderer/gl_renderer.h @@ -28,6 +28,8 @@ class FBlurShader; class FTonemapShader; class FColormapShader; class FLensShader; +class FFXAALumaShader; +class FFXAAShader; class FPresentShader; class FPresent3DRowShader; class F2DDrawer; @@ -104,6 +106,8 @@ public: FColormapShader *mColormapShader; FHardwareTexture *mTonemapPalette; FLensShader *mLensShader; + FFXAALumaShader *mFXAALumaShader; + FFXAAShader *mFXAAShader; FPresentShader *mPresentShader; FPresent3DRowShader *mPresent3dRowShader; @@ -180,6 +184,7 @@ public: void BindTonemapPalette(int texunit); void ClearTonemapPalette(); void LensDistortScene(); + void ApplyFXAA(); void CopyToBackbuffer(const GL_IRECT *bounds, bool applyGamma); void DrawPresentTexture(const GL_IRECT &box, bool applyGamma); void Flush(); diff --git a/src/gl/scene/gl_scene.cpp b/src/gl/scene/gl_scene.cpp index 0c76b4bb1b..4b7bc762f5 100644 --- a/src/gl/scene/gl_scene.cpp +++ b/src/gl/scene/gl_scene.cpp @@ -832,6 +832,7 @@ sector_t * FGLRenderer::RenderViewpoint (AActor * camera, GL_IRECT * bounds, flo TonemapScene(); ColormapScene(); LensDistortScene(); + ApplyFXAA(); // This should be done after postprocessing, not before. mBuffers->BindCurrentFB(); diff --git a/src/gl/shaders/gl_fxaashader.cpp b/src/gl/shaders/gl_fxaashader.cpp new file mode 100644 index 0000000000..277c7fbb3d --- /dev/null +++ b/src/gl/shaders/gl_fxaashader.cpp @@ -0,0 +1,99 @@ +// +//--------------------------------------------------------------------------- +// +// Copyright(C) 2016 Alexey Lysiuk +// All rights reserved. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this program. If not, see http://www.gnu.org/licenses/ +// +//-------------------------------------------------------------------------- +// + +// +// Fast approXimate Anti-Aliasing (FXAA) post-processing +// + +#include "gl/system/gl_system.h" +#include "gl/shaders/gl_fxaashader.h" + +EXTERN_CVAR(Int, gl_fxaa) + +void FFXAALumaShader::Bind() +{ + if (!mShader) + { + mShader.Compile(FShaderProgram::Vertex, "shaders/glsl/screenquad.vp", "", 330); + mShader.Compile(FShaderProgram::Fragment, "shaders/glsl/fxaa.fp", "#define FXAA_LUMA_PASS\n", 330); + mShader.SetFragDataLocation(0, "FragColor"); + mShader.Link("shaders/glsl/fxaa"); + mShader.SetAttribLocation(0, "PositionInProjection"); + InputTexture.Init(mShader, "InputTexture"); + } + + mShader.Bind(); +} + +static int GetMaxVersion() +{ + return gl.glslversion >= 4.f ? 400 : 330; +} + +static FString GetDefines() +{ + int quality; + + switch (gl_fxaa) + { + default: + case FFXAAShader::Low: quality = 10; break; + case FFXAAShader::Medium: quality = 12; break; + case FFXAAShader::High: quality = 29; break; + case FFXAAShader::Extreme: quality = 39; break; + } + + const int gatherAlpha = GetMaxVersion() >= 400 ? 1 : 0; + + // TODO: enable FXAA_GATHER4_ALPHA on OpenGL earlier than 4.0 + // when GL_ARB_gpu_shader5/GL_NV_gpu_shader5 extensions are supported + + FString result; + result.Format( + "#define FXAA_QUALITY__PRESET %i\n" + "#define FXAA_GATHER4_ALPHA %i\n", + quality, gatherAlpha); + + return result; +} + +void FFXAAShader::Bind() +{ + assert(gl_fxaa > 0 && gl_fxaa < Count); + FShaderProgram &shader = mShaders[gl_fxaa]; + + if (!shader) + { + const FString defines = GetDefines(); + const int maxVersion = GetMaxVersion(); + + shader.Compile(FShaderProgram::Vertex, "shaders/glsl/screenquad.vp", "", 330); + shader.Compile(FShaderProgram::Fragment, "shaders/glsl/fxaa.fp", defines, maxVersion); + shader.SetFragDataLocation(0, "FragColor"); + shader.Link("shaders/glsl/fxaa"); + shader.SetAttribLocation(0, "PositionInProjection"); + InputTexture.Init(shader, "InputTexture"); + ReciprocalResolution.Init(shader, "ReciprocalResolution"); + } + + shader.Bind(); +} diff --git a/src/gl/shaders/gl_fxaashader.h b/src/gl/shaders/gl_fxaashader.h new file mode 100644 index 0000000000..5ebcd232e7 --- /dev/null +++ b/src/gl/shaders/gl_fxaashader.h @@ -0,0 +1,66 @@ +// +//--------------------------------------------------------------------------- +// +// Copyright(C) 2016 Alexey Lysiuk +// All rights reserved. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this program. If not, see http://www.gnu.org/licenses/ +// +//-------------------------------------------------------------------------- +// + +// +// Fast approXimate Anti-Aliasing (FXAA) post-processing +// + +#ifndef __GL_FXAASHADER_H__ +#define __GL_FXAASHADER_H__ + +#include "gl_shaderprogram.h" + +class FFXAALumaShader +{ +public: + void Bind(); + + FBufferedUniform1i InputTexture; + +private: + FShaderProgram mShader; +}; + + +class FFXAAShader +{ +public: + enum Quality + { + None, + Low, + Medium, + High, + Extreme, + Count + }; + + void Bind(); + + FBufferedUniform1i InputTexture; + FBufferedUniform2f ReciprocalResolution; + +private: + FShaderProgram mShaders[Count]; +}; + +#endif // __GL_FXAASHADER_H__ diff --git a/wadsrc/static/language.enu b/wadsrc/static/language.enu index 813d6b8f61..224764a871 100644 --- a/wadsrc/static/language.enu +++ b/wadsrc/static/language.enu @@ -2633,6 +2633,7 @@ GLPREFMNU_MULTISAMPLE = "Multisample"; GLPREFMNU_TONEMAP = "Tonemap Mode"; GLPREFMNU_BLOOM = "Bloom effect"; GLPREFMNU_LENS = "Lens distortion effect"; +GLPREFMNU_FXAA = "FXAA Quality"; // Option Values OPTVAL_SMART = "Smart"; @@ -2709,4 +2710,8 @@ OPTVAL_QUADBUFFERED = "Quad-buffered"; OPTVAL_UNCHARTED2 = "Uncharted 2"; OPTVAL_HEJLDAWSON = "Hejl Dawson"; OPTVAL_REINHARD = "Reinhard"; -OPTVAL_PALETTE = "Palette"; \ No newline at end of file +OPTVAL_PALETTE = "Palette"; +OPTVAL_LOW = "Low"; +OPTVAL_MEDIUM = "Medium"; +OPTVAL_HIGH = "High"; +OPTVAL_EXTREME = "Extreme"; diff --git a/wadsrc/static/menudef.zz b/wadsrc/static/menudef.zz index 6f96ea286c..7e798a0390 100644 --- a/wadsrc/static/menudef.zz +++ b/wadsrc/static/menudef.zz @@ -42,6 +42,15 @@ OptionValue "TonemapModes" 5, "$OPTVAL_PALETTE" } +OptionValue "FXAAQuality" +{ + 0, "$OPTVAL_OFF" + 1, "$OPTVAL_LOW" + 2, "$OPTVAL_MEDIUM" + 3, "$OPTVAL_HIGH" + 4, "$OPTVAL_EXTREME" +} + OptionValue "TextureFormats" { 0, "$OPTVAL_RGBA8" @@ -228,4 +237,5 @@ OptionMenu "GLPrefOptions" Option "$GLPREFMNU_TONEMAP", gl_tonemap, "TonemapModes" Option "$GLPREFMNU_BLOOM", gl_bloom, "OnOff" Option "$GLPREFMNU_LENS", gl_lens, "OnOff" + Option "$GLPREFMNU_FXAA", gl_fxaa, "FXAAQuality" } diff --git a/wadsrc/static/shaders/glsl/fxaa.fp b/wadsrc/static/shaders/glsl/fxaa.fp new file mode 100644 index 0000000000..7fcdf8c819 --- /dev/null +++ b/wadsrc/static/shaders/glsl/fxaa.fp @@ -0,0 +1,615 @@ +//---------------------------------------------------------------------------------- +// File: es3-kepler\FXAA/FXAA3_11.h +// SDK Version: v3.00 +// Email: gameworks@nvidia.com +// Site: http://developer.nvidia.com/ +// +// Copyright (c) 2014-2015, NVIDIA CORPORATION. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// * Neither the name of NVIDIA CORPORATION nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY +// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR +// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY +// OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +//---------------------------------------------------------------------------------- + +in vec2 TexCoord; +out vec4 FragColor; + +uniform sampler2D InputTexture; + +#ifdef FXAA_LUMA_PASS + +void main() +{ + vec3 tex = texture(InputTexture, TexCoord).rgb; + vec3 luma = vec3(0.299, 0.587, 0.114); + FragColor = vec4(tex, dot(tex, luma)); +} + +#else // FXAA itself + +//============================================================================ +// NVIDIA FXAA 3.11 by TIMOTHY LOTTES +//============================================================================ + +#define FXAA_DISCARD 1 + +#define FXAA_GREEN_AS_LUMA 0 + +#define FxaaBool bool +#define FxaaDiscard discard +#define FxaaFloat float +#define FxaaFloat2 vec2 +#define FxaaFloat3 vec3 +#define FxaaFloat4 vec4 +#define FxaaHalf float +#define FxaaHalf2 vec2 +#define FxaaHalf3 vec3 +#define FxaaHalf4 vec4 +#define FxaaInt2 ivec2 +#define FxaaSat(x) clamp(x, 0.0, 1.0) +#define FxaaTex sampler2D + +#define FxaaTexTop(t, p) textureLod(t, p, 0.0) +#define FxaaTexOff(t, p, o, r) textureLodOffset(t, p, 0.0, o) + +#if (FXAA_GATHER4_ALPHA == 1) + #define FxaaTexAlpha4(t, p) textureGather(t, p, 3) + #define FxaaTexOffAlpha4(t, p, o) textureGatherOffset(t, p, o, 3) + #define FxaaTexGreen4(t, p) textureGather(t, p, 1) + #define FxaaTexOffGreen4(t, p, o) textureGatherOffset(t, p, o, 1) +#endif + +#if (FXAA_GREEN_AS_LUMA == 0) + FxaaFloat FxaaLuma(FxaaFloat4 rgba) { return rgba.w; } +#else + FxaaFloat FxaaLuma(FxaaFloat4 rgba) { return rgba.y; } +#endif + +#if (FXAA_QUALITY__PRESET == 10) + #define FXAA_QUALITY__PS 3 + #define FXAA_QUALITY__P0 1.5 + #define FXAA_QUALITY__P1 3.0 + #define FXAA_QUALITY__P2 12.0 +#elif (FXAA_QUALITY__PRESET == 11) + #define FXAA_QUALITY__PS 4 + #define FXAA_QUALITY__P0 1.0 + #define FXAA_QUALITY__P1 1.5 + #define FXAA_QUALITY__P2 3.0 + #define FXAA_QUALITY__P3 12.0 +#elif (FXAA_QUALITY__PRESET == 12) + #define FXAA_QUALITY__PS 5 + #define FXAA_QUALITY__P0 1.0 + #define FXAA_QUALITY__P1 1.5 + #define FXAA_QUALITY__P2 2.0 + #define FXAA_QUALITY__P3 4.0 + #define FXAA_QUALITY__P4 12.0 +#elif (FXAA_QUALITY__PRESET == 13) + #define FXAA_QUALITY__PS 6 + #define FXAA_QUALITY__P0 1.0 + #define FXAA_QUALITY__P1 1.5 + #define FXAA_QUALITY__P2 2.0 + #define FXAA_QUALITY__P3 2.0 + #define FXAA_QUALITY__P4 4.0 + #define FXAA_QUALITY__P5 12.0 +#elif (FXAA_QUALITY__PRESET == 14) + #define FXAA_QUALITY__PS 7 + #define FXAA_QUALITY__P0 1.0 + #define FXAA_QUALITY__P1 1.5 + #define FXAA_QUALITY__P2 2.0 + #define FXAA_QUALITY__P3 2.0 + #define FXAA_QUALITY__P4 2.0 + #define FXAA_QUALITY__P5 4.0 + #define FXAA_QUALITY__P6 12.0 +#elif (FXAA_QUALITY__PRESET == 15) + #define FXAA_QUALITY__PS 8 + #define FXAA_QUALITY__P0 1.0 + #define FXAA_QUALITY__P1 1.5 + #define FXAA_QUALITY__P2 2.0 + #define FXAA_QUALITY__P3 2.0 + #define FXAA_QUALITY__P4 2.0 + #define FXAA_QUALITY__P5 2.0 + #define FXAA_QUALITY__P6 4.0 + #define FXAA_QUALITY__P7 12.0 +#elif (FXAA_QUALITY__PRESET == 20) + #define FXAA_QUALITY__PS 3 + #define FXAA_QUALITY__P0 1.5 + #define FXAA_QUALITY__P1 2.0 + #define FXAA_QUALITY__P2 8.0 +#elif (FXAA_QUALITY__PRESET == 21) + #define FXAA_QUALITY__PS 4 + #define FXAA_QUALITY__P0 1.0 + #define FXAA_QUALITY__P1 1.5 + #define FXAA_QUALITY__P2 2.0 + #define FXAA_QUALITY__P3 8.0 +#elif (FXAA_QUALITY__PRESET == 22) + #define FXAA_QUALITY__PS 5 + #define FXAA_QUALITY__P0 1.0 + #define FXAA_QUALITY__P1 1.5 + #define FXAA_QUALITY__P2 2.0 + #define FXAA_QUALITY__P3 2.0 + #define FXAA_QUALITY__P4 8.0 +#elif (FXAA_QUALITY__PRESET == 23) + #define FXAA_QUALITY__PS 6 + #define FXAA_QUALITY__P0 1.0 + #define FXAA_QUALITY__P1 1.5 + #define FXAA_QUALITY__P2 2.0 + #define FXAA_QUALITY__P3 2.0 + #define FXAA_QUALITY__P4 2.0 + #define FXAA_QUALITY__P5 8.0 +#elif (FXAA_QUALITY__PRESET == 24) + #define FXAA_QUALITY__PS 7 + #define FXAA_QUALITY__P0 1.0 + #define FXAA_QUALITY__P1 1.5 + #define FXAA_QUALITY__P2 2.0 + #define FXAA_QUALITY__P3 2.0 + #define FXAA_QUALITY__P4 2.0 + #define FXAA_QUALITY__P5 3.0 + #define FXAA_QUALITY__P6 8.0 +#elif (FXAA_QUALITY__PRESET == 25) + #define FXAA_QUALITY__PS 8 + #define FXAA_QUALITY__P0 1.0 + #define FXAA_QUALITY__P1 1.5 + #define FXAA_QUALITY__P2 2.0 + #define FXAA_QUALITY__P3 2.0 + #define FXAA_QUALITY__P4 2.0 + #define FXAA_QUALITY__P5 2.0 + #define FXAA_QUALITY__P6 4.0 + #define FXAA_QUALITY__P7 8.0 +#elif (FXAA_QUALITY__PRESET == 26) + #define FXAA_QUALITY__PS 9 + #define FXAA_QUALITY__P0 1.0 + #define FXAA_QUALITY__P1 1.5 + #define FXAA_QUALITY__P2 2.0 + #define FXAA_QUALITY__P3 2.0 + #define FXAA_QUALITY__P4 2.0 + #define FXAA_QUALITY__P5 2.0 + #define FXAA_QUALITY__P6 2.0 + #define FXAA_QUALITY__P7 4.0 + #define FXAA_QUALITY__P8 8.0 +#elif (FXAA_QUALITY__PRESET == 27) + #define FXAA_QUALITY__PS 10 + #define FXAA_QUALITY__P0 1.0 + #define FXAA_QUALITY__P1 1.5 + #define FXAA_QUALITY__P2 2.0 + #define FXAA_QUALITY__P3 2.0 + #define FXAA_QUALITY__P4 2.0 + #define FXAA_QUALITY__P5 2.0 + #define FXAA_QUALITY__P6 2.0 + #define FXAA_QUALITY__P7 2.0 + #define FXAA_QUALITY__P8 4.0 + #define FXAA_QUALITY__P9 8.0 +#elif (FXAA_QUALITY__PRESET == 28) + #define FXAA_QUALITY__PS 11 + #define FXAA_QUALITY__P0 1.0 + #define FXAA_QUALITY__P1 1.5 + #define FXAA_QUALITY__P2 2.0 + #define FXAA_QUALITY__P3 2.0 + #define FXAA_QUALITY__P4 2.0 + #define FXAA_QUALITY__P5 2.0 + #define FXAA_QUALITY__P6 2.0 + #define FXAA_QUALITY__P7 2.0 + #define FXAA_QUALITY__P8 2.0 + #define FXAA_QUALITY__P9 4.0 + #define FXAA_QUALITY__P10 8.0 +#elif (FXAA_QUALITY__PRESET == 29) + #define FXAA_QUALITY__PS 12 + #define FXAA_QUALITY__P0 1.0 + #define FXAA_QUALITY__P1 1.5 + #define FXAA_QUALITY__P2 2.0 + #define FXAA_QUALITY__P3 2.0 + #define FXAA_QUALITY__P4 2.0 + #define FXAA_QUALITY__P5 2.0 + #define FXAA_QUALITY__P6 2.0 + #define FXAA_QUALITY__P7 2.0 + #define FXAA_QUALITY__P8 2.0 + #define FXAA_QUALITY__P9 2.0 + #define FXAA_QUALITY__P10 4.0 + #define FXAA_QUALITY__P11 8.0 +#elif (FXAA_QUALITY__PRESET == 39) + #define FXAA_QUALITY__PS 12 + #define FXAA_QUALITY__P0 1.0 + #define FXAA_QUALITY__P1 1.0 + #define FXAA_QUALITY__P2 1.0 + #define FXAA_QUALITY__P3 1.0 + #define FXAA_QUALITY__P4 1.0 + #define FXAA_QUALITY__P5 1.5 + #define FXAA_QUALITY__P6 2.0 + #define FXAA_QUALITY__P7 2.0 + #define FXAA_QUALITY__P8 2.0 + #define FXAA_QUALITY__P9 2.0 + #define FXAA_QUALITY__P10 4.0 + #define FXAA_QUALITY__P11 8.0 +#endif + +FxaaFloat4 FxaaPixelShader(FxaaFloat2 pos, FxaaTex tex, FxaaFloat2 fxaaQualityRcpFrame, + FxaaFloat fxaaQualitySubpix, FxaaFloat fxaaQualityEdgeThreshold, FxaaFloat fxaaQualityEdgeThresholdMin) +{ + FxaaFloat2 posM; + posM.x = pos.x; + posM.y = pos.y; + #if (FXAA_GATHER4_ALPHA == 1) + #if (FXAA_DISCARD == 0) + FxaaFloat4 rgbyM = FxaaTexTop(tex, posM); + #if (FXAA_GREEN_AS_LUMA == 0) + #define lumaM rgbyM.w + #else + #define lumaM rgbyM.y + #endif + #endif + #if (FXAA_GREEN_AS_LUMA == 0) + FxaaFloat4 luma4A = FxaaTexAlpha4(tex, posM); + FxaaFloat4 luma4B = FxaaTexOffAlpha4(tex, posM, FxaaInt2(-1, -1)); + #else + FxaaFloat4 luma4A = FxaaTexGreen4(tex, posM); + FxaaFloat4 luma4B = FxaaTexOffGreen4(tex, posM, FxaaInt2(-1, -1)); + #endif + #if (FXAA_DISCARD == 1) + #define lumaM luma4A.w + #endif + #define lumaE luma4A.z + #define lumaS luma4A.x + #define lumaSE luma4A.y + #define lumaNW luma4B.w + #define lumaN luma4B.z + #define lumaW luma4B.x + #else + FxaaFloat4 rgbyM = FxaaTexTop(tex, posM); + #if (FXAA_GREEN_AS_LUMA == 0) + #define lumaM rgbyM.w + #else + #define lumaM rgbyM.y + #endif + FxaaFloat lumaS = FxaaLuma(FxaaTexOff(tex, posM, FxaaInt2( 0, 1), fxaaQualityRcpFrame.xy)); + FxaaFloat lumaE = FxaaLuma(FxaaTexOff(tex, posM, FxaaInt2( 1, 0), fxaaQualityRcpFrame.xy)); + FxaaFloat lumaN = FxaaLuma(FxaaTexOff(tex, posM, FxaaInt2( 0,-1), fxaaQualityRcpFrame.xy)); + FxaaFloat lumaW = FxaaLuma(FxaaTexOff(tex, posM, FxaaInt2(-1, 0), fxaaQualityRcpFrame.xy)); + #endif +/*--------------------------------------------------------------------------*/ + FxaaFloat maxSM = max(lumaS, lumaM); + FxaaFloat minSM = min(lumaS, lumaM); + FxaaFloat maxESM = max(lumaE, maxSM); + FxaaFloat minESM = min(lumaE, minSM); + FxaaFloat maxWN = max(lumaN, lumaW); + FxaaFloat minWN = min(lumaN, lumaW); + FxaaFloat rangeMax = max(maxWN, maxESM); + FxaaFloat rangeMin = min(minWN, minESM); + FxaaFloat rangeMaxScaled = rangeMax * fxaaQualityEdgeThreshold; + FxaaFloat range = rangeMax - rangeMin; + FxaaFloat rangeMaxClamped = max(fxaaQualityEdgeThresholdMin, rangeMaxScaled); + FxaaBool earlyExit = range < rangeMaxClamped; +/*--------------------------------------------------------------------------*/ + if(earlyExit) + #if (FXAA_DISCARD == 1) + FxaaDiscard; + #else + return rgbyM; + #endif +/*--------------------------------------------------------------------------*/ + #if (FXAA_GATHER4_ALPHA == 0) + FxaaFloat lumaNW = FxaaLuma(FxaaTexOff(tex, posM, FxaaInt2(-1,-1), fxaaQualityRcpFrame.xy)); + FxaaFloat lumaSE = FxaaLuma(FxaaTexOff(tex, posM, FxaaInt2( 1, 1), fxaaQualityRcpFrame.xy)); + FxaaFloat lumaNE = FxaaLuma(FxaaTexOff(tex, posM, FxaaInt2( 1,-1), fxaaQualityRcpFrame.xy)); + FxaaFloat lumaSW = FxaaLuma(FxaaTexOff(tex, posM, FxaaInt2(-1, 1), fxaaQualityRcpFrame.xy)); + #else + FxaaFloat lumaNE = FxaaLuma(FxaaTexOff(tex, posM, FxaaInt2(1, -1), fxaaQualityRcpFrame.xy)); + FxaaFloat lumaSW = FxaaLuma(FxaaTexOff(tex, posM, FxaaInt2(-1, 1), fxaaQualityRcpFrame.xy)); + #endif +/*--------------------------------------------------------------------------*/ + FxaaFloat lumaNS = lumaN + lumaS; + FxaaFloat lumaWE = lumaW + lumaE; + FxaaFloat subpixRcpRange = 1.0/range; + FxaaFloat subpixNSWE = lumaNS + lumaWE; + FxaaFloat edgeHorz1 = (-2.0 * lumaM) + lumaNS; + FxaaFloat edgeVert1 = (-2.0 * lumaM) + lumaWE; +/*--------------------------------------------------------------------------*/ + FxaaFloat lumaNESE = lumaNE + lumaSE; + FxaaFloat lumaNWNE = lumaNW + lumaNE; + FxaaFloat edgeHorz2 = (-2.0 * lumaE) + lumaNESE; + FxaaFloat edgeVert2 = (-2.0 * lumaN) + lumaNWNE; +/*--------------------------------------------------------------------------*/ + FxaaFloat lumaNWSW = lumaNW + lumaSW; + FxaaFloat lumaSWSE = lumaSW + lumaSE; + FxaaFloat edgeHorz4 = (abs(edgeHorz1) * 2.0) + abs(edgeHorz2); + FxaaFloat edgeVert4 = (abs(edgeVert1) * 2.0) + abs(edgeVert2); + FxaaFloat edgeHorz3 = (-2.0 * lumaW) + lumaNWSW; + FxaaFloat edgeVert3 = (-2.0 * lumaS) + lumaSWSE; + FxaaFloat edgeHorz = abs(edgeHorz3) + edgeHorz4; + FxaaFloat edgeVert = abs(edgeVert3) + edgeVert4; +/*--------------------------------------------------------------------------*/ + FxaaFloat subpixNWSWNESE = lumaNWSW + lumaNESE; + FxaaFloat lengthSign = fxaaQualityRcpFrame.x; + FxaaBool horzSpan = edgeHorz >= edgeVert; + FxaaFloat subpixA = subpixNSWE * 2.0 + subpixNWSWNESE; +/*--------------------------------------------------------------------------*/ + if(!horzSpan) lumaN = lumaW; + if(!horzSpan) lumaS = lumaE; + if(horzSpan) lengthSign = fxaaQualityRcpFrame.y; + FxaaFloat subpixB = (subpixA * (1.0/12.0)) - lumaM; +/*--------------------------------------------------------------------------*/ + FxaaFloat gradientN = lumaN - lumaM; + FxaaFloat gradientS = lumaS - lumaM; + FxaaFloat lumaNN = lumaN + lumaM; + FxaaFloat lumaSS = lumaS + lumaM; + FxaaBool pairN = abs(gradientN) >= abs(gradientS); + FxaaFloat gradient = max(abs(gradientN), abs(gradientS)); + if(pairN) lengthSign = -lengthSign; + FxaaFloat subpixC = FxaaSat(abs(subpixB) * subpixRcpRange); +/*--------------------------------------------------------------------------*/ + FxaaFloat2 posB; + posB.x = posM.x; + posB.y = posM.y; + FxaaFloat2 offNP; + offNP.x = (!horzSpan) ? 0.0 : fxaaQualityRcpFrame.x; + offNP.y = ( horzSpan) ? 0.0 : fxaaQualityRcpFrame.y; + if(!horzSpan) posB.x += lengthSign * 0.5; + if( horzSpan) posB.y += lengthSign * 0.5; +/*--------------------------------------------------------------------------*/ + FxaaFloat2 posN; + posN.x = posB.x - offNP.x * FXAA_QUALITY__P0; + posN.y = posB.y - offNP.y * FXAA_QUALITY__P0; + FxaaFloat2 posP; + posP.x = posB.x + offNP.x * FXAA_QUALITY__P0; + posP.y = posB.y + offNP.y * FXAA_QUALITY__P0; + FxaaFloat subpixD = ((-2.0)*subpixC) + 3.0; + FxaaFloat lumaEndN = FxaaLuma(FxaaTexTop(tex, posN)); + FxaaFloat subpixE = subpixC * subpixC; + FxaaFloat lumaEndP = FxaaLuma(FxaaTexTop(tex, posP)); +/*--------------------------------------------------------------------------*/ + if(!pairN) lumaNN = lumaSS; + FxaaFloat gradientScaled = gradient * 1.0/4.0; + FxaaFloat lumaMM = lumaM - lumaNN * 0.5; + FxaaFloat subpixF = subpixD * subpixE; + FxaaBool lumaMLTZero = lumaMM < 0.0; +/*--------------------------------------------------------------------------*/ + lumaEndN -= lumaNN * 0.5; + lumaEndP -= lumaNN * 0.5; + FxaaBool doneN = abs(lumaEndN) >= gradientScaled; + FxaaBool doneP = abs(lumaEndP) >= gradientScaled; + if(!doneN) posN.x -= offNP.x * FXAA_QUALITY__P1; + if(!doneN) posN.y -= offNP.y * FXAA_QUALITY__P1; + FxaaBool doneNP = (!doneN) || (!doneP); + if(!doneP) posP.x += offNP.x * FXAA_QUALITY__P1; + if(!doneP) posP.y += offNP.y * FXAA_QUALITY__P1; +/*--------------------------------------------------------------------------*/ + if(doneNP) { + if(!doneN) lumaEndN = FxaaLuma(FxaaTexTop(tex, posN.xy)); + if(!doneP) lumaEndP = FxaaLuma(FxaaTexTop(tex, posP.xy)); + if(!doneN) lumaEndN = lumaEndN - lumaNN * 0.5; + if(!doneP) lumaEndP = lumaEndP - lumaNN * 0.5; + doneN = abs(lumaEndN) >= gradientScaled; + doneP = abs(lumaEndP) >= gradientScaled; + if(!doneN) posN.x -= offNP.x * FXAA_QUALITY__P2; + if(!doneN) posN.y -= offNP.y * FXAA_QUALITY__P2; + doneNP = (!doneN) || (!doneP); + if(!doneP) posP.x += offNP.x * FXAA_QUALITY__P2; + if(!doneP) posP.y += offNP.y * FXAA_QUALITY__P2; +/*--------------------------------------------------------------------------*/ + #if (FXAA_QUALITY__PS > 3) + if(doneNP) { + if(!doneN) lumaEndN = FxaaLuma(FxaaTexTop(tex, posN.xy)); + if(!doneP) lumaEndP = FxaaLuma(FxaaTexTop(tex, posP.xy)); + if(!doneN) lumaEndN = lumaEndN - lumaNN * 0.5; + if(!doneP) lumaEndP = lumaEndP - lumaNN * 0.5; + doneN = abs(lumaEndN) >= gradientScaled; + doneP = abs(lumaEndP) >= gradientScaled; + if(!doneN) posN.x -= offNP.x * FXAA_QUALITY__P3; + if(!doneN) posN.y -= offNP.y * FXAA_QUALITY__P3; + doneNP = (!doneN) || (!doneP); + if(!doneP) posP.x += offNP.x * FXAA_QUALITY__P3; + if(!doneP) posP.y += offNP.y * FXAA_QUALITY__P3; +/*--------------------------------------------------------------------------*/ + #if (FXAA_QUALITY__PS > 4) + if(doneNP) { + if(!doneN) lumaEndN = FxaaLuma(FxaaTexTop(tex, posN.xy)); + if(!doneP) lumaEndP = FxaaLuma(FxaaTexTop(tex, posP.xy)); + if(!doneN) lumaEndN = lumaEndN - lumaNN * 0.5; + if(!doneP) lumaEndP = lumaEndP - lumaNN * 0.5; + doneN = abs(lumaEndN) >= gradientScaled; + doneP = abs(lumaEndP) >= gradientScaled; + if(!doneN) posN.x -= offNP.x * FXAA_QUALITY__P4; + if(!doneN) posN.y -= offNP.y * FXAA_QUALITY__P4; + doneNP = (!doneN) || (!doneP); + if(!doneP) posP.x += offNP.x * FXAA_QUALITY__P4; + if(!doneP) posP.y += offNP.y * FXAA_QUALITY__P4; +/*--------------------------------------------------------------------------*/ + #if (FXAA_QUALITY__PS > 5) + if(doneNP) { + if(!doneN) lumaEndN = FxaaLuma(FxaaTexTop(tex, posN.xy)); + if(!doneP) lumaEndP = FxaaLuma(FxaaTexTop(tex, posP.xy)); + if(!doneN) lumaEndN = lumaEndN - lumaNN * 0.5; + if(!doneP) lumaEndP = lumaEndP - lumaNN * 0.5; + doneN = abs(lumaEndN) >= gradientScaled; + doneP = abs(lumaEndP) >= gradientScaled; + if(!doneN) posN.x -= offNP.x * FXAA_QUALITY__P5; + if(!doneN) posN.y -= offNP.y * FXAA_QUALITY__P5; + doneNP = (!doneN) || (!doneP); + if(!doneP) posP.x += offNP.x * FXAA_QUALITY__P5; + if(!doneP) posP.y += offNP.y * FXAA_QUALITY__P5; +/*--------------------------------------------------------------------------*/ + #if (FXAA_QUALITY__PS > 6) + if(doneNP) { + if(!doneN) lumaEndN = FxaaLuma(FxaaTexTop(tex, posN.xy)); + if(!doneP) lumaEndP = FxaaLuma(FxaaTexTop(tex, posP.xy)); + if(!doneN) lumaEndN = lumaEndN - lumaNN * 0.5; + if(!doneP) lumaEndP = lumaEndP - lumaNN * 0.5; + doneN = abs(lumaEndN) >= gradientScaled; + doneP = abs(lumaEndP) >= gradientScaled; + if(!doneN) posN.x -= offNP.x * FXAA_QUALITY__P6; + if(!doneN) posN.y -= offNP.y * FXAA_QUALITY__P6; + doneNP = (!doneN) || (!doneP); + if(!doneP) posP.x += offNP.x * FXAA_QUALITY__P6; + if(!doneP) posP.y += offNP.y * FXAA_QUALITY__P6; +/*--------------------------------------------------------------------------*/ + #if (FXAA_QUALITY__PS > 7) + if(doneNP) { + if(!doneN) lumaEndN = FxaaLuma(FxaaTexTop(tex, posN.xy)); + if(!doneP) lumaEndP = FxaaLuma(FxaaTexTop(tex, posP.xy)); + if(!doneN) lumaEndN = lumaEndN - lumaNN * 0.5; + if(!doneP) lumaEndP = lumaEndP - lumaNN * 0.5; + doneN = abs(lumaEndN) >= gradientScaled; + doneP = abs(lumaEndP) >= gradientScaled; + if(!doneN) posN.x -= offNP.x * FXAA_QUALITY__P7; + if(!doneN) posN.y -= offNP.y * FXAA_QUALITY__P7; + doneNP = (!doneN) || (!doneP); + if(!doneP) posP.x += offNP.x * FXAA_QUALITY__P7; + if(!doneP) posP.y += offNP.y * FXAA_QUALITY__P7; +/*--------------------------------------------------------------------------*/ + #if (FXAA_QUALITY__PS > 8) + if(doneNP) { + if(!doneN) lumaEndN = FxaaLuma(FxaaTexTop(tex, posN.xy)); + if(!doneP) lumaEndP = FxaaLuma(FxaaTexTop(tex, posP.xy)); + if(!doneN) lumaEndN = lumaEndN - lumaNN * 0.5; + if(!doneP) lumaEndP = lumaEndP - lumaNN * 0.5; + doneN = abs(lumaEndN) >= gradientScaled; + doneP = abs(lumaEndP) >= gradientScaled; + if(!doneN) posN.x -= offNP.x * FXAA_QUALITY__P8; + if(!doneN) posN.y -= offNP.y * FXAA_QUALITY__P8; + doneNP = (!doneN) || (!doneP); + if(!doneP) posP.x += offNP.x * FXAA_QUALITY__P8; + if(!doneP) posP.y += offNP.y * FXAA_QUALITY__P8; +/*--------------------------------------------------------------------------*/ + #if (FXAA_QUALITY__PS > 9) + if(doneNP) { + if(!doneN) lumaEndN = FxaaLuma(FxaaTexTop(tex, posN.xy)); + if(!doneP) lumaEndP = FxaaLuma(FxaaTexTop(tex, posP.xy)); + if(!doneN) lumaEndN = lumaEndN - lumaNN * 0.5; + if(!doneP) lumaEndP = lumaEndP - lumaNN * 0.5; + doneN = abs(lumaEndN) >= gradientScaled; + doneP = abs(lumaEndP) >= gradientScaled; + if(!doneN) posN.x -= offNP.x * FXAA_QUALITY__P9; + if(!doneN) posN.y -= offNP.y * FXAA_QUALITY__P9; + doneNP = (!doneN) || (!doneP); + if(!doneP) posP.x += offNP.x * FXAA_QUALITY__P9; + if(!doneP) posP.y += offNP.y * FXAA_QUALITY__P9; +/*--------------------------------------------------------------------------*/ + #if (FXAA_QUALITY__PS > 10) + if(doneNP) { + if(!doneN) lumaEndN = FxaaLuma(FxaaTexTop(tex, posN.xy)); + if(!doneP) lumaEndP = FxaaLuma(FxaaTexTop(tex, posP.xy)); + if(!doneN) lumaEndN = lumaEndN - lumaNN * 0.5; + if(!doneP) lumaEndP = lumaEndP - lumaNN * 0.5; + doneN = abs(lumaEndN) >= gradientScaled; + doneP = abs(lumaEndP) >= gradientScaled; + if(!doneN) posN.x -= offNP.x * FXAA_QUALITY__P10; + if(!doneN) posN.y -= offNP.y * FXAA_QUALITY__P10; + doneNP = (!doneN) || (!doneP); + if(!doneP) posP.x += offNP.x * FXAA_QUALITY__P10; + if(!doneP) posP.y += offNP.y * FXAA_QUALITY__P10; +/*--------------------------------------------------------------------------*/ + #if (FXAA_QUALITY__PS > 11) + if(doneNP) { + if(!doneN) lumaEndN = FxaaLuma(FxaaTexTop(tex, posN.xy)); + if(!doneP) lumaEndP = FxaaLuma(FxaaTexTop(tex, posP.xy)); + if(!doneN) lumaEndN = lumaEndN - lumaNN * 0.5; + if(!doneP) lumaEndP = lumaEndP - lumaNN * 0.5; + doneN = abs(lumaEndN) >= gradientScaled; + doneP = abs(lumaEndP) >= gradientScaled; + if(!doneN) posN.x -= offNP.x * FXAA_QUALITY__P11; + if(!doneN) posN.y -= offNP.y * FXAA_QUALITY__P11; + doneNP = (!doneN) || (!doneP); + if(!doneP) posP.x += offNP.x * FXAA_QUALITY__P11; + if(!doneP) posP.y += offNP.y * FXAA_QUALITY__P11; +/*--------------------------------------------------------------------------*/ + #if (FXAA_QUALITY__PS > 12) + if(doneNP) { + if(!doneN) lumaEndN = FxaaLuma(FxaaTexTop(tex, posN.xy)); + if(!doneP) lumaEndP = FxaaLuma(FxaaTexTop(tex, posP.xy)); + if(!doneN) lumaEndN = lumaEndN - lumaNN * 0.5; + if(!doneP) lumaEndP = lumaEndP - lumaNN * 0.5; + doneN = abs(lumaEndN) >= gradientScaled; + doneP = abs(lumaEndP) >= gradientScaled; + if(!doneN) posN.x -= offNP.x * FXAA_QUALITY__P12; + if(!doneN) posN.y -= offNP.y * FXAA_QUALITY__P12; + doneNP = (!doneN) || (!doneP); + if(!doneP) posP.x += offNP.x * FXAA_QUALITY__P12; + if(!doneP) posP.y += offNP.y * FXAA_QUALITY__P12; +/*--------------------------------------------------------------------------*/ + } + #endif +/*--------------------------------------------------------------------------*/ + } + #endif +/*--------------------------------------------------------------------------*/ + } + #endif +/*--------------------------------------------------------------------------*/ + } + #endif +/*--------------------------------------------------------------------------*/ + } + #endif +/*--------------------------------------------------------------------------*/ + } + #endif +/*--------------------------------------------------------------------------*/ + } + #endif +/*--------------------------------------------------------------------------*/ + } + #endif +/*--------------------------------------------------------------------------*/ + } + #endif +/*--------------------------------------------------------------------------*/ + } + #endif +/*--------------------------------------------------------------------------*/ + } +/*--------------------------------------------------------------------------*/ + FxaaFloat dstN = posM.x - posN.x; + FxaaFloat dstP = posP.x - posM.x; + if(!horzSpan) dstN = posM.y - posN.y; + if(!horzSpan) dstP = posP.y - posM.y; +/*--------------------------------------------------------------------------*/ + FxaaBool goodSpanN = (lumaEndN < 0.0) != lumaMLTZero; + FxaaFloat spanLength = (dstP + dstN); + FxaaBool goodSpanP = (lumaEndP < 0.0) != lumaMLTZero; + FxaaFloat spanLengthRcp = 1.0/spanLength; +/*--------------------------------------------------------------------------*/ + FxaaBool directionN = dstN < dstP; + FxaaFloat dst = min(dstN, dstP); + FxaaBool goodSpan = directionN ? goodSpanN : goodSpanP; + FxaaFloat subpixG = subpixF * subpixF; + FxaaFloat pixelOffset = (dst * (-spanLengthRcp)) + 0.5; + FxaaFloat subpixH = subpixG * fxaaQualitySubpix; +/*--------------------------------------------------------------------------*/ + FxaaFloat pixelOffsetGood = goodSpan ? pixelOffset : 0.0; + FxaaFloat pixelOffsetSubpix = max(pixelOffsetGood, subpixH); + if(!horzSpan) posM.x += pixelOffsetSubpix * lengthSign; + if( horzSpan) posM.y += pixelOffsetSubpix * lengthSign; + #if (FXAA_DISCARD == 1) + return FxaaTexTop(tex, posM); + #else + return FxaaFloat4(FxaaTexTop(tex, posM).xyz, lumaM); + #endif +} + +uniform vec2 ReciprocalResolution; + +void main() +{ + FragColor = FxaaPixelShader(TexCoord, InputTexture, ReciprocalResolution, 0.75f, 0.166f, 0.0833f); +} + +#endif // FXAA_LUMA_PASS