gl: Introduce the concept of scaling passes to the backend

This commit is contained in:
kd-11 2024-02-22 03:53:57 +03:00 committed by kd-11
parent e7d8ef924f
commit 12694dcf69
11 changed files with 148 additions and 14 deletions

View File

@ -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

View File

@ -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)
{

View File

@ -12,6 +12,7 @@
#include <unordered_map>
#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<gl::framebuffer_holder> m_framebuffer_cache;
gl::fbo m_flip_fbo;
std::unique_ptr<gl::texture> m_flip_tex_color[2];
// Present
std::unique_ptr<gl::upscaler> m_upscaler;
output_scaling_mode m_output_scaling = output_scaling_mode::bilinear;
//vaos are mandatory for core profile
gl::vao m_vao;

View File

@ -482,6 +482,7 @@ namespace gl
m_sampler.set_parameteri(GL_TEXTURE_MIN_FILTER, static_cast<GLenum>(m_input_filter));
m_sampler.set_parameteri(GL_TEXTURE_MAG_FILTER, static_cast<GLenum>(m_input_filter));
}
program_handle.uniforms["gamma"] = gamma;
program_handle.uniforms["limit_range"] = limited_rgb + 0;
program_handle.uniforms["stereo_display_mode"] = static_cast<u8>(stereo_mode);

View File

@ -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<int>(buffer_width), static_cast<int>(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<gl::nearest_upscale_pass>();
break;
case output_scaling_mode::fsr:
// Unimplemented
[[ fallthrough ]];
case output_scaling_mode::bilinear:
default:
m_upscaler = std::make_unique<gl::bilinear_upscale_pass>();
}
}
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<GLuint> 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);
}

View File

@ -49,6 +49,9 @@
namespace gl
{
using flags32_t = u32;
using handle32_t = u32;
template<typename Type, uint BindId, uint GetStateId>
class save_binding_state_base
{

View File

@ -0,0 +1,8 @@
#pragma once
#include "static_pass.hpp"
namespace gl
{
using bilinear_upscale_pass = static_upscale_pass<gl::filter::linear>;
}

View File

@ -0,0 +1,9 @@
#include "stdafx.h"
namespace gl
{
namespace FidelityFX
{
}
}

View File

@ -0,0 +1,8 @@
#pragma once
#include "static_pass.hpp"
namespace gl
{
using nearest_upscale_pass = static_upscale_pass<gl::filter::nearest>;
}

View File

@ -0,0 +1,49 @@
#pragma once
#include "../glutils/fbo.h"
#include "upscaling.h"
namespace gl
{
template<gl::filter Filter>
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;
};
}

View File

@ -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;
};
}