OpenGL: Implement FXAA
This commit is contained in:
		 Marshall Mohror
					Marshall Mohror
				
			
				
					committed by
					
						 Fernando Sahmkow
						Fernando Sahmkow
					
				
			
			
				
	
			
			
			 Fernando Sahmkow
						Fernando Sahmkow
					
				
			
						parent
						
							74e39ed6ee
						
					
				
				
					commit
					48cf376462
				
			| @@ -13,6 +13,8 @@ set(SHADER_FILES | ||||
|     convert_depth_to_float.frag | ||||
|     convert_float_to_depth.frag | ||||
|     full_screen_triangle.vert | ||||
|     fxaa.frag | ||||
|     fxaa.vert | ||||
|     opengl_copy_bc4.comp | ||||
|     opengl_present.frag | ||||
|     opengl_present.vert | ||||
|   | ||||
							
								
								
									
										72
									
								
								src/video_core/host_shaders/fxaa.frag
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										72
									
								
								src/video_core/host_shaders/fxaa.frag
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,72 @@ | ||||
| // Adapted from | ||||
| // https://www.geeks3d.com/20110405/fxaa-fast-approximate-anti-aliasing-demo-glsl-opengl-test-radeon-geforce/3/ | ||||
|  | ||||
| #version 460 | ||||
|  | ||||
| #ifdef VULKAN | ||||
|  | ||||
| #define BINDING_COLOR_TEXTURE 1 | ||||
|  | ||||
| #else // ^^^ Vulkan ^^^ // vvv OpenGL vvv | ||||
|  | ||||
| #define BINDING_COLOR_TEXTURE 0 | ||||
|  | ||||
| #endif | ||||
|  | ||||
| layout (location = 0) in vec4 posPos; | ||||
|  | ||||
| layout (location = 0) out vec4 frag_color; | ||||
|  | ||||
| layout (binding = BINDING_COLOR_TEXTURE) uniform sampler2D input_texture; | ||||
|  | ||||
| const float FXAA_SPAN_MAX = 8.0; | ||||
| const float FXAA_REDUCE_MUL = 1.0 / 8.0; | ||||
| const float FXAA_REDUCE_MIN = 1.0 / 128.0; | ||||
|  | ||||
| #define FxaaTexLod0(t, p) textureLod(t, p, 0.0) | ||||
| #define FxaaTexOff(t, p, o) textureLodOffset(t, p, 0.0, o) | ||||
|  | ||||
| vec3 FxaaPixelShader(vec4 posPos, sampler2D tex) { | ||||
|  | ||||
|     vec3 rgbNW = FxaaTexLod0(tex, posPos.zw).xyz; | ||||
|     vec3 rgbNE = FxaaTexOff(tex, posPos.zw, ivec2(1,0)).xyz; | ||||
|     vec3 rgbSW = FxaaTexOff(tex, posPos.zw, ivec2(0,1)).xyz; | ||||
|     vec3 rgbSE = FxaaTexOff(tex, posPos.zw, ivec2(1,1)).xyz; | ||||
|     vec3 rgbM  = FxaaTexLod0(tex, posPos.xy).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))); | ||||
| /*---------------------------------------------------------*/ | ||||
|     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)) / textureSize(tex, 0); | ||||
| /*--------------------------------------------------------*/ | ||||
|     vec3 rgbA = (1.0 / 2.0) * ( | ||||
|         FxaaTexLod0(tex, posPos.xy + dir * (1.0 / 3.0 - 0.5)).xyz + | ||||
|         FxaaTexLod0(tex, posPos.xy + dir * (2.0 / 3.0 - 0.5)).xyz); | ||||
|     vec3 rgbB = rgbA * (1.0 / 2.0) + (1.0 / 4.0) * ( | ||||
|         FxaaTexLod0(tex, posPos.xy + dir * (0.0 / 3.0 - 0.5)).xyz + | ||||
|         FxaaTexLod0(tex, posPos.xy + dir * (3.0 / 3.0 - 0.5)).xyz); | ||||
|     float lumaB = dot(rgbB, luma); | ||||
|     if((lumaB < lumaMin) || (lumaB > lumaMax)) return rgbA; | ||||
|     return rgbB; | ||||
| } | ||||
|  | ||||
| void main() { | ||||
|   frag_color = vec4(FxaaPixelShader(posPos, input_texture), 1.0); | ||||
| } | ||||
							
								
								
									
										40
									
								
								src/video_core/host_shaders/fxaa.vert
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										40
									
								
								src/video_core/host_shaders/fxaa.vert
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,40 @@ | ||||
| // Copyright 2019 yuzu Emulator Project | ||||
| // Licensed under GPLv2 or any later version | ||||
| // Refer to the license.txt file included. | ||||
|  | ||||
| #version 460 | ||||
|  | ||||
| out gl_PerVertex { | ||||
|     vec4 gl_Position; | ||||
| }; | ||||
|  | ||||
| const vec2 vertices[4] = | ||||
|     vec2[4](vec2(-1.0, 1.0), vec2(1.0, 1.0), vec2(-1.0, -1.0), vec2(1.0, -1.0)); | ||||
|  | ||||
| layout (location = 0) out vec4 posPos; | ||||
|  | ||||
| #ifdef VULKAN | ||||
|  | ||||
| #define BINDING_COLOR_TEXTURE 1 | ||||
|  | ||||
| #else // ^^^ Vulkan ^^^ // vvv OpenGL vvv | ||||
|  | ||||
| #define BINDING_COLOR_TEXTURE 0 | ||||
|  | ||||
| #endif | ||||
|  | ||||
| layout (binding = BINDING_COLOR_TEXTURE) uniform sampler2D input_texture; | ||||
|  | ||||
| const float FXAA_SUBPIX_SHIFT = 0; | ||||
|  | ||||
| void main() { | ||||
| #ifdef VULKAN | ||||
|   vec2 vertex = vertices[gl_VertexIndex]; | ||||
| #else | ||||
|   vec2 vertex = vertices[gl_VertexID]; | ||||
| #endif | ||||
|   gl_Position = vec4(vertex, 0.0, 1.0); | ||||
|   vec2 vert_tex_coord = (vertex + 1.0) / 2.0; | ||||
|   posPos.xy = vert_tex_coord; | ||||
|   posPos.zw = vert_tex_coord - (0.5 + FXAA_SUBPIX_SHIFT) / textureSize(input_texture, 0); | ||||
| } | ||||
| @@ -166,7 +166,7 @@ void OGLFramebuffer::Create() { | ||||
|         return; | ||||
|  | ||||
|     MICROPROFILE_SCOPE(OpenGL_ResourceCreation); | ||||
|     glGenFramebuffers(1, &handle); | ||||
|     glCreateFramebuffers(1, &handle); | ||||
| } | ||||
|  | ||||
| void OGLFramebuffer::Release() { | ||||
|   | ||||
| @@ -21,6 +21,8 @@ | ||||
| #include "core/memory.h" | ||||
| #include "core/perf_stats.h" | ||||
| #include "core/telemetry_session.h" | ||||
| #include "video_core/host_shaders/fxaa_frag.h" | ||||
| #include "video_core/host_shaders/fxaa_vert.h" | ||||
| #include "video_core/host_shaders/opengl_present_frag.h" | ||||
| #include "video_core/host_shaders/opengl_present_vert.h" | ||||
| #include "video_core/host_shaders/present_bicubic_frag.h" | ||||
| @@ -254,6 +256,8 @@ void RendererOpenGL::LoadColorToActiveGLTexture(u8 color_r, u8 color_g, u8 color | ||||
|  | ||||
| void RendererOpenGL::InitOpenGLObjects() { | ||||
|     // Create shader programs | ||||
|     fxaa_vertex = CreateProgram(HostShaders::FXAA_VERT, GL_VERTEX_SHADER); | ||||
|     fxaa_fragment = CreateProgram(HostShaders::FXAA_FRAG, GL_FRAGMENT_SHADER); | ||||
|     present_vertex = CreateProgram(HostShaders::OPENGL_PRESENT_VERT, GL_VERTEX_SHADER); | ||||
|     present_bilinear_fragment = CreateProgram(HostShaders::OPENGL_PRESENT_FRAG, GL_FRAGMENT_SHADER); | ||||
|     present_bicubic_fragment = CreateProgram(HostShaders::PRESENT_BICUBIC_FRAG, GL_FRAGMENT_SHADER); | ||||
| @@ -287,6 +291,8 @@ void RendererOpenGL::InitOpenGLObjects() { | ||||
|  | ||||
|     // Clear screen to black | ||||
|     LoadColorToActiveGLTexture(0, 0, 0, 0, screen_info.texture); | ||||
|  | ||||
|     fxaa_framebuffer.Create(); | ||||
| } | ||||
|  | ||||
| void RendererOpenGL::AddTelemetryFields() { | ||||
| @@ -338,14 +344,83 @@ void RendererOpenGL::ConfigureFramebufferTexture(TextureInfo& texture, | ||||
|     texture.resource.Release(); | ||||
|     texture.resource.Create(GL_TEXTURE_2D); | ||||
|     glTextureStorage2D(texture.resource.handle, 1, internal_format, texture.width, texture.height); | ||||
|     fxaa_texture.Release(); | ||||
|     fxaa_texture.Create(GL_TEXTURE_2D); | ||||
|     glTextureStorage2D(fxaa_texture.handle, 1, GL_RGBA16F, texture.width, texture.height); | ||||
|     glNamedFramebufferTexture(fxaa_framebuffer.handle, GL_COLOR_ATTACHMENT0, fxaa_texture.handle, | ||||
|                               0); | ||||
| } | ||||
|  | ||||
| void RendererOpenGL::DrawScreen(const Layout::FramebufferLayout& layout) { | ||||
|     // TODO: Signal state tracker about these changes | ||||
|     state_tracker.NotifyScreenDrawVertexArray(); | ||||
|     state_tracker.NotifyPolygonModes(); | ||||
|     state_tracker.NotifyViewport0(); | ||||
|     state_tracker.NotifyScissor0(); | ||||
|     state_tracker.NotifyColorMask(0); | ||||
|     state_tracker.NotifyBlend0(); | ||||
|     state_tracker.NotifyFramebuffer(); | ||||
|     state_tracker.NotifyFrontFace(); | ||||
|     state_tracker.NotifyCullTest(); | ||||
|     state_tracker.NotifyDepthTest(); | ||||
|     state_tracker.NotifyStencilTest(); | ||||
|     state_tracker.NotifyPolygonOffset(); | ||||
|     state_tracker.NotifyRasterizeEnable(); | ||||
|     state_tracker.NotifyFramebufferSRGB(); | ||||
|     state_tracker.NotifyLogicOp(); | ||||
|     state_tracker.NotifyClipControl(); | ||||
|     state_tracker.NotifyAlphaTest(); | ||||
|  | ||||
|     state_tracker.ClipControl(GL_LOWER_LEFT, GL_ZERO_TO_ONE); | ||||
|  | ||||
|     // Update background color before drawing | ||||
|     glClearColor(Settings::values.bg_red.GetValue() / 255.0f, | ||||
|                  Settings::values.bg_green.GetValue() / 255.0f, | ||||
|                  Settings::values.bg_blue.GetValue() / 255.0f, 1.0f); | ||||
|  | ||||
|     glEnable(GL_CULL_FACE); | ||||
|     glDisable(GL_COLOR_LOGIC_OP); | ||||
|     glDisable(GL_DEPTH_TEST); | ||||
|     glDisable(GL_STENCIL_TEST); | ||||
|     glDisable(GL_POLYGON_OFFSET_FILL); | ||||
|     glDisable(GL_RASTERIZER_DISCARD); | ||||
|     glDisable(GL_ALPHA_TEST); | ||||
|     glDisablei(GL_BLEND, 0); | ||||
|     glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); | ||||
|     glCullFace(GL_BACK); | ||||
|     glFrontFace(GL_CW); | ||||
|     glColorMaski(0, GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); | ||||
|  | ||||
|     glBindTextureUnit(0, screen_info.display_texture); | ||||
|  | ||||
|     if (Settings::values.anti_aliasing.GetValue() == Settings::AntiAliasing::Fxaa) { | ||||
|         program_manager.BindPresentPrograms(fxaa_vertex.handle, fxaa_fragment.handle); | ||||
|  | ||||
|         glEnablei(GL_SCISSOR_TEST, 0); | ||||
|         glScissorIndexed(0, 0, 0, | ||||
|                          framebuffer_crop_rect.GetWidth() != 0 ? framebuffer_crop_rect.GetWidth() | ||||
|                                                                : screen_info.texture.width, | ||||
|                          framebuffer_crop_rect.GetHeight() != 0 ? framebuffer_crop_rect.GetHeight() | ||||
|                                                                 : screen_info.texture.height); | ||||
|         glViewportIndexedf(0, 0.0f, 0.0f, static_cast<GLfloat>(screen_info.texture.width), | ||||
|                            static_cast<GLfloat>(screen_info.texture.height)); | ||||
|         glDepthRangeIndexed(0, 0.0, 0.0); | ||||
|  | ||||
|         glBindSampler(0, present_sampler.handle); | ||||
|         GLint old_read_fb; | ||||
|         GLint old_draw_fb; | ||||
|         glGetIntegerv(GL_READ_FRAMEBUFFER_BINDING, &old_read_fb); | ||||
|         glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &old_draw_fb); | ||||
|         glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fxaa_framebuffer.handle); | ||||
|  | ||||
|         glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); | ||||
|  | ||||
|         glBindFramebuffer(GL_READ_FRAMEBUFFER, old_read_fb); | ||||
|         glBindFramebuffer(GL_DRAW_FRAMEBUFFER, old_draw_fb); | ||||
|  | ||||
|         glBindTextureUnit(0, fxaa_texture.handle); | ||||
|     } | ||||
|  | ||||
|     // Set projection matrix | ||||
|     const std::array ortho_matrix = | ||||
|         MakeOrthographicMatrix(static_cast<float>(layout.width), static_cast<float>(layout.height)); | ||||
| @@ -422,47 +497,14 @@ void RendererOpenGL::DrawScreen(const Layout::FramebufferLayout& layout) { | ||||
|     }; | ||||
|     glNamedBufferSubData(vertex_buffer.handle, 0, sizeof(vertices), std::data(vertices)); | ||||
|  | ||||
|     // TODO: Signal state tracker about these changes | ||||
|     state_tracker.NotifyScreenDrawVertexArray(); | ||||
|     state_tracker.NotifyPolygonModes(); | ||||
|     state_tracker.NotifyViewport0(); | ||||
|     state_tracker.NotifyScissor0(); | ||||
|     state_tracker.NotifyColorMask(0); | ||||
|     state_tracker.NotifyBlend0(); | ||||
|     state_tracker.NotifyFramebuffer(); | ||||
|     state_tracker.NotifyFrontFace(); | ||||
|     state_tracker.NotifyCullTest(); | ||||
|     state_tracker.NotifyDepthTest(); | ||||
|     state_tracker.NotifyStencilTest(); | ||||
|     state_tracker.NotifyPolygonOffset(); | ||||
|     state_tracker.NotifyRasterizeEnable(); | ||||
|     state_tracker.NotifyFramebufferSRGB(); | ||||
|     state_tracker.NotifyLogicOp(); | ||||
|     state_tracker.NotifyClipControl(); | ||||
|     state_tracker.NotifyAlphaTest(); | ||||
|  | ||||
|     state_tracker.ClipControl(GL_LOWER_LEFT, GL_ZERO_TO_ONE); | ||||
|     glEnable(GL_CULL_FACE); | ||||
|     if (screen_info.display_srgb) { | ||||
|         glEnable(GL_FRAMEBUFFER_SRGB); | ||||
|     } else { | ||||
|         glDisable(GL_FRAMEBUFFER_SRGB); | ||||
|     } | ||||
|     glDisable(GL_COLOR_LOGIC_OP); | ||||
|     glDisable(GL_DEPTH_TEST); | ||||
|     glDisable(GL_STENCIL_TEST); | ||||
|     glDisable(GL_POLYGON_OFFSET_FILL); | ||||
|     glDisable(GL_RASTERIZER_DISCARD); | ||||
|     glDisable(GL_ALPHA_TEST); | ||||
|     glDisablei(GL_BLEND, 0); | ||||
|     glDisablei(GL_SCISSOR_TEST, 0); | ||||
|     glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); | ||||
|     glCullFace(GL_BACK); | ||||
|     glFrontFace(GL_CW); | ||||
|     glColorMaski(0, GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); | ||||
|     glViewportIndexedf(0, 0.0f, 0.0f, static_cast<GLfloat>(layout.width), | ||||
|                        static_cast<GLfloat>(layout.height)); | ||||
|     glDepthRangeIndexed(0, 0.0, 0.0); | ||||
|  | ||||
|     glEnableVertexAttribArray(PositionLocation); | ||||
|     glEnableVertexAttribArray(TexCoordLocation); | ||||
| @@ -482,7 +524,6 @@ void RendererOpenGL::DrawScreen(const Layout::FramebufferLayout& layout) { | ||||
|         glBindVertexBuffer(0, vertex_buffer.handle, 0, sizeof(ScreenRectVertex)); | ||||
|     } | ||||
|  | ||||
|     glBindTextureUnit(0, screen_info.display_texture); | ||||
|     if (Settings::values.scaling_filter.GetValue() != Settings::ScalingFilter::NearestNeighbor) { | ||||
|         glBindSampler(0, present_sampler.handle); | ||||
|     } else { | ||||
|   | ||||
| @@ -111,6 +111,8 @@ private: | ||||
|     OGLSampler present_sampler; | ||||
|     OGLSampler present_sampler_nn; | ||||
|     OGLBuffer vertex_buffer; | ||||
|     OGLProgram fxaa_vertex; | ||||
|     OGLProgram fxaa_fragment; | ||||
|     OGLProgram present_vertex; | ||||
|     OGLProgram present_bilinear_fragment; | ||||
|     OGLProgram present_bicubic_fragment; | ||||
| @@ -123,6 +125,8 @@ private: | ||||
|  | ||||
|     /// Display information for Switch screen | ||||
|     ScreenInfo screen_info; | ||||
|     OGLTexture fxaa_texture; | ||||
|     OGLFramebuffer fxaa_framebuffer; | ||||
|  | ||||
|     /// OpenGL framebuffer data | ||||
|     std::vector<u8> gl_framebuffer_data; | ||||
|   | ||||
		Reference in New Issue
	
	Block a user