Compare commits

..

9 commits

43 changed files with 5252 additions and 340 deletions

View file

@ -48,6 +48,8 @@ foreach(KEY IN ITEMS
"turbo_limit"
"texture_filter"
"antialiasing_filter"
"output_scaling"
"fsr_sharpness"
"texture_sampling"
"delay_game_render_thread_us"
"simulate_3ds_gpu_timings"

View file

@ -726,6 +726,8 @@ void QtConfig::ReadRendererValues() {
ReadGlobalSetting(Settings::values.texture_filter);
ReadGlobalSetting(Settings::values.antialiasing_filter);
ReadGlobalSetting(Settings::values.output_scaling);
ReadGlobalSetting(Settings::values.fsr_sharpness);
ReadGlobalSetting(Settings::values.texture_sampling);
ReadGlobalSetting(Settings::values.delay_game_render_thread_us);
@ -1276,6 +1278,8 @@ void QtConfig::SaveRendererValues() {
WriteGlobalSetting(Settings::values.texture_filter);
WriteGlobalSetting(Settings::values.antialiasing_filter);
WriteGlobalSetting(Settings::values.output_scaling);
WriteGlobalSetting(Settings::values.fsr_sharpness);
WriteGlobalSetting(Settings::values.texture_sampling);
WriteGlobalSetting(Settings::values.delay_game_render_thread_us);

View file

@ -27,6 +27,8 @@ ConfigureEnhancements::ConfigureEnhancements(QWidget* parent)
updateShaders(static_cast<Settings::StereoRenderOption>(currentIndex));
});
connect(ui->fsr_sharpness_slider, &QSlider::valueChanged, this,
&ConfigureEnhancements::SetFSRSharpnessIndicatorText);
ui->toggle_preload_textures->setEnabled(ui->toggle_custom_textures->isChecked());
ui->toggle_async_custom_loading->setEnabled(ui->toggle_custom_textures->isChecked());
connect(ui->toggle_custom_textures, &QCheckBox::toggled, this, [this] {
@ -35,12 +37,18 @@ ConfigureEnhancements::ConfigureEnhancements(QWidget* parent)
if (!ui->toggle_preload_textures->isEnabled())
ui->toggle_preload_textures->setChecked(false);
});
connect(ui->output_scaling_combobox, &QComboBox::currentIndexChanged, this, &ConfigureEnhancements::SetFSRSharpnessEnabled);
}
ConfigureEnhancements::~ConfigureEnhancements() = default;
void ConfigureEnhancements::SetConfiguration() {
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()) {
ConfigurationShared::SetPerGameSetting(ui->resolution_factor_combobox,
&Settings::values.resolution_factor);
@ -52,6 +60,10 @@ void ConfigureEnhancements::SetConfiguration() {
&Settings::values.antialiasing_filter);
ConfigurationShared::SetHighlight(ui->widget_antialiasing_filter,
!Settings::values.antialiasing_filter.UsingGlobal());
ConfigurationShared::SetPerGameSetting(ui->output_scaling_combobox,
&Settings::values.output_scaling);
ConfigurationShared::SetHighlight(ui->widget_output_scaling,
!Settings::values.output_scaling.UsingGlobal());
} else {
ui->resolution_factor_combobox->setCurrentIndex(
Settings::values.resolution_factor.GetValue());
@ -59,8 +71,10 @@ void ConfigureEnhancements::SetConfiguration() {
static_cast<int>(Settings::values.texture_filter.GetValue()));
ui->antialiasing_filter_combobox->setCurrentIndex(
static_cast<int>(Settings::values.antialiasing_filter.GetValue()));
ui->output_scaling_combobox->setCurrentIndex(
static_cast<int>(Settings::values.output_scaling.GetValue()));
}
ui->fsr_sharpness_slider->setEnabled(ui->output_scaling_combobox->currentIndex() == 3);
ui->render_3d_combobox->setCurrentIndex(
static_cast<int>(Settings::values.render_3d.GetValue()));
ui->swap_eyes_3d->setChecked(Settings::values.swap_eyes_3d.GetValue());
@ -68,7 +82,6 @@ void ConfigureEnhancements::SetConfiguration() {
ui->mono_rendering_eye->setCurrentIndex(
static_cast<int>(Settings::values.mono_render_option.GetValue()));
updateShaders(Settings::values.render_3d.GetValue());
ui->toggle_linear_filter->setChecked(Settings::values.filter_mode.GetValue());
ui->use_integer_scaling->setChecked(Settings::values.use_integer_scaling.GetValue());
ui->toggle_dump_textures->setChecked(Settings::values.dump_textures.GetValue());
ui->toggle_custom_textures->setChecked(Settings::values.custom_textures.GetValue());
@ -77,6 +90,13 @@ void ConfigureEnhancements::SetConfiguration() {
ui->disable_right_eye_render->setChecked(Settings::values.disable_right_eye_render.GetValue());
}
void ConfigureEnhancements::SetFSRSharpnessIndicatorText(int percentage) {
ui->fsr_sharpness_indicator->setText(tr("%1%", "FSR Sharpness (e.g. 50%)").arg(percentage));
}
void ConfigureEnhancements::SetFSRSharpnessEnabled(int output) {
ui->fsr_sharpness_slider->setEnabled(output == 3);
}
void ConfigureEnhancements::updateShaders(Settings::StereoRenderOption stereo_option) {
ui->shader_combobox->clear();
ui->shader_combobox->setEnabled(true);
@ -130,16 +150,17 @@ void ConfigureEnhancements::ApplyConfiguration() {
Settings::values.pp_shader_name =
ui->shader_combobox->itemText(ui->shader_combobox->currentIndex()).toStdString();
}
Settings::values.fsr_sharpness = ui->fsr_sharpness_slider->sliderPosition();
Settings::values.disable_right_eye_render = ui->disable_right_eye_render->isChecked();
ConfigurationShared::ApplyPerGameSetting(&Settings::values.filter_mode,
ui->toggle_linear_filter, linear_filter);
ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_integer_scaling,
ui->use_integer_scaling, use_integer_scaling);
ConfigurationShared::ApplyPerGameSetting(&Settings::values.texture_filter,
ui->texture_filter_combobox);
ConfigurationShared::ApplyPerGameSetting(&Settings::values.antialiasing_filter,
ui->antialiasing_filter_combobox);
ConfigurationShared::ApplyPerGameSetting(&Settings::values.output_scaling,
ui->output_scaling_combobox);
ConfigurationShared::ApplyPerGameSetting(&Settings::values.dump_textures,
ui->toggle_dump_textures, dump_textures);
ConfigurationShared::ApplyPerGameSetting(&Settings::values.custom_textures,
@ -159,7 +180,7 @@ void ConfigureEnhancements::SetupPerGameUI() {
ui->widget_resolution->setEnabled(Settings::values.resolution_factor.UsingGlobal());
ui->widget_texture_filter->setEnabled(Settings::values.texture_filter.UsingGlobal());
ui->widget_antialiasing_filter->setEnabled(Settings::values.antialiasing_filter.UsingGlobal());
ui->toggle_linear_filter->setEnabled(Settings::values.filter_mode.UsingGlobal());
ui->widget_output_scaling->setEnabled(Settings::values.output_scaling.UsingGlobal());
ui->use_integer_scaling->setEnabled(Settings::values.use_integer_scaling.UsingGlobal());
ui->toggle_dump_textures->setEnabled(Settings::values.dump_textures.UsingGlobal());
ui->toggle_custom_textures->setEnabled(Settings::values.custom_textures.UsingGlobal());
@ -177,8 +198,6 @@ void ConfigureEnhancements::SetupPerGameUI() {
ui->widget_shader->setVisible(false);
ConfigurationShared::SetColoredTristate(ui->toggle_linear_filter, Settings::values.filter_mode,
linear_filter);
ConfigurationShared::SetColoredTristate(
ui->use_integer_scaling, Settings::values.use_integer_scaling, use_integer_scaling);
ConfigurationShared::SetColoredTristate(ui->toggle_dump_textures,
@ -205,4 +224,8 @@ void ConfigureEnhancements::SetupPerGameUI() {
ConfigurationShared::SetColoredComboBox(
ui->antialiasing_filter_combobox, ui->widget_antialiasing_filter,
static_cast<int>(Settings::values.antialiasing_filter.GetValue(true)));
ConfigurationShared::SetColoredComboBox(
ui->output_scaling_combobox, ui->widget_output_scaling,
static_cast<int>(Settings::values.output_scaling.GetValue(true)));
}

View file

@ -36,7 +36,8 @@ public:
private:
void updateShaders(Settings::StereoRenderOption stereo_option);
void updateTextureFilter(int index);
void SetFSRSharpnessIndicatorText(int percentage);
void SetFSRSharpnessEnabled(int output);
std::unique_ptr<Ui::ConfigureEnhancements> ui;
ConfigurationShared::CheckState linear_filter;
ConfigurationShared::CheckState use_integer_scaling;

View file

@ -121,10 +121,184 @@
</widget>
</item>
<item>
<widget class="QCheckBox" name="toggle_linear_filter">
<property name="text">
<string>Enable Linear Filtering</string>
<widget class="QWidget" name="widget_output_scaling" native="true">
<property name="enabled">
<bool>true</bool>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_12">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QLabel" name="output_scaling_label">
<property name="text">
<string>Output Scaling</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="output_scaling_combobox">
<item>
<property name="text">
<string>Nearest</string>
</property>
</item>
<item>
<property name="text">
<string>Bilinear</string>
</property>
</item>
<item>
<property name="text">
<string>Adaptive</string>
</property>
</item>
<item>
<property name="text">
<string>AMD FidelityFX Super Resolution 1</string>
</property>
</item>
<item>
<property name="text">
<string>Sharp Bilinear</string>
</property>
</item>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QWidget" name="widget_fsr_sharpness" native="true">
<layout class="QHBoxLayout" name="horizontalLayout_16">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QWidget" name="widget_fsr_sharpness_1" native="true">
<layout class="QHBoxLayout" name="horizontalLayout_17">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QLabel" name="fsr_sharpness_label">
<property name="text">
<string>FSR Sharpness</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Orientation::Horizontal</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Policy::Preferred</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>30</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QWidget" name="widget_fsr_sharpness_2" native="true">
<layout class="QHBoxLayout" name="horizontalLayout_18">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QSlider" name="fsr_sharpness_slider">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
<property name="maximum">
<number>100</number>
</property>
<property name="pageStep">
<number>5</number>
</property>
<property name="orientation">
<enum>Qt::Orientation::Horizontal</enum>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="fsr_sharpness_indicator">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>32</width>
<height>0</height>
</size>
</property>
<property name="text">
<string>0 %</string>
</property>
<property name="alignment">
<set>Qt::AlignmentFlag::AlignCenter</set>
</property>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
</item>
<item>
@ -457,7 +631,6 @@
</widget>
<tabstops>
<tabstop>resolution_factor_combobox</tabstop>
<tabstop>toggle_linear_filter</tabstop>
<tabstop>shader_combobox</tabstop>
<tabstop>texture_filter_combobox</tabstop>
<tabstop>antialiasing_filter_combobox</tabstop>

View file

@ -69,6 +69,23 @@ std::string_view GetAntialiasingFilterName(AntiAliasingFilter filter) {
return "Invalid";
}
}
std::string_view GetOutputScalingName(OutputScaling scaling) {
switch (scaling) {
case OutputScaling::Nearest:
return "Nearest";
case OutputScaling::Bilinear:
return "Bilinear";
case OutputScaling::Adaptive:
return "Adaptive";
case OutputScaling::FSR:
return "AMD FidelityFX Super Resolution 1";
case OutputScaling::SharpBilinear:
return "Sharp Bilinear";
default:
return "Invalid";
}
}
std::string_view GetTextureSamplingName(TextureSampling sampling) {
switch (sampling) {
case TextureSampling::GameControlled:
@ -116,6 +133,7 @@ void LogSettings() {
log_setting("Renderer_FilterMode", values.filter_mode.GetValue());
log_setting("Renderer_TextureFilter", GetTextureFilterName(values.texture_filter.GetValue()));
log_setting("Renderer_AntialiasingFilter", GetAntialiasingFilterName(values.antialiasing_filter.GetValue()));
log_setting("Renderer_OutputScaling", GetOutputScalingName(values.output_scaling.GetValue()));
log_setting("Renderer_TextureSampling",
GetTextureSamplingName(values.texture_sampling.GetValue()));
log_setting("Renderer_DelayGameRenderThreasUs", values.delay_game_render_thread_us.GetValue());
@ -230,6 +248,8 @@ void RestoreGlobalState(bool is_powered_on) {
values.frame_limit.SetGlobal(true);
values.texture_filter.SetGlobal(true);
values.antialiasing_filter.SetGlobal(true);
values.output_scaling.SetGlobal(true);
values.fsr_sharpness.SetGlobal(true);
values.texture_sampling.SetGlobal(true);
values.delay_game_render_thread_us.SetGlobal(true);
values.simulate_3ds_gpu_timings.SetGlobal(true);

View file

@ -118,6 +118,14 @@ enum class AntiAliasingFilter : u32 {
SMAA = 2,
};
enum class OutputScaling : u32 {
Nearest = 0,
Bilinear = 1,
Adaptive = 2,
FSR = 3,
SharpBilinear = 4,
};
enum class TextureSampling : u32 {
GameControlled = 0,
NearestNeighbor = 1,
@ -546,6 +554,8 @@ struct Values {
SwitchableSetting<double, true> turbo_limit{200, 0, 1000, Keys::turbo_limit};
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<int, true> fsr_sharpness{50, 0, 100, Keys::fsr_sharpness};
SwitchableSetting<TextureSampling> texture_sampling{TextureSampling::GameControlled,
Keys::texture_sampling};
SwitchableSetting<u16, true> delay_game_render_thread_us{0, 0, 65000,

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

@ -53,7 +53,7 @@ FXAA_SUBPIX_CAP - Insures fine detail is not completely removed.
layout(location = 0) in vec2 frag_tex_coord;
layout(location = 0) out vec4 color;
layout (set = 0, binding = 0) uniform sampler2D screen_textures[3];
layout (set = 0, binding = 0) uniform sampler2D color_texture;
layout (push_constant, std140) uniform DrawInfo {
mat4 modelview_matrix;
@ -64,14 +64,8 @@ layout (push_constant, std140) uniform DrawInfo {
int layer;
int reverse_interlaced;
int convert_colors;
int areatex;
int searchtex;
int smaa_input;
};
/*
screen_textures[0] = color_texture
*/
#ifndef FXAA_PRESET
#define FXAA_PRESET 5
#endif
@ -263,7 +257,7 @@ vec3 sRGBToLinear(vec3 c) {
void main()
{
vec4 pixel = vec4(FxaaPixelShader(frag_tex_coord, screen_textures[0], vec2(i_resolution.z, i_resolution.w)), 1.0) * 1.0;
vec4 pixel = vec4(FxaaPixelShader(frag_tex_coord, color_texture, vec2(i_resolution.z, i_resolution.w)), 1.0) * 1.0;
if (convert_colors == 1){
pixel = vec4(sRGBToLinear(pixel.rgb), pixel.a);
}

View file

@ -10,18 +10,12 @@ layout (push_constant, std140) uniform DrawInfo {
int layer;
int reverse_interlaced;
int convert_colors;
int areatex;
int searchtex;
int smaa_input;
};
layout(location = 0) in vec2 vert_position;
layout(location = 1) in vec2 vert_tex_coord;
layout(location = 0) out vec2 frag_tex_coord;
layout (set = 0, binding = 0) uniform sampler2D screen_textures[3];
/*
screen_textures[0] = color_texture
*/
void main()
{
gl_Position = vec4(vert_position, 0.0, 1.0);

View file

@ -1,7 +1,7 @@
void main() {
if (SMAA_EDT == 0.0) {
color = vec4(SMAALumaEdgeDetectionPS(frag_tex_coord, offset, screen_textures[0]), 0.0, 0.0);
color = vec4(SMAALumaEdgeDetectionPS(frag_tex_coord, offset, color_texture), 0.0, 0.0);
} else if (SMAA_EDT <= 1.0) {
color = vec4(SMAAColorEdgeDetectionPS(frag_tex_coord, offset, screen_textures[0]), 0.0, 0.0);
color = vec4(SMAAColorEdgeDetectionPS(frag_tex_coord, offset, color_texture), 0.0, 0.0);
}
}

View file

@ -13,9 +13,6 @@ layout (push_constant, std140) uniform DrawInfo {
int layer;
int reverse_interlaced;
int convert_colors;
int areatex;
int searchtex;
int smaa_input;
};
#define SMAA_RT_METRICS vec4(i_resolution.z, i_resolution.w, i_resolution.x, i_resolution.y)
@ -27,9 +24,7 @@ layout (push_constant, std140) uniform DrawInfo {
layout(location = 0) in vec2 frag_tex_coord;
layout(location = 1) in vec4 offset[3];
layout(location = 0) out vec4 color;
layout (set = 0, binding = 0) uniform sampler2D screen_textures[3];
/*
screen_textures[0] = color_texture
*/
layout (set = 0, binding = 0) uniform sampler2D color_texture;
#define SMAA_INCLUDE_VS 0
//#include "SMAA.hlsl"

View file

@ -13,9 +13,6 @@ layout (push_constant, std140) uniform DrawInfo {
int layer;
int reverse_interlaced;
int convert_colors;
int areatex;
int searchtex;
int smaa_input;
};
#define SMAA_RT_METRICS vec4(i_resolution.z, i_resolution.w, i_resolution.x, i_resolution.y)

View file

@ -1,4 +1,4 @@
void main() {
vec4 subsampleIndices = vec4(0.0);
color = SMAABlendingWeightCalculationPS(frag_tex_coord, pixcoord, offset, screen_textures[0], screen_textures[1], screen_textures[2], subsampleIndices);
color = SMAABlendingWeightCalculationPS(frag_tex_coord, pixcoord, offset, color_texture, areaTex, searchTex, subsampleIndices);
}

View file

@ -13,9 +13,6 @@ layout (push_constant, std140) uniform DrawInfo {
int layer;
int reverse_interlaced;
int convert_colors;
int areatex;
int searchtex;
int smaa_input;
};
#define SMAA_RT_METRICS vec4(i_resolution.z, i_resolution.w, i_resolution.x, i_resolution.y)
@ -28,11 +25,9 @@ layout(location = 0) in vec2 frag_tex_coord;
layout(location = 1) in vec2 pixcoord;
layout(location = 2) in vec4 offset[3];
layout(location = 0) out vec4 color;
layout (set = 0, binding = 0) uniform sampler2D screen_textures[3];
/*
screen_textures[0] = color_texture
screen_textures[1] = areaTex;
screen_textures[2] = searchTex;
*/
layout (set = 0, binding = 0) uniform sampler2D color_texture;
layout (set = 0, binding = 1) uniform sampler2D areaTex;
layout (set = 0, binding = 2) uniform sampler2D searchTex;
#define SMAA_INCLUDE_VS 0
//#include "SMAA.hlsl"

View file

@ -13,9 +13,6 @@ layout (push_constant, std140) uniform DrawInfo {
int layer;
int reverse_interlaced;
int convert_colors;
int areatex;
int searchtex;
int smaa_input;
};
#define SMAA_RT_METRICS vec4(i_resolution.z, i_resolution.w, i_resolution.x, i_resolution.y)

View file

@ -3,7 +3,7 @@ vec3 LinearTosRGB(vec3 c) {
}
void main() {
vec4 pixel = SMAANeighborhoodBlendingPS(frag_tex_coord, offset, screen_textures[1], screen_textures[0]);
vec4 pixel = SMAANeighborhoodBlendingPS(frag_tex_coord, offset, SMAA_Input, color_texture);
if (convert_colors == 2){
pixel = vec4(LinearTosRGB(pixel.rgb), pixel.a);
}

View file

@ -13,9 +13,6 @@ layout (push_constant, std140) uniform DrawInfo {
int layer;
int reverse_interlaced;
int convert_colors;
int areatex;
int searchtex;
int smaa_input;
};
#define SMAA_RT_METRICS vec4(i_resolution.z, i_resolution.w, i_resolution.x, i_resolution.y)
@ -25,10 +22,8 @@ layout (push_constant, std140) uniform DrawInfo {
layout(location = 0) in vec2 frag_tex_coord;
layout(location = 1) in vec4 offset;
layout(location = 0) out vec4 color;
layout (set = 0, binding = 0) uniform sampler2D screen_textures[3];
/*
screen_textures[0] = color_texture
screen_textures[1] = SMAA_Input;
*/
layout (set = 0, binding = 0) uniform sampler2D color_texture;
layout (set = 0, binding = 1) uniform sampler2D SMAA_Input;
#define SMAA_INCLUDE_VS 0
//#include "SMAA.hlsl"

View file

@ -13,9 +13,6 @@ layout (push_constant, std140) uniform DrawInfo {
int layer;
int reverse_interlaced;
int convert_colors;
int areatex;
int searchtex;
int smaa_input;
};
#define SMAA_RT_METRICS vec4(i_resolution.z, i_resolution.w, i_resolution.x, i_resolution.y)

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

@ -2,10 +2,8 @@
layout(location = 0) in vec2 frag_tex_coord;
layout(location = 0) out vec4 color;
layout (set = 0, binding = 0) uniform sampler2D screen_textures[3];
/*
screen_textures[0] = color_texture
*/
layout (set = 0, binding = 0) uniform sampler2D color_texture;
layout (push_constant, std140) uniform DrawInfo {
mat4 modelview_matrix;
vec4 i_resolution;
@ -15,9 +13,6 @@ layout (push_constant, std140) uniform DrawInfo {
int layer;
int reverse_interlaced;
int convert_colors;
int areatex;
int searchtex;
int smaa_input;
};
/***** Area Sampling *****/
@ -97,7 +92,7 @@ vec3 LinearTosRGB(vec3 c) {
}
void main() {
vec4 pixel = AreaSampling(screen_textures[0], frag_tex_coord);
vec4 pixel = AreaSampling(color_texture, frag_tex_coord);
if (convert_colors == 2){
pixel = vec4(LinearTosRGB(pixel.rgb), pixel.a);
}

View file

@ -11,9 +11,6 @@ layout (push_constant, std140) uniform DrawInfo {
int layer;
int reverse_interlaced;
int convert_colors;
int areatex;
int searchtex;
int smaa_input;
};
void main()
{

View file

@ -16,25 +16,25 @@ layout (push_constant, std140) uniform DrawInfo {
int screen_id_r;
int layer;
int reverse_interlaced;
int convert_colors;
};
layout (set = 0, binding = 0) uniform sampler2D screen_textures[3];
layout (set = 0, binding = 0) uniform sampler2D color_texture;
vec4 GetScreen(int screen_id) {
#ifdef ARRAY_DYNAMIC_INDEX
return texture(screen_textures[screen_id], frag_tex_coord);
#else
switch (screen_id) {
case 0:
return texture(screen_textures[0], frag_tex_coord);
case 1:
return texture(screen_textures[1], frag_tex_coord);
case 2:
return texture(screen_textures[2], frag_tex_coord);
}
#endif
vec3 sRGBToLinear(vec3 c) {
return mix(c / 12.92, pow((c + 0.055) / 1.055, vec3(2.4)), step(0.04045, c));
}
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() {
color = GetScreen(screen_id_l);
vec4 pixel = texture(color_texture, frag_tex_coord);
if (convert_colors == 2){
pixel = vec4(LinearTosRGB(pixel.rgb), pixel.a);
} else if (convert_colors == 1){
pixel = vec4(sRGBToLinear(pixel.rgb), pixel.a);
}
color = pixel;
}

View file

@ -30,25 +30,11 @@ layout (push_constant, std140) uniform DrawInfo {
int reverse_interlaced;
};
layout (set = 0, binding = 0) uniform sampler2D screen_textures[3];
vec4 GetScreen(int screen_id) {
#ifdef ARRAY_DYNAMIC_INDEX
return texture(screen_textures[screen_id], frag_tex_coord);
#else
switch (screen_id) {
case 0:
return texture(screen_textures[0], frag_tex_coord);
case 1:
return texture(screen_textures[1], frag_tex_coord);
case 2:
return texture(screen_textures[2], frag_tex_coord);
}
#endif
}
layout (set = 0, binding = 0) uniform sampler2D color_texture_l;
layout (set = 0, binding = 1) uniform sampler2D color_texture_r;
void main() {
vec4 color_tex_l = GetScreen(screen_id_l);
vec4 color_tex_r = GetScreen(screen_id_r);
vec4 color_tex_l = texture(color_texture_l, frag_tex_coord);
vec4 color_tex_r = texture(color_texture_r, frag_tex_coord);
color = vec4(color_tex_l.rgb*l+color_tex_r.rgb*r, color_tex_l.a);
}

View file

@ -18,27 +18,13 @@ layout (push_constant, std140) uniform DrawInfo {
int reverse_interlaced;
};
layout (set = 0, binding = 0) uniform sampler2D screen_textures[3];
vec4 GetScreen(int screen_id) {
#ifdef ARRAY_DYNAMIC_INDEX
return texture(screen_textures[screen_id], frag_tex_coord);
#else
switch (screen_id) {
case 0:
return texture(screen_textures[0], frag_tex_coord);
case 1:
return texture(screen_textures[1], frag_tex_coord);
case 2:
return texture(screen_textures[2], frag_tex_coord);
}
#endif
}
layout (set = 0, binding = 0) uniform sampler2D color_texture_l;
layout (set = 0, binding = 1) uniform sampler2D color_texture_r;
void main() {
float screen_row = o_resolution.x * frag_tex_coord.x;
if (int(screen_row) % 2 == reverse_interlaced)
color = GetScreen(screen_id_l);
color = texture(color_texture_l, frag_tex_coord);
else
color = GetScreen(screen_id_r);
color = texture(color_texture_r, frag_tex_coord);
}

View file

@ -19,22 +19,7 @@ layout (push_constant, std140) uniform DrawInfo {
int convert_colors;
};
layout (set = 0, binding = 0) uniform sampler2D screen_textures[3];
vec4 GetScreen(int screen_id) {
#ifdef ARRAY_DYNAMIC_INDEX
return texture(screen_textures[screen_id], frag_tex_coord);
#else
switch (screen_id) {
case 0:
return texture(screen_textures[0], frag_tex_coord);
case 1:
return texture(screen_textures[1], frag_tex_coord);
case 2:
return texture(screen_textures[2], frag_tex_coord);
}
#endif
}
layout (set = 0, binding = 0) uniform sampler2D color_texture;
vec3 sRGBToLinear(vec3 c) {
return mix(c / 12.92, pow((c + 0.055) / 1.055, vec3(2.4)), step(0.04045, c));
@ -45,7 +30,7 @@ vec3 LinearTosRGB(vec3 c) {
}
void main() {
vec4 pixel = GetScreen(screen_id_l);
vec4 pixel = texture(color_texture, frag_tex_coord);
if (convert_colors == 2){
pixel = vec4(LinearTosRGB(pixel.rgb), pixel.a);
} else if (convert_colors == 1){

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 (currOutputScreenRects[i].GetHeight() != 0 && currOutputScreenRects[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, currOutputScreenRects[i].GetWidth(), currOutputScreenRects[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 ||
@ -639,6 +681,7 @@ void RendererOpenGL::AttachUniforms(){
uniform_i_resolution = glGetUniformLocation(state.draw.shader_program, "i_resolution");
uniform_o_resolution = glGetUniformLocation(state.draw.shader_program, "o_resolution");
uniform_convert_colors = glGetUniformLocation(state.draw.shader_program, "convert_colors");
uniform_fsr_sharpening = glGetUniformLocation(state.draw.shader_program, "FSR_SHARPENING");
uniform_layer = glGetUniformLocation(state.draw.shader_program, "layer");
attrib_position = glGetAttribLocation(state.draw.shader_program, "vert_position");
attrib_tex_coord = glGetAttribLocation(state.draw.shader_program, "vert_tex_coord");
@ -654,23 +697,19 @@ 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
bool isDownsampling = false;
int scalingMode; //0 is Nearest Neighbor, 1 is Gamma Corrected Bilinear, 2 is High Quality Scaling (Upsampling via Gamma Corrected Bilinear, Downsampling is Gamma Corrected Area Sampling)
if (Settings::values.filter_mode.GetValue()){
scalingMode = 2;
} else {
scalingMode = 0;
}
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;
@ -752,7 +791,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();
@ -771,15 +810,19 @@ 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);
if (scalingMode == 3){
glUniform1i(uniform_convert_colors, 0);
} else {
glUniform1i(uniform_convert_colors, 1);
}
glUniform4f(uniform_i_resolution, textureWidth, textureHeight, 1.0f / textureWidth, 1.0f / textureHeight);
state.Apply();
glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(pass_through_vertices), pass_through_vertices.data());
@ -795,7 +838,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();
@ -814,12 +857,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);
@ -833,12 +876,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);
@ -852,12 +895,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;
@ -879,19 +922,23 @@ 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);
glUniform1i(uniform_smaa_input, 1);
glUniform1i(uniform_convert_colors, 0);
if (scalingMode == 3){
glUniform1i(uniform_convert_colors, 2);
} else {
glUniform1i(uniform_convert_colors, 0);
}
glUniform4f(uniform_i_resolution, textureWidth, textureHeight, 1.0f / textureWidth, 1.0f / textureHeight);
state.Apply();
glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(pass_through_vertices), pass_through_vertices.data());
@ -905,7 +952,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();
@ -913,7 +960,11 @@ void RendererOpenGL::DrawSingleScreen(const ScreenInfo& screen_info, float scree
state.texture_units[0].texture_2d = screen_info.display_texture;
state.texture_units[0].sampler = samplers[1].handle;
glUniform1i(uniform_color_texture, 0);
glUniform1i(uniform_convert_colors, 1);
if (scalingMode == 3){
glUniform1i(uniform_convert_colors, 0);
} else {
glUniform1i(uniform_convert_colors, 1);
}
state.Apply();
glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(rotate_vertices), rotate_vertices.data());
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
@ -932,7 +983,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);
@ -955,7 +1006,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);
@ -964,6 +1015,152 @@ void RendererOpenGL::DrawSingleScreen(const ScreenInfo& screen_info, float scree
glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(output_vertices), output_vertices.data());
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
}
} else if (scalingMode == 3){
//Use intermiedatetextures[currScreen]
if (isDownsampling){
// EASU (1x)
state.viewport.x = 0;
state.viewport.y = 0;
state.viewport.width = textureWidth;
state.viewport.height = textureHeight;
state.Apply();
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, intermediateTextures[currScreen][4].handle, 0);
glClear(GL_COLOR_BUFFER_BIT);
state.draw.shader_program = FSR_PASS_0_shader.handle;
state.Apply();
AttachUniforms();
state.texture_units[0].texture_2d = antialiasFBOTexture[currScreen].handle;
state.texture_units[0].sampler = samplers[0].handle;
glUniform4f(uniform_i_resolution, textureWidth, textureHeight, 1.0f / textureWidth, 1.0f / textureHeight);
glUniform4f(uniform_o_resolution, textureWidth, textureHeight, 1.0f / textureWidth, 1.0f / textureHeight);
state.Apply();
glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(pass_through_vertices), pass_through_vertices.data());
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
// RCAS
state.viewport.x = 0;
state.viewport.y = 0;
state.viewport.width = textureWidth;
state.viewport.height = textureHeight;
state.Apply();
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, intermediateTextures[currScreen][5].handle, 0);
glClear(GL_COLOR_BUFFER_BIT);
state.draw.shader_program = FSR_PASS_1_shader.handle;
state.Apply();
AttachUniforms();
state.texture_units[0].texture_2d = intermediateTextures[currScreen][4].handle;
state.texture_units[0].sampler = samplers[1].handle;
glUniform1f(uniform_fsr_sharpening, fsr_sharpening);
glUniform4f(uniform_o_resolution, textureWidth, textureHeight, 1.0f / textureWidth, 1.0f / textureHeight);
state.Apply();
glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(pass_through_vertices), pass_through_vertices.data());
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
// Area Sampling
state.draw.read_framebuffer = originalReadFramebuffer;
state.draw.draw_framebuffer = originalDrawFramebuffer;
state.Apply();
state.viewport.x = originalViewport[0];
state.viewport.y = originalViewport[1];
state.viewport.width = originalViewport[2];
state.viewport.height = originalViewport[3];
state.Apply();
state.draw.shader_program = AREA_SAMPLING_shader.handle;
state.Apply();
AttachUniforms();
state.texture_units[0].texture_2d = intermediateTextures[currScreen][5].handle;
state.texture_units[0].sampler = samplers[0].handle;
glUniform1i(uniform_color_texture, 0);
glUniform1i(uniform_convert_colors, 0);
glUniform4f(uniform_i_resolution, textureWidth, textureHeight, 1.0f / textureWidth, 1.0f / textureHeight);
glUniform4f(uniform_o_resolution, screenWidth, screenHeight, 1.0f / screenWidth, 1.0f / screenHeight);
glUniformMatrix3x2fv(uniform_modelview_matrix, 1, GL_FALSE, ortho_matrix.data());
state.Apply();
glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(output_vertices), output_vertices.data());
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
} else {
// EASU (to output resolution)
state.viewport.x = 0;
state.viewport.y = 0;
state.viewport.width = screenWidth;
state.viewport.height = screenHeight;
state.Apply();
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, intermediateOutputSizeTextures[currOutputScreen][1].handle, 0);
glClear(GL_COLOR_BUFFER_BIT);
state.draw.shader_program = FSR_PASS_0_shader.handle;
state.Apply();
AttachUniforms();
state.texture_units[0].texture_2d = antialiasFBOTexture[currScreen].handle;
state.texture_units[0].sampler = samplers[0].handle;
glUniform4f(uniform_i_resolution, textureWidth, textureHeight, 1.0f / textureWidth, 1.0f / textureHeight);
glUniform4f(uniform_o_resolution, screenWidth, screenHeight, 1.0f / screenWidth, 1.0f / screenHeight);
state.Apply();
glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(pass_through_vertices), pass_through_vertices.data());
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
// RCAS
state.viewport.x = 0;
state.viewport.y = 0;
state.viewport.width = screenWidth;
state.viewport.height = screenHeight;
state.Apply();
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, intermediateOutputSizeTextures[currOutputScreen][2].handle, 0);
glClear(GL_COLOR_BUFFER_BIT);
state.draw.shader_program = FSR_PASS_1_shader.handle;
state.Apply();
AttachUniforms();
state.texture_units[0].texture_2d = intermediateOutputSizeTextures[currOutputScreen][1].handle;
state.texture_units[0].sampler = samplers[1].handle;
glUniform1f(uniform_fsr_sharpening, fsr_sharpening);
glUniform4f(uniform_o_resolution, screenWidth, screenHeight, 1.0f / screenWidth, 1.0f / screenHeight);
state.Apply();
glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(pass_through_vertices), pass_through_vertices.data());
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
// Normal Present
state.draw.read_framebuffer = originalReadFramebuffer;
state.draw.draw_framebuffer = originalDrawFramebuffer;
state.Apply();
state.viewport.x = originalViewport[0];
state.viewport.y = originalViewport[1];
state.viewport.width = originalViewport[2];
state.viewport.height = originalViewport[3];
state.Apply();
state.draw.shader_program = Present_shader.handle;
state.Apply();
AttachUniforms();
state.texture_units[0].texture_2d = intermediateOutputSizeTextures[currOutputScreen][2].handle;
state.texture_units[0].sampler = samplers[1].handle;
glUniform1i(uniform_color_texture, 0);
glUniform1i(uniform_convert_colors, 0);
glUniformMatrix3x2fv(uniform_modelview_matrix, 1, GL_FALSE, ortho_matrix.data());
state.Apply();
glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(output_vertices), output_vertices.data());
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
}
} else if (scalingMode == 4){
//Output
state.draw.read_framebuffer = originalReadFramebuffer;
state.draw.draw_framebuffer = originalDrawFramebuffer;
state.Apply();
state.viewport.x = originalViewport[0];
state.viewport.y = originalViewport[1];
state.viewport.width = originalViewport[2];
state.viewport.height = originalViewport[3];
state.Apply();
state.draw.shader_program = SharpBilinear_shader.handle;
state.Apply();
AttachUniforms();
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);
glUniform4f(uniform_i_resolution, textureWidth, textureHeight, 1.0f / textureWidth, 1.0f / textureHeight);
glUniform4f(uniform_o_resolution, screenWidth, screenHeight, 1.0f / screenWidth, 1.0f / screenHeight);
glUniformMatrix3x2fv(uniform_modelview_matrix, 1, GL_FALSE, ortho_matrix.data());
state.Apply();
glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(output_vertices), output_vertices.data());
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
} else {
//Output
state.draw.read_framebuffer = originalReadFramebuffer;
@ -977,7 +1174,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 {
@ -1047,7 +1244,8 @@ void RendererOpenGL::DrawSingleScreenStereo(const ScreenInfo& screen_info_l,
}
const u32 scale_factor = GetResolutionScaleFactor();
const GLuint sampler = samplers[Settings::values.filter_mode.GetValue()].handle;
int scalingMode = static_cast<int>(Settings::values.output_scaling.GetValue());
const GLuint sampler = samplers[scalingMode > 0 ? 1 : 0].handle;
glUniform4f(uniform_i_resolution,
static_cast<float>(screen_info_l.texture.width * scale_factor),
static_cast<float>(screen_info_l.texture.height * scale_factor),
@ -1098,13 +1296,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
currOutputScreenRects[0] = layout.top_screen;
currOutputScreenRects[1] = layout.bottom_screen;
currOutputScreenRects[2] = layout.additional_screen;
if (currOutputScreenRects[0] != prevOutputScreenRects[0] || currOutputScreenRects[1] != prevOutputScreenRects[1] || currOutputScreenRects[2] != prevOutputScreenRects[2]){
AllocateOutputSizeTextures();
}
prevOutputScreenRects[0] = currOutputScreenRects[0];
prevOutputScreenRects[1] = currOutputScreenRects[1];
prevOutputScreenRects[2] = currOutputScreenRects[2];
//Set the Viewport
state.viewport.x = 0;
state.viewport.y = 0;
@ -1136,18 +1345,23 @@ void RendererOpenGL::DrawScreens(const Layout::FramebufferLayout& layout, bool f
glUniform1i(uniform_layer, 0);
if (!Settings::values.swap_screen.GetValue()) {
currOutputScreen = 0;
DrawTopScreen(layout, top_screen);
glUniform1i(uniform_layer, 0);
ApplySecondLayerOpacity(layout.bottom_opacity);
currOutputScreen = 1;
DrawBottomScreen(layout, bottom_screen);
} else {
currOutputScreen = 1;
DrawBottomScreen(layout, bottom_screen);
glUniform1i(uniform_layer, 0);
ApplySecondLayerOpacity(layout.top_opacity);
currOutputScreen = 0;
DrawTopScreen(layout, top_screen);
}
if (layout.additional_screen_enabled) {
currOutputScreen = 2;
const auto& additional_screen = layout.additional_screen;
if (!Settings::values.swap_screen.GetValue()) {
DrawTopScreen(layout, additional_screen);

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,23 @@ 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, 7>, 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> prevOutputScreenRects;
std::array<Common::Rectangle<u32>, 3> currOutputScreenRects;
int currOutputScreen;
OGLTexture areatex;
OGLTexture searchtex;
@ -129,6 +134,8 @@ private:
// Shader Uniform for converting colors. 0 is no conversion, 1 is sRGB -> linear, 2 is Linear -> sRGB
GLuint uniform_convert_colors;
GLuint uniform_fsr_sharpening;
// Shader uniform for Dolphin compatibility
GLuint uniform_i_resolution;

View file

@ -60,14 +60,6 @@ MICROPROFILE_DEFINE(Vulkan_RenderFrame, "Vulkan", "Render Frame", MP_RGB(128, 12
namespace Vulkan {
struct ScreenRectVertex {
ScreenRectVertex() = default;
ScreenRectVertex(float x, float y, float u, float v)
: position{Common::MakeVec(x, y)}, tex_coord{Common::MakeVec(u, v)} {}
Common::Vec2f position;
Common::Vec2f tex_coord;
};
constexpr u32 VERTEX_BUFFER_SIZE = sizeof(ScreenRectVertex) * 8192;
@ -80,8 +72,10 @@ constexpr std::array<f32, 4 * 4> MakeOrthographicMatrix(u32 width, u32 height) {
// clang-format on
}
constexpr static std::array<vk::DescriptorSetLayoutBinding, 1> PRESENT_BINDINGS = {{
{0, vk::DescriptorType::eCombinedImageSampler, 3, vk::ShaderStageFlagBits::eFragment},
constexpr static std::array<vk::DescriptorSetLayoutBinding, 3> PRESENT_BINDINGS = {{
{0, vk::DescriptorType::eCombinedImageSampler, 1, vk::ShaderStageFlagBits::eFragment},
{1, vk::DescriptorType::eCombinedImageSampler, 1, vk::ShaderStageFlagBits::eFragment},
{2, vk::DescriptorType::eCombinedImageSampler, 1, vk::ShaderStageFlagBits::eFragment},
}};
namespace {
@ -153,6 +147,8 @@ RendererVulkan::RendererVulkan(Core::System& system, Pica::PicaCore& pica_,
CompileShaders();
BuildLayouts();
CreateTextureRenderPass();
AllocatePPTextures();
CreatePPTextureFramebuffers();
BuildPipelines();
if (secondary_window) {
secondary_present_window_ptr = std::make_unique<PresentWindow>(
@ -199,6 +195,18 @@ RendererVulkan::~RendererVulkan() {
vmaDestroyImage(instance.GetAllocator(), info.texture.image, info.texture.allocation);
}
for (int j = 0; j < intermediateTextures.size(); j++) {
for (int i = 0; i < intermediateTextures[0].size(); i++){
device.destroyFramebuffer(intermediateTextureFBOs[j][i]);
device.destroyImageView(intermediateTextures[j][i].image_view);
vmaDestroyImage(instance.GetAllocator(), intermediateTextures[j][i].image, intermediateTextures[j][i].allocation);
}
device.destroyFramebuffer(antialiasTextureFBOs[j]);
device.destroyImageView(antialiasTextures[j].image_view);
vmaDestroyImage(instance.GetAllocator(), antialiasTextures[j].image, antialiasTextures[j].allocation);
}
device.destroyRenderPass(textureRenderpass);
device.destroyPipeline(cursor_pipeline);
device.destroyShaderModule(cursor_vertex_shader);
device.destroyShaderModule(cursor_fragment_shader);
@ -231,7 +239,7 @@ void RendererVulkan::PrepareRendertarget() {
void RendererVulkan::CreateTextureRenderPass(){
const vk::AttachmentReference color_ref = {
.attachment = 0,
.layout = vk::ImageLayout::eGeneral,
.layout = vk::ImageLayout::eColorAttachmentOptimal,
};
const vk::SubpassDescription subpass = {
@ -246,12 +254,22 @@ void RendererVulkan::CreateTextureRenderPass(){
const vk::AttachmentDescription color_attachment = {
.format = vk::Format::eR16G16B16A16Sfloat,
.samples = vk::SampleCountFlagBits::e1,
.loadOp = vk::AttachmentLoadOp::eClear,
.storeOp = vk::AttachmentStoreOp::eStore,
.stencilLoadOp = vk::AttachmentLoadOp::eDontCare,
.stencilStoreOp = vk::AttachmentStoreOp::eDontCare,
.initialLayout = vk::ImageLayout::eUndefined,
.finalLayout = vk::ImageLayout::eTransferSrcOptimal,
.finalLayout = vk::ImageLayout::eShaderReadOnlyOptimal,
};
vk::SubpassDependency dependency = {
.srcSubpass = VK_SUBPASS_EXTERNAL,
.dstSubpass = 0,
.srcStageMask = vk::PipelineStageFlagBits::eColorAttachmentOutput,
.dstStageMask = vk::PipelineStageFlagBits::eFragmentShader,
.srcAccessMask = vk::AccessFlagBits::eColorAttachmentWrite,
.dstAccessMask = vk::AccessFlagBits::eShaderRead,
};
const vk::RenderPassCreateInfo renderpass_info = {
@ -259,8 +277,8 @@ void RendererVulkan::CreateTextureRenderPass(){
.pAttachments = &color_attachment,
.subpassCount = 1,
.pSubpasses = &subpass,
.dependencyCount = 0,
.pDependencies = nullptr,
.dependencyCount = 1,
.pDependencies = &dependency,
};
textureRenderpass = instance.GetDevice().createRenderPass(renderpass_info);
}
@ -285,7 +303,7 @@ void RendererVulkan::AllocateTexture(TextureInfo& texture, int width, int height
.mipLevels = 1,
.arrayLayers = 1,
.samples = vk::SampleCountFlagBits::e1,
.usage = vk::ImageUsageFlagBits::eSampled,
.usage = vk::ImageUsageFlagBits::eSampled | vk::ImageUsageFlagBits::eColorAttachment,
};
const VmaAllocationCreateInfo alloc_info = {
@ -303,8 +321,10 @@ void RendererVulkan::AllocateTexture(TextureInfo& texture, int width, int height
VkResult result = vmaCreateImage(instance.GetAllocator(), &unsafe_image_info, &alloc_info,
&unsafe_image, &texture.allocation, nullptr);
if (result != VK_SUCCESS) [[unlikely]] {
LOG_CRITICAL(Render_Vulkan, "Failed allocating texture with error {}", result);
LOG_CRITICAL(Render_Vulkan, "Failed allocating regular texture ({}x{}) with error {}", texture.width, texture.height, result);
UNREACHABLE();
} else {
LOG_INFO(Render_Vulkan, "Successfully allocated regular texture");
}
texture.image = vk::Image{unsafe_image};
@ -327,14 +347,25 @@ void RendererVulkan::AllocateTexture(TextureInfo& texture, int width, int height
void RendererVulkan::AllocatePPTextures(){
int TopWidth = 400;
int TopHeight = 240;
int BottomWidth = 320;
int BottomHeight = 240;
if (currTopTextureWidth != 0 && currBottomTextureWidth != 0 && currTopTextureHeight != 0 && currBottomTextureHeight != 0){
TopWidth = currTopTextureWidth;
TopHeight = currTopTextureHeight;
BottomWidth = currBottomTextureWidth;
BottomHeight = currBottomTextureHeight;
}
for (int i = 0; i < intermediateTextures[0].size(); i++){
AllocateTexture(intermediateTextures[0][i], currTopTextureWidth, currTopTextureHeight, vk::Format::eR16G16B16A16Sfloat);
AllocateTexture(intermediateTextures[0][i], TopWidth, TopHeight, vk::Format::eR16G16B16A16Sfloat);
}
for (int i = 0; i < intermediateTextures[1].size(); i++){
AllocateTexture(intermediateTextures[1][i], currBottomTextureWidth, currBottomTextureHeight, vk::Format::eR16G16B16A16Sfloat);
AllocateTexture(intermediateTextures[1][i], BottomWidth, BottomHeight, vk::Format::eR16G16B16A16Sfloat);
}
AllocateTexture(antialiasTextures[0], currTopTextureWidth, currTopTextureHeight, vk::Format::eR16G16B16A16Sfloat);
AllocateTexture(antialiasTextures[1], currBottomTextureWidth, currBottomTextureHeight, vk::Format::eR16G16B16A16Sfloat);
AllocateTexture(antialiasTextures[0], TopWidth, TopHeight, vk::Format::eR16G16B16A16Sfloat);
AllocateTexture(antialiasTextures[1], BottomWidth, BottomHeight, vk::Format::eR16G16B16A16Sfloat);
};
void RendererVulkan::CreateTextureFramebuffer(TextureInfo& texture, vk::Framebuffer& framebuffer) {
@ -360,18 +391,137 @@ void RendererVulkan::CreatePPTextureFramebuffers(){
}
};
void RendererVulkan::PrepareDraw(Frame* frame, const Layout::FramebufferLayout& layout) {
const auto sampler = present_samplers[Settings::values.filter_mode.GetValue()];
void RendererVulkan::PrepareTextureDraw(TextureInfo framebufferTexture, vk::Framebuffer framebuffer, vk::Pipeline shaderPipeline, std::vector<TextureInfo> texturesToSample, int filterMode){
const auto sampler = present_samplers[filterMode];
const auto present_set = present_heap.Commit();
for (u32 index = 0; index < screen_infos.size(); index++) {
update_queue.AddImageSampler(present_set, 0, index, screen_infos[index].image_view,
sampler);
for (u32 i = 0; i < texturesToSample.size(); i++) {
update_queue.AddImageSampler(present_set, i, 0, texturesToSample[i].image_view, sampler, vk::ImageLayout::eShaderReadOnlyOptimal);
}
renderpass_cache.EndRendering();
scheduler.Record([this, framebufferTexture, framebuffer, shaderPipeline, present_set](vk::CommandBuffer cmdbuf) {
const vk::Viewport viewport = {
.x = 0.0f,
.y = 0.0f,
.width = static_cast<float>(framebufferTexture.width),
.height = static_cast<float>(framebufferTexture.height),
.minDepth = 0.0f,
.maxDepth = 1.0f,
};
const vk::Rect2D scissor = {
.offset = {0, 0},
.extent = {framebufferTexture.width, framebufferTexture.height},
};
const vk::ClearColorValue clear_color = {
.float32 =
std::array{
0.0f,
0.0f,
0.0f,
0.0f,
},
};
cmdbuf.setViewport(0, viewport);
cmdbuf.setScissor(0, scissor);
const vk::ClearValue clear{.color = clear_color};
const vk::PipelineLayout layout{*present_pipeline_layout};
const vk::RenderPassBeginInfo renderpass_begin_info = {
.renderPass = textureRenderpass,
.framebuffer = framebuffer,
.renderArea =
vk::Rect2D{
.offset = {0, 0},
.extent = {framebufferTexture.width, framebufferTexture.height},
},
.clearValueCount = 1,
.pClearValues = &clear,
};
const std::array<float, 4> blendConstants = { 0.0f, 0.0f, 0.0f, 1.0f };
cmdbuf.setBlendConstants(blendConstants.data());
cmdbuf.beginRenderPass(renderpass_begin_info, vk::SubpassContents::eInline);
cmdbuf.bindPipeline(vk::PipelineBindPoint::eGraphics, shaderPipeline);
cmdbuf.bindDescriptorSets(vk::PipelineBindPoint::eGraphics, layout, 0, present_set, {});
});
}
void RendererVulkan::PrepareTextureDrawFromScreenInfo(TextureInfo framebufferTexture, vk::Framebuffer framebuffer, vk::Pipeline shaderPipeline, std::vector<u32> screenids, int filterMode){
const auto sampler = present_samplers[filterMode];
const auto present_set = present_heap.Commit();
for (u32 i = 0; i < screenids.size(); i++) {
update_queue.AddImageSampler(present_set, i, 0, screen_infos[screenids[i]].image_view,
sampler, vk::ImageLayout::eGeneral);
}
renderpass_cache.EndRendering();
scheduler.Record([this, framebufferTexture, framebuffer, shaderPipeline, present_set](vk::CommandBuffer cmdbuf) {
const vk::Viewport viewport = {
.x = 0.0f,
.y = 0.0f,
.width = static_cast<float>(framebufferTexture.width),
.height = static_cast<float>(framebufferTexture.height),
.minDepth = 0.0f,
.maxDepth = 1.0f,
};
const vk::Rect2D scissor = {
.offset = {0, 0},
.extent = {framebufferTexture.width, framebufferTexture.height},
};
const vk::ClearColorValue clear_color = {
.float32 =
std::array{
0.0f,
0.0f,
0.0f,
0.0f,
},
};
cmdbuf.setViewport(0, viewport);
cmdbuf.setScissor(0, scissor);
const vk::ClearValue clear{.color = clear_color};
const vk::PipelineLayout layout{*present_pipeline_layout};
const vk::RenderPassBeginInfo renderpass_begin_info = {
.renderPass = textureRenderpass,
.framebuffer = framebuffer,
.renderArea =
vk::Rect2D{
.offset = {0, 0},
.extent = {framebufferTexture.width, framebufferTexture.height},
},
.clearValueCount = 1,
.pClearValues = &clear,
};
const std::array<float, 4> blendConstants = { 0.0f, 0.0f, 0.0f, 1.0f };
cmdbuf.setBlendConstants(blendConstants.data());
cmdbuf.beginRenderPass(renderpass_begin_info, vk::SubpassContents::eInline);
cmdbuf.bindPipeline(vk::PipelineBindPoint::eGraphics, shaderPipeline);
cmdbuf.bindDescriptorSets(vk::PipelineBindPoint::eGraphics, layout, 0, present_set, {});
});
}
void RendererVulkan::PrepareDrawFromScreenInfo(Frame* frame, const Layout::FramebufferLayout& layout, vk::Pipeline shaderPipeline, std::vector<u32> screenids, int filterMode) {
const auto sampler = present_samplers[filterMode];
const auto present_set = present_heap.Commit();
for (u32 i = 0; i < screenids.size(); i++) {
update_queue.AddImageSampler(present_set, i, 0, screen_infos[screenids[i]].image_view,
sampler, vk::ImageLayout::eGeneral);
}
renderpass_cache.EndRendering();
vk::RenderPass currentRenderPass;
if (clearingColorAttachment){
currentRenderPass = main_present_window.Renderpass();
} else {
currentRenderPass = main_present_window.LoadRenderpass();
}
scheduler.Record([this, layout, frame, present_set,
renderpass = main_present_window.Renderpass(),
index = current_pipeline](vk::CommandBuffer cmdbuf) {
currentRenderPass,
shaderPipeline](vk::CommandBuffer cmdbuf) {
const vk::Viewport viewport = {
.x = 0.0f,
.y = 0.0f,
@ -392,7 +542,7 @@ void RendererVulkan::PrepareDraw(Frame* frame, const Layout::FramebufferLayout&
const vk::ClearValue clear{.color = clear_color};
const vk::PipelineLayout layout{*present_pipeline_layout};
const vk::RenderPassBeginInfo renderpass_begin_info = {
.renderPass = renderpass,
.renderPass = currentRenderPass,
.framebuffer = frame->framebuffer,
.renderArea =
vk::Rect2D{
@ -402,12 +552,68 @@ void RendererVulkan::PrepareDraw(Frame* frame, const Layout::FramebufferLayout&
.clearValueCount = 1,
.pClearValues = &clear,
};
const std::array<float, 4> blendConstants = { 0.0f, 0.0f, 0.0f, 1.0f };
cmdbuf.setBlendConstants(blendConstants.data());
cmdbuf.beginRenderPass(renderpass_begin_info, vk::SubpassContents::eInline);
cmdbuf.bindPipeline(vk::PipelineBindPoint::eGraphics, present_pipelines[index]);
cmdbuf.bindPipeline(vk::PipelineBindPoint::eGraphics, shaderPipeline);
cmdbuf.bindDescriptorSets(vk::PipelineBindPoint::eGraphics, layout, 0, present_set, {});
});
}
void RendererVulkan::PrepareDrawFromTextureInfo(Frame* frame, const Layout::FramebufferLayout& layout, vk::Pipeline shaderPipeline, std::vector<TextureInfo> texturesToSample, int filterMode) {
const auto sampler = present_samplers[filterMode];
const auto present_set = present_heap.Commit();
for (u32 i = 0; i < texturesToSample.size(); i++) {
update_queue.AddImageSampler(present_set, i, 0, texturesToSample[i].image_view, sampler, vk::ImageLayout::eShaderReadOnlyOptimal);
}
renderpass_cache.EndRendering();
vk::RenderPass currentRenderPass;
if (clearingColorAttachment){
currentRenderPass = main_present_window.Renderpass();
} else {
currentRenderPass = main_present_window.LoadRenderpass();
}
scheduler.Record([this, layout, frame, present_set,
currentRenderPass,
shaderPipeline](vk::CommandBuffer cmdbuf) {
const vk::Viewport viewport = {
.x = 0.0f,
.y = 0.0f,
.width = static_cast<float>(layout.width),
.height = static_cast<float>(layout.height),
.minDepth = 0.0f,
.maxDepth = 1.0f,
};
const vk::Rect2D scissor = {
.offset = {0, 0},
.extent = {layout.width, layout.height},
};
cmdbuf.setViewport(0, viewport);
cmdbuf.setScissor(0, scissor);
const vk::ClearValue clear{.color = clear_color};
const vk::PipelineLayout layout{*present_pipeline_layout};
const vk::RenderPassBeginInfo renderpass_begin_info = {
.renderPass = currentRenderPass,
.framebuffer = frame->framebuffer,
.renderArea =
vk::Rect2D{
.offset = {0, 0},
.extent = {frame->width, frame->height},
},
.clearValueCount = 1,
.pClearValues = &clear,
};
const std::array<float, 4> blendConstants = { 0.0f, 0.0f, 0.0f, 1.0f };
cmdbuf.setBlendConstants(blendConstants.data());
cmdbuf.beginRenderPass(renderpass_begin_info, vk::SubpassContents::eInline);
cmdbuf.bindPipeline(vk::PipelineBindPoint::eGraphics, shaderPipeline);
cmdbuf.bindDescriptorSets(vk::PipelineBindPoint::eGraphics, layout, 0, present_set, {});
});
}
void RendererVulkan::RenderToWindow(PresentWindow& window, const Layout::FramebufferLayout& layout,
bool flipped) {
Frame* frame = window.GetRenderFrame();
@ -935,7 +1141,7 @@ void RendererVulkan::ConfigureFramebufferTexture(TextureInfo& texture,
VkResult result = vmaCreateImage(instance.GetAllocator(), &unsafe_image_info, &alloc_info,
&unsafe_image, &texture.allocation, nullptr);
if (result != VK_SUCCESS) [[unlikely]] {
LOG_CRITICAL(Render_Vulkan, "Failed allocating texture with error {}", result);
LOG_CRITICAL(Render_Vulkan, "Failed allocating framebuffer texture with error {}", result);
UNREACHABLE();
}
texture.image = vk::Image{unsafe_image};
@ -983,7 +1189,7 @@ void RendererVulkan::FillScreen(Common::Vec3<u8> color, const TextureInfo& textu
const vk::ImageMemoryBarrier pre_barrier = {
.srcAccessMask = vk::AccessFlagBits::eShaderRead | vk::AccessFlagBits::eTransferRead,
.dstAccessMask = vk::AccessFlagBits::eTransferWrite,
.oldLayout = vk::ImageLayout::eGeneral,
.oldLayout = vk::ImageLayout::eShaderReadOnlyOptimal,
.newLayout = vk::ImageLayout::eTransferDstOptimal,
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
@ -995,7 +1201,7 @@ void RendererVulkan::FillScreen(Common::Vec3<u8> color, const TextureInfo& textu
.srcAccessMask = vk::AccessFlagBits::eTransferWrite,
.dstAccessMask = vk::AccessFlagBits::eShaderRead | vk::AccessFlagBits::eTransferRead,
.oldLayout = vk::ImageLayout::eTransferDstOptimal,
.newLayout = vk::ImageLayout::eGeneral,
.newLayout = vk::ImageLayout::eShaderReadOnlyOptimal,
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
.image = image,
@ -1034,19 +1240,19 @@ void RendererVulkan::DrawSingleScreen(u32 screen_id, float screenLeft, float scr
Layout::DisplayOrientation orientation) {
const ScreenInfo& screen_info = screen_infos[screen_id];
const auto& texcoords = screen_info.texcoords;
const u32 scale_factor = GetResolutionScaleFactor();
// Texture Width and Height when correctly rotated to landscape
float textureWidth = static_cast<float>(screen_info.texture.height * scale_factor);
float textureHeight = static_cast<float>(screen_info.texture.width * scale_factor);
// Texture Width and Height when correctly rotated to landscape
bool isDownsampling = false;
int scalingMode; //0 is Nearest Neighbor, 1 is Gamma Corrected Bilinear, 2 is High Quality Scaling (Upsampling via Gamma Corrected Bilinear, Downsampling is Gamma Corrected Area Sampling)
if (Settings::values.filter_mode.GetValue()){
scalingMode = 2;
int currentScreen;
if (textureWidth == currTopTextureWidth && textureHeight == currTopTextureHeight){
currentScreen = 0;
} else {
scalingMode = 0;
currentScreen = 1;
}
bool isDownsampling = false;
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
if (orientation == Layout::DisplayOrientation::Landscape || orientation == Layout::DisplayOrientation::LandscapeFlipped) {
if (textureWidth > screenWidth){
@ -1060,19 +1266,18 @@ void RendererVulkan::DrawSingleScreen(u32 screen_id, float screenLeft, float scr
// Rotate Internal Texture to Landscape (The 3DS stores images rotated 90° internally)
std::array<ScreenRectVertex, 4> rotate_vertices;
rotate_vertices = {{
ScreenRectVertex(-1.f, 1.f, texcoords.bottom, texcoords.left), //Left, Top
ScreenRectVertex(1.f, 1.f, texcoords.bottom, texcoords.right), //Right, Top
ScreenRectVertex(-1.f, -1.f, texcoords.top, texcoords.left), //Left, Bottom
ScreenRectVertex(1.f, -1.f, texcoords.top, texcoords.right), //Right, Bottom
ScreenRectVertex(-1.f, 1.f, texcoords.top, texcoords.left), //Left, Top
ScreenRectVertex(1.f, 1.f, texcoords.top, texcoords.right), //Right, Top
ScreenRectVertex(-1.f, -1.f, texcoords.bottom, texcoords.left), //Left, Bottom
ScreenRectVertex(1.f, -1.f, texcoords.bottom, texcoords.right), //Right, Bottom
}};
// Vertices for 1:1 Texture Mapping.
std::array<ScreenRectVertex, 4> pass_through_vertices;
pass_through_vertices = {{
ScreenRectVertex(-1.f, 1.f, 0.f, 1.f), //Left, Top
ScreenRectVertex(1.f, 1.f, 1.f, 1.f), //Right, Top
ScreenRectVertex(-1.f, -1.f, 0.f, 0.f), //Left, Bottom
ScreenRectVertex(1.f, -1.f, 1.f, 0.f), //Right, Bottom
ScreenRectVertex(-1.f, 1.f, 0.f, 0.f), //Left, Top
ScreenRectVertex(1.f, 1.f, 1.f, 0.f), //Right, Top
ScreenRectVertex(-1.f, -1.f, 0.f, 1.f), //Left, Bottom
ScreenRectVertex(1.f, -1.f, 1.f, 1.f), //Right, Bottom
}};
// Vertices for Azahar's Output Layout
@ -1080,71 +1285,120 @@ void RendererVulkan::DrawSingleScreen(u32 screen_id, float screenLeft, float scr
switch (orientation) {
case Layout::DisplayOrientation::Landscape:
output_vertices = {{
ScreenRectVertex(screenLeft, screenTop, 0.f, 1.f), //Left, Top
ScreenRectVertex(screenLeft + screenWidth, screenTop, 1.f, 1.f), //Right, Top
ScreenRectVertex(screenLeft, screenTop + screenHeight, 0.f, 0.f), //Left, Bottom
ScreenRectVertex(screenLeft + screenWidth, screenTop + screenHeight, 1.f, 0.f), //Right, Bottom
ScreenRectVertex(screenLeft, screenTop, 0.f, 0.f),
ScreenRectVertex(screenLeft + screenWidth, screenTop, 1.f, 0.f),
ScreenRectVertex(screenLeft, screenTop + screenHeight, 0.f, 1.f),
ScreenRectVertex(screenLeft + screenWidth, screenTop + screenHeight, 1.f, 1.f),
}};
break;
case Layout::DisplayOrientation::Portrait:
output_vertices = {{
ScreenRectVertex(screenLeft, screenTop, 1.f, 1.f), //Left, Top
ScreenRectVertex(screenLeft + screenWidth, screenTop, 1.f, 0.f), //Right, Top
ScreenRectVertex(screenLeft, screenTop + screenHeight, 0.f, 1.f), //Left, Bottom
ScreenRectVertex(screenLeft + screenWidth, screenTop + screenHeight, 0.f, 0.f), //Right, Bottom
ScreenRectVertex(screenLeft, screenTop, 1.f, 0.f),
ScreenRectVertex(screenLeft + screenWidth, screenTop, 1.f, 1.f),
ScreenRectVertex(screenLeft, screenTop + screenHeight, 0.f, 0.f),
ScreenRectVertex(screenLeft + screenWidth, screenTop + screenHeight, 0.f, 1.f),
}};
std::swap(screenHeight, screenWidth);
break;
case Layout::DisplayOrientation::LandscapeFlipped:
output_vertices = {{
ScreenRectVertex(screenLeft, screenTop, 0.f, 0.f), //Left, Top
ScreenRectVertex(screenLeft + screenWidth, screenTop, 1.f, 0.f), //Right, Top
ScreenRectVertex(screenLeft, screenTop + screenHeight, 0.f, 1.f), //Left, Bottom
ScreenRectVertex(screenLeft + screenWidth, screenTop + screenHeight, 1.f, 1.f), //Right, Bottom
ScreenRectVertex(screenLeft, screenTop, 0.f, 1.f),
ScreenRectVertex(screenLeft + screenWidth, screenTop, 1.f, 1.f),
ScreenRectVertex(screenLeft, screenTop + screenHeight, 0.f, 0.f),
ScreenRectVertex(screenLeft + screenWidth, screenTop + screenHeight, 1.f, 0.f),
}};
break;
case Layout::DisplayOrientation::PortraitFlipped:
output_vertices = {{
ScreenRectVertex(screenLeft, screenTop, 0.f, 0.f), //Left, Top
ScreenRectVertex(screenLeft + screenWidth, screenTop, 0.f, 1.f), //Right, Top
ScreenRectVertex(screenLeft, screenTop + screenHeight, 1.f, 0.f), //Left, Bottom
ScreenRectVertex(screenLeft + screenWidth, screenTop + screenHeight, 1.f, 1.f), //Right, Bottom
ScreenRectVertex(screenLeft, screenTop, 0.f, 1.f),
ScreenRectVertex(screenLeft + screenWidth, screenTop, 0.f, 0.f),
ScreenRectVertex(screenLeft, screenTop + screenHeight, 1.f, 1.f),
ScreenRectVertex(screenLeft + screenWidth, screenTop + screenHeight, 1.f, 0.f),
}};
std::swap(screenHeight, screenWidth);
break;
default:
LOG_ERROR(Render_OpenGL, "Unknown DisplayOrientation: {}", orientation);
break;
}
const u64 size = sizeof(ScreenRectVertex) * output_vertices.size();
auto [data, offset, invalidate] = vertex_buffer.Map(size, 16);
std::memcpy(data, output_vertices.data(), size);
vertex_buffer.Commit(size);
draw_info.i_resolution =
Common::MakeVec(static_cast<f32>(screen_info.texture.width * scale_factor),
static_cast<f32>(screen_info.texture.height * scale_factor),
1.0f / static_cast<f32>(screen_info.texture.width * scale_factor),
1.0f / static_cast<f32>(screen_info.texture.height * scale_factor));
draw_info.o_resolution = Common::MakeVec(screenWidth, screenHeight, 1.0f / screenWidth, 1.0f / screenHeight);
draw_info.screen_id_l = screen_id;
int passes = 5;
std::vector<VertexBufferPointer> vertexBufferPointers(passes);
for (auto& vbp : vertexBufferPointers){
std::tie(vbp.data, vbp.offset, vbp.invalidate) = vertex_buffer.Map(size, 16);
vertex_buffer.Commit(size);
}
std::vector<PresentUniformData> drawInfos(passes);
for (auto& info : drawInfos){
info = draw_info;
}
scheduler.Record([this, offset = offset, info = draw_info](vk::CommandBuffer cmdbuf) {
const u32 first_vertex = static_cast<u32>(offset) / sizeof(ScreenRectVertex);
// Attempted Multipass
std::vector<u32> screen_ids = {screen_id};
PrepareTextureDrawFromScreenInfo(intermediateTextures[currentScreen][0], intermediateTextureFBOs[currentScreen][0], post_pipelines_texture[0], screen_ids, 1);
UpdateVertexBuffer(rotate_vertices, vertexBufferPointers[0]);
drawInfos[0].convert_colors = 1;
Draw(vertexBufferPointers[0], drawInfos[0]);
std::vector<TextureInfo> texturesToSample = {intermediateTextures[currentScreen][0]};
PrepareDrawFromTextureInfo(currentFrame, currentFramebufferLayout, present_pipelines[current_pipeline], texturesToSample, 1);
ApplySecondLayerOpacity();
UpdateVertexBuffer(output_vertices, vertexBufferPointers[1]);
drawInfos[1].convert_colors = 2;
Draw(vertexBufferPointers[1], drawInfos[1]);
}
void RendererVulkan::UpdateVertexBuffer(std::array<ScreenRectVertex, 4> vertices, VertexBufferPointer vbp){
const u64 size = sizeof(ScreenRectVertex) * vertices.size();
std::memcpy(vbp.data, vertices.data(), size);
}
void RendererVulkan::Draw(VertexBufferPointer vbp, PresentUniformData pushconstant){
scheduler.Record([this, vbp, pushconstant](vk::CommandBuffer cmdbuf) {
const u32 first_vertex = static_cast<u32>(vbp.offset) / sizeof(ScreenRectVertex);
cmdbuf.pushConstants(*present_pipeline_layout,
vk::ShaderStageFlagBits::eFragment | vk::ShaderStageFlagBits::eVertex,
0, sizeof(info), &info);
0, sizeof(pushconstant), &pushconstant);
cmdbuf.bindVertexBuffers(0, vertex_buffer.Handle(), {0});
cmdbuf.draw(4, 1, first_vertex, 0);
cmdbuf.endRenderPass();
});
}
void RendererVulkan::ApplySecondLayerOpacity() {
float alpha;
if (applyingOpacity){
if (drawingPrimaryScreen){
alpha = 1.0;
} else {
if (usingTopOpacity){
if (currentFramebufferLayout.top_opacity < 1) {
alpha = currentFramebufferLayout.top_opacity;
} else {
return;
}
} else {
if (currentFramebufferLayout.bottom_opacity < 1) {
alpha = currentFramebufferLayout.bottom_opacity;
} else {
return;
}
}
}
scheduler.Record([alpha](vk::CommandBuffer cmdbuf) {
const std::array<float, 4> blend_constants = {0.0f, 0.0f, 0.0f, alpha};
cmdbuf.setBlendConstants(blend_constants.data());
});
}
}
void RendererVulkan::DrawSingleScreenStereo(u32 screen_id_l, u32 screen_id_r, float x, float y,
float w, float h,
Layout::DisplayOrientation orientation) {
const ScreenInfo& screen_info_l = screen_infos[screen_id_l];
const auto& texcoords = screen_info_l.texcoords;
const u32 scale_factor = GetResolutionScaleFactor();
float textureWidth = static_cast<float>(screen_info_l.texture.height * scale_factor);
float textureHeight = static_cast<float>(screen_info_l.texture.width * scale_factor);
std::array<ScreenRectVertex, 4> vertices;
switch (orientation) {
@ -1186,38 +1440,23 @@ void RendererVulkan::DrawSingleScreenStereo(u32 screen_id_l, u32 screen_id_r, fl
LOG_ERROR(Render_Vulkan, "Unknown DisplayOrientation: {}", orientation);
break;
}
const u64 size = sizeof(ScreenRectVertex) * vertices.size();
auto [data, offset, invalidate] = vertex_buffer.Map(size, 16);
std::memcpy(data, vertices.data(), size);
vertex_buffer.Commit(size);
int passes = 1;
std::vector<VertexBufferPointer> vertexBufferPointers(passes);
for (auto& vbp : vertexBufferPointers){
std::tie(vbp.data, vbp.offset, vbp.invalidate) = vertex_buffer.Map(size, 16);
vertex_buffer.Commit(size);
}
const u32 scale_factor = GetResolutionScaleFactor();
draw_info.i_resolution =
Common::MakeVec(static_cast<f32>(screen_info_l.texture.width * scale_factor),
static_cast<f32>(screen_info_l.texture.height * scale_factor),
1.0f / static_cast<f32>(screen_info_l.texture.width * scale_factor),
1.0f / static_cast<f32>(screen_info_l.texture.height * scale_factor));
draw_info.o_resolution = Common::MakeVec(h, w, 1.0f / h, 1.0f / w);
std::vector<u32> screenids = {screen_id_l, screen_id_r};
PrepareDrawFromScreenInfo(currentFrame, currentFramebufferLayout, present_pipelines[current_pipeline], screenids, 1);
ApplySecondLayerOpacity(); // Apply the initial default opacity value; Needed to avoid flickering
UpdateVertexBuffer(vertices, vertexBufferPointers[0]);
draw_info.i_resolution = Common::MakeVec(static_cast<f32>(textureWidth), static_cast<f32>(textureHeight), 1.0f / static_cast<f32>(textureWidth), 1.0f / static_cast<f32>(textureHeight));
draw_info.o_resolution = Common::MakeVec(w, h, 1.0f / w, 1.0f / h);
draw_info.screen_id_l = screen_id_l;
draw_info.screen_id_r = screen_id_r;
scheduler.Record([this, offset = offset, info = draw_info](vk::CommandBuffer cmdbuf) {
const u32 first_vertex = static_cast<u32>(offset) / sizeof(ScreenRectVertex);
cmdbuf.pushConstants(*present_pipeline_layout,
vk::ShaderStageFlagBits::eFragment | vk::ShaderStageFlagBits::eVertex,
0, sizeof(info), &info);
cmdbuf.bindVertexBuffers(0, vertex_buffer.Handle(), {0});
cmdbuf.draw(4, 1, first_vertex, 0);
});
}
void RendererVulkan::ApplySecondLayerOpacity(float alpha) {
scheduler.Record([alpha](vk::CommandBuffer cmdbuf) {
const std::array<float, 4> blend_constants = {0.0f, 0.0f, 0.0f, alpha};
cmdbuf.setBlendConstants(blend_constants.data());
});
Draw(vertexBufferPointers[0], draw_info);
}
void RendererVulkan::DrawTopScreen(const Layout::FramebufferLayout& layout,
@ -1246,6 +1485,7 @@ void RendererVulkan::DrawTopScreen(const Layout::FramebufferLayout& layout,
DrawSingleScreen(leftside, top_screen_left / 2, top_screen_top, top_screen_width / 2,
top_screen_height, orientation);
draw_info.layer = 1;
clearingColorAttachment = false;
DrawSingleScreen(rightside, static_cast<float>((top_screen_left / 2) + (layout.width / 2)),
top_screen_top, top_screen_width / 2, top_screen_height, orientation);
break;
@ -1254,6 +1494,7 @@ void RendererVulkan::DrawTopScreen(const Layout::FramebufferLayout& layout,
DrawSingleScreen(leftside, top_screen_left, top_screen_top, top_screen_width,
top_screen_height, orientation);
draw_info.layer = 1;
clearingColorAttachment = false;
DrawSingleScreen(rightside, top_screen_left + layout.width / 2, top_screen_top,
top_screen_width, top_screen_height, orientation);
break;
@ -1262,6 +1503,7 @@ void RendererVulkan::DrawTopScreen(const Layout::FramebufferLayout& layout,
DrawSingleScreen(leftside, top_screen_left, top_screen_top, top_screen_width,
top_screen_height, orientation);
draw_info.layer = 1;
clearingColorAttachment = false;
DrawSingleScreen(
rightside,
static_cast<float>(layout.cardboard.top_screen_right_eye + (layout.width / 2)),
@ -1347,33 +1589,49 @@ void RendererVulkan::DrawScreens(Frame* frame, const Layout::FramebufferLayout&
ReloadPipeline(layout.render_3d_mode);
}
PrepareDraw(frame, layout);
// Track Texture Changes
currTopTextureWidth = static_cast<float>(screen_infos[0].texture.height * GetResolutionScaleFactor());
currTopTextureHeight = static_cast<float>(screen_infos[0].texture.width * GetResolutionScaleFactor());
currBottomTextureWidth = static_cast<float>(screen_infos[2].texture.height * GetResolutionScaleFactor());
currBottomTextureHeight = static_cast<float>(screen_infos[2].texture.width * GetResolutionScaleFactor());
if (currTopTextureWidth != prevTopTextureWidth || currTopTextureHeight != prevTopTextureHeight || currBottomTextureWidth != prevBottomTextureWidth || currBottomTextureHeight != prevBottomTextureHeight){
AllocatePPTextures();
CreatePPTextureFramebuffers();
LOG_INFO(Render_Vulkan, "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;
currentFrame = frame;
currentFramebufferLayout = layout;
const auto& top_screen = layout.top_screen;
const auto& bottom_screen = layout.bottom_screen;
draw_info.modelview = MakeOrthographicMatrix(layout.width, layout.height);
draw_info.layer = 0;
// Apply the initial default opacity value; Needed to avoid flickering
ApplySecondLayerOpacity(1.0f);
clearingColorAttachment = true;
applyingOpacity = true;
if (!Settings::values.swap_screen.GetValue()) {
drawingPrimaryScreen = true;
DrawTopScreen(layout, top_screen);
draw_info.layer = 0;
if (layout.bottom_opacity < 1) {
ApplySecondLayerOpacity(layout.bottom_opacity);
}
drawingPrimaryScreen = false;
usingTopOpacity = false;
clearingColorAttachment = false;
DrawBottomScreen(layout, bottom_screen);
} else {
drawingPrimaryScreen = true;
DrawBottomScreen(layout, bottom_screen);
draw_info.layer = 0;
if (layout.top_opacity < 1) {
ApplySecondLayerOpacity(layout.top_opacity);
}
drawingPrimaryScreen = false;
usingTopOpacity = true;
clearingColorAttachment = false;
DrawTopScreen(layout, top_screen);
}
applyingOpacity = false;
if (layout.additional_screen_enabled) {
const auto& additional_screen = layout.additional_screen;
if (!Settings::values.swap_screen.GetValue()) {
@ -1383,9 +1641,8 @@ void RendererVulkan::DrawScreens(Frame* frame, const Layout::FramebufferLayout&
}
}
DrawCursor(layout);
scheduler.Record([](vk::CommandBuffer cmdbuf) { cmdbuf.endRenderPass(); });
// Needs to be fixed
// DrawCursor(layout);
}
void RendererVulkan::DrawCursor(const Layout::FramebufferLayout& layout) {

View file

@ -48,6 +48,21 @@ struct TextureInfo {
VmaAllocation allocation;
};
struct ScreenRectVertex {
ScreenRectVertex() = default;
ScreenRectVertex(float x, float y, float u, float v)
: position{Common::MakeVec(x, y)}, tex_coord{Common::MakeVec(u, v)} {}
Common::Vec2f position;
Common::Vec2f tex_coord;
};
struct VertexBufferPointer {
unsigned char* data;
unsigned int offset;
bool invalidate;
};
struct ScreenInfo {
TextureInfo texture;
Common::Rectangle<f32> texcoords;
@ -63,11 +78,8 @@ struct PresentUniformData {
int layer = 0;
int reverse_interlaced = 0;
int convert_colors;
int areatex;
int searchtex;
int smaa_input;
};
static_assert(sizeof(PresentUniformData) == 128,
static_assert(sizeof(PresentUniformData) == 116,
"PresentUniformData does not structure in shader!");
class RendererVulkan : public VideoCore::RendererBase {
@ -101,8 +113,18 @@ private:
void RenderScreenshot();
void RenderScreenshotWithStagingCopy();
bool TryRenderScreenshotWithHostMemory();
void PrepareDraw(Frame* frame, const Layout::FramebufferLayout& layout);
void PrepareTextureDraw(TextureInfo& textureInfo, vk::Pipeline& pipeline, int filterMode, std::vector<vk::ImageView> imageViews);
// Sets up command buffer for sampling from a screen_info to the screen framebuffer
void PrepareDrawFromScreenInfo(Frame* frame, const Layout::FramebufferLayout& layout, vk::Pipeline shaderPipeline, std::vector<u32> screenids, int filterMode);
// Sets up command buffer for sampling from a texture to the screen framebuffer
void PrepareDrawFromTextureInfo(Frame* frame, const Layout::FramebufferLayout& layout, vk::Pipeline shaderPipeline, std::vector<TextureInfo> texturesToSample, int filterMode);
// Sets up command buffer for sampling from a texture to an intermediate texture framebuffer
void PrepareTextureDraw(TextureInfo framebufferTexture, vk::Framebuffer framebuffer, vk::Pipeline shaderPipeline, std::vector<TextureInfo> texturesToSample, int filterMode);
// Sets up command buffer for sampling from a screen_info to an intermediate texture framebuffer
void PrepareTextureDrawFromScreenInfo(TextureInfo framebufferTexture, vk::Framebuffer framebuffer, vk::Pipeline shaderPipeline, std::vector<u32> screenids, int filterMode);
void UpdateVertexBuffer(std::array<ScreenRectVertex, 4> vertices, VertexBufferPointer vbp);
void Draw(VertexBufferPointer vbp, PresentUniformData pushconstant);
void RenderToWindow(PresentWindow& window, const Layout::FramebufferLayout& layout,
bool flipped);
@ -117,7 +139,7 @@ private:
void DrawSingleScreenStereo(u32 screen_id_l, u32 screen_id_r, float x, float y, float w,
float h, Layout::DisplayOrientation orientation);
void ApplySecondLayerOpacity(float alpha);
void ApplySecondLayerOpacity();
void DrawCursor(const Layout::FramebufferLayout& layout);
@ -135,7 +157,6 @@ private:
// Create Framebuffers that are attached to the Post Processing Textures
void CreatePPTextureFramebuffers();
void AllocateSMAATextures();
private:
Memory::MemorySystem& memory;
Pica::PicaCore& pica;
@ -193,12 +214,21 @@ private:
// Array of framebuffer objects. 0 is top screen, 1 is bottom screen.
std::array<std::array<vk::Framebuffer, 5>, 2> intermediateTextureFBOs;
std::array<vk::Framebuffer, 2 > antialiasTextureFBOs;
int currTopTextureWidth;
int currTopTextureHeight;
int currBottomTextureWidth;
int currBottomTextureHeight;
float currTopTextureWidth;
float currTopTextureHeight;
float currBottomTextureWidth;
float currBottomTextureHeight;
float prevTopTextureWidth;
float prevTopTextureHeight;
float prevBottomTextureWidth;
float prevBottomTextureHeight;
u32 current_pipeline = 0;
Frame* currentFrame;
Layout::FramebufferLayout currentFramebufferLayout;
bool clearingColorAttachment = true;
bool applyingOpacity = true;
bool drawingPrimaryScreen = false;
bool usingTopOpacity = false;
std::array<ScreenInfo, 3> screen_infos{};
PresentUniformData draw_info{};
vk::ClearColorValue clear_color{};

View file

@ -318,7 +318,6 @@ vk::UniqueInstance CreateInstance(const Common::DynamicLibrary& library,
.engineVersion = VK_MAKE_VERSION(1, 0, 0),
.apiVersion = TargetVulkanApiVersion,
};
boost::container::static_vector<const char*, 2> layers;
if (enable_validation) {
layers.push_back("VK_LAYER_KHRONOS_validation");

View file

@ -104,7 +104,7 @@ PresentWindow::PresentWindow(Frontend::EmuWindow& emu_window_, const Instance& i
surface{CreateSurface(instance.GetInstance(), emu_window)}, next_surface{surface},
swapchain{instance, emu_window.GetFramebufferLayout().width,
emu_window.GetFramebufferLayout().height, surface, low_refresh_rate_},
graphics_queue{instance.GetGraphicsQueue()}, present_renderpass{CreateRenderpass()},
graphics_queue{instance.GetGraphicsQueue()}, present_renderpass{CreateRenderpass()}, present_load_renderpass{CreateLoadRenderpass()},
vsync_enabled{Settings::values.use_vsync.GetValue()},
blit_supported{
CanBlitToSwapchain(instance.GetPhysicalDevice(), swapchain.GetSurfaceFormat().format)},
@ -157,6 +157,7 @@ PresentWindow::~PresentWindow() {
const vk::Device device = instance.GetDevice();
device.destroyCommandPool(command_pool);
device.destroyRenderPass(present_renderpass);
device.destroyRenderPass(present_load_renderpass);
for (auto& frame : swap_chain) {
device.destroyImageView(frame.image_view);
device.destroyFramebuffer(frame.framebuffer);
@ -512,16 +513,72 @@ vk::RenderPass PresentWindow::CreateRenderpass() {
.finalLayout = vk::ImageLayout::eTransferSrcOptimal,
};
const vk::SubpassDependency dependency = {
.srcSubpass = VK_SUBPASS_EXTERNAL,
.dstSubpass = 0,
.srcStageMask = vk::PipelineStageFlagBits::eColorAttachmentOutput,
.dstStageMask = vk::PipelineStageFlagBits::eFragmentShader,
.srcAccessMask = vk::AccessFlagBits::eColorAttachmentWrite,
.dstAccessMask = vk::AccessFlagBits::eShaderRead,
};
const vk::RenderPassCreateInfo renderpass_info = {
.attachmentCount = 1,
.pAttachments = &color_attachment,
.subpassCount = 1,
.pSubpasses = &subpass,
.dependencyCount = 0,
.pDependencies = nullptr,
.dependencyCount = 1,
.pDependencies = &dependency,
};
return instance.GetDevice().createRenderPass(renderpass_info);
}
vk::RenderPass PresentWindow::CreateLoadRenderpass() {
const vk::AttachmentReference color_ref = {
.attachment = 0,
.layout = vk::ImageLayout::eGeneral,
};
const vk::SubpassDescription subpass = {
.pipelineBindPoint = vk::PipelineBindPoint::eGraphics,
.inputAttachmentCount = 0,
.pInputAttachments = nullptr,
.colorAttachmentCount = 1u,
.pColorAttachments = &color_ref,
.pResolveAttachments = 0,
.pDepthStencilAttachment = nullptr,
};
const vk::AttachmentDescription color_attachment = {
.format = swapchain.GetSurfaceFormat().format,
.samples = vk::SampleCountFlagBits::e1,
.loadOp = vk::AttachmentLoadOp::eLoad,
.storeOp = vk::AttachmentStoreOp::eStore,
.stencilLoadOp = vk::AttachmentLoadOp::eDontCare,
.stencilStoreOp = vk::AttachmentStoreOp::eDontCare,
.initialLayout = vk::ImageLayout::eTransferSrcOptimal,
.finalLayout = vk::ImageLayout::eTransferSrcOptimal,
};
const vk::SubpassDependency dependency = {
.srcSubpass = VK_SUBPASS_EXTERNAL,
.dstSubpass = 0,
.srcStageMask = vk::PipelineStageFlagBits::eColorAttachmentOutput,
.dstStageMask = vk::PipelineStageFlagBits::eFragmentShader,
.srcAccessMask = vk::AccessFlagBits::eColorAttachmentWrite,
.dstAccessMask = vk::AccessFlagBits::eShaderRead,
};
const vk::RenderPassCreateInfo renderpass_info = {
.attachmentCount = 1,
.pAttachments = &color_attachment,
.subpassCount = 1,
.pSubpasses = &subpass,
.dependencyCount = 1,
.pDependencies = &dependency,
};
return instance.GetDevice().createRenderPass(renderpass_info);
}
} // namespace Vulkan

View file

@ -58,6 +58,10 @@ public:
[[nodiscard]] vk::RenderPass Renderpass() const noexcept {
return present_renderpass;
}
// Returns Renderpass that doesn't clear the image
[[nodiscard]] vk::RenderPass LoadRenderpass() const noexcept {
return present_load_renderpass;
}
u32 ImageCount() const noexcept {
return swapchain.GetImageCount();
@ -69,7 +73,7 @@ private:
void CopyToSwapchain(Frame* frame);
vk::RenderPass CreateRenderpass();
vk::RenderPass CreateLoadRenderpass();
private:
Frontend::EmuWindow& emu_window;
const Instance& instance;
@ -81,6 +85,7 @@ private:
vk::CommandPool command_pool;
vk::Queue graphics_queue;
vk::RenderPass present_renderpass;
vk::RenderPass present_load_renderpass;
std::vector<Frame> swap_chain;
std::queue<Frame*> free_queue;
std::queue<Frame*> present_queue;