Skip to content

Commit

Permalink
FXAA
Browse files Browse the repository at this point in the history
  • Loading branch information
jpcy committed Feb 8, 2016
1 parent 4403cc8 commit 198fd4d
Show file tree
Hide file tree
Showing 5 changed files with 184 additions and 29 deletions.
11 changes: 9 additions & 2 deletions code/renderer_bgfx/Main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -407,7 +407,14 @@ void Main::renderScene(const refdef_t *def)

// Tonemap the scene framebuffer color.
bgfx::setTexture(MaterialTextureBundleIndex::DiffuseMap, matStageUniforms_->diffuseMap.handle, sceneFbColor_);
renderFullscreenQuad(defaultFb_, ShaderProgramId::Fullscreen_ToneMap, BGFX_STATE_RGB_WRITE, isTextureOriginBottomLeft_);
renderFullscreenQuad(aa_ == AntiAliasing::FXAA ? fxaaFb_ : defaultFb_, ShaderProgramId::Fullscreen_ToneMap, BGFX_STATE_RGB_WRITE, isTextureOriginBottomLeft_);

// FXAA.
if (aa_ == AntiAliasing::FXAA)
{
bgfx::setTexture(MaterialTextureBundleIndex::DiffuseMap, matStageUniforms_->diffuseMap.handle, fxaaColor_);
renderFullscreenQuad(defaultFb_, ShaderProgramId::Fullscreen_FXAA, BGFX_STATE_RGB_WRITE, isTextureOriginBottomLeft_);
}
}
}

Expand Down Expand Up @@ -838,7 +845,7 @@ void Main::renderCamera(uint8_t visCacheId, vec3 pvsPosition, vec3 position, mat

SetDrawCallGeometry(dc);
bgfx::setTransform(dc.modelMatrix.get());
uint64_t state = BGFX_STATE_DEPTH_TEST_LESS | BGFX_STATE_DEPTH_WRITE | BGFX_STATE_MSAA;
uint64_t state = BGFX_STATE_DEPTH_TEST_LESS | BGFX_STATE_DEPTH_WRITE;

// Grab the cull state. Doesn't matter which stage, since it's global to the material.
state |= mat->stages[0].getState() & BGFX_STATE_CULL_MASK;
Expand Down
45 changes: 21 additions & 24 deletions code/renderer_bgfx/Main_init.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,8 @@ void WarnOnce(WarnOnceId::Enum id)

ConsoleVariables::ConsoleVariables()
{
aa = ri.Cvar_Get("r_aa", "", CVAR_ARCHIVE | CVAR_LATCH);
ri.Cvar_SetDescription(aa, "<empty> None\nfxaa Fast Approximate Anti-Aliasing (FXAA v2)\n");
backend = ri.Cvar_Get("r_backend", "", CVAR_ARCHIVE | CVAR_LATCH);

{
Expand All @@ -109,7 +111,7 @@ ConsoleVariables::ConsoleVariables()

#define FORMAT "%-10s%s\n"
std::string description;
description += va(FORMAT, "", "Autodetect");
description += va(FORMAT, "<empty>", "Autodetect");

for (const BackendMap &map : backendMaps)
{
Expand All @@ -132,7 +134,6 @@ ConsoleVariables::ConsoleVariables()
bgfx_stats = ri.Cvar_Get("r_bgfx_stats", "0", CVAR_CHEAT);
debugText = ri.Cvar_Get("r_debugText", "0", CVAR_CHEAT);
maxAnisotropy = ri.Cvar_Get("r_maxAnisotropy", "0", CVAR_ARCHIVE | CVAR_LATCH);
msaa = ri.Cvar_Get("r_msaa", "4", CVAR_ARCHIVE | CVAR_LATCH);
overBrightBits = ri.Cvar_Get ("r_overBrightBits", "1", CVAR_ARCHIVE | CVAR_LATCH);
picmip = ri.Cvar_Get("r_picmip", "0", CVAR_ARCHIVE | CVAR_LATCH);
ri.Cvar_CheckRange(picmip, 0, 16, qtrue);
Expand Down Expand Up @@ -338,23 +339,6 @@ void Main::initialize()
resetFlags |= BGFX_RESET_MAXANISOTROPY;
}

if (cvars.msaa->integer == 2)
{
resetFlags |= BGFX_RESET_MSAA_X2;
}
else if (cvars.msaa->integer == 4)
{
resetFlags |= BGFX_RESET_MSAA_X4;
}
else if (cvars.msaa->integer == 8)
{
resetFlags |= BGFX_RESET_MSAA_X8;
}
else if (cvars.msaa->integer == 16)
{
resetFlags |= BGFX_RESET_MSAA_X16;
}

bgfx::reset(glConfig.vidWidth, glConfig.vidHeight, resetFlags);
const bgfx::Caps *caps = bgfx::getCaps();

Expand Down Expand Up @@ -385,6 +369,7 @@ void Main::initialize()
fragMem[FragmentShaderId::Depth_AlphaTest] = MR(Depth_AlphaTest_fragment_##backend); \
fragMem[FragmentShaderId::Fog] = MR(Fog_fragment_##backend); \
fragMem[FragmentShaderId::Fullscreen_Blit] = MR(Fullscreen_Blit_fragment_##backend); \
fragMem[FragmentShaderId::Fullscreen_FXAA] = MR(Fullscreen_FXAA_fragment_##backend); \
fragMem[FragmentShaderId::Fullscreen_LinearDepth] = MR(Fullscreen_LinearDepth_fragment_##backend); \
fragMem[FragmentShaderId::Fullscreen_ToneMap] = MR(Fullscreen_ToneMap_fragment_##backend); \
fragMem[FragmentShaderId::Generic] = MR(Generic_fragment_##backend); \
Expand Down Expand Up @@ -416,6 +401,7 @@ void Main::initialize()
fragMap[ShaderProgramId::Depth_AlphaTest] = FragmentShaderId::Depth_AlphaTest;
fragMap[ShaderProgramId::Fog] = FragmentShaderId::Fog;
fragMap[ShaderProgramId::Fullscreen_Blit] = FragmentShaderId::Fullscreen_Blit;
fragMap[ShaderProgramId::Fullscreen_FXAA] = FragmentShaderId::Fullscreen_FXAA;
fragMap[ShaderProgramId::Fullscreen_LinearDepth] = FragmentShaderId::Fullscreen_LinearDepth;
fragMap[ShaderProgramId::Fullscreen_ToneMap] = FragmentShaderId::Fullscreen_ToneMap;
fragMap[ShaderProgramId::Generic] = FragmentShaderId::Generic;
Expand All @@ -428,6 +414,7 @@ void Main::initialize()
vertMap[ShaderProgramId::Depth_AlphaTest] = VertexShaderId::Depth_AlphaTest;
vertMap[ShaderProgramId::Fog] = VertexShaderId::Fog;
vertMap[ShaderProgramId::Fullscreen_Blit] = VertexShaderId::Fullscreen;
vertMap[ShaderProgramId::Fullscreen_FXAA] = VertexShaderId::Fullscreen;
vertMap[ShaderProgramId::Fullscreen_LinearDepth] = VertexShaderId::Fullscreen;
vertMap[ShaderProgramId::Fullscreen_ToneMap] = VertexShaderId::Fullscreen;
vertMap[ShaderProgramId::Generic] = VertexShaderId::Generic;
Expand Down Expand Up @@ -464,15 +451,25 @@ void Main::initialize()
ri.Error(ERR_DROP, "Error creating shader program");
}

// Parse anti-aliasing cvar.
aa_ = Q_stricmp(cvars.aa->string, "fxaa") == 0 ? AntiAliasing::FXAA : AntiAliasing::None;

// FXAA frame buffer.
if (aa_ == AntiAliasing::FXAA)
{
fxaaColor_ = bgfx::createTexture2D(bgfx::BackbufferRatio::Equal, 1, bgfx::TextureFormat::BGRA8, BGFX_TEXTURE_RT | BGFX_TEXTURE_U_CLAMP | BGFX_TEXTURE_V_CLAMP);
fxaaFb_.handle = bgfx::createFrameBuffer(1, &fxaaColor_, true);
}

// Linear depth frame buffer.
linearDepthFb_.handle = bgfx::createFrameBuffer(bgfx::BackbufferRatio::Equal, bgfx::TextureFormat::R16F);

// Scene frame buffer.
sceneFbColor_ = bgfx::createTexture2D(glConfig.vidWidth, glConfig.vidHeight, 1, bgfx::TextureFormat::RGBA16F, BGFX_TEXTURE_RT|BGFX_TEXTURE_U_CLAMP|BGFX_TEXTURE_V_CLAMP);
sceneFbDepth_ = bgfx::createTexture2D(glConfig.vidWidth, glConfig.vidHeight, 1, bgfx::TextureFormat::D24, BGFX_TEXTURE_RT);
sceneFbColor_ = bgfx::createTexture2D(bgfx::BackbufferRatio::Equal, 1, bgfx::TextureFormat::RGBA16F, BGFX_TEXTURE_RT | BGFX_TEXTURE_U_CLAMP | BGFX_TEXTURE_V_CLAMP);
sceneFbDepth_ = bgfx::createTexture2D(bgfx::BackbufferRatio::Equal, 1, bgfx::TextureFormat::D24, BGFX_TEXTURE_RT);
bgfx::TextureHandle sceneTextures[] = { sceneFbColor_, sceneFbDepth_ };
sceneFb_.handle = bgfx::createFrameBuffer(2, sceneTextures, true);

// Linear depth frame buffer.
linearDepthFb_.handle = bgfx::createFrameBuffer(glConfig.vidWidth, glConfig.vidHeight, bgfx::TextureFormat::R16F);

// Dynamic lights.
// Calculate the smallest square POT texture size to fit the dynamic lights data.
const int sr = (int)ceil(sqrtf(maxDynamicLights_ * sizeof(DynamicLight) / 4.0f));
Expand Down
17 changes: 14 additions & 3 deletions code/renderer_bgfx/Precompiled.h
Original file line number Diff line number Diff line change
Expand Up @@ -96,11 +96,11 @@ struct ConsoleVariables
{
ConsoleVariables();

cvar_t *aa;
cvar_t *backend;
cvar_t *bgfx_stats;
cvar_t *debugText;
cvar_t *maxAnisotropy;
cvar_t *msaa;
cvar_t *overBrightBits;
cvar_t *picmip;
cvar_t *screenshotJpegQuality;
Expand Down Expand Up @@ -188,7 +188,7 @@ struct DrawCall
mat4 modelMatrix = mat4::identity;
float softSpriteDepth = 0;
uint8_t sort = 0;
uint64_t state = BGFX_STATE_RGB_WRITE | BGFX_STATE_ALPHA_WRITE | BGFX_STATE_MSAA;
uint64_t state = BGFX_STATE_RGB_WRITE | BGFX_STATE_ALPHA_WRITE;
VertexBuffer vb;
float zOffset = 0.0f;
float zScale = 1.0f;
Expand Down Expand Up @@ -1367,6 +1367,7 @@ class Main
Depth_AlphaTest,
Fog,
Fullscreen_Blit,
Fullscreen_FXAA,
Fullscreen_LinearDepth,
Fullscreen_ToneMap,
Generic,
Expand Down Expand Up @@ -1400,6 +1401,7 @@ class Main
Depth_AlphaTest,
Fog,
Fullscreen_Blit,
Fullscreen_FXAA,
Fullscreen_LinearDepth,
Fullscreen_ToneMap,
Generic,
Expand Down Expand Up @@ -1474,10 +1476,12 @@ class Main
/// @name Framebuffers
/// @{
static const FrameBuffer defaultFb_;
FrameBuffer fxaaFb_;
bgfx::TextureHandle fxaaColor_;
FrameBuffer linearDepthFb_;
FrameBuffer sceneFb_;
bgfx::TextureHandle sceneFbColor_;
bgfx::TextureHandle sceneFbDepth_;
FrameBuffer linearDepthFb_;
/// @}

/// @name Game-specific hacks
Expand Down Expand Up @@ -1530,6 +1534,13 @@ class Main
std::unique_ptr<Uniforms_MaterialStage> matStageUniforms_;
/// @}

enum class AntiAliasing
{
None,
FXAA
};

AntiAliasing aa_;
const Entity *currentEntity_ = nullptr;
float halfTexelOffset_ = 0;
bool isTextureOriginBottomLeft_ = false;
Expand Down
1 change: 1 addition & 0 deletions premake5.lua
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ newaction
compileShader(BGFX_PATH, "Fog", "fragment")
compileShader(BGFX_PATH, "Fog", "vertex")
compileShader(BGFX_PATH, "Fullscreen_Blit", "fragment")
compileShader(BGFX_PATH, "Fullscreen_FXAA", "fragment")
compileShader(BGFX_PATH, "Fullscreen_LinearDepth", "fragment")
compileShader(BGFX_PATH, "Fullscreen_ToneMap", "fragment")
compileShader(BGFX_PATH, "Fullscreen", "vertex")
Expand Down
139 changes: 139 additions & 0 deletions shaders/Fullscreen_FXAA_fragment.sc
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
$input v_texcoord0

#include <bgfx_shader.sh>

SAMPLER2D(u_DiffuseMap, 0);

/**
Basic FXAA implementation based on the code on geeks3d.com with the
modification that the texture2DLod stuff was removed since it's
unsupported by WebGL.
--
From:
https://github.com/mitsuhiko/webgl-meincraft
Copyright (c) 2011 by Armin Ronacher.
Some 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.
* The names of the contributors may not be used to endorse or
promote products derived from this software without specific
prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"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.
*/

#ifndef FXAA_REDUCE_MIN
#define FXAA_REDUCE_MIN (1.0/ 128.0)
#endif
#ifndef FXAA_REDUCE_MUL
#define FXAA_REDUCE_MUL (1.0 / 8.0)
#endif
#ifndef FXAA_SPAN_MAX
#define FXAA_SPAN_MAX 8.0
#endif

//optimized version for mobile, where dependent
//texture reads can be a bottleneck
vec4 fxaa(sampler2D tex, vec2 fragCoord, vec2 resolution,
vec2 v_rgbNW, vec2 v_rgbNE,
vec2 v_rgbSW, vec2 v_rgbSE,
vec2 v_rgbM) {
vec4 color;
mediump vec2 inverseVP = vec2(1.0 / resolution.x, 1.0 / resolution.y);
vec3 rgbNW = texture2D(tex, v_rgbNW).xyz;
vec3 rgbNE = texture2D(tex, v_rgbNE).xyz;
vec3 rgbSW = texture2D(tex, v_rgbSW).xyz;
vec3 rgbSE = texture2D(tex, v_rgbSE).xyz;
vec4 texColor = texture2D(tex, v_rgbM);
vec3 rgbM = texColor.xyz;
vec3 luma = vec3(0.299, 0.587, 0.114);
float lumaNW = dot(rgbNW, luma);
float lumaNE = dot(rgbNE, luma);
float lumaSW = dot(rgbSW, luma);
float lumaSE = dot(rgbSE, luma);
float lumaM = dot(rgbM, luma);
float lumaMin = min(lumaM, min(min(lumaNW, lumaNE), min(lumaSW, lumaSE)));
float lumaMax = max(lumaM, max(max(lumaNW, lumaNE), max(lumaSW, lumaSE)));

mediump vec2 dir;
dir.x = -((lumaNW + lumaNE) - (lumaSW + lumaSE));
dir.y = ((lumaNW + lumaSW) - (lumaNE + lumaSE));

float dirReduce = max((lumaNW + lumaNE + lumaSW + lumaSE) *
(0.25 * FXAA_REDUCE_MUL), FXAA_REDUCE_MIN);

float rcpDirMin = 1.0 / (min(abs(dir.x), abs(dir.y)) + dirReduce);
dir = min(vec2(FXAA_SPAN_MAX, FXAA_SPAN_MAX),
max(vec2(-FXAA_SPAN_MAX, -FXAA_SPAN_MAX),
dir * rcpDirMin)) * inverseVP;

vec3 rgbA = 0.5 * (
texture2D(tex, fragCoord * inverseVP + dir * (1.0 / 3.0 - 0.5)).xyz +
texture2D(tex, fragCoord * inverseVP + dir * (2.0 / 3.0 - 0.5)).xyz);
vec3 rgbB = rgbA * 0.5 + 0.25 * (
texture2D(tex, fragCoord * inverseVP + dir * -0.5).xyz +
texture2D(tex, fragCoord * inverseVP + dir * 0.5).xyz);

float lumaB = dot(rgbB, luma);
if ((lumaB < lumaMin) || (lumaB > lumaMax))
color = vec4(rgbA, texColor.a);
else
color = vec4(rgbB, texColor.a);
return color;
}

void texcoords(vec2 fragCoord, vec2 resolution,
out vec2 v_rgbNW, out vec2 v_rgbNE,
out vec2 v_rgbSW, out vec2 v_rgbSE,
out vec2 v_rgbM) {
vec2 inverseVP = 1.0 / resolution.xy;
v_rgbNW = (fragCoord + vec2(-1.0, -1.0)) * inverseVP;
v_rgbNE = (fragCoord + vec2(1.0, -1.0)) * inverseVP;
v_rgbSW = (fragCoord + vec2(-1.0, 1.0)) * inverseVP;
v_rgbSE = (fragCoord + vec2(1.0, 1.0)) * inverseVP;
v_rgbM = vec2(fragCoord * inverseVP);
}

vec4 apply(sampler2D tex, vec2 fragCoord, vec2 resolution) {
mediump vec2 v_rgbNW;
mediump vec2 v_rgbNE;
mediump vec2 v_rgbSW;
mediump vec2 v_rgbSE;
mediump vec2 v_rgbM;

//compute the texture coords
texcoords(fragCoord, resolution, v_rgbNW, v_rgbNE, v_rgbSW, v_rgbSE, v_rgbM);

//compute FXAA
return fxaa(tex, fragCoord, resolution, v_rgbNW, v_rgbNE, v_rgbSW, v_rgbSE, v_rgbM);
}

void main()
{
gl_FragColor = apply(u_DiffuseMap, v_texcoord0 * u_viewRect.zw, u_viewRect.zw);
}

0 comments on commit 198fd4d

Please sign in to comment.