diff --git a/rpcs3/Emu/CMakeLists.txt b/rpcs3/Emu/CMakeLists.txt index 7e728bc6bc..14949b09bb 100644 --- a/rpcs3/Emu/CMakeLists.txt +++ b/rpcs3/Emu/CMakeLists.txt @@ -518,6 +518,7 @@ target_sources(rpcs3_emu PRIVATE RSX/GL/glutils/program.cpp RSX/GL/glutils/ring_buffer.cpp RSX/GL/glutils/sampler.cpp + RSX/GL/upscalers/fsr1/fsr_pass.cpp RSX/GL/GLCommonDecompiler.cpp RSX/GL/GLCompute.cpp RSX/GL/GLDraw.cpp diff --git a/rpcs3/Emu/RSX/GL/GLGSRender.cpp b/rpcs3/Emu/RSX/GL/GLGSRender.cpp index 515f10cf5a..94581866b0 100644 --- a/rpcs3/Emu/RSX/GL/GLGSRender.cpp +++ b/rpcs3/Emu/RSX/GL/GLGSRender.cpp @@ -411,10 +411,7 @@ void GLGSRender::on_exit() m_framebuffer_cache.clear(); - if (m_flip_fbo) - { - m_flip_fbo.remove(); - } + m_upscaler.reset(); for (auto& flip_tex_image : m_flip_tex_color) { diff --git a/rpcs3/Emu/RSX/GL/GLGSRender.h b/rpcs3/Emu/RSX/GL/GLGSRender.h index 8fd5481815..3d17fb96f8 100644 --- a/rpcs3/Emu/RSX/GL/GLGSRender.h +++ b/rpcs3/Emu/RSX/GL/GLGSRender.h @@ -12,6 +12,7 @@ #include #include "glutils/ring_buffer.h" +#include "upscalers/upscaling.h" #ifdef _MSC_VER #pragma comment(lib, "opengl32.lib") @@ -125,9 +126,12 @@ class GLGSRender : public GSRender, public ::rsx::reports::ZCULL_control //buffer gl::fbo* m_draw_fbo = nullptr; std::list m_framebuffer_cache; - gl::fbo m_flip_fbo; std::unique_ptr m_flip_tex_color[2]; + // Present + std::unique_ptr m_upscaler; + output_scaling_mode m_output_scaling = output_scaling_mode::bilinear; + //vaos are mandatory for core profile gl::vao m_vao; diff --git a/rpcs3/Emu/RSX/GL/GLOverlays.cpp b/rpcs3/Emu/RSX/GL/GLOverlays.cpp index ee276cf2bb..56e2a1bde2 100644 --- a/rpcs3/Emu/RSX/GL/GLOverlays.cpp +++ b/rpcs3/Emu/RSX/GL/GLOverlays.cpp @@ -482,6 +482,7 @@ namespace gl m_sampler.set_parameteri(GL_TEXTURE_MIN_FILTER, static_cast(m_input_filter)); m_sampler.set_parameteri(GL_TEXTURE_MAG_FILTER, static_cast(m_input_filter)); } + program_handle.uniforms["gamma"] = gamma; program_handle.uniforms["limit_range"] = limited_rgb + 0; program_handle.uniforms["stereo_display_mode"] = static_cast(stereo_mode); diff --git a/rpcs3/Emu/RSX/GL/GLPresent.cpp b/rpcs3/Emu/RSX/GL/GLPresent.cpp index 0e51230c92..4ff3204eb5 100644 --- a/rpcs3/Emu/RSX/GL/GLPresent.cpp +++ b/rpcs3/Emu/RSX/GL/GLPresent.cpp @@ -1,8 +1,12 @@ #include "stdafx.h" #include "GLGSRender.h" +#include "upscalers/bilinear_pass.hpp" +#include "upscalers/nearest_pass.hpp" + #include "Emu/Cell/Modules/cellVideoOut.h" #include "Emu/RSX/Overlays/overlay_manager.h" #include "Emu/RSX/Overlays/overlay_debug_overlay.h" + #include "util/video_provider.h" LOG_CHANNEL(screenshot_log, "SCREENSHOT"); @@ -298,27 +302,40 @@ void GLGSRender::flip(const rsx::display_flip_info_t& info) } const areai screen_area = coordi({}, { static_cast(buffer_width), static_cast(buffer_height) }); - const bool use_full_rgb_range_output = g_cfg.video.full_rgb_range_output.get(); - // TODO: Implement FSR for OpenGL and remove this fallback to bilinear - const gl::filter filter = g_cfg.video.output_scaling == output_scaling_mode::nearest ? gl::filter::nearest : gl::filter::linear; + + if (!m_upscaler || m_output_scaling != g_cfg.video.output_scaling) + { + m_output_scaling = g_cfg.video.output_scaling; + + switch (m_output_scaling) + { + case output_scaling_mode::nearest: + m_upscaler = std::make_unique(); + break; + case output_scaling_mode::fsr: + // Unimplemented + [[ fallthrough ]]; + case output_scaling_mode::bilinear: + default: + m_upscaler = std::make_unique(); + } + } if (use_full_rgb_range_output && rsx::fcmp(avconfig.gamma, 1.f) && avconfig.stereo_mode == stereo_render_mode_options::disabled) { // Blit source image to the screen - m_flip_fbo.recreate(); - m_flip_fbo.bind(); - m_flip_fbo.color = image_to_flip; - m_flip_fbo.read_buffer(m_flip_fbo.color); - m_flip_fbo.draw_buffer(m_flip_fbo.color); - m_flip_fbo.blit(gl::screen, screen_area, aspect_ratio.flipped_vertical(), gl::buffers::color, filter); + m_upscaler->scale_output(cmd, image_to_flip, gl::screen, screen_area, aspect_ratio.flipped_vertical(), gl::UPSCALE_AND_COMMIT); } else { const f32 gamma = avconfig.gamma; const bool limited_range = !use_full_rgb_range_output; const rsx::simple_array images{ image_to_flip, image_to_flip2 }; + const auto filter = m_output_scaling == output_scaling_mode::nearest ? gl::filter::nearest : gl::filter::linear; + // FIXME: Upscaling should optionally happen before this step. + // With linear and nearest scaling, it really doesn't matter here, but for FSR we cannot just bind the images and use a hardware filter. gl::screen.bind(); m_video_output_pass.run(cmd, areau(aspect_ratio), images, gamma, limited_range, avconfig.stereo_mode, filter); } diff --git a/rpcs3/Emu/RSX/GL/glutils/common.h b/rpcs3/Emu/RSX/GL/glutils/common.h index 0de9fe7afd..63e03cbab2 100644 --- a/rpcs3/Emu/RSX/GL/glutils/common.h +++ b/rpcs3/Emu/RSX/GL/glutils/common.h @@ -49,6 +49,9 @@ namespace gl { + using flags32_t = u32; + using handle32_t = u32; + template class save_binding_state_base { diff --git a/rpcs3/Emu/RSX/GL/upscalers/bilinear_pass.hpp b/rpcs3/Emu/RSX/GL/upscalers/bilinear_pass.hpp new file mode 100644 index 0000000000..7172406b17 --- /dev/null +++ b/rpcs3/Emu/RSX/GL/upscalers/bilinear_pass.hpp @@ -0,0 +1,8 @@ +#pragma once + +#include "static_pass.hpp" + +namespace gl +{ + using bilinear_upscale_pass = static_upscale_pass; +} diff --git a/rpcs3/Emu/RSX/GL/upscalers/fsr1/fsr_pass.cpp b/rpcs3/Emu/RSX/GL/upscalers/fsr1/fsr_pass.cpp new file mode 100644 index 0000000000..7f00db6ddf --- /dev/null +++ b/rpcs3/Emu/RSX/GL/upscalers/fsr1/fsr_pass.cpp @@ -0,0 +1,9 @@ +#include "stdafx.h" + +namespace gl +{ + namespace FidelityFX + { + + } +} diff --git a/rpcs3/Emu/RSX/GL/upscalers/nearest_pass.hpp b/rpcs3/Emu/RSX/GL/upscalers/nearest_pass.hpp new file mode 100644 index 0000000000..8027ca9c38 --- /dev/null +++ b/rpcs3/Emu/RSX/GL/upscalers/nearest_pass.hpp @@ -0,0 +1,8 @@ +#pragma once + +#include "static_pass.hpp" + +namespace gl +{ + using nearest_upscale_pass = static_upscale_pass; +} diff --git a/rpcs3/Emu/RSX/GL/upscalers/static_pass.hpp b/rpcs3/Emu/RSX/GL/upscalers/static_pass.hpp new file mode 100644 index 0000000000..ff31c70e16 --- /dev/null +++ b/rpcs3/Emu/RSX/GL/upscalers/static_pass.hpp @@ -0,0 +1,49 @@ +#pragma once + +#include "../glutils/fbo.h" + +#include "upscaling.h" + +namespace gl +{ + template + class static_upscale_pass : public upscaler + { + public: + static_upscale_pass() = default; + ~static_upscale_pass() + { + if (m_flip_fbo) + { + m_flip_fbo.remove(); + } + } + + gl::handle32_t scale_output( + const gl::command_context& /*cmd*/, // State + gl::handle32_t src, // Source input + const gl::fbo& screen, // Present target. May be VK_NULL_HANDLE for some passes + const areai& src_region, // Scaling request information + const areai& dst_region, // Ditto + gl::flags32_t mode // Mode + ) override + { + if (mode & UPSCALE_AND_COMMIT) + { + m_flip_fbo.recreate(); + m_flip_fbo.bind(); + m_flip_fbo.color = src; + m_flip_fbo.read_buffer(m_flip_fbo.color); + m_flip_fbo.draw_buffer(m_flip_fbo.color); + m_flip_fbo.blit(screen, src_region, dst_region, gl::buffers::color, Filter); + return 0; + } + + // Upscaling source only is unsupported + return src; + } + + private: + gl::fbo m_flip_fbo; + }; +} diff --git a/rpcs3/Emu/RSX/GL/upscalers/upscaling.h b/rpcs3/Emu/RSX/GL/upscalers/upscaling.h new file mode 100644 index 0000000000..3581fa2cd3 --- /dev/null +++ b/rpcs3/Emu/RSX/GL/upscalers/upscaling.h @@ -0,0 +1,37 @@ +#pragma once + +#include "util/types.hpp" + +#include "../glutils/fbo.h" +#include "../glutils/image.h" +#include "../glutils/state_tracker.hpp" + +namespace gl +{ + namespace upscaling_flags_ + { + enum upscaling_flags + { + UPSCALE_DEFAULT_VIEW = (1 << 0), + UPSCALE_LEFT_VIEW = (1 << 0), + UPSCALE_RIGHT_VIEW = (1 << 1), + UPSCALE_AND_COMMIT = (1 << 2) + }; + } + + using namespace upscaling_flags_; + + struct upscaler + { + virtual ~upscaler() {} + + virtual gl::handle32_t scale_output( + const gl::command_context& cmd, // State + gl::handle32_t src, // Source input + const gl::fbo& screen, // Present target. May be VK_NULL_HANDLE for some passes + const areai& src_region, // Scaling request information + const areai& dst_region, // Ditto + gl::flags32_t mode // Mode + ) = 0; + }; +}