diff --git a/src/gl_framebuffer.c b/src/gl_framebuffer.c index ce6eb0603..4d6248129 100644 --- a/src/gl_framebuffer.c +++ b/src/gl_framebuffer.c @@ -1001,3 +1001,13 @@ void GL_FramebufferDeleteAll(void) GL_FramebufferEnsureDeleted(i); } } + +int GL_FramebufferFxaaPreset(void) +{ + static const int fxaa_cvar_to_preset[18] = { + 0, 10, 11, 12, 13, 14, 15, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 39 + }; + extern cvar_t vid_framebuffer_fxaa; + + return fxaa_cvar_to_preset[bound(0, vid_framebuffer_fxaa.integer, 17)]; +} diff --git a/src/gl_framebuffer.h b/src/gl_framebuffer.h index 03d78a2b5..87d822b35 100644 --- a/src/gl_framebuffer.h +++ b/src/gl_framebuffer.h @@ -63,6 +63,7 @@ qbool GL_FramebufferEndWorldNormals(framebuffer_id id); int GL_FramebufferMultisamples(framebuffer_id framebuffer); void GL_FramebufferDeleteAll(void); +int GL_FramebufferFxaaPreset(void); #define USE_FRAMEBUFFER_SCREEN 1 #define USE_FRAMEBUFFER_3DONLY 2 diff --git a/src/glc_framebuffer.c b/src/glc_framebuffer.c index ceb0f0ed0..f08da070d 100644 --- a/src/glc_framebuffer.c +++ b/src/glc_framebuffer.c @@ -39,18 +39,21 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #define POST_PROCESS_PALETTE 1 #define POST_PROCESS_3DONLY 2 +#define POST_PROCESS_FXAA 4 static texture_ref non_framebuffer_screen_texture; qbool GLC_CompilePostProcessProgram(void) { extern cvar_t vid_software_palette, vid_framebuffer; + int fxaa_preset = GL_FramebufferFxaaPreset(); int post_process_flags = (vid_software_palette.integer ? POST_PROCESS_PALETTE : 0) | - (vid_framebuffer.integer == USE_FRAMEBUFFER_3DONLY ? POST_PROCESS_3DONLY : 0); + (vid_framebuffer.integer == USE_FRAMEBUFFER_3DONLY ? POST_PROCESS_3DONLY : 0) | + (fxaa_preset > 0 ? POST_PROCESS_FXAA : 0) | (fxaa_preset << 4); // mix in preset to detect change if (R_ProgramRecompileNeeded(r_program_post_process_glc, post_process_flags)) { - static char included_definitions[512]; + static char included_definitions[131072]; memset(included_definitions, 0, sizeof(included_definitions)); if (post_process_flags & POST_PROCESS_PALETTE) { @@ -59,6 +62,39 @@ qbool GLC_CompilePostProcessProgram(void) if (post_process_flags & POST_PROCESS_3DONLY) { strlcat(included_definitions, "#define EZ_POSTPROCESS_OVERLAY\n", sizeof(included_definitions)); } + if (post_process_flags & POST_PROCESS_FXAA) { + qbool supported = true; + if (!SDL_GL_ExtensionSupported("GL_EXT_gpu_shader4")) + { + Com_Printf("WARNING: Missing GL_EXT_gpu_shader4, FXAA not available."); + supported = false; + } +#ifndef __APPLE__ + if (!SDL_GL_ExtensionSupported("GL_ARB_gpu_shader5")) + { + Com_Printf("WARNING: Missing GL_ARB_gpu_shader5, FXAA not available."); + supported = false; + } +#endif + if (supported) + { + extern const unsigned char fxaa_h_glsl[]; + char buffer[33]; + const char *settings = + "#extension GL_EXT_gpu_shader4 : enable\n" +#ifndef __APPLE__ + "#extension GL_ARB_gpu_shader5 : enable\n" +#endif + "#define EZ_POSTPROCESS_FXAA\n" + "#define FXAA_PC 1\n" + "#define FXAA_GLSL_120 1\n" + "#define FXAA_GREEN_AS_LUMA 1\n"; + snprintf(buffer, sizeof(buffer), "#define FXAA_QUALITY__PRESET %d\n", fxaa_preset); + strlcat(included_definitions, settings, sizeof(included_definitions)); + strlcat(included_definitions, buffer, sizeof(included_definitions)); + strlcat(included_definitions, (const char *)fxaa_h_glsl, sizeof(included_definitions)); + } + } // Initialise program for drawing image R_ProgramCompileWithInclude(r_program_post_process_glc, included_definitions); diff --git a/src/glm_framebuffer.c b/src/glm_framebuffer.c index 5d9031e0e..79637fd1d 100644 --- a/src/glm_framebuffer.c +++ b/src/glm_framebuffer.c @@ -43,7 +43,6 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #define POST_PROCESS_FXAA 8 extern cvar_t vid_software_palette, vid_framebuffer, vid_framebuffer_hdr, vid_framebuffer_hdr_tonemap, vid_framebuffer_multisample; -extern cvar_t vid_framebuffer_fxaa; static texture_ref non_framebuffer_screen_texture; qbool GLM_CompilePostProcessVAO(void) @@ -82,19 +81,15 @@ qbool GLM_CompilePostProcessVAO(void) return R_VertexArrayCreated(vao_postprocess); } -static const int fxaa_cvar_to_preset[18] = { - 0, 10, 11, 12, 13, 14, 15, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 39 -}; - // If this returns false then the framebuffer will be blitted instead qbool GLM_CompilePostProcessProgram(void) { - int fxaa_preset = fxaa_cvar_to_preset[bound(0, vid_framebuffer_fxaa.integer, 17)]; + int fxaa_preset = GL_FramebufferFxaaPreset(); int post_process_flags = (vid_software_palette.integer ? POST_PROCESS_PALETTE : 0) | (vid_framebuffer.integer == USE_FRAMEBUFFER_3DONLY ? POST_PROCESS_3DONLY : 0) | (vid_framebuffer_hdr.integer && vid_framebuffer_hdr_tonemap.integer ? POST_PROCESS_TONEMAP : 0) | - (vid_framebuffer_fxaa.integer ? POST_PROCESS_FXAA : 0) | (fxaa_preset << 4); // mix in preset to detect change + (fxaa_preset > 0 ? POST_PROCESS_FXAA : 0) | (fxaa_preset << 4); // mix in preset to detect change if (R_ProgramRecompileNeeded(r_program_post_process, post_process_flags)) { static char included_definitions[131072]; diff --git a/src/glsl/glc/glc_post_process_screen.fragment.glsl b/src/glsl/glc/glc_post_process_screen.fragment.glsl index 8de7ab230..2b7a85d06 100644 --- a/src/glsl/glc/glc_post_process_screen.fragment.glsl +++ b/src/glsl/glc/glc_post_process_screen.fragment.glsl @@ -13,9 +13,46 @@ uniform float contrast; varying vec2 TextureCoord; +vec4 sampleBase(void) +{ +#ifdef EZ_POSTPROCESS_FXAA + // This is technically not the correct place to apply FXAA as it should sample + // a tonemapped, and gamma adjusted texture. However, the rendering pipeline + // prohibits this as this post_process_screen shader performs both tonemapping + // gamma, as well as combining HUD and world textures, so placing FXAA after + // this shader would apply FXAA to the HUD as well, which is detrimental. + // As it happens, applying FXAA to the world before tonemapping and gamma still + // looks ok, so it's still valuable without shuffling around shaders. + // Should world tonemap and gamma be broken out to a separate shader at some point + // that shader would ideally then also populate luma in the alpha channel, to be + // used by the FXAA algorithm instead of relying on green channel. + return FxaaPixelShader( + TextureCoord, // FxaaFloat2 pos, + FxaaFloat4(0.0f, 0.0f, 0.0f, 0.0f), // FxaaFloat4 fxaaConsolePosPos, + base, // FxaaTex tex, + base, // FxaaTex fxaaConsole360TexExpBiasNegOne, + base, // FxaaTex fxaaConsole360TexExpBiasNegTwo, + vec2(1.0/1280.0, 1.0/720.0), // FxaaFloat2 fxaaQualityRcpFrame, + FxaaFloat4(0.0f, 0.0f, 0.0f, 0.0f), // FxaaFloat4 fxaaConsoleRcpFrameOpt, + FxaaFloat4(0.0f, 0.0f, 0.0f, 0.0f), // FxaaFloat4 fxaaConsoleRcpFrameOpt2, + FxaaFloat4(0.0f, 0.0f, 0.0f, 0.0f), // FxaaFloat4 fxaaConsole360RcpFrameOpt2, + 0.75f, // FxaaFloat fxaaQualitySubpix (default), + 0.166f, // FxaaFloat fxaaQualityEdgeThreshold (default), + 0.0f, // FxaaFloat fxaaQualityEdgeThresholdMin (default if green as luma), + 0.0f, // FxaaFloat fxaaConsoleEdgeSharpness, + 0.0f, // FxaaFloat fxaaConsoleEdgeThreshold, + 0.0f, // FxaaFloat fxaaConsoleEdgeThresholdMin, + FxaaFloat4(0.0f, 0.0f, 0.0f, 0.0f) // FxaaFloat4 fxaaConsole360ConstDir, + ); +#else + return texture2D(base, TextureCoord); +#endif +} + + void main() { - vec4 frag_colour = texture2D(base, TextureCoord); + vec4 frag_colour = sampleBase(); #ifdef EZ_POSTPROCESS_OVERLAY vec4 add = texture2D(overlay, TextureCoord);