mirror of
https://git.suyu.dev/suyu/suyu.git
synced 2024-11-22 10:51:50 -05:00
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
|
@ -52,6 +52,8 @@ add_library(video_core STATIC
|
|||
engines/puller.cpp
|
||||
engines/puller.h
|
||||
framebuffer_config.h
|
||||
fsr.cpp
|
||||
fsr.h
|
||||
host1x/codecs/codec.cpp
|
||||
host1x/codecs/codec.h
|
||||
host1x/codecs/h264.cpp
|
||||
|
@ -110,6 +112,8 @@ add_library(video_core STATIC
|
|||
renderer_opengl/gl_device.h
|
||||
renderer_opengl/gl_fence_manager.cpp
|
||||
renderer_opengl/gl_fence_manager.h
|
||||
renderer_opengl/gl_fsr.cpp
|
||||
renderer_opengl/gl_fsr.h
|
||||
renderer_opengl/gl_graphics_pipeline.cpp
|
||||
renderer_opengl/gl_graphics_pipeline.h
|
||||
renderer_opengl/gl_rasterizer.cpp
|
||||
|
|
148
src/video_core/fsr.cpp
Normal file
148
src/video_core/fsr.cpp
Normal file
|
@ -0,0 +1,148 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include <cmath>
|
||||
#include "video_core/fsr.h"
|
||||
|
||||
namespace FSR {
|
||||
namespace {
|
||||
// Reimplementations of the constant generating functions in ffx_fsr1.h
|
||||
// GCC generated a lot of warnings when using the official header.
|
||||
u32 AU1_AH1_AF1(f32 f) {
|
||||
static constexpr u32 base[512]{
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0001, 0x0002, 0x0004, 0x0008, 0x0010, 0x0020, 0x0040,
|
||||
0x0080, 0x0100, 0x0200, 0x0400, 0x0800, 0x0c00, 0x1000, 0x1400, 0x1800, 0x1c00, 0x2000,
|
||||
0x2400, 0x2800, 0x2c00, 0x3000, 0x3400, 0x3800, 0x3c00, 0x4000, 0x4400, 0x4800, 0x4c00,
|
||||
0x5000, 0x5400, 0x5800, 0x5c00, 0x6000, 0x6400, 0x6800, 0x6c00, 0x7000, 0x7400, 0x7800,
|
||||
0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff,
|
||||
0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff,
|
||||
0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff,
|
||||
0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff,
|
||||
0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff,
|
||||
0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff,
|
||||
0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff,
|
||||
0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff,
|
||||
0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff,
|
||||
0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff,
|
||||
0x7bff, 0x7bff, 0x7bff, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000,
|
||||
0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000,
|
||||
0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000,
|
||||
0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000,
|
||||
0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000,
|
||||
0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000,
|
||||
0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000,
|
||||
0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000,
|
||||
0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000,
|
||||
0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8001, 0x8002, 0x8004, 0x8008,
|
||||
0x8010, 0x8020, 0x8040, 0x8080, 0x8100, 0x8200, 0x8400, 0x8800, 0x8c00, 0x9000, 0x9400,
|
||||
0x9800, 0x9c00, 0xa000, 0xa400, 0xa800, 0xac00, 0xb000, 0xb400, 0xb800, 0xbc00, 0xc000,
|
||||
0xc400, 0xc800, 0xcc00, 0xd000, 0xd400, 0xd800, 0xdc00, 0xe000, 0xe400, 0xe800, 0xec00,
|
||||
0xf000, 0xf400, 0xf800, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff,
|
||||
0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff,
|
||||
0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff,
|
||||
0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff,
|
||||
0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff,
|
||||
0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff,
|
||||
0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff,
|
||||
0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff,
|
||||
0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff,
|
||||
0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff,
|
||||
0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff,
|
||||
};
|
||||
static constexpr s8 shift[512]{
|
||||
0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
|
||||
0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
|
||||
0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
|
||||
0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
|
||||
0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
|
||||
0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
|
||||
0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x17, 0x16,
|
||||
0x15, 0x14, 0x13, 0x12, 0x11, 0x10, 0x0f, 0x0e, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d,
|
||||
0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d,
|
||||
0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
|
||||
0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
|
||||
0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
|
||||
0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
|
||||
0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
|
||||
0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
|
||||
0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
|
||||
0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
|
||||
0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
|
||||
0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
|
||||
0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
|
||||
0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
|
||||
0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
|
||||
0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
|
||||
0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x17,
|
||||
0x16, 0x15, 0x14, 0x13, 0x12, 0x11, 0x10, 0x0f, 0x0e, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d,
|
||||
0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d,
|
||||
0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
|
||||
0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
|
||||
0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
|
||||
0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
|
||||
0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
|
||||
0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
|
||||
0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
|
||||
0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
|
||||
0x18, 0x18,
|
||||
};
|
||||
const u32 u = Common::BitCast<u32>(f);
|
||||
const u32 i = u >> 23;
|
||||
return base[i] + ((u & 0x7fffff) >> shift[i]);
|
||||
}
|
||||
|
||||
u32 AU1_AH2_AF2(f32 a[2]) {
|
||||
return AU1_AH1_AF1(a[0]) + (AU1_AH1_AF1(a[1]) << 16);
|
||||
}
|
||||
|
||||
void FsrEasuCon(u32 con0[4], u32 con1[4], u32 con2[4], u32 con3[4], f32 inputViewportInPixelsX,
|
||||
f32 inputViewportInPixelsY, f32 inputSizeInPixelsX, f32 inputSizeInPixelsY,
|
||||
f32 outputSizeInPixelsX, f32 outputSizeInPixelsY) {
|
||||
con0[0] = Common::BitCast<u32>(inputViewportInPixelsX / outputSizeInPixelsX);
|
||||
con0[1] = Common::BitCast<u32>(inputViewportInPixelsY / outputSizeInPixelsY);
|
||||
con0[2] = Common::BitCast<u32>(0.5f * inputViewportInPixelsX / outputSizeInPixelsX - 0.5f);
|
||||
con0[3] = Common::BitCast<u32>(0.5f * inputViewportInPixelsY / outputSizeInPixelsY - 0.5f);
|
||||
con1[0] = Common::BitCast<u32>(1.0f / inputSizeInPixelsX);
|
||||
con1[1] = Common::BitCast<u32>(1.0f / inputSizeInPixelsY);
|
||||
con1[2] = Common::BitCast<u32>(1.0f / inputSizeInPixelsX);
|
||||
con1[3] = Common::BitCast<u32>(-1.0f / inputSizeInPixelsY);
|
||||
con2[0] = Common::BitCast<u32>(-1.0f / inputSizeInPixelsX);
|
||||
con2[1] = Common::BitCast<u32>(2.0f / inputSizeInPixelsY);
|
||||
con2[2] = Common::BitCast<u32>(1.0f / inputSizeInPixelsX);
|
||||
con2[3] = Common::BitCast<u32>(2.0f / inputSizeInPixelsY);
|
||||
con3[0] = Common::BitCast<u32>(0.0f / inputSizeInPixelsX);
|
||||
con3[1] = Common::BitCast<u32>(4.0f / inputSizeInPixelsY);
|
||||
con3[2] = con3[3] = 0;
|
||||
}
|
||||
} // Anonymous namespace
|
||||
|
||||
void FsrEasuConOffset(u32 con0[4], u32 con1[4], u32 con2[4], u32 con3[4],
|
||||
f32 inputViewportInPixelsX, f32 inputViewportInPixelsY,
|
||||
f32 inputSizeInPixelsX, f32 inputSizeInPixelsY, f32 outputSizeInPixelsX,
|
||||
f32 outputSizeInPixelsY, f32 inputOffsetInPixelsX, f32 inputOffsetInPixelsY) {
|
||||
FsrEasuCon(con0, con1, con2, con3, inputViewportInPixelsX, inputViewportInPixelsY,
|
||||
inputSizeInPixelsX, inputSizeInPixelsY, outputSizeInPixelsX, outputSizeInPixelsY);
|
||||
con0[2] = Common::BitCast<u32>(0.5f * inputViewportInPixelsX / outputSizeInPixelsX - 0.5f +
|
||||
inputOffsetInPixelsX);
|
||||
con0[3] = Common::BitCast<u32>(0.5f * inputViewportInPixelsY / outputSizeInPixelsY - 0.5f +
|
||||
inputOffsetInPixelsY);
|
||||
}
|
||||
|
||||
void FsrRcasCon(u32* con, f32 sharpness) {
|
||||
sharpness = std::exp2f(-sharpness);
|
||||
f32 hSharp[2]{sharpness, sharpness};
|
||||
con[0] = Common::BitCast<u32>(sharpness);
|
||||
con[1] = AU1_AH2_AF2(hSharp);
|
||||
con[2] = 0;
|
||||
con[3] = 0;
|
||||
}
|
||||
} // namespace FSR
|
19
src/video_core/fsr.h
Normal file
19
src/video_core/fsr.h
Normal file
|
@ -0,0 +1,19 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "common/bit_cast.h"
|
||||
#include "common/common_types.h"
|
||||
|
||||
namespace FSR {
|
||||
// Reimplementations of the constant generating functions in ffx_fsr1.h
|
||||
// GCC generated a lot of warnings when using the official header.
|
||||
void FsrEasuConOffset(u32 con0[4], u32 con1[4], u32 con2[4], u32 con3[4],
|
||||
f32 inputViewportInPixelsX, f32 inputViewportInPixelsY,
|
||||
f32 inputSizeInPixelsX, f32 inputSizeInPixelsY, f32 outputSizeInPixelsX,
|
||||
f32 outputSizeInPixelsY, f32 inputOffsetInPixelsX, f32 inputOffsetInPixelsY);
|
||||
|
||||
void FsrRcasCon(u32* con, f32 sharpness);
|
||||
|
||||
} // namespace FSR
|
|
@ -3,12 +3,16 @@
|
|||
|
||||
set(FIDELITYFX_INCLUDE_DIR ${CMAKE_SOURCE_DIR}/externals/FidelityFX-FSR/ffx-fsr)
|
||||
|
||||
set(GLSL_INCLUDES
|
||||
fidelityfx_fsr.comp
|
||||
set(FIDELITYFX_FILES
|
||||
${FIDELITYFX_INCLUDE_DIR}/ffx_a.h
|
||||
${FIDELITYFX_INCLUDE_DIR}/ffx_fsr1.h
|
||||
)
|
||||
|
||||
set(GLSL_INCLUDES
|
||||
fidelityfx_fsr.comp
|
||||
${FIDELITYFX_FILES}
|
||||
)
|
||||
|
||||
set(SHADER_FILES
|
||||
astc_decoder.comp
|
||||
blit_color_float.frag
|
||||
|
@ -24,6 +28,9 @@ set(SHADER_FILES
|
|||
fxaa.vert
|
||||
opengl_convert_s8d24.comp
|
||||
opengl_copy_bc4.comp
|
||||
opengl_fidelityfx_fsr.frag
|
||||
opengl_fidelityfx_fsr_easu.frag
|
||||
opengl_fidelityfx_fsr_rcas.frag
|
||||
opengl_present.frag
|
||||
opengl_present.vert
|
||||
opengl_present_scaleforce.frag
|
||||
|
@ -118,6 +125,25 @@ foreach(FILENAME IN ITEMS ${SHADER_FILES})
|
|||
endif()
|
||||
endforeach()
|
||||
|
||||
foreach(FILEPATH IN ITEMS ${FIDELITYFX_FILES})
|
||||
get_filename_component(FILENAME ${FILEPATH} NAME)
|
||||
string(REPLACE "." "_" HEADER_NAME ${FILENAME})
|
||||
set(SOURCE_FILE ${FILEPATH})
|
||||
set(SOURCE_HEADER_FILE ${SHADER_DIR}/${HEADER_NAME}.h)
|
||||
add_custom_command(
|
||||
OUTPUT
|
||||
${SOURCE_HEADER_FILE}
|
||||
COMMAND
|
||||
${CMAKE_COMMAND} -P ${HEADER_GENERATOR} ${SOURCE_FILE} ${SOURCE_HEADER_FILE} ${INPUT_FILE}
|
||||
MAIN_DEPENDENCY
|
||||
${SOURCE_FILE}
|
||||
DEPENDS
|
||||
${INPUT_FILE}
|
||||
# HEADER_GENERATOR should be included here but msbuild seems to assume it's always modified
|
||||
)
|
||||
set(SHADER_HEADERS ${SHADER_HEADERS} ${SOURCE_HEADER_FILE})
|
||||
endforeach()
|
||||
|
||||
set(SHADER_SOURCES ${SHADER_FILES})
|
||||
list(APPEND SHADER_SOURCES ${GLSL_INCLUDES})
|
||||
|
||||
|
|
108
src/video_core/host_shaders/opengl_fidelityfx_fsr.frag
Normal file
108
src/video_core/host_shaders/opengl_fidelityfx_fsr.frag
Normal file
|
@ -0,0 +1,108 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
//!#version 460 core
|
||||
#extension GL_ARB_separate_shader_objects : enable
|
||||
#extension GL_ARB_shading_language_420pack : enable
|
||||
|
||||
#extension GL_AMD_gpu_shader_half_float : enable
|
||||
#extension GL_NV_gpu_shader5 : enable
|
||||
|
||||
// FidelityFX Super Resolution Sample
|
||||
//
|
||||
// Copyright (c) 2021 Advanced Micro Devices, Inc. All rights reserved.
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files(the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions :
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
layout (location = 0) uniform uvec4 constants[4];
|
||||
|
||||
#define A_GPU 1
|
||||
#define A_GLSL 1
|
||||
|
||||
#ifdef YUZU_USE_FP16
|
||||
#define A_HALF
|
||||
#endif
|
||||
#include "ffx_a.h"
|
||||
|
||||
#ifndef YUZU_USE_FP16
|
||||
layout (binding=0) uniform sampler2D InputTexture;
|
||||
#if USE_EASU
|
||||
#define FSR_EASU_F 1
|
||||
AF4 FsrEasuRF(AF2 p) { AF4 res = textureGather(InputTexture, p, 0); return res; }
|
||||
AF4 FsrEasuGF(AF2 p) { AF4 res = textureGather(InputTexture, p, 1); return res; }
|
||||
AF4 FsrEasuBF(AF2 p) { AF4 res = textureGather(InputTexture, p, 2); return res; }
|
||||
#endif
|
||||
#if USE_RCAS
|
||||
#define FSR_RCAS_F
|
||||
AF4 FsrRcasLoadF(ASU2 p) { return texelFetch(InputTexture, ASU2(p), 0); }
|
||||
void FsrRcasInputF(inout AF1 r, inout AF1 g, inout AF1 b) {}
|
||||
#endif
|
||||
#else
|
||||
layout (binding=0) uniform sampler2D InputTexture;
|
||||
#if USE_EASU
|
||||
#define FSR_EASU_H 1
|
||||
AH4 FsrEasuRH(AF2 p) { AH4 res = AH4(textureGather(InputTexture, p, 0)); return res; }
|
||||
AH4 FsrEasuGH(AF2 p) { AH4 res = AH4(textureGather(InputTexture, p, 1)); return res; }
|
||||
AH4 FsrEasuBH(AF2 p) { AH4 res = AH4(textureGather(InputTexture, p, 2)); return res; }
|
||||
#endif
|
||||
#if USE_RCAS
|
||||
#define FSR_RCAS_H
|
||||
AH4 FsrRcasLoadH(ASW2 p) { return AH4(texelFetch(InputTexture, ASU2(p), 0)); }
|
||||
void FsrRcasInputH(inout AH1 r,inout AH1 g,inout AH1 b){}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include "ffx_fsr1.h"
|
||||
|
||||
#if USE_RCAS
|
||||
layout(location = 0) in vec2 frag_texcoord;
|
||||
#endif
|
||||
layout (location = 0) out vec4 frag_color;
|
||||
|
||||
void CurrFilter(AU2 pos)
|
||||
{
|
||||
#if USE_EASU
|
||||
#ifndef YUZU_USE_FP16
|
||||
AF3 c;
|
||||
FsrEasuF(c, pos, constants[0], constants[1], constants[2], constants[3]);
|
||||
frag_color = AF4(c, 1.0);
|
||||
#else
|
||||
AH3 c;
|
||||
FsrEasuH(c, pos, constants[0], constants[1], constants[2], constants[3]);
|
||||
frag_color = AH4(c, 1.0);
|
||||
#endif
|
||||
#endif
|
||||
#if USE_RCAS
|
||||
#ifndef YUZU_USE_FP16
|
||||
AF3 c;
|
||||
FsrRcasF(c.r, c.g, c.b, pos, constants[0]);
|
||||
frag_color = AF4(c, 1.0);
|
||||
#else
|
||||
AH3 c;
|
||||
FsrRcasH(c.r, c.g, c.b, pos, constants[0]);
|
||||
frag_color = AH4(c, 1.0);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
void main()
|
||||
{
|
||||
#if USE_RCAS
|
||||
CurrFilter(AU2(frag_texcoord * vec2(textureSize(InputTexture, 0))));
|
||||
#else
|
||||
CurrFilter(AU2(gl_FragCoord.xy));
|
||||
#endif
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#version 460 core
|
||||
#extension GL_GOOGLE_include_directive : enable
|
||||
|
||||
#define USE_EASU 1
|
||||
|
||||
#include "opengl_fidelityfx_fsr.frag"
|
|
@ -0,0 +1,9 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#version 460 core
|
||||
#extension GL_GOOGLE_include_directive : enable
|
||||
|
||||
#define USE_RCAS 1
|
||||
|
||||
#include "opengl_fidelityfx_fsr.frag"
|
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,6 +630,8 @@ 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);
|
||||
|
||||
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) {
|
||||
|
@ -588,6 +642,7 @@ void RendererOpenGL::DrawScreen(const Layout::FramebufferLayout& layout) {
|
|||
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) {
|
||||
scale_u /= Settings::values.resolution_info.up_factor;
|
||||
|
@ -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;
|
||||
|
||||
|
|
|
@ -1,12 +1,11 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include <cmath>
|
||||
#include "common/bit_cast.h"
|
||||
#include "common/common_types.h"
|
||||
#include "common/div_ceil.h"
|
||||
#include "common/settings.h"
|
||||
|
||||
#include "video_core/fsr.h"
|
||||
#include "video_core/host_shaders/vulkan_fidelityfx_fsr_easu_fp16_comp_spv.h"
|
||||
#include "video_core/host_shaders/vulkan_fidelityfx_fsr_easu_fp32_comp_spv.h"
|
||||
#include "video_core/host_shaders/vulkan_fidelityfx_fsr_rcas_fp16_comp_spv.h"
|
||||
|
@ -17,146 +16,7 @@
|
|||
#include "video_core/vulkan_common/vulkan_device.h"
|
||||
|
||||
namespace Vulkan {
|
||||
namespace {
|
||||
// Reimplementations of the constant generating functions in ffx_fsr1.h
|
||||
// GCC generated a lot of warnings when using the official header.
|
||||
u32 AU1_AH1_AF1(f32 f) {
|
||||
static constexpr u32 base[512]{
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0001, 0x0002, 0x0004, 0x0008, 0x0010, 0x0020, 0x0040,
|
||||
0x0080, 0x0100, 0x0200, 0x0400, 0x0800, 0x0c00, 0x1000, 0x1400, 0x1800, 0x1c00, 0x2000,
|
||||
0x2400, 0x2800, 0x2c00, 0x3000, 0x3400, 0x3800, 0x3c00, 0x4000, 0x4400, 0x4800, 0x4c00,
|
||||
0x5000, 0x5400, 0x5800, 0x5c00, 0x6000, 0x6400, 0x6800, 0x6c00, 0x7000, 0x7400, 0x7800,
|
||||
0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff,
|
||||
0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff,
|
||||
0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff,
|
||||
0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff,
|
||||
0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff,
|
||||
0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff,
|
||||
0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff,
|
||||
0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff,
|
||||
0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff,
|
||||
0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff,
|
||||
0x7bff, 0x7bff, 0x7bff, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000,
|
||||
0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000,
|
||||
0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000,
|
||||
0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000,
|
||||
0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000,
|
||||
0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000,
|
||||
0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000,
|
||||
0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000,
|
||||
0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000,
|
||||
0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8001, 0x8002, 0x8004, 0x8008,
|
||||
0x8010, 0x8020, 0x8040, 0x8080, 0x8100, 0x8200, 0x8400, 0x8800, 0x8c00, 0x9000, 0x9400,
|
||||
0x9800, 0x9c00, 0xa000, 0xa400, 0xa800, 0xac00, 0xb000, 0xb400, 0xb800, 0xbc00, 0xc000,
|
||||
0xc400, 0xc800, 0xcc00, 0xd000, 0xd400, 0xd800, 0xdc00, 0xe000, 0xe400, 0xe800, 0xec00,
|
||||
0xf000, 0xf400, 0xf800, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff,
|
||||
0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff,
|
||||
0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff,
|
||||
0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff,
|
||||
0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff,
|
||||
0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff,
|
||||
0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff,
|
||||
0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff,
|
||||
0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff,
|
||||
0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff,
|
||||
0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff, 0xfbff,
|
||||
};
|
||||
static constexpr s8 shift[512]{
|
||||
0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
|
||||
0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
|
||||
0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
|
||||
0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
|
||||
0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
|
||||
0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
|
||||
0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x17, 0x16,
|
||||
0x15, 0x14, 0x13, 0x12, 0x11, 0x10, 0x0f, 0x0e, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d,
|
||||
0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d,
|
||||
0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
|
||||
0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
|
||||
0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
|
||||
0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
|
||||
0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
|
||||
0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
|
||||
0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
|
||||
0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
|
||||
0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
|
||||
0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
|
||||
0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
|
||||
0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
|
||||
0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
|
||||
0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
|
||||
0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x17,
|
||||
0x16, 0x15, 0x14, 0x13, 0x12, 0x11, 0x10, 0x0f, 0x0e, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d,
|
||||
0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d,
|
||||
0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
|
||||
0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
|
||||
0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
|
||||
0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
|
||||
0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
|
||||
0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
|
||||
0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
|
||||
0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
|
||||
0x18, 0x18,
|
||||
};
|
||||
const u32 u = Common::BitCast<u32>(f);
|
||||
const u32 i = u >> 23;
|
||||
return base[i] + ((u & 0x7fffff) >> shift[i]);
|
||||
}
|
||||
|
||||
u32 AU1_AH2_AF2(f32 a[2]) {
|
||||
return AU1_AH1_AF1(a[0]) + (AU1_AH1_AF1(a[1]) << 16);
|
||||
}
|
||||
|
||||
void FsrEasuCon(u32 con0[4], u32 con1[4], u32 con2[4], u32 con3[4], f32 inputViewportInPixelsX,
|
||||
f32 inputViewportInPixelsY, f32 inputSizeInPixelsX, f32 inputSizeInPixelsY,
|
||||
f32 outputSizeInPixelsX, f32 outputSizeInPixelsY) {
|
||||
con0[0] = Common::BitCast<u32>(inputViewportInPixelsX / outputSizeInPixelsX);
|
||||
con0[1] = Common::BitCast<u32>(inputViewportInPixelsY / outputSizeInPixelsY);
|
||||
con0[2] = Common::BitCast<u32>(0.5f * inputViewportInPixelsX / outputSizeInPixelsX - 0.5f);
|
||||
con0[3] = Common::BitCast<u32>(0.5f * inputViewportInPixelsY / outputSizeInPixelsY - 0.5f);
|
||||
con1[0] = Common::BitCast<u32>(1.0f / inputSizeInPixelsX);
|
||||
con1[1] = Common::BitCast<u32>(1.0f / inputSizeInPixelsY);
|
||||
con1[2] = Common::BitCast<u32>(1.0f / inputSizeInPixelsX);
|
||||
con1[3] = Common::BitCast<u32>(-1.0f / inputSizeInPixelsY);
|
||||
con2[0] = Common::BitCast<u32>(-1.0f / inputSizeInPixelsX);
|
||||
con2[1] = Common::BitCast<u32>(2.0f / inputSizeInPixelsY);
|
||||
con2[2] = Common::BitCast<u32>(1.0f / inputSizeInPixelsX);
|
||||
con2[3] = Common::BitCast<u32>(2.0f / inputSizeInPixelsY);
|
||||
con3[0] = Common::BitCast<u32>(0.0f / inputSizeInPixelsX);
|
||||
con3[1] = Common::BitCast<u32>(4.0f / inputSizeInPixelsY);
|
||||
con3[2] = con3[3] = 0;
|
||||
}
|
||||
|
||||
void FsrEasuConOffset(u32 con0[4], u32 con1[4], u32 con2[4], u32 con3[4],
|
||||
f32 inputViewportInPixelsX, f32 inputViewportInPixelsY,
|
||||
f32 inputSizeInPixelsX, f32 inputSizeInPixelsY, f32 outputSizeInPixelsX,
|
||||
f32 outputSizeInPixelsY, f32 inputOffsetInPixelsX, f32 inputOffsetInPixelsY) {
|
||||
FsrEasuCon(con0, con1, con2, con3, inputViewportInPixelsX, inputViewportInPixelsY,
|
||||
inputSizeInPixelsX, inputSizeInPixelsY, outputSizeInPixelsX, outputSizeInPixelsY);
|
||||
con0[2] = Common::BitCast<u32>(0.5f * inputViewportInPixelsX / outputSizeInPixelsX - 0.5f +
|
||||
inputOffsetInPixelsX);
|
||||
con0[3] = Common::BitCast<u32>(0.5f * inputViewportInPixelsY / outputSizeInPixelsY - 0.5f +
|
||||
inputOffsetInPixelsY);
|
||||
}
|
||||
|
||||
void FsrRcasCon(u32* con, f32 sharpness) {
|
||||
sharpness = std::exp2f(-sharpness);
|
||||
f32 hSharp[2]{sharpness, sharpness};
|
||||
con[0] = Common::BitCast<u32>(sharpness);
|
||||
con[1] = AU1_AH2_AF2(hSharp);
|
||||
con[2] = 0;
|
||||
con[3] = 0;
|
||||
}
|
||||
} // Anonymous namespace
|
||||
using namespace FSR;
|
||||
|
||||
FSR::FSR(const Device& device_, MemoryAllocator& memory_allocator_, size_t image_count_,
|
||||
VkExtent2D output_size_)
|
||||
|
|
|
@ -460,7 +460,7 @@
|
|||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>AMD FidelityFX™️ Super Resolution (Vulkan Only)</string>
|
||||
<string>AMD FidelityFX™️ Super Resolution</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
|
|
|
@ -983,11 +983,6 @@ void GMainWindow::InitializeWidgets() {
|
|||
filter_status_button->setFocusPolicy(Qt::NoFocus);
|
||||
connect(filter_status_button, &QPushButton::clicked, this,
|
||||
&GMainWindow::OnToggleAdaptingFilter);
|
||||
auto filter = Settings::values.scaling_filter.GetValue();
|
||||
if (Settings::values.renderer_backend.GetValue() == Settings::RendererBackend::OpenGL &&
|
||||
filter == Settings::ScalingFilter::Fsr) {
|
||||
Settings::values.scaling_filter.SetValue(Settings::ScalingFilter::NearestNeighbor);
|
||||
}
|
||||
UpdateFilterText();
|
||||
filter_status_button->setCheckable(true);
|
||||
filter_status_button->setChecked(true);
|
||||
|
@ -3469,10 +3464,6 @@ void GMainWindow::OnToggleAdaptingFilter() {
|
|||
} else {
|
||||
filter = static_cast<Settings::ScalingFilter>(static_cast<u32>(filter) + 1);
|
||||
}
|
||||
if (Settings::values.renderer_backend.GetValue() == Settings::RendererBackend::OpenGL &&
|
||||
filter == Settings::ScalingFilter::Fsr) {
|
||||
filter = Settings::ScalingFilter::NearestNeighbor;
|
||||
}
|
||||
Settings::values.scaling_filter.SetValue(filter);
|
||||
filter_status_button->setChecked(true);
|
||||
UpdateFilterText();
|
||||
|
|
Loading…
Reference in a new issue