From b90eff4bc666548a77eb58ac152408c80ff952b3 Mon Sep 17 00:00:00 2001 From: Liam Date: Sun, 14 Jan 2024 21:11:28 -0500 Subject: renderer_opengl: split out SMAA --- src/video_core/renderer_opengl/present/fsr.cpp | 106 +++++++++++++++++++++++ src/video_core/renderer_opengl/present/fsr.h | 43 ++++++++++ src/video_core/renderer_opengl/present/smaa.cpp | 108 ++++++++++++++++++++++++ src/video_core/renderer_opengl/present/smaa.h | 35 ++++++++ src/video_core/renderer_opengl/present/util.h | 32 +++++++ 5 files changed, 324 insertions(+) create mode 100644 src/video_core/renderer_opengl/present/fsr.cpp create mode 100644 src/video_core/renderer_opengl/present/fsr.h create mode 100644 src/video_core/renderer_opengl/present/smaa.cpp create mode 100644 src/video_core/renderer_opengl/present/smaa.h create mode 100644 src/video_core/renderer_opengl/present/util.h (limited to 'src/video_core/renderer_opengl/present') diff --git a/src/video_core/renderer_opengl/present/fsr.cpp b/src/video_core/renderer_opengl/present/fsr.cpp new file mode 100644 index 000000000..e5945b80b --- /dev/null +++ b/src/video_core/renderer_opengl/present/fsr.cpp @@ -0,0 +1,106 @@ +// 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_shader_manager.h" +#include "video_core/renderer_opengl/gl_shader_util.h" +#include "video_core/renderer_opengl/present/fsr.h" + +namespace OpenGL { +using namespace FSR; + +using FsrConstants = std::array; + +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& screen, + u32 input_image_width, u32 input_image_height, + const Common::Rectangle& 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(fsr_tex_width) != output_image_width || + static_cast(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(output_image_width), + static_cast(output_image_height)); + + const f32 input_width = static_cast(input_image_width); + const f32 input_height = static_cast(input_image_height); + const f32 output_width = static_cast(screen.GetWidth()); + const f32 output_height = static_cast(screen.GetHeight()); + const f32 viewport_width = (crop_rect.right - crop_rect.left) * input_width; + const f32 viewport_x = crop_rect.left * input_width; + const f32 viewport_height = (crop_rect.bottom - crop_rect.top) * input_height; + const f32 viewport_y = crop_rect.top * input_height; + + FsrConstants constants; + FsrEasuConOffset(constants.data() + 0, constants.data() + 4, constants.data() + 8, + constants.data() + 12, viewport_width, viewport_height, input_width, + input_height, output_width, output_height, viewport_x, viewport_y); + + 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(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 diff --git a/src/video_core/renderer_opengl/present/fsr.h b/src/video_core/renderer_opengl/present/fsr.h new file mode 100644 index 000000000..a5092e396 --- /dev/null +++ b/src/video_core/renderer_opengl/present/fsr.h @@ -0,0 +1,43 @@ +// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include + +#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& screen, + u32 input_image_width, u32 input_image_height, + const Common::Rectangle& 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 diff --git a/src/video_core/renderer_opengl/present/smaa.cpp b/src/video_core/renderer_opengl/present/smaa.cpp new file mode 100644 index 000000000..a9a0eb6c6 --- /dev/null +++ b/src/video_core/renderer_opengl/present/smaa.cpp @@ -0,0 +1,108 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "video_core/host_shaders/opengl_smaa_glsl.h" +#include "video_core/host_shaders/smaa_blending_weight_calculation_frag.h" +#include "video_core/host_shaders/smaa_blending_weight_calculation_vert.h" +#include "video_core/host_shaders/smaa_edge_detection_frag.h" +#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_shader_manager.h" +#include "video_core/renderer_opengl/gl_shader_util.h" +#include "video_core/renderer_opengl/present/smaa.h" +#include "video_core/renderer_opengl/present/util.h" +#include "video_core/smaa_area_tex.h" +#include "video_core/smaa_search_tex.h" + +namespace OpenGL { + +SMAA::SMAA(u32 width, u32 height) { + const auto SmaaShader = [&](std::string_view specialized_source, GLenum stage) { + std::string shader_source{specialized_source}; + ReplaceInclude(shader_source, "opengl_smaa.glsl", HostShaders::OPENGL_SMAA_GLSL); + return CreateProgram(shader_source, stage); + }; + + edge_detection_vert = SmaaShader(HostShaders::SMAA_EDGE_DETECTION_VERT, GL_VERTEX_SHADER); + edge_detection_frag = SmaaShader(HostShaders::SMAA_EDGE_DETECTION_FRAG, GL_FRAGMENT_SHADER); + blending_weight_calculation_vert = + SmaaShader(HostShaders::SMAA_BLENDING_WEIGHT_CALCULATION_VERT, GL_VERTEX_SHADER); + blending_weight_calculation_frag = + SmaaShader(HostShaders::SMAA_BLENDING_WEIGHT_CALCULATION_FRAG, GL_FRAGMENT_SHADER); + neighborhood_blending_vert = + SmaaShader(HostShaders::SMAA_NEIGHBORHOOD_BLENDING_VERT, GL_VERTEX_SHADER); + neighborhood_blending_frag = + SmaaShader(HostShaders::SMAA_NEIGHBORHOOD_BLENDING_FRAG, GL_FRAGMENT_SHADER); + + glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0); + glPixelStorei(GL_UNPACK_SWAP_BYTES, GL_FALSE); + glPixelStorei(GL_UNPACK_LSB_FIRST, GL_FALSE); + glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); + glPixelStorei(GL_UNPACK_IMAGE_HEIGHT, 0); + glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0); + glPixelStorei(GL_UNPACK_SKIP_ROWS, 0); + glPixelStorei(GL_UNPACK_ALIGNMENT, 4); + + area_tex.Create(GL_TEXTURE_2D); + glTextureStorage2D(area_tex.handle, 1, GL_RG8, AREATEX_WIDTH, AREATEX_HEIGHT); + glTextureSubImage2D(area_tex.handle, 0, 0, 0, AREATEX_WIDTH, AREATEX_HEIGHT, GL_RG, + GL_UNSIGNED_BYTE, areaTexBytes); + search_tex.Create(GL_TEXTURE_2D); + glTextureStorage2D(search_tex.handle, 1, GL_R8, SEARCHTEX_WIDTH, SEARCHTEX_HEIGHT); + glTextureSubImage2D(search_tex.handle, 0, 0, 0, SEARCHTEX_WIDTH, SEARCHTEX_HEIGHT, GL_RED, + GL_UNSIGNED_BYTE, searchTexBytes); + + edges_tex.Create(GL_TEXTURE_2D); + glTextureStorage2D(edges_tex.handle, 1, GL_RG16F, width, height); + + blend_tex.Create(GL_TEXTURE_2D); + glTextureStorage2D(blend_tex.handle, 1, GL_RGBA16F, width, height); + + sampler = CreateBilinearSampler(); + + framebuffer.Create(); + + texture.Create(GL_TEXTURE_2D); + glTextureStorage2D(texture.handle, 1, GL_RGBA16F, width, height); + glNamedFramebufferTexture(framebuffer.handle, GL_COLOR_ATTACHMENT0, texture.handle, 0); +} + +SMAA::~SMAA() = default; + +GLuint SMAA::Draw(ProgramManager& program_manager, GLuint input_texture) { + glClearColor(0, 0, 0, 0); + glFrontFace(GL_CCW); + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, framebuffer.handle); + glBindSampler(0, sampler.handle); + glBindSampler(1, sampler.handle); + glBindSampler(2, sampler.handle); + + glBindTextureUnit(0, input_texture); + glNamedFramebufferTexture(framebuffer.handle, GL_COLOR_ATTACHMENT0, edges_tex.handle, 0); + glClear(GL_COLOR_BUFFER_BIT); + program_manager.BindPresentPrograms(edge_detection_vert.handle, edge_detection_frag.handle); + glDrawArrays(GL_TRIANGLES, 0, 3); + + glBindTextureUnit(0, edges_tex.handle); + glBindTextureUnit(1, area_tex.handle); + glBindTextureUnit(2, search_tex.handle); + glNamedFramebufferTexture(framebuffer.handle, GL_COLOR_ATTACHMENT0, blend_tex.handle, 0); + glClear(GL_COLOR_BUFFER_BIT); + program_manager.BindPresentPrograms(blending_weight_calculation_vert.handle, + blending_weight_calculation_frag.handle); + glDrawArrays(GL_TRIANGLES, 0, 3); + + glBindTextureUnit(0, input_texture); + glBindTextureUnit(1, blend_tex.handle); + glNamedFramebufferTexture(framebuffer.handle, GL_COLOR_ATTACHMENT0, texture.handle, 0); + program_manager.BindPresentPrograms(neighborhood_blending_vert.handle, + neighborhood_blending_frag.handle); + glClear(GL_COLOR_BUFFER_BIT); + glDrawArrays(GL_TRIANGLES, 0, 3); + glFrontFace(GL_CW); + + return texture.handle; +} + +} // namespace OpenGL diff --git a/src/video_core/renderer_opengl/present/smaa.h b/src/video_core/renderer_opengl/present/smaa.h new file mode 100644 index 000000000..a48cb4fa9 --- /dev/null +++ b/src/video_core/renderer_opengl/present/smaa.h @@ -0,0 +1,35 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "video_core/renderer_opengl/gl_resource_manager.h" + +namespace OpenGL { + +class ProgramManager; + +class SMAA { +public: + explicit SMAA(u32 width, u32 height); + ~SMAA(); + + GLuint Draw(ProgramManager& program_manager, GLuint input_texture); + +private: + OGLProgram edge_detection_vert; + OGLProgram blending_weight_calculation_vert; + OGLProgram neighborhood_blending_vert; + OGLProgram edge_detection_frag; + OGLProgram blending_weight_calculation_frag; + OGLProgram neighborhood_blending_frag; + OGLTexture area_tex; + OGLTexture search_tex; + OGLTexture edges_tex; + OGLTexture blend_tex; + OGLSampler sampler; + OGLFramebuffer framebuffer; + OGLTexture texture; +}; + +} // namespace OpenGL diff --git a/src/video_core/renderer_opengl/present/util.h b/src/video_core/renderer_opengl/present/util.h new file mode 100644 index 000000000..0aa8b110c --- /dev/null +++ b/src/video_core/renderer_opengl/present/util.h @@ -0,0 +1,32 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include + +#include "common/assert.h" +#include "video_core/renderer_opengl/gl_resource_manager.h" + +namespace OpenGL { + +static inline void ReplaceInclude(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(), include_content); +}; + +static inline OGLSampler CreateBilinearSampler() { + OGLSampler sampler; + sampler.Create(); + glSamplerParameteri(sampler.handle, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glSamplerParameteri(sampler.handle, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glSamplerParameteri(sampler.handle, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glSamplerParameteri(sampler.handle, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glSamplerParameteri(sampler.handle, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); + return sampler; +} + +} // namespace OpenGL -- cgit v1.2.3