video_core/opengl: Add FSR upscaling filter to the OpenGL renderer
This commit is contained in:
parent
380dcde154
commit
c4a49eb1dd
14 changed files with 547 additions and 172 deletions
101
src/video_core/renderer_opengl/gl_fsr.cpp
Normal file
101
src/video_core/renderer_opengl/gl_fsr.cpp
Normal file
|
@ -0,0 +1,101 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "common/settings.h"
|
||||
#include "video_core/fsr.h"
|
||||
#include "video_core/renderer_opengl/gl_fsr.h"
|
||||
#include "video_core/renderer_opengl/gl_shader_manager.h"
|
||||
#include "video_core/renderer_opengl/gl_shader_util.h"
|
||||
|
||||
namespace OpenGL {
|
||||
using namespace FSR;
|
||||
|
||||
using FsrConstants = std::array<u32, 4 * 4>;
|
||||
|
||||
FSR::FSR(std::string_view fsr_vertex_source, std::string_view fsr_easu_source,
|
||||
std::string_view fsr_rcas_source)
|
||||
: fsr_vertex{CreateProgram(fsr_vertex_source, GL_VERTEX_SHADER)},
|
||||
fsr_easu_frag{CreateProgram(fsr_easu_source, GL_FRAGMENT_SHADER)},
|
||||
fsr_rcas_frag{CreateProgram(fsr_rcas_source, GL_FRAGMENT_SHADER)} {
|
||||
glProgramUniform2f(fsr_vertex.handle, 0, 1.0f, 1.0f);
|
||||
glProgramUniform2f(fsr_vertex.handle, 1, 0.0f, 0.0f);
|
||||
}
|
||||
|
||||
FSR::~FSR() = default;
|
||||
|
||||
void FSR::Draw(ProgramManager& program_manager, const Common::Rectangle<u32>& screen,
|
||||
u32 input_image_width, u32 input_image_height,
|
||||
const Common::Rectangle<int>& crop_rect) {
|
||||
|
||||
const auto output_image_width = screen.GetWidth();
|
||||
const auto output_image_height = screen.GetHeight();
|
||||
|
||||
if (fsr_intermediate_tex.handle) {
|
||||
GLint fsr_tex_width, fsr_tex_height;
|
||||
glGetTextureLevelParameteriv(fsr_intermediate_tex.handle, 0, GL_TEXTURE_WIDTH,
|
||||
&fsr_tex_width);
|
||||
glGetTextureLevelParameteriv(fsr_intermediate_tex.handle, 0, GL_TEXTURE_HEIGHT,
|
||||
&fsr_tex_height);
|
||||
if (static_cast<u32>(fsr_tex_width) != output_image_width ||
|
||||
static_cast<u32>(fsr_tex_height) != output_image_height) {
|
||||
fsr_intermediate_tex.Release();
|
||||
}
|
||||
}
|
||||
if (!fsr_intermediate_tex.handle) {
|
||||
fsr_intermediate_tex.Create(GL_TEXTURE_2D);
|
||||
glTextureStorage2D(fsr_intermediate_tex.handle, 1, GL_RGB16F, output_image_width,
|
||||
output_image_height);
|
||||
glNamedFramebufferTexture(fsr_framebuffer.handle, GL_COLOR_ATTACHMENT0,
|
||||
fsr_intermediate_tex.handle, 0);
|
||||
}
|
||||
|
||||
GLint old_draw_fb;
|
||||
glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &old_draw_fb);
|
||||
|
||||
glFrontFace(GL_CW);
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fsr_framebuffer.handle);
|
||||
glViewportIndexedf(0, 0.0f, 0.0f, static_cast<GLfloat>(output_image_width),
|
||||
static_cast<GLfloat>(output_image_height));
|
||||
|
||||
FsrConstants constants;
|
||||
FsrEasuConOffset(
|
||||
constants.data() + 0, constants.data() + 4, constants.data() + 8, constants.data() + 12,
|
||||
|
||||
static_cast<f32>(crop_rect.GetWidth()), static_cast<f32>(crop_rect.GetHeight()),
|
||||
static_cast<f32>(input_image_width), static_cast<f32>(input_image_height),
|
||||
static_cast<f32>(output_image_width), static_cast<f32>(output_image_height),
|
||||
static_cast<f32>(crop_rect.left), static_cast<f32>(crop_rect.top));
|
||||
|
||||
glProgramUniform4uiv(fsr_easu_frag.handle, 0, sizeof(constants), std::data(constants));
|
||||
|
||||
program_manager.BindPresentPrograms(fsr_vertex.handle, fsr_easu_frag.handle);
|
||||
glDrawArrays(GL_TRIANGLES, 0, 3);
|
||||
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, old_draw_fb);
|
||||
glBindTextureUnit(0, fsr_intermediate_tex.handle);
|
||||
|
||||
const float sharpening =
|
||||
static_cast<float>(Settings::values.fsr_sharpening_slider.GetValue()) / 100.0f;
|
||||
|
||||
FsrRcasCon(constants.data(), sharpening);
|
||||
glProgramUniform4uiv(fsr_rcas_frag.handle, 0, sizeof(constants), std::data(constants));
|
||||
}
|
||||
|
||||
void FSR::InitBuffers() {
|
||||
fsr_framebuffer.Create();
|
||||
}
|
||||
|
||||
void FSR::ReleaseBuffers() {
|
||||
fsr_framebuffer.Release();
|
||||
fsr_intermediate_tex.Release();
|
||||
}
|
||||
|
||||
const OGLProgram& FSR::GetPresentFragmentProgram() const noexcept {
|
||||
return fsr_rcas_frag;
|
||||
}
|
||||
|
||||
bool FSR::AreBuffersInitialized() const noexcept {
|
||||
return fsr_framebuffer.handle;
|
||||
}
|
||||
|
||||
} // namespace OpenGL
|
43
src/video_core/renderer_opengl/gl_fsr.h
Normal file
43
src/video_core/renderer_opengl/gl_fsr.h
Normal file
|
@ -0,0 +1,43 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string_view>
|
||||
|
||||
#include "common/common_types.h"
|
||||
#include "common/math_util.h"
|
||||
#include "video_core/fsr.h"
|
||||
#include "video_core/renderer_opengl/gl_resource_manager.h"
|
||||
|
||||
namespace OpenGL {
|
||||
|
||||
class ProgramManager;
|
||||
|
||||
class FSR {
|
||||
public:
|
||||
explicit FSR(std::string_view fsr_vertex_source, std::string_view fsr_easu_source,
|
||||
std::string_view fsr_rcas_source);
|
||||
~FSR();
|
||||
|
||||
void Draw(ProgramManager& program_manager, const Common::Rectangle<u32>& screen,
|
||||
u32 input_image_width, u32 input_image_height,
|
||||
const Common::Rectangle<int>& crop_rect);
|
||||
|
||||
void InitBuffers();
|
||||
|
||||
void ReleaseBuffers();
|
||||
|
||||
[[nodiscard]] const OGLProgram& GetPresentFragmentProgram() const noexcept;
|
||||
|
||||
[[nodiscard]] bool AreBuffersInitialized() const noexcept;
|
||||
|
||||
private:
|
||||
OGLFramebuffer fsr_framebuffer;
|
||||
OGLProgram fsr_vertex;
|
||||
OGLProgram fsr_easu_frag;
|
||||
OGLProgram fsr_rcas_frag;
|
||||
OGLTexture fsr_intermediate_tex;
|
||||
};
|
||||
|
||||
} // namespace OpenGL
|
|
@ -17,8 +17,14 @@
|
|||
#include "core/frontend/emu_window.h"
|
||||
#include "core/memory.h"
|
||||
#include "core/telemetry_session.h"
|
||||
#include "video_core/host_shaders/ffx_a_h.h"
|
||||
#include "video_core/host_shaders/ffx_fsr1_h.h"
|
||||
#include "video_core/host_shaders/full_screen_triangle_vert.h"
|
||||
#include "video_core/host_shaders/fxaa_frag.h"
|
||||
#include "video_core/host_shaders/fxaa_vert.h"
|
||||
#include "video_core/host_shaders/opengl_fidelityfx_fsr_easu_frag.h"
|
||||
#include "video_core/host_shaders/opengl_fidelityfx_fsr_frag.h"
|
||||
#include "video_core/host_shaders/opengl_fidelityfx_fsr_rcas_frag.h"
|
||||
#include "video_core/host_shaders/opengl_present_frag.h"
|
||||
#include "video_core/host_shaders/opengl_present_scaleforce_frag.h"
|
||||
#include "video_core/host_shaders/opengl_present_vert.h"
|
||||
|
@ -31,6 +37,7 @@
|
|||
#include "video_core/host_shaders/smaa_edge_detection_vert.h"
|
||||
#include "video_core/host_shaders/smaa_neighborhood_blending_frag.h"
|
||||
#include "video_core/host_shaders/smaa_neighborhood_blending_vert.h"
|
||||
#include "video_core/renderer_opengl/gl_fsr.h"
|
||||
#include "video_core/renderer_opengl/gl_rasterizer.h"
|
||||
#include "video_core/renderer_opengl/gl_shader_manager.h"
|
||||
#include "video_core/renderer_opengl/gl_shader_util.h"
|
||||
|
@ -268,12 +275,17 @@ void RendererOpenGL::InitOpenGLObjects() {
|
|||
fxaa_vertex = CreateProgram(HostShaders::FXAA_VERT, GL_VERTEX_SHADER);
|
||||
fxaa_fragment = CreateProgram(HostShaders::FXAA_FRAG, GL_FRAGMENT_SHADER);
|
||||
|
||||
const auto SmaaShader = [](std::string_view specialized_source, GLenum stage) {
|
||||
std::string shader_source{specialized_source};
|
||||
constexpr std::string_view include_string = "#include \"opengl_smaa.glsl\"";
|
||||
const auto replace_include = [](std::string& shader_source, std::string_view include_name,
|
||||
std::string_view include_content) {
|
||||
const std::string include_string = fmt::format("#include \"{}\"", include_name);
|
||||
const std::size_t pos = shader_source.find(include_string);
|
||||
ASSERT(pos != std::string::npos);
|
||||
shader_source.replace(pos, include_string.size(), HostShaders::OPENGL_SMAA_GLSL);
|
||||
shader_source.replace(pos, include_string.size(), include_content);
|
||||
};
|
||||
|
||||
const auto SmaaShader = [&](std::string_view specialized_source, GLenum stage) {
|
||||
std::string shader_source{specialized_source};
|
||||
replace_include(shader_source, "opengl_smaa.glsl", HostShaders::OPENGL_SMAA_GLSL);
|
||||
return CreateProgram(shader_source, stage);
|
||||
};
|
||||
|
||||
|
@ -298,14 +310,32 @@ void RendererOpenGL::InitOpenGLObjects() {
|
|||
CreateProgram(fmt::format("#version 460\n{}", HostShaders::OPENGL_PRESENT_SCALEFORCE_FRAG),
|
||||
GL_FRAGMENT_SHADER);
|
||||
|
||||
std::string fsr_source{HostShaders::OPENGL_FIDELITYFX_FSR_FRAG};
|
||||
replace_include(fsr_source, "ffx_a.h", HostShaders::FFX_A_H);
|
||||
replace_include(fsr_source, "ffx_fsr1.h", HostShaders::FFX_FSR1_H);
|
||||
|
||||
std::string fsr_easu_frag_source{HostShaders::OPENGL_FIDELITYFX_FSR_EASU_FRAG};
|
||||
std::string fsr_rcas_frag_source{HostShaders::OPENGL_FIDELITYFX_FSR_RCAS_FRAG};
|
||||
replace_include(fsr_easu_frag_source, "opengl_fidelityfx_fsr.frag", fsr_source);
|
||||
replace_include(fsr_rcas_frag_source, "opengl_fidelityfx_fsr.frag", fsr_source);
|
||||
|
||||
fsr = std::make_unique<FSR>(HostShaders::FULL_SCREEN_TRIANGLE_VERT, fsr_easu_frag_source,
|
||||
fsr_rcas_frag_source);
|
||||
|
||||
// Generate presentation sampler
|
||||
present_sampler.Create();
|
||||
glSamplerParameteri(present_sampler.handle, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glSamplerParameteri(present_sampler.handle, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glSamplerParameteri(present_sampler.handle, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
glSamplerParameteri(present_sampler.handle, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
glSamplerParameteri(present_sampler.handle, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
|
||||
|
||||
present_sampler_nn.Create();
|
||||
glSamplerParameteri(present_sampler_nn.handle, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
glSamplerParameteri(present_sampler_nn.handle, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
glSamplerParameteri(present_sampler_nn.handle, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
glSamplerParameteri(present_sampler_nn.handle, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
glSamplerParameteri(present_sampler_nn.handle, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
|
||||
|
||||
// Generate VBO handle for drawing
|
||||
vertex_buffer.Create();
|
||||
|
@ -525,6 +555,31 @@ void RendererOpenGL::DrawScreen(const Layout::FramebufferLayout& layout) {
|
|||
|
||||
glBindTextureUnit(0, aa_texture.handle);
|
||||
}
|
||||
glDisablei(GL_SCISSOR_TEST, 0);
|
||||
|
||||
if (Settings::values.scaling_filter.GetValue() == Settings::ScalingFilter::Fsr) {
|
||||
if (!fsr->AreBuffersInitialized()) {
|
||||
fsr->InitBuffers();
|
||||
}
|
||||
|
||||
auto crop_rect = framebuffer_crop_rect;
|
||||
if (crop_rect.GetWidth() == 0) {
|
||||
crop_rect.right = framebuffer_width;
|
||||
}
|
||||
if (crop_rect.GetHeight() == 0) {
|
||||
crop_rect.bottom = framebuffer_height;
|
||||
}
|
||||
crop_rect = crop_rect.Scale(Settings::values.resolution_info.up_factor);
|
||||
const auto fsr_input_width = Settings::values.resolution_info.ScaleUp(framebuffer_width);
|
||||
const auto fsr_input_height = Settings::values.resolution_info.ScaleUp(framebuffer_height);
|
||||
glBindSampler(0, present_sampler.handle);
|
||||
fsr->Draw(program_manager, layout.screen, fsr_input_width, fsr_input_height, crop_rect);
|
||||
} else {
|
||||
if (fsr->AreBuffersInitialized()) {
|
||||
fsr->ReleaseBuffers();
|
||||
}
|
||||
}
|
||||
|
||||
const std::array ortho_matrix =
|
||||
MakeOrthographicMatrix(static_cast<float>(layout.width), static_cast<float>(layout.height));
|
||||
|
||||
|
@ -540,10 +595,7 @@ void RendererOpenGL::DrawScreen(const Layout::FramebufferLayout& layout) {
|
|||
case Settings::ScalingFilter::ScaleForce:
|
||||
return present_scaleforce_fragment.handle;
|
||||
case Settings::ScalingFilter::Fsr:
|
||||
LOG_WARNING(
|
||||
Render_OpenGL,
|
||||
"FidelityFX Super Resolution is not supported in OpenGL, changing to ScaleForce");
|
||||
return present_scaleforce_fragment.handle;
|
||||
return fsr->GetPresentFragmentProgram().handle;
|
||||
default:
|
||||
return present_bilinear_fragment.handle;
|
||||
}
|
||||
|
@ -578,15 +630,18 @@ void RendererOpenGL::DrawScreen(const Layout::FramebufferLayout& layout) {
|
|||
f32 scale_u = static_cast<f32>(framebuffer_width) / static_cast<f32>(screen_info.texture.width);
|
||||
f32 scale_v =
|
||||
static_cast<f32>(framebuffer_height) / static_cast<f32>(screen_info.texture.height);
|
||||
// Scale the output by the crop width/height. This is commonly used with 1280x720 rendering
|
||||
// (e.g. handheld mode) on a 1920x1080 framebuffer.
|
||||
if (framebuffer_crop_rect.GetWidth() > 0) {
|
||||
scale_u = static_cast<f32>(framebuffer_crop_rect.GetWidth()) /
|
||||
static_cast<f32>(screen_info.texture.width);
|
||||
}
|
||||
if (framebuffer_crop_rect.GetHeight() > 0) {
|
||||
scale_v = static_cast<f32>(framebuffer_crop_rect.GetHeight()) /
|
||||
static_cast<f32>(screen_info.texture.height);
|
||||
|
||||
if (Settings::values.scaling_filter.GetValue() != Settings::ScalingFilter::Fsr) {
|
||||
// Scale the output by the crop width/height. This is commonly used with 1280x720 rendering
|
||||
// (e.g. handheld mode) on a 1920x1080 framebuffer.
|
||||
if (framebuffer_crop_rect.GetWidth() > 0) {
|
||||
scale_u = static_cast<f32>(framebuffer_crop_rect.GetWidth()) /
|
||||
static_cast<f32>(screen_info.texture.width);
|
||||
}
|
||||
if (framebuffer_crop_rect.GetHeight() > 0) {
|
||||
scale_v = static_cast<f32>(framebuffer_crop_rect.GetHeight()) /
|
||||
static_cast<f32>(screen_info.texture.height);
|
||||
}
|
||||
}
|
||||
if (Settings::values.anti_aliasing.GetValue() == Settings::AntiAliasing::Fxaa &&
|
||||
!screen_info.was_accelerated) {
|
||||
|
@ -612,7 +667,6 @@ void RendererOpenGL::DrawScreen(const Layout::FramebufferLayout& layout) {
|
|||
} else {
|
||||
glDisable(GL_FRAMEBUFFER_SRGB);
|
||||
}
|
||||
glDisablei(GL_SCISSOR_TEST, 0);
|
||||
glViewportIndexedf(0, 0.0f, 0.0f, static_cast<GLfloat>(layout.width),
|
||||
static_cast<GLfloat>(layout.height));
|
||||
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
|
||||
#include "video_core/renderer_base.h"
|
||||
#include "video_core/renderer_opengl/gl_device.h"
|
||||
#include "video_core/renderer_opengl/gl_fsr.h"
|
||||
#include "video_core/renderer_opengl/gl_rasterizer.h"
|
||||
#include "video_core/renderer_opengl/gl_resource_manager.h"
|
||||
#include "video_core/renderer_opengl/gl_shader_manager.h"
|
||||
|
@ -141,6 +142,8 @@ private:
|
|||
OGLTexture smaa_edges_tex;
|
||||
OGLTexture smaa_blend_tex;
|
||||
|
||||
std::unique_ptr<FSR> fsr;
|
||||
|
||||
/// OpenGL framebuffer data
|
||||
std::vector<u8> gl_framebuffer_data;
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue