added fsr/sharpbilinear shaders, and readied opengl for integration

This commit is contained in:
KojoZero 2026-05-29 04:44:17 -07:00
parent 300b68e18d
commit 1035238473
16 changed files with 4303 additions and 49 deletions

View file

@ -44,9 +44,9 @@ ConfigureEnhancements::~ConfigureEnhancements() = default;
void ConfigureEnhancements::SetConfiguration() {
const s32 volume =
static_cast<s32>(Settings::values.fsr_sharpness.GetValue() * 100);
ui->fsr_sharpness_slider->setValue(volume);
const s32 sharpness =
static_cast<s32>(Settings::values.fsr_sharpness.GetValue());
ui->fsr_sharpness_slider->setValue(sharpness);
SetFSRSharpnessIndicatorText(ui->fsr_sharpness_slider->sliderPosition());
if (!Settings::IsConfiguringGlobal()) {

View file

@ -554,7 +554,7 @@ struct Values {
SwitchableSetting<TextureFilter> texture_filter{TextureFilter::NoFilter, Keys::texture_filter};
SwitchableSetting<AntiAliasingFilter> antialiasing_filter{AntiAliasingFilter::None, Keys::antialiasing_filter};
SwitchableSetting<OutputScaling> output_scaling{OutputScaling::Adaptive, Keys::output_scaling};
SwitchableSetting<float, true> fsr_sharpness{0.8f, 0.f, 1.f, Keys::fsr_sharpness};
SwitchableSetting<int, true> fsr_sharpness{80, 0, 100, Keys::fsr_sharpness};
SwitchableSetting<TextureSampling> texture_sampling{TextureSampling::GameControlled,
Keys::texture_sampling};
SwitchableSetting<u16, true> delay_game_render_thread_us{0, 0, 16000,

View file

@ -47,6 +47,17 @@ set(SHADER_FILES
scaling/opengl_area_sampling.vert
scaling/vulkan_area_sampling.frag
scaling/vulkan_area_sampling.vert
scaling/FSR/OpenGL/opengl_fsr_pass0.vert
scaling/FSR/OpenGL/opengl_fsr_pass0_part1.frag
scaling/FSR/OpenGL/opengl_fsr_pass0_part2.frag
scaling/FSR/OpenGL/opengl_fsr_pass1.vert
scaling/FSR/OpenGL/opengl_fsr_pass1_part1.frag
scaling/FSR/OpenGL/opengl_fsr_pass1_part2.frag
scaling/FSR/OpenGL/opengl_fsr_pass1_part3.frag
scaling/FSR/ffx_a.h
scaling/FSR/ffx_fsr1.h
scaling/SharpBilinear/OpenGL/opengl_sharpbilinear.vert
scaling/SharpBilinear/OpenGL/opengl_sharpbilinear.frag
full_screen_triangle.vert
opengl_present.frag
opengl_present.vert

View file

@ -0,0 +1,12 @@
// FSR - [EASU] EDGE ADAPTIVE SPATIAL UPSAMPLING
// SM 4.0 compatible: no textureGather, direct texelFetch of 12 unique texels.
layout(location = 0) in vec2 vert_position;
layout(location = 1) in vec2 vert_tex_coord;
layout(location = 0) out vec2 frag_tex_coord;
void main()
{
gl_Position = vec4(vert_position, 0.0, 1.0);
frag_tex_coord = vert_tex_coord;
}

View file

@ -0,0 +1,20 @@
// FSR - [EASU] EDGE ADAPTIVE SPATIAL UPSAMPLING
// SM 4.0 compatible: no textureGather, direct texelFetch of 12 unique texels.
layout(location = 0) in vec2 frag_tex_coord;
layout(location = 0) out vec4 color;
layout(binding = 0) uniform sampler2D color_texture;
uniform vec4 i_resolution;
uniform vec4 o_resolution;
#define A_GPU 1
#define A_GLSL 1
// #include "ffx_a.h"
// // We intentionally do NOT define FSR_EASU_F here.
// // We only need FsrEasuCon (which compiles under A_GPU alone),
// // and we inline the EASU filter logic below to avoid the
// // textureGather-based callback system entirely.
// // This yields 12 texelFetch calls instead of the original
// // 12 textureGather calls (4 gathers x 3 channels), and is
// // faster than emulating gathers with 48 individual fetches.
// #include "ffx_fsr1.h"

View file

@ -0,0 +1,193 @@
void main() {
// --- Setup constants (same as original) ---
AU4 con0, con1, con2, con3;
FsrEasuCon(con0, con1, con2, con3,
i_resolution.x, i_resolution.y,
i_resolution.x, i_resolution.y,
o_resolution.x, o_resolution.y);
AU2 gxy = AU2(frag_tex_coord.xy * o_resolution.xy);
// --- Get position of 'f' (the center texel of the kernel) ---
AF2 pp = AF2(gxy) * AF2_AU2(con0.xy) + AF2_AU2(con0.zw);
AF2 fp = floor(pp);
pp -= fp;
// --- Fetch all 12 unique texels directly as RGB ---
// The 12-tap kernel layout relative to 'fp':
// b c (0,-1) (1,-1)
// e f g h (-1,0) (0,0) (1,0) (2,0)
// i j k l (-1,1) (0,1) (1,1) (2,1)
// n o (0, 2) (1, 2)
ivec2 sp = ivec2(fp);
AF3 b = texelFetch(color_texture, sp + ivec2( 0,-1), 0).rgb;
AF3 c = texelFetch(color_texture, sp + ivec2( 1,-1), 0).rgb;
AF3 e = texelFetch(color_texture, sp + ivec2(-1, 0), 0).rgb;
AF3 f = texelFetch(color_texture, sp + ivec2( 0, 0), 0).rgb;
AF3 g = texelFetch(color_texture, sp + ivec2( 1, 0), 0).rgb;
AF3 h = texelFetch(color_texture, sp + ivec2( 2, 0), 0).rgb;
AF3 i = texelFetch(color_texture, sp + ivec2(-1, 1), 0).rgb;
AF3 j = texelFetch(color_texture, sp + ivec2( 0, 1), 0).rgb;
AF3 k = texelFetch(color_texture, sp + ivec2( 1, 1), 0).rgb;
AF3 l = texelFetch(color_texture, sp + ivec2( 2, 1), 0).rgb;
AF3 n = texelFetch(color_texture, sp + ivec2( 0, 2), 0).rgb;
AF3 o = texelFetch(color_texture, sp + ivec2( 1, 2), 0).rgb;
// --- Approximate luma (luma times 2, in 2 FMA/MAD) ---
AF1 bL = b.b * AF1_(0.5) + (b.r * AF1_(0.5) + b.g);
AF1 cL = c.b * AF1_(0.5) + (c.r * AF1_(0.5) + c.g);
AF1 eL = e.b * AF1_(0.5) + (e.r * AF1_(0.5) + e.g);
AF1 fL = f.b * AF1_(0.5) + (f.r * AF1_(0.5) + f.g);
AF1 gL = g.b * AF1_(0.5) + (g.r * AF1_(0.5) + g.g);
AF1 hL = h.b * AF1_(0.5) + (h.r * AF1_(0.5) + h.g);
AF1 iL = i.b * AF1_(0.5) + (i.r * AF1_(0.5) + i.g);
AF1 jL = j.b * AF1_(0.5) + (j.r * AF1_(0.5) + j.g);
AF1 kL = k.b * AF1_(0.5) + (k.r * AF1_(0.5) + k.g);
AF1 lL = l.b * AF1_(0.5) + (l.r * AF1_(0.5) + l.g);
AF1 nL = n.b * AF1_(0.5) + (n.r * AF1_(0.5) + n.g);
AF1 oL = o.b * AF1_(0.5) + (o.r * AF1_(0.5) + o.g);
// --- Accumulate direction and length ---
// Inlined FsrEasuSetF for each of the 4 bilinear quadrants.
// Each quadrant computes gradient direction and edge length
// from its 5-tap cross pattern centered on the quadrant's
// nearest texel.
//
// Quadrant layout (bilinear weights):
// s=(1-x)(1-y) t=x(1-y)
// u=(1-x)y v=xy
//
// Cross pattern for each quadrant:
// s: center=f, left=e, right=g, up=b, down=j
// t: center=g, left=f, right=h, up=c, down=k
// u: center=j, left=i, right=k, up=f, down=n
// v: center=k, left=j, right=l, up=g, down=o
AF2 dir = AF2_(0.0);
AF1 len = AF1_(0.0);
// Quadrant s
{
AF1 w = (AF1_(1.0) - pp.x) * (AF1_(1.0) - pp.y);
AF1 dc = gL - fL; AF1 cb = fL - eL;
AF1 lenX = max(abs(dc), abs(cb));
lenX = APrxLoRcpF1(lenX);
AF1 dirX = gL - eL;
dir.x += dirX * w;
lenX = ASatF1(abs(dirX) * lenX); lenX *= lenX; len += lenX * w;
AF1 ec = jL - fL; AF1 ca = fL - bL;
AF1 lenY = max(abs(ec), abs(ca));
lenY = APrxLoRcpF1(lenY);
AF1 dirY = jL - bL;
dir.y += dirY * w;
lenY = ASatF1(abs(dirY) * lenY); lenY *= lenY; len += lenY * w;
}
// Quadrant t
{
AF1 w = pp.x * (AF1_(1.0) - pp.y);
AF1 dc = hL - gL; AF1 cb = gL - fL;
AF1 lenX = max(abs(dc), abs(cb));
lenX = APrxLoRcpF1(lenX);
AF1 dirX = hL - fL;
dir.x += dirX * w;
lenX = ASatF1(abs(dirX) * lenX); lenX *= lenX; len += lenX * w;
AF1 ec = kL - gL; AF1 ca = gL - cL;
AF1 lenY = max(abs(ec), abs(ca));
lenY = APrxLoRcpF1(lenY);
AF1 dirY = kL - cL;
dir.y += dirY * w;
lenY = ASatF1(abs(dirY) * lenY); lenY *= lenY; len += lenY * w;
}
// Quadrant u
{
AF1 w = (AF1_(1.0) - pp.x) * pp.y;
AF1 dc = kL - jL; AF1 cb = jL - iL;
AF1 lenX = max(abs(dc), abs(cb));
lenX = APrxLoRcpF1(lenX);
AF1 dirX = kL - iL;
dir.x += dirX * w;
lenX = ASatF1(abs(dirX) * lenX); lenX *= lenX; len += lenX * w;
AF1 ec = nL - jL; AF1 ca = jL - fL;
AF1 lenY = max(abs(ec), abs(ca));
lenY = APrxLoRcpF1(lenY);
AF1 dirY = nL - fL;
dir.y += dirY * w;
lenY = ASatF1(abs(dirY) * lenY); lenY *= lenY; len += lenY * w;
}
// Quadrant v
{
AF1 w = pp.x * pp.y;
AF1 dc = lL - kL; AF1 cb = kL - jL;
AF1 lenX = max(abs(dc), abs(cb));
lenX = APrxLoRcpF1(lenX);
AF1 dirX = lL - jL;
dir.x += dirX * w;
lenX = ASatF1(abs(dirX) * lenX); lenX *= lenX; len += lenX * w;
AF1 ec = oL - kL; AF1 ca = kL - gL;
AF1 lenY = max(abs(ec), abs(ca));
lenY = APrxLoRcpF1(lenY);
AF1 dirY = oL - gL;
dir.y += dirY * w;
lenY = ASatF1(abs(dirY) * lenY); lenY *= lenY; len += lenY * w;
}
// --- Normalize direction ---
AF2 dir2 = dir * dir;
AF1 dirR = dir2.x + dir2.y;
AP1 zro = dirR < AF1_(1.0 / 32768.0);
dirR = APrxLoRsqF1(dirR);
dirR = zro ? AF1_(1.0) : dirR;
dir.x = zro ? AF1_(1.0) : dir.x;
dir *= AF2_(dirR);
// --- Shape length ---
len = len * AF1_(0.5);
len *= len;
AF1 stretch = (dir.x * dir.x + dir.y * dir.y) * APrxLoRcpF1(max(abs(dir.x), abs(dir.y)));
AF2 len2 = AF2(AF1_(1.0) + (stretch - AF1_(1.0)) * len, AF1_(1.0) + AF1_(-0.5) * len);
AF1 lob = AF1_(0.5) + AF1_((1.0 / 4.0 - 0.04) - 0.5) * len;
AF1 clp = APrxLoRcpF1(lob);
// --- Min/max of 4 nearest (f, g, j, k) for de-ringing ---
AF3 min4 = min(min(f, g), min(j, k));
AF3 max4 = max(max(f, g), max(j, k));
// --- Accumulate 12 taps (inlined FsrEasuTapF) ---
AF3 aC = AF3_(0.0);
AF1 aW = AF1_(0.0);
// Macro for the Lanczos-like kernel evaluation per tap.
// Rotates offset by direction, applies anisotropic scaling,
// evaluates the approximated windowed Lanczos kernel, accumulates.
#define FSR_EASU_TAP(OFF_X, OFF_Y, COLOR) { \
AF2 v; \
v.x = ((OFF_X) - pp.x) * dir.x + ((OFF_Y) - pp.y) * dir.y; \
v.y = ((OFF_X) - pp.x) * (-dir.y) + ((OFF_Y) - pp.y) * dir.x; \
v *= len2; \
AF1 d2 = min(v.x * v.x + v.y * v.y, clp); \
AF1 wB = AF1_(2.0 / 5.0) * d2 + AF1_(-1.0); \
AF1 wA = lob * d2 + AF1_(-1.0); \
wB *= wB; wA *= wA; \
wB = AF1_(25.0 / 16.0) * wB + AF1_(-(25.0 / 16.0 - 1.0)); \
AF1 w = wB * wA; \
aC += (COLOR) * w; aW += w; }
FSR_EASU_TAP( 0.0, -1.0, b) // b
FSR_EASU_TAP( 1.0, -1.0, c) // c
FSR_EASU_TAP(-1.0, 1.0, i) // i
FSR_EASU_TAP( 0.0, 1.0, j) // j
FSR_EASU_TAP( 0.0, 0.0, f) // f
FSR_EASU_TAP(-1.0, 0.0, e) // e
FSR_EASU_TAP( 1.0, 1.0, k) // k
FSR_EASU_TAP( 2.0, 1.0, l) // l
FSR_EASU_TAP( 2.0, 0.0, h) // h
FSR_EASU_TAP( 1.0, 0.0, g) // g
FSR_EASU_TAP( 1.0, 2.0, o) // o
FSR_EASU_TAP( 0.0, 2.0, n) // n
#undef FSR_EASU_TAP
// --- Normalize and de-ring ---
AF3 pix = min(max4, max(min4, aC * AF3_(ARcpF1(aW))));
color = vec4(pix, 1.0);
}

View file

@ -0,0 +1,12 @@
// FSR - [RCAS] ROBUST CONTRAST ADAPTIVE SHARPENING
//? #version 450
layout(location = 0) in vec2 vert_position;
layout(location = 1) in vec2 vert_tex_coord;
layout(location = 0) out vec2 frag_tex_coord;
void main()
{
gl_Position = vec4(vert_position, 0.0, 1.0);
frag_tex_coord = vert_tex_coord;
}

View file

@ -0,0 +1,10 @@
// FSR - [RCAS] ROBUST CONTRAST ADAPTIVE SHARPENING
layout(location = 0) in vec2 frag_tex_coord;
layout(location = 0) out vec4 color;
layout(binding = 0) uniform sampler2D color_texture;
uniform float FSR_SHARPENING;
uniform vec4 o_resolution;
#define A_GPU 1
#define A_GLSL 1
// #include "ffx_a.h"

View file

@ -0,0 +1,7 @@
#define FSR_RCAS_F 1
AU4 con0;
AF4 FsrRcasLoadF(ASU2 p) { return AF4(texelFetch(color_texture, p, 0)); }
void FsrRcasInputF(inout AF1 r, inout AF1 g, inout AF1 b) {}
// #include "ffx_fsr1.h"

View file

@ -0,0 +1,9 @@
void main() {
FsrRcasCon(con0, params.FSR_SHARPENING);
AU2 gxy = AU2(frag_tex_coord.xy * o_resolution.xy); // Integer pixel position in output.
AF3 Gamma2Color = AF3(0, 0, 0);
FsrRcasF(Gamma2Color.r, Gamma2Color.g, Gamma2Color.b, gxy, con0);
color = vec4(Gamma2Color, 1.0);
}

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,52 @@
/*
Author: KojoZero (modified from rsn8887's shader)
License: Public domain
This is an integer prescale filter that should be combined
with a bilinear hardware filtering (GL_BILINEAR filter or some such) to achieve
a smooth scaling result with minimum blur. This is good for pixelgraphics
that are scaled by non-integer factors.
This is a modified version rsn8887's shader which has been modified to scale
until above the output resolution, rather than right below the output resolution.
The prescale factor and texel coordinates are precalculated
in the vertex shader for speed.
*/
layout(location = 0) in vec2 frag_tex_coord;
layout(location = 1) in vec2 precalc_texel;
layout(location = 2) in vec2 precalc_scale;
layout(location = 0) out vec4 color;
layout(binding = 0) uniform sampler2D color_texture;
uniform vec4 i_resolution;
uniform vec4 o_resolution;
uniform int convert_colors;
vec3 LinearTosRGB(vec3 c) {
return mix(c * 12.92, 1.055 * pow(c, vec3(1.0/2.4)) - 0.055, step(0.0031308, c));
}
void main()
{
vec2 texel = precalc_texel;
vec2 scale = precalc_scale;
vec2 texel_floored = floor(texel);
vec2 s = fract(texel);
vec2 region_range = 0.5 - 0.5 / scale;
// Figure out where in the texel to sample to get correct pre-scaled bilinear.
// Uses the hardware bilinear interpolator to avoid having to sample 4 times manually.
vec2 center_dist = s - 0.5;
vec2 f = (center_dist - clamp(center_dist, -region_range, region_range)) * scale + 0.5;
vec2 mod_texel = texel_floored + f;
vec4 pixel = vec4(texture(color_texture, mod_texel / i_resolution.xy).rgb, 1.0);
if (convert_colors == 2){
pixel = vec4(LinearTosRGB(pixel.rgb), pixel.a);
}
color = pixel;
}

View file

@ -0,0 +1,16 @@
layout(location = 0) in vec2 vert_position;
layout(location = 1) in vec2 vert_tex_coord;
layout(location = 0) out vec2 frag_tex_coord;
layout(location = 1) out vec2 precalc_texel;
layout(location = 2) out vec2 precalc_scale;
uniform mat3x2 modelview_matrix;
uniform vec4 i_resolution;
uniform vec4 o_resolution;
void main()
{
gl_Position = vec4(mat2(modelview_matrix) * vert_position + modelview_matrix[2], 0.0, 1.0);
frag_tex_coord = vert_tex_coord;
precalc_scale = ceil(o_resolution.xy / i_resolution.xy);
precalc_texel = vert_tex_coord.xy * i_resolution.xy;
}

View file

@ -44,6 +44,17 @@
#include "video_core/host_shaders/antialiasing/SearchTex.h"
#include "video_core/host_shaders/scaling/opengl_area_sampling_frag.h"
#include "video_core/host_shaders/scaling/opengl_area_sampling_vert.h"
#include "video_core/host_shaders/scaling/FSR/OpenGL/opengl_fsr_pass0_vert.h"
#include "video_core/host_shaders/scaling/FSR/OpenGL/opengl_fsr_pass0_part1_frag.h"
#include "video_core/host_shaders/scaling/FSR/OpenGL/opengl_fsr_pass0_part2_frag.h"
#include "video_core/host_shaders/scaling/FSR/OpenGL/opengl_fsr_pass1_vert.h"
#include "video_core/host_shaders/scaling/FSR/OpenGL/opengl_fsr_pass1_part1_frag.h"
#include "video_core/host_shaders/scaling/FSR/OpenGL/opengl_fsr_pass1_part2_frag.h"
#include "video_core/host_shaders/scaling/FSR/OpenGL/opengl_fsr_pass1_part3_frag.h"
#include "video_core/host_shaders/scaling/FSR/ffx_a_h.h"
#include "video_core/host_shaders/scaling/FSR/ffx_fsr1_h.h"
#include "video_core/host_shaders/scaling/SharpBilinear/OpenGL/opengl_sharpbilinear_vert.h"
#include "video_core/host_shaders/scaling/SharpBilinear/OpenGL/opengl_sharpbilinear_frag.h"
namespace OpenGL {
@ -381,22 +392,37 @@ void RendererOpenGL::AllocateSMAATextures(){
}
void RendererOpenGL::AllocatePPTextures(){
for (int i = 0; i < 5; i++){
intermediateTextureTop[i].Release();
intermediateTextureTop[i].Create();
intermediateTextureTop[i].Allocate(GL_TEXTURE_2D, 1, GL_RGBA16F, currTopTextureWidth, currTopTextureHeight);
intermediateTextureBottom[i].Release();
intermediateTextureBottom[i].Create();
intermediateTextureBottom[i].Allocate(GL_TEXTURE_2D, 1, GL_RGBA16F, currBottomTextureWidth, currBottomTextureHeight);
}
antialiasFBOTextureTop.Release();
antialiasFBOTextureTop.Create();
antialiasFBOTextureTop.Allocate(GL_TEXTURE_2D, 1, GL_RGBA16F, currTopTextureWidth, currTopTextureHeight);
antialiasFBOTextureBottom.Release();
antialiasFBOTextureBottom.Create();
antialiasFBOTextureBottom.Allocate(GL_TEXTURE_2D, 1, GL_RGBA16F, currBottomTextureWidth, currBottomTextureHeight);
LOG_INFO(Render_OpenGL, "Reallocated Shaders");
for (int j = 0; j < intermediateTextures[0].size(); j++){
intermediateTextures[0][j].Release();
intermediateTextures[0][j].Create();
intermediateTextures[0][j].Allocate(GL_TEXTURE_2D, 1, GL_RGBA16F, currTopTextureWidth, currTopTextureHeight);
intermediateTextures[1][j].Release();
intermediateTextures[1][j].Create();
intermediateTextures[1][j].Allocate(GL_TEXTURE_2D, 1, GL_RGBA16F, currBottomTextureWidth, currBottomTextureHeight);
}
antialiasFBOTexture[0].Release();
antialiasFBOTexture[0].Create();
antialiasFBOTexture[0].Allocate(GL_TEXTURE_2D, 1, GL_RGBA16F, currTopTextureWidth, currTopTextureHeight);
antialiasFBOTexture[1].Release();
antialiasFBOTexture[1].Create();
antialiasFBOTexture[1].Allocate(GL_TEXTURE_2D, 1, GL_RGBA16F, currBottomTextureWidth, currBottomTextureHeight);
LOG_INFO(Render_OpenGL, "Reallocated Textures");
}
void RendererOpenGL::AllocateOutputSizeTextures(){
for (int i = 0; i < intermediateOutputSizeTextures.size(); i++){
if (currScreenRects[i].GetHeight() != 0 && currScreenRects[i].GetWidth() != 0){
for (int j = 0; j < intermediateOutputSizeTextures[0].size(); j++){
intermediateOutputSizeTextures[i][j].Release();
intermediateOutputSizeTextures[i][j].Create();
intermediateOutputSizeTextures[i][j].Allocate(GL_TEXTURE_2D, 1, GL_RGBA16F, currScreenRects[i].GetWidth(), currScreenRects[i].GetHeight());
}
}
}
LOG_INFO(Render_OpenGL, "Reallocated OutputSize Textures");
}
/**
@ -548,7 +574,23 @@ void RendererOpenGL::ReloadShader(Settings::StereoRenderOption render_3d) {
SMAA_PASS_2_shader.Create(SMAA_PASS_2_shader_vert_data, SMAA_PASS_2_shader_frag_data);
//
std::string FSR_PASS_0_shader_frag_data = fragment_shader_precision_OES;
FSR_PASS_0_shader_frag_data += HostShaders::OPENGL_FSR_PASS0_PART1_FRAG;
FSR_PASS_0_shader_frag_data += HostShaders::FFX_A_H;
FSR_PASS_0_shader_frag_data += HostShaders::FFX_FSR1_H;
FSR_PASS_0_shader_frag_data += HostShaders::OPENGL_FSR_PASS0_PART2_FRAG;
FSR_PASS_0_shader.Create(HostShaders::OPENGL_FSR_PASS0_VERT, FSR_PASS_0_shader_frag_data);
std::string FSR_PASS_1_shader_frag_data = fragment_shader_precision_OES;
FSR_PASS_1_shader_frag_data += HostShaders::OPENGL_FSR_PASS1_PART1_FRAG;
FSR_PASS_1_shader_frag_data += HostShaders::FFX_A_H;
FSR_PASS_1_shader_frag_data += HostShaders::OPENGL_FSR_PASS1_PART2_FRAG;
FSR_PASS_1_shader_frag_data += HostShaders::FFX_FSR1_H;
FSR_PASS_1_shader_frag_data += HostShaders::OPENGL_FSR_PASS1_PART3_FRAG;
FSR_PASS_1_shader.Create(HostShaders::OPENGL_FSR_PASS1_VERT, FSR_PASS_1_shader_frag_data);
SharpBilinear_shader.Create(HostShaders::OPENGL_SHARPBILINEAR_VERT, HostShaders::OPENGL_SHARPBILINEAR_FRAG);
state.Apply();
if (render_3d == Settings::StereoRenderOption::Anaglyph ||
render_3d == Settings::StereoRenderOption::Interlaced ||
@ -654,12 +696,11 @@ void RendererOpenGL::DrawSingleScreen(const ScreenInfo& screen_info, float scree
const u32 scale_factor = GetResolutionScaleFactor();
float textureWidth = static_cast<float>(screen_info.texture.height * scale_factor);
float textureHeight = static_cast<float>(screen_info.texture.width * scale_factor);
int currScreen;
if (textureWidth == currTopTextureWidth && textureHeight == currTopTextureHeight){
currAntialiasFBOTexture = &antialiasFBOTextureTop;
currIntermediateTexture = &intermediateTextureTop;
currScreen = 0;
} else {
currAntialiasFBOTexture = &antialiasFBOTextureBottom;
currIntermediateTexture = &intermediateTextureBottom;
currScreen = 1;
}
// Texture Width and Height when correctly rotated to landscape
@ -667,6 +708,7 @@ void RendererOpenGL::DrawSingleScreen(const ScreenInfo& screen_info, float scree
int scalingMode; //0 is Nearest Neighbor, 1 is Gamma Corrected Bilinear, 2 is Adaptive (Bilinear/Area), 3 is FSR, 4 is Sharp Bilinear
scalingMode = static_cast<int>(Settings::values.output_scaling.GetValue());
int antialiasingMode = static_cast<int>(Settings::values.antialiasing_filter.GetValue()); //0 is none, 1 is FXAA, 2 is SMAA
float fsr_sharpening = 2 - (2 * (Settings::values.fsr_sharpness.GetValue()/ 100.0f));
if (orientation == Layout::DisplayOrientation::Landscape || orientation == Layout::DisplayOrientation::LandscapeFlipped) {
if (textureWidth > screenWidth){
isDownsampling = true;
@ -748,7 +790,7 @@ void RendererOpenGL::DrawSingleScreen(const ScreenInfo& screen_info, float scree
state.viewport.width = textureWidth;
state.viewport.height = textureHeight;
state.Apply();
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, (*currIntermediateTexture)[0].handle, 0);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, intermediateTextures[currScreen][0].handle, 0);
glClear(GL_COLOR_BUFFER_BIT);
state.draw.shader_program = SimplePresent_shader.handle;
state.Apply();
@ -767,12 +809,12 @@ void RendererOpenGL::DrawSingleScreen(const ScreenInfo& screen_info, float scree
state.viewport.width = textureWidth;
state.viewport.height = textureHeight;
state.Apply();
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, (*currAntialiasFBOTexture).handle, 0);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, antialiasFBOTexture[currScreen].handle, 0);
glClear(GL_COLOR_BUFFER_BIT);
state.draw.shader_program = FXAA_shader.handle;
state.Apply();
AttachUniforms();
state.texture_units[0].texture_2d = (*currIntermediateTexture)[0].handle;
state.texture_units[0].texture_2d = intermediateTextures[currScreen][0].handle;
state.texture_units[0].sampler = samplers[1].handle;
glUniform1i(uniform_color_texture, 0);
glUniform1i(uniform_convert_colors, 1);
@ -791,7 +833,7 @@ void RendererOpenGL::DrawSingleScreen(const ScreenInfo& screen_info, float scree
state.viewport.width = textureWidth;
state.viewport.height = textureHeight;
state.Apply();
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, (*currIntermediateTexture)[0].handle, 0);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, intermediateTextures[currScreen][0].handle, 0);
glClear(GL_COLOR_BUFFER_BIT);
state.draw.shader_program = SimplePresent_shader.handle;
state.Apply();
@ -810,12 +852,12 @@ void RendererOpenGL::DrawSingleScreen(const ScreenInfo& screen_info, float scree
state.viewport.width = textureWidth;
state.viewport.height = textureHeight;
state.Apply();
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, (*currIntermediateTexture)[3].handle, 0);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, intermediateTextures[currScreen][3].handle, 0);
glClear(GL_COLOR_BUFFER_BIT);
state.draw.shader_program = SimplePresent_shader.handle;
state.Apply();
AttachUniforms();
state.texture_units[0].texture_2d = (*currIntermediateTexture)[0].handle;
state.texture_units[0].texture_2d = intermediateTextures[currScreen][0].handle;
state.texture_units[0].sampler = samplers[1].handle;
glUniform1i(uniform_color_texture, 0);
glUniform1i(uniform_convert_colors, 1);
@ -829,12 +871,12 @@ void RendererOpenGL::DrawSingleScreen(const ScreenInfo& screen_info, float scree
state.viewport.width = textureWidth;
state.viewport.height = textureHeight;
state.Apply();
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, (*currIntermediateTexture)[1].handle, 0);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, intermediateTextures[currScreen][1].handle, 0);
glClear(GL_COLOR_BUFFER_BIT);
state.draw.shader_program = SMAA_PASS_0_shader.handle;
state.Apply();
AttachUniforms();
state.texture_units[0].texture_2d = (*currIntermediateTexture)[0].handle;
state.texture_units[0].texture_2d = intermediateTextures[currScreen][0].handle;
state.texture_units[0].sampler = samplers[1].handle;
glUniform1i(uniform_color_texture, 0);
glUniform4f(uniform_i_resolution, textureWidth, textureHeight, 1.0f / textureWidth, 1.0f / textureHeight);
@ -848,12 +890,12 @@ void RendererOpenGL::DrawSingleScreen(const ScreenInfo& screen_info, float scree
state.viewport.width = textureWidth;
state.viewport.height = textureHeight;
state.Apply();
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, (*currIntermediateTexture)[2].handle, 0);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, intermediateTextures[currScreen][2].handle, 0);
glClear(GL_COLOR_BUFFER_BIT);
state.draw.shader_program = SMAA_PASS_1_shader.handle;
state.Apply();
AttachUniforms();
state.texture_units[0].texture_2d = (*currIntermediateTexture)[1].handle;
state.texture_units[0].texture_2d = intermediateTextures[currScreen][1].handle;
state.texture_units[0].sampler = samplers[1].handle;
state.texture_units[1].texture_2d = areatex.handle;
state.texture_units[1].sampler = samplers[1].handle;
@ -875,14 +917,14 @@ void RendererOpenGL::DrawSingleScreen(const ScreenInfo& screen_info, float scree
state.viewport.width = textureWidth;
state.viewport.height = textureHeight;
state.Apply();
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, (*currAntialiasFBOTexture).handle, 0);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, antialiasFBOTexture[currScreen].handle, 0);
glClear(GL_COLOR_BUFFER_BIT);
state.draw.shader_program = SMAA_PASS_2_shader.handle;
state.Apply();
AttachUniforms();
state.texture_units[0].texture_2d = (*currIntermediateTexture)[2].handle;
state.texture_units[0].texture_2d = intermediateTextures[currScreen][2].handle;
state.texture_units[0].sampler = samplers[1].handle;
state.texture_units[1].texture_2d = (*currIntermediateTexture)[3].handle;
state.texture_units[1].texture_2d = intermediateTextures[currScreen][3].handle;
state.texture_units[1].sampler = samplers[1].handle;
GLuint uniform_smaa_input = glGetUniformLocation(state.draw.shader_program, "SMAA_Input");
glUniform1i(uniform_color_texture, 0);
@ -901,7 +943,7 @@ void RendererOpenGL::DrawSingleScreen(const ScreenInfo& screen_info, float scree
state.viewport.width = textureWidth;
state.viewport.height = textureHeight;
state.Apply();
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, (*currAntialiasFBOTexture).handle, 0);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, antialiasFBOTexture[currScreen].handle, 0);
glClear(GL_COLOR_BUFFER_BIT);
state.draw.shader_program = SimplePresent_shader.handle;
state.Apply();
@ -928,7 +970,7 @@ void RendererOpenGL::DrawSingleScreen(const ScreenInfo& screen_info, float scree
state.draw.shader_program = AREA_SAMPLING_shader.handle;
state.Apply();
AttachUniforms();
state.texture_units[0].texture_2d = (*currAntialiasFBOTexture).handle;
state.texture_units[0].texture_2d = antialiasFBOTexture[currScreen].handle;
state.texture_units[0].sampler = samplers[0].handle;
glUniform1i(uniform_color_texture, 0);
glUniform1i(uniform_convert_colors, 2);
@ -951,7 +993,7 @@ void RendererOpenGL::DrawSingleScreen(const ScreenInfo& screen_info, float scree
state.draw.shader_program = Present_shader.handle;
state.Apply();
AttachUniforms();
state.texture_units[0].texture_2d = (*currAntialiasFBOTexture).handle;
state.texture_units[0].texture_2d = antialiasFBOTexture[currScreen].handle;
state.texture_units[0].sampler = samplers[1].handle;
glUniform1i(uniform_color_texture, 0);
glUniform1i(uniform_convert_colors, 2);
@ -973,7 +1015,7 @@ void RendererOpenGL::DrawSingleScreen(const ScreenInfo& screen_info, float scree
state.draw.shader_program = Present_shader.handle;
state.Apply();
AttachUniforms();
state.texture_units[0].texture_2d = (*currAntialiasFBOTexture).handle;
state.texture_units[0].texture_2d = antialiasFBOTexture[currScreen].handle;
if (scalingMode == 1){
state.texture_units[0].sampler = samplers[1].handle;
} else {
@ -1095,13 +1137,24 @@ void RendererOpenGL::DrawScreens(const Layout::FramebufferLayout& layout, bool f
currBottomTextureHeight = static_cast<float>(screen_infos[2].texture.width * GetResolutionScaleFactor());
if (currTopTextureWidth != prevTopTextureWidth || currTopTextureHeight != prevTopTextureHeight || currBottomTextureWidth != prevBottomTextureWidth || currBottomTextureHeight != prevBottomTextureHeight){
AllocatePPTextures();
LOG_INFO(Render_OpenGL, "PrevTopTexture Res: {}x{}, CurrTopTexture Res: {}x{}, PrevBottomTexture Res: {}x{}, CurrBottomTexture Res: {}x{}", prevTopTextureWidth, prevTopTextureHeight, currTopTextureWidth, currTopTextureHeight, prevBottomTextureWidth, prevBottomTextureHeight, currBottomTextureWidth, currBottomTextureHeight);
// LOG_INFO(Render_OpenGL, "PrevTopTexture Res: {}x{}, CurrTopTexture Res: {}x{}, PrevBottomTexture Res: {}x{}, CurrBottomTexture Res: {}x{}", prevTopTextureWidth, prevTopTextureHeight, currTopTextureWidth, currTopTextureHeight, prevBottomTextureWidth, prevBottomTextureHeight, currBottomTextureWidth, currBottomTextureHeight);
}
prevTopTextureWidth = currTopTextureWidth;
prevTopTextureHeight = currTopTextureHeight;
prevBottomTextureWidth = currBottomTextureWidth;
prevBottomTextureHeight = currBottomTextureHeight;
//Track Layout Changes
currScreenRects[0] = layout.top_screen;
currScreenRects[1] = layout.bottom_screen;
currScreenRects[2] = layout.additional_screen;
if (currScreenRects[0] != prevScreenRects[0] || currScreenRects[1] != prevScreenRects[1] || currScreenRects[2] != prevScreenRects[2]){
AllocateOutputSizeTextures();
}
prevScreenRects[0] = currScreenRects[0];
prevScreenRects[1] = currScreenRects[1];
prevScreenRects[2] = currScreenRects[2];
//Set the Viewport
state.viewport.x = 0;
state.viewport.y = 0;

View file

@ -60,6 +60,7 @@ private:
void ReloadShader(Settings::StereoRenderOption render_3d);
void AllocateSMAATextures();
void AllocatePPTextures();
void AllocateOutputSizeTextures();
void PrepareRendertarget();
void RenderScreenshot();
void RenderToMailbox(const Layout::FramebufferLayout& layout,
@ -102,19 +103,22 @@ private:
OGLProgram SMAA_PASS_1_shader;
OGLProgram SMAA_PASS_2_shader;
OGLProgram AREA_SAMPLING_shader;
OGLProgram FSR_PASS_0_shader;
OGLProgram FSR_PASS_1_shader;
OGLProgram SharpBilinear_shader;
OGLFramebuffer screenshot_framebuffer;
std::array<OGLSampler, 2> samplers;
// OpenGL objects for post processing
OGLFramebuffer textureFBO;
std::array<OGLTexture, 5> intermediateTextureTop;
std::array<OGLTexture, 5> intermediateTextureBottom;
OGLTexture antialiasFBOTextureTop;
OGLTexture antialiasFBOTextureBottom;
//Textures for Top and Bottom Screen Respectively
std::array<std::array<OGLTexture, 5>, 2> intermediateTextures;
std::array<OGLTexture, 2> antialiasFBOTexture;
OGLTexture* currAntialiasFBOTexture;
std::array<OGLTexture, 5>* currIntermediateTexture;
//Intermediate Textures at output size. These are for Top Screen, Bottom Screen and Additional Screen Respectively
std::array<std::array<OGLTexture, 3>, 3> intermediateOutputSizeTextures;
std::array<Common::Rectangle<u32>, 3> prevScreenRects;
std::array<Common::Rectangle<u32>, 3> currScreenRects;
OGLTexture areatex;
OGLTexture searchtex;