Skip to content

Commit

Permalink
add some filter (WIP)
Browse files Browse the repository at this point in the history
  • Loading branch information
nishinji committed Jul 20, 2023
1 parent a317c4a commit df36650
Show file tree
Hide file tree
Showing 19 changed files with 738 additions and 4 deletions.
5 changes: 4 additions & 1 deletion vita3k/gui/src/settings_dialog.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -541,10 +541,13 @@ void draw_settings_dialog(GuiState &gui, EmuEnvState &emuenv) {
// Screen Filter
ImGui::Spacing();
int curr_filter = 0;
const std::array<const char *, 5> possible_filters = {
const std::array<const char *, 8> possible_filters = {
"Nearest",
"Bilinear",
"Bicubic",
"Gaussian",
"5xBR",
"4xHQ",
"FXAA",
"FSR"
};
Expand Down
7 changes: 5 additions & 2 deletions vita3k/renderer/include/renderer/state.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,11 @@ enum struct Filter : int {
NEAREST = 1 << 0,
BILINEAR = 1 << 1,
BICUBIC = 1 << 2,
FXAA = 1 << 3,
FSR = 1 << 4
GAUSSIAN = 1 << 3,
XBR = 1 << 4,
XHQ = 1 << 5,
FXAA = 1 << 6,
FSR = 1 << 7
};

struct State {
Expand Down
46 changes: 46 additions & 0 deletions vita3k/renderer/include/renderer/vulkan/screen_filters.h
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,52 @@ class BicubicScreenFilter : public SinglePassScreenFilter {
}
};

class GaussianScreenFilter : public SinglePassScreenFilter {
protected:
// the Bicubic filter uses a custom shader
std::string_view get_fragment_name() override;
vk::Sampler create_sampler() override;

public:
GaussianScreenFilter(ScreenRenderer &screen)
: SinglePassScreenFilter(screen) {}

std::string_view get_name() override {
return "Gaussian";
}
};

class xBRScreenFilter : public SinglePassScreenFilter {
protected:
// the Bicubic filter uses a custom shader
std::string_view get_fragment_name() override;
vk::Sampler create_sampler() override;

public:
xBRScreenFilter(ScreenRenderer & screen)
: SinglePassScreenFilter(screen) {}

std::string_view get_name() override {
return "5xBR";
}
};

class xHQScreenFilter : public SinglePassScreenFilter {
protected:
// the Bicubic filter uses a custom shader
std::string_view get_fragment_name() override;
std::string_view get_vertex_name() override;
vk::Sampler create_sampler() override;

public:
xHQScreenFilter(ScreenRenderer &screen)
: SinglePassScreenFilter(screen) {}

std::string_view get_name() override {
return "4xHQ";
}
};

class FXAAScreenFilter : public SinglePassScreenFilter {
protected:
// the FXAA filter uses a custom shader
Expand Down
2 changes: 1 addition & 1 deletion vita3k/renderer/src/vulkan/renderer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -711,7 +711,7 @@ uint32_t VKState::get_device_id() {
}

int VKState::get_supported_filters() {
int filters = static_cast<int>(Filter::NEAREST) | static_cast<int>(Filter::BILINEAR) | static_cast<int>(Filter::BICUBIC) | static_cast<int>(Filter::FXAA);
int filters = static_cast<int>(Filter::NEAREST) | static_cast<int>(Filter::BILINEAR) | static_cast<int>(Filter::BICUBIC) | static_cast<int>(Filter::GAUSSIAN) | static_cast<int>(Filter::XBR) | static_cast<int>(Filter::XHQ) | static_cast<int>(Filter::FXAA);
if (support_fsr)
filters |= static_cast<int>(Filter::FSR);
return filters;
Expand Down
49 changes: 49 additions & 0 deletions vita3k/renderer/src/vulkan/screen_filters.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -346,6 +346,55 @@ vk::Sampler BicubicScreenFilter::create_sampler() {
return screen.state.device.createSampler(sampler_info);
}

std::string_view GaussianScreenFilter::get_fragment_name() {
return "render_main_gaussian.frag.spv";
}

vk::Sampler GaussianScreenFilter::create_sampler() {
vk::SamplerCreateInfo sampler_info{
.magFilter = vk::Filter::eNearest,
.minFilter = vk::Filter::eNearest,
.addressModeU = vk::SamplerAddressMode::eClampToEdge,
.addressModeV = vk::SamplerAddressMode::eClampToEdge,
.addressModeW = vk::SamplerAddressMode::eClampToEdge,
};
return screen.state.device.createSampler(sampler_info);
}

std::string_view xBRScreenFilter::get_fragment_name() {
return "render_main_5xbr.frag.spv";
}

vk::Sampler xBRScreenFilter::create_sampler() {
vk::SamplerCreateInfo sampler_info{
.magFilter = vk::Filter::eNearest,
.minFilter = vk::Filter::eNearest,
.addressModeU = vk::SamplerAddressMode::eClampToEdge,
.addressModeV = vk::SamplerAddressMode::eClampToEdge,
.addressModeW = vk::SamplerAddressMode::eClampToEdge,
};
return screen.state.device.createSampler(sampler_info);
}

std::string_view xHQScreenFilter::get_vertex_name() {
return "render_main_4xhq.vert.spv";
}

std::string_view xHQScreenFilter::get_fragment_name() {
return "render_main_4xhq.frag.spv";
}

vk::Sampler xHQScreenFilter::create_sampler() {
vk::SamplerCreateInfo sampler_info{
.magFilter = vk::Filter::eNearest,
.minFilter = vk::Filter::eNearest,
.addressModeU = vk::SamplerAddressMode::eClampToEdge,
.addressModeV = vk::SamplerAddressMode::eClampToEdge,
.addressModeW = vk::SamplerAddressMode::eClampToEdge,
};
return screen.state.device.createSampler(sampler_info);
}

std::string_view FXAAScreenFilter::get_fragment_name() {
return "render_main_fxaa.frag.spv";
}
Expand Down
8 changes: 8 additions & 0 deletions vita3k/renderer/src/vulkan/screen_renderer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -372,6 +372,14 @@ void ScreenRenderer::set_filter(const std::string_view &filter) {
this->filter = std::make_unique<FXAAScreenFilter>(*this);
else if (filter == "Bicubic")
this->filter = std::make_unique<BicubicScreenFilter>(*this);
else if (filter == "Gaussian")
this->filter = std::make_unique<GaussianScreenFilter>(*this);
else if (filter == "5xBR")
this->filter = std::make_unique<xBRScreenFilter>(*this);
else if (filter == "4xHQ")
this->filter = std::make_unique<xHQScreenFilter>(*this);
else if (filter == "FXAA")
this->filter = std::make_unique<FXAAScreenFilter>(*this);
else if (filter == "Nearest")
this->filter = std::make_unique<NearestScreenFilter>(*this);
else
Expand Down
67 changes: 67 additions & 0 deletions vita3k/shaders-builtin/opengl/render_main_4xhq.frag
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
// Vita3K emulator project
// Code adapted from http://horde3d.org/wiki/index.php?title=Shading_Technique_-_FXAA

#version 410 core

uniform sampler2D fb;

out vec3 color_frag;

in vec4 v_texcoord0;
in vec4 v_texcoord1;
in vec4 v_texcoord2;
in vec4 v_texcoord3;
in vec4 v_texcoord4;
in vec4 v_texcoord5;
in vec4 v_texcoord6;

const float mx = 0.325; // start smoothing factor
const float k = -0.250; // smoothing decrease factor
const float max_w = 0.25; // max. smoothing weigth
const float min_w =-0.05; // min smoothing/sharpening weigth

void main()
{
vec3 c = texture2D(fb, v_texcoord0.xy).xyz;
vec3 i1 = texture2D(fb, v_texcoord1.xy).xyz;
vec3 i2 = texture2D(fb, v_texcoord2.xy).xyz;
vec3 i3 = texture2D(fb, v_texcoord3.xy).xyz;
vec3 i4 = texture2D(fb, v_texcoord4.xy).xyz;
vec3 o1 = texture2D(fb, v_texcoord5.xy).xyz;
vec3 o3 = texture2D(fb, v_texcoord6.xy).xyz;
vec3 o2 = texture2D(fb, v_texcoord5.zw).xyz;
vec3 o4 = texture2D(fb, v_texcoord6.zw).xyz;

vec3 dt = vec3(1.0,1.0,1.0);

float ko1=dot(abs(o1-c),dt);
float ko2=dot(abs(o2-c),dt);
float ko3=dot(abs(o3-c),dt);
float ko4=dot(abs(o4-c),dt);

float sd1 = dot(abs(i1-i3),dt);
float sd2 = dot(abs(i2-i4),dt);

float w1 = step(ko1,ko3)*sd2;
float w2 = step(ko2,ko4)*sd1;
float w3 = step(ko3,ko1)*sd2;
float w4 = step(ko4,ko2)*sd1;

c = (w1*o1+w2*o2+w3*o3+w4*o4+0.1*c)/(w1+w2+w3+w4+0.1);

float lc = c.r+c.g+c.b+0.2;

w1 = (i1.r+i1.g+i1.b+lc)*0.2;
w1 = clamp(k*dot(abs(c-i1),dt)/w1+mx,min_w,max_w);

w2 = (i2.r+i2.g+i2.b+lc)*0.2;
w2 = clamp(k*dot(abs(c-i2),dt)/w2+mx,min_w,max_w);

w3 = (i3.r+i3.g+i3.b+lc)*0.2;
w3 = clamp(k*dot(abs(c-i3),dt)/w3+mx,min_w,max_w);

w4 = (i4.r+i4.g+i4.b+lc)*0.2;
w4 = clamp(k*dot(abs(c-i4),dt)/w4+mx,min_w,max_w);

color_frag.rgb = w1*i1 + w2*i2 + w3*i3 + w4*i4 + (1.0-w1-w2-w3-w4)*c;
}
50 changes: 50 additions & 0 deletions vita3k/shaders-builtin/opengl/render_main_4xhq.vert
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
// Vita3K emulator project
// Copyright (C) 2023 Vita3K team
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License along
// with this program; if not, write to the Free Software Foundation, Inc.,
// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.

#version 410 core

in vec3 position_vertex;
in vec2 uv_vertex;
uniform vec2 inv_frame_size;

out vec4 v_texcoord0;
out vec4 v_texcoord1;
out vec4 v_texcoord2;
out vec4 v_texcoord3;
out vec4 v_texcoord4;
out vec4 v_texcoord5;
out vec4 v_texcoord6;

void main()
{
float x = inv_frame_size.x;
float y = inv_frame_size.y;
vec2 dg1 = vec2( x,y);
vec2 dg2 = vec2(-x,y);
vec2 sd1 = dg1*0.5;
vec2 sd2 = dg2*0.5;
gl_Position = vec4(position_vertex, 1.0);
v_texcoord0 = uv_vertex.xyxy;
v_texcoord1.xy = v_texcoord0.xy - sd1;
v_texcoord2.xy = v_texcoord0.xy - sd2;
v_texcoord3.xy = v_texcoord0.xy + sd1;
v_texcoord4.xy = v_texcoord0.xy + sd2;
v_texcoord5.xy = v_texcoord0.xy - dg1;
v_texcoord6.xy = v_texcoord0.xy + dg1;
v_texcoord5.zw = v_texcoord0.xy - dg2;
v_texcoord6.zw = v_texcoord0.xy + dg2;
}
113 changes: 113 additions & 0 deletions vita3k/shaders-builtin/opengl/render_main_5xBR.frag
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
// Vita3K emulator project
// Code adapted from https://github.com/hrydgard/ppsspp/blob/master/assets/shaders/5xBR.fsh

#version 410 core

uniform sampler2D fb;
uniform vec2 inv_frame_size;
in vec2 uv_frag;
out vec3 FragColor;

const float coef = 2.0;
const vec3 rgbw = vec3(16.163, 23.351, 8.4772);

const vec4 Ao = vec4( 1.0, -1.0, -1.0, 1.0 );
const vec4 Bo = vec4( 1.0, 1.0, -1.0,-1.0 );
const vec4 Co = vec4( 1.5, 0.5, -0.5, 0.5 );
const vec4 Ax = vec4( 1.0, -1.0, -1.0, 1.0 );
const vec4 Bx = vec4( 0.5, 2.0, -0.5,-2.0 );
const vec4 Cx = vec4( 1.0, 1.0, -0.5, 0.0 );
const vec4 Ay = vec4( 1.0, -1.0, -1.0, 1.0 );
const vec4 By = vec4( 2.0, 0.5, -2.0,-0.5 );
const vec4 Cy = vec4( 2.0, 0.0, -1.0, 0.5 );


vec4 df(vec4 A, vec4 B) {
return abs(A-B);
}

vec4 weighted_distance(vec4 a, vec4 b, vec4 c, vec4 d, vec4 e, vec4 f, vec4 g, vec4 h) {
return (df(a,b) + df(a,c) + df(d,e) + df(d,f) + 4.0*df(g,h));
}


void main(){

//bool upscale = inv_frame_size.x > (1.6 * inv_frame_size.x);
vec3 res = texture2D(fb, uv_frag.xy).xyz;

// Let's skip the whole scaling if output size smaller than 1.6x of input size
//if (upscale) {

bvec4 edr, edr_left, edr_up, px; // px = pixel, edr = edge detection rule
bvec4 interp_restriction_lv1, interp_restriction_lv2_left, interp_restriction_lv2_up;
bvec4 nc; // new_color
bvec4 fx, fx_left, fx_up; // inequations of straight lines.

vec2 pS = 1.0 / inv_frame_size.xy;
vec2 fp = fract(uv_frag.xy*pS.xy);
vec2 TexCoord_0 = uv_frag.xy-fp*inv_frame_size.xy;
vec2 dx = vec2(inv_frame_size.x,0.0);
vec2 dy = vec2(0.0,inv_frame_size.y);
vec2 y2 = dy + dy; vec2 x2 = dx + dx;

vec3 A = texture2D(fb, TexCoord_0 -dx -dy ).xyz;
vec3 B = texture2D(fb, TexCoord_0 -dy ).xyz;
vec3 C = texture2D(fb, TexCoord_0 +dx -dy ).xyz;
vec3 D = texture2D(fb, TexCoord_0 -dx ).xyz;
vec3 E = texture2D(fb, TexCoord_0 ).xyz;
vec3 F = texture2D(fb, TexCoord_0 +dx ).xyz;
vec3 G = texture2D(fb, TexCoord_0 -dx +dy ).xyz;
vec3 H = texture2D(fb, TexCoord_0 +dy ).xyz;
vec3 I = texture2D(fb, TexCoord_0 +dx +dy ).xyz;
vec3 A1 = texture2D(fb, TexCoord_0 -dx -y2).xyz;
vec3 C1 = texture2D(fb, TexCoord_0 +dx -y2).xyz;
vec3 A0 = texture2D(fb, TexCoord_0 -x2 -dy).xyz;
vec3 G0 = texture2D(fb, TexCoord_0 -x2 +dy).xyz;
vec3 C4 = texture2D(fb, TexCoord_0 +x2 -dy).xyz;
vec3 I4 = texture2D(fb, TexCoord_0 +x2 +dy).xyz;
vec3 G5 = texture2D(fb, TexCoord_0 -dx +y2).xyz;
vec3 I5 = texture2D(fb, TexCoord_0 +dx +y2).xyz;
vec3 B1 = texture2D(fb, TexCoord_0 -y2).xyz;
vec3 D0 = texture2D(fb, TexCoord_0 -x2 ).xyz;
vec3 H5 = texture2D(fb, TexCoord_0 +y2).xyz;
vec3 F4 = texture2D(fb, TexCoord_0 +x2 ).xyz;

vec4 b = vec4(dot(B ,rgbw), dot(D ,rgbw), dot(H ,rgbw), dot(F ,rgbw));
vec4 c = vec4(dot(C ,rgbw), dot(A ,rgbw), dot(G ,rgbw), dot(I ,rgbw));
vec4 d = vec4(b.y, b.z, b.w, b.x);
vec4 e = vec4(dot(E,rgbw));
vec4 f = vec4(b.w, b.x, b.y, b.z);
vec4 g = vec4(c.z, c.w, c.x, c.y);
vec4 h = vec4(b.z, b.w, b.x, b.y);
vec4 i = vec4(c.w, c.x, c.y, c.z);
vec4 i4 = vec4(dot(I4,rgbw), dot(C1,rgbw), dot(A0,rgbw), dot(G5,rgbw));
vec4 i5 = vec4(dot(I5,rgbw), dot(C4,rgbw), dot(A1,rgbw), dot(G0,rgbw));
vec4 h5 = vec4(dot(H5,rgbw), dot(F4,rgbw), dot(B1,rgbw), dot(D0,rgbw));
vec4 f4 = vec4(h5.y, h5.z, h5.w, h5.x);

// These inequations define the line below which interpolation occurs.
fx = greaterThan(Ao*fp.y+Bo*fp.x,Co);
fx_left = greaterThan(Ax*fp.y+Bx*fp.x,Cx);
fx_up = greaterThan(Ay*fp.y+By*fp.x,Cy);

interp_restriction_lv1 = bvec4(vec4(notEqual(e,f))*vec4(notEqual(e,h)));
interp_restriction_lv2_left = bvec4(vec4(notEqual(e,g))*vec4(notEqual(d,g)));
interp_restriction_lv2_up = bvec4(vec4(notEqual(e,c))*vec4(notEqual(b,c)));

edr = bvec4(vec4(lessThan(weighted_distance( e, c, g, i, h5, f4, h, f), weighted_distance( h, d, i5, f, i4, b, e, i)))*vec4(interp_restriction_lv1));
edr_left = bvec4(vec4(lessThanEqual(coef*df(f,g),df(h,c)))*vec4(interp_restriction_lv2_left));
edr_up = bvec4(vec4(greaterThanEqual(df(f,g),coef*df(h,c)))*vec4(interp_restriction_lv2_up));

nc.x = ( edr.x && (fx.x || edr_left.x && fx_left.x || edr_up.x && fx_up.x) );
nc.y = ( edr.y && (fx.y || edr_left.y && fx_left.y || edr_up.y && fx_up.y) );
nc.z = ( edr.z && (fx.z || edr_left.z && fx_left.z || edr_up.z && fx_up.z) );
nc.w = ( edr.w && (fx.w || edr_left.w && fx_left.w || edr_up.w && fx_up.w) );

px = lessThanEqual(df(e,f),df(e,h));

res = nc.x ? px.x ? F : H : nc.y ? px.y ? B : F : nc.z ? px.z ? D : B : nc.w ? px.w ? H : D : E;
//}
FragColor.rgb = res;
//FragColor.a = 1.0;
}
Loading

0 comments on commit df36650

Please sign in to comment.