OpenGL: Implement FXAA
This commit is contained in:
parent
74e39ed6ee
commit
48cf376462
|
@ -13,6 +13,8 @@ set(SHADER_FILES
|
||||||
convert_depth_to_float.frag
|
convert_depth_to_float.frag
|
||||||
convert_float_to_depth.frag
|
convert_float_to_depth.frag
|
||||||
full_screen_triangle.vert
|
full_screen_triangle.vert
|
||||||
|
fxaa.frag
|
||||||
|
fxaa.vert
|
||||||
opengl_copy_bc4.comp
|
opengl_copy_bc4.comp
|
||||||
opengl_present.frag
|
opengl_present.frag
|
||||||
opengl_present.vert
|
opengl_present.vert
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
|
@ -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;
|
return;
|
||||||
|
|
||||||
MICROPROFILE_SCOPE(OpenGL_ResourceCreation);
|
MICROPROFILE_SCOPE(OpenGL_ResourceCreation);
|
||||||
glGenFramebuffers(1, &handle);
|
glCreateFramebuffers(1, &handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
void OGLFramebuffer::Release() {
|
void OGLFramebuffer::Release() {
|
||||||
|
|
|
@ -21,6 +21,8 @@
|
||||||
#include "core/memory.h"
|
#include "core/memory.h"
|
||||||
#include "core/perf_stats.h"
|
#include "core/perf_stats.h"
|
||||||
#include "core/telemetry_session.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_frag.h"
|
||||||
#include "video_core/host_shaders/opengl_present_vert.h"
|
#include "video_core/host_shaders/opengl_present_vert.h"
|
||||||
#include "video_core/host_shaders/present_bicubic_frag.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() {
|
void RendererOpenGL::InitOpenGLObjects() {
|
||||||
// Create shader programs
|
// 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_vertex = CreateProgram(HostShaders::OPENGL_PRESENT_VERT, GL_VERTEX_SHADER);
|
||||||
present_bilinear_fragment = CreateProgram(HostShaders::OPENGL_PRESENT_FRAG, GL_FRAGMENT_SHADER);
|
present_bilinear_fragment = CreateProgram(HostShaders::OPENGL_PRESENT_FRAG, GL_FRAGMENT_SHADER);
|
||||||
present_bicubic_fragment = CreateProgram(HostShaders::PRESENT_BICUBIC_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
|
// Clear screen to black
|
||||||
LoadColorToActiveGLTexture(0, 0, 0, 0, screen_info.texture);
|
LoadColorToActiveGLTexture(0, 0, 0, 0, screen_info.texture);
|
||||||
|
|
||||||
|
fxaa_framebuffer.Create();
|
||||||
}
|
}
|
||||||
|
|
||||||
void RendererOpenGL::AddTelemetryFields() {
|
void RendererOpenGL::AddTelemetryFields() {
|
||||||
|
@ -338,14 +344,83 @@ void RendererOpenGL::ConfigureFramebufferTexture(TextureInfo& texture,
|
||||||
texture.resource.Release();
|
texture.resource.Release();
|
||||||
texture.resource.Create(GL_TEXTURE_2D);
|
texture.resource.Create(GL_TEXTURE_2D);
|
||||||
glTextureStorage2D(texture.resource.handle, 1, internal_format, texture.width, texture.height);
|
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) {
|
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
|
// Update background color before drawing
|
||||||
glClearColor(Settings::values.bg_red.GetValue() / 255.0f,
|
glClearColor(Settings::values.bg_red.GetValue() / 255.0f,
|
||||||
Settings::values.bg_green.GetValue() / 255.0f,
|
Settings::values.bg_green.GetValue() / 255.0f,
|
||||||
Settings::values.bg_blue.GetValue() / 255.0f, 1.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
|
// Set projection matrix
|
||||||
const std::array ortho_matrix =
|
const std::array ortho_matrix =
|
||||||
MakeOrthographicMatrix(static_cast<float>(layout.width), static_cast<float>(layout.height));
|
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));
|
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) {
|
if (screen_info.display_srgb) {
|
||||||
glEnable(GL_FRAMEBUFFER_SRGB);
|
glEnable(GL_FRAMEBUFFER_SRGB);
|
||||||
} else {
|
} else {
|
||||||
glDisable(GL_FRAMEBUFFER_SRGB);
|
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);
|
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),
|
glViewportIndexedf(0, 0.0f, 0.0f, static_cast<GLfloat>(layout.width),
|
||||||
static_cast<GLfloat>(layout.height));
|
static_cast<GLfloat>(layout.height));
|
||||||
glDepthRangeIndexed(0, 0.0, 0.0);
|
|
||||||
|
|
||||||
glEnableVertexAttribArray(PositionLocation);
|
glEnableVertexAttribArray(PositionLocation);
|
||||||
glEnableVertexAttribArray(TexCoordLocation);
|
glEnableVertexAttribArray(TexCoordLocation);
|
||||||
|
@ -482,7 +524,6 @@ void RendererOpenGL::DrawScreen(const Layout::FramebufferLayout& layout) {
|
||||||
glBindVertexBuffer(0, vertex_buffer.handle, 0, sizeof(ScreenRectVertex));
|
glBindVertexBuffer(0, vertex_buffer.handle, 0, sizeof(ScreenRectVertex));
|
||||||
}
|
}
|
||||||
|
|
||||||
glBindTextureUnit(0, screen_info.display_texture);
|
|
||||||
if (Settings::values.scaling_filter.GetValue() != Settings::ScalingFilter::NearestNeighbor) {
|
if (Settings::values.scaling_filter.GetValue() != Settings::ScalingFilter::NearestNeighbor) {
|
||||||
glBindSampler(0, present_sampler.handle);
|
glBindSampler(0, present_sampler.handle);
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -111,6 +111,8 @@ private:
|
||||||
OGLSampler present_sampler;
|
OGLSampler present_sampler;
|
||||||
OGLSampler present_sampler_nn;
|
OGLSampler present_sampler_nn;
|
||||||
OGLBuffer vertex_buffer;
|
OGLBuffer vertex_buffer;
|
||||||
|
OGLProgram fxaa_vertex;
|
||||||
|
OGLProgram fxaa_fragment;
|
||||||
OGLProgram present_vertex;
|
OGLProgram present_vertex;
|
||||||
OGLProgram present_bilinear_fragment;
|
OGLProgram present_bilinear_fragment;
|
||||||
OGLProgram present_bicubic_fragment;
|
OGLProgram present_bicubic_fragment;
|
||||||
|
@ -123,6 +125,8 @@ private:
|
||||||
|
|
||||||
/// Display information for Switch screen
|
/// Display information for Switch screen
|
||||||
ScreenInfo screen_info;
|
ScreenInfo screen_info;
|
||||||
|
OGLTexture fxaa_texture;
|
||||||
|
OGLFramebuffer fxaa_framebuffer;
|
||||||
|
|
||||||
/// OpenGL framebuffer data
|
/// OpenGL framebuffer data
|
||||||
std::vector<u8> gl_framebuffer_data;
|
std::vector<u8> gl_framebuffer_data;
|
||||||
|
|
Reference in New Issue