This commit is contained in:
KojoZero 2026-05-27 19:37:40 +01:00 committed by GitHub
commit b3f5cb04c2
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
54 changed files with 20468 additions and 108 deletions

View file

@ -47,6 +47,7 @@ foreach(KEY IN ITEMS
"frame_limit"
"turbo_limit"
"texture_filter"
"antialiasing_filter"
"texture_sampling"
"delay_game_render_thread_us"
"simulate_3ds_gpu_timings"

View file

@ -725,6 +725,7 @@ void QtConfig::ReadRendererValues() {
ReadGlobalSetting(Settings::values.bg_blue);
ReadGlobalSetting(Settings::values.texture_filter);
ReadGlobalSetting(Settings::values.antialiasing_filter);
ReadGlobalSetting(Settings::values.texture_sampling);
ReadGlobalSetting(Settings::values.delay_game_render_thread_us);
@ -1274,6 +1275,7 @@ void QtConfig::SaveRendererValues() {
WriteGlobalSetting(Settings::values.bg_blue);
WriteGlobalSetting(Settings::values.texture_filter);
WriteGlobalSetting(Settings::values.antialiasing_filter);
WriteGlobalSetting(Settings::values.texture_sampling);
WriteGlobalSetting(Settings::values.delay_game_render_thread_us);

View file

@ -48,11 +48,17 @@ void ConfigureEnhancements::SetConfiguration() {
&Settings::values.texture_filter);
ConfigurationShared::SetHighlight(ui->widget_texture_filter,
!Settings::values.texture_filter.UsingGlobal());
ConfigurationShared::SetPerGameSetting(ui->antialiasing_filter_combobox,
&Settings::values.antialiasing_filter);
ConfigurationShared::SetHighlight(ui->widget_antialiasing_filter,
!Settings::values.antialiasing_filter.UsingGlobal());
} else {
ui->resolution_factor_combobox->setCurrentIndex(
Settings::values.resolution_factor.GetValue());
ui->texture_filter_combobox->setCurrentIndex(
static_cast<int>(Settings::values.texture_filter.GetValue()));
ui->antialiasing_filter_combobox->setCurrentIndex(
static_cast<int>(Settings::values.antialiasing_filter.GetValue()));
}
ui->render_3d_combobox->setCurrentIndex(
@ -132,6 +138,8 @@ void ConfigureEnhancements::ApplyConfiguration() {
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.dump_textures,
ui->toggle_dump_textures, dump_textures);
ConfigurationShared::ApplyPerGameSetting(&Settings::values.custom_textures,
@ -150,6 +158,7 @@ void ConfigureEnhancements::SetupPerGameUI() {
if (Settings::IsConfiguringGlobal()) {
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->use_integer_scaling->setEnabled(Settings::values.use_integer_scaling.UsingGlobal());
ui->toggle_dump_textures->setEnabled(Settings::values.dump_textures.UsingGlobal());
@ -192,4 +201,8 @@ void ConfigureEnhancements::SetupPerGameUI() {
ConfigurationShared::SetColoredComboBox(
ui->texture_filter_combobox, ui->widget_texture_filter,
static_cast<int>(Settings::values.texture_filter.GetValue(true)));
ConfigurationShared::SetColoredComboBox(
ui->antialiasing_filter_combobox, ui->widget_antialiasing_filter,
static_cast<int>(Settings::values.antialiasing_filter.GetValue(true)));
}

View file

@ -112,12 +112,12 @@
</item>
<item>
<widget class="QCheckBox" name="use_integer_scaling">
<property name="text">
<string>Use Integer Scaling</string>
</property>
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Use Integer Scaling&lt;/p&gt;&lt;p&gt;Enforces that the larger screen in all layouts is an integer scale of the 240px height of the original 3DS screen.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Use Integer Scaling</string>
</property>
</widget>
</item>
<item>
@ -127,6 +127,50 @@
</property>
</widget>
</item>
<item>
<widget class="QWidget" name="widget_antialiasing_filter" native="true">
<layout class="QHBoxLayout" name="horizontalLayout_10">
<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="antialiasing_filter_label">
<property name="text">
<string>Anti-Aliasing</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="antialiasing_filter_combobox">
<item>
<property name="text">
<string>None</string>
</property>
</item>
<item>
<property name="text">
<string>FXAA</string>
</property>
</item>
<item>
<property name="text">
<string>SMAA</string>
</property>
</item>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QWidget" name="widget_shader" native="true">
<layout class="QHBoxLayout" name="horizontalLayout_2">
@ -329,12 +373,12 @@
</item>
<item>
<widget class="QCheckBox" name="disable_right_eye_render">
<property name="text">
<string>Disable Right Eye Rendering</string>
</property>
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Disable Right Eye Rendering&lt;/p&gt;&lt;p&gt;Disables rendering the right eye image when not using stereoscopic mode. Greatly improves performance in some applications, but can cause flickering in others.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Disable Right Eye Rendering</string>
</property>
</widget>
</item>
<item>
@ -399,7 +443,7 @@
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
<enum>Qt::Orientation::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
@ -416,6 +460,7 @@
<tabstop>toggle_linear_filter</tabstop>
<tabstop>shader_combobox</tabstop>
<tabstop>texture_filter_combobox</tabstop>
<tabstop>antialiasing_filter_combobox</tabstop>
<tabstop>render_3d_combobox</tabstop>
<tabstop>factor_3d</tabstop>
<tabstop>mono_rendering_eye</tabstop>

View file

@ -57,6 +57,18 @@ std::string_view GetTextureFilterName(TextureFilter filter) {
}
}
std::string_view GetAntialiasingFilterName(AntiAliasingFilter filter) {
switch (filter) {
case AntiAliasingFilter::None:
return "None";
case AntiAliasingFilter::FXAA:
return "FXAA";
case AntiAliasingFilter::SMAA:
return "SMAA";
default:
return "Invalid";
}
}
std::string_view GetTextureSamplingName(TextureSampling sampling) {
switch (sampling) {
case TextureSampling::GameControlled:
@ -103,6 +115,7 @@ void LogSettings() {
log_setting("Renderer_PostProcessingShader", values.pp_shader_name.GetValue());
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_TextureSampling",
GetTextureSamplingName(values.texture_sampling.GetValue()));
log_setting("Renderer_DelayGameRenderThreasUs", values.delay_game_render_thread_us.GetValue());
@ -216,6 +229,7 @@ void RestoreGlobalState(bool is_powered_on) {
values.use_integer_scaling.SetGlobal(true);
values.frame_limit.SetGlobal(true);
values.texture_filter.SetGlobal(true);
values.antialiasing_filter.SetGlobal(true);
values.texture_sampling.SetGlobal(true);
values.delay_game_render_thread_us.SetGlobal(true);
values.simulate_3ds_gpu_timings.SetGlobal(true);

View file

@ -112,6 +112,12 @@ enum class TextureFilter : u32 {
MMPX = 5,
};
enum class AntiAliasingFilter : u32 {
None = 0,
FXAA = 1,
SMAA = 2,
};
enum class TextureSampling : u32 {
GameControlled = 0,
NearestNeighbor = 1,
@ -539,6 +545,7 @@ struct Values {
SwitchableSetting<double, true> frame_limit{100, 0, 1000, Keys::frame_limit};
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<TextureSampling> texture_sampling{TextureSampling::GameControlled,
Keys::texture_sampling};
SwitchableSetting<u16, true> delay_game_render_thread_us{0, 0, 65000,

View file

@ -13,17 +13,55 @@ set(SHADER_FILES
texture_filtering/mmpx.frag
texture_filtering/x_gradient.frag
texture_filtering/y_gradient.frag
antialiasing/OpenGL/opengl_fxaa.frag
antialiasing/OpenGL/opengl_fxaa.vert
antialiasing/OpenGL/opengl_smaa_pass0_pre.frag
antialiasing/OpenGL/opengl_smaa_pass0_pre.vert
antialiasing/OpenGL/opengl_smaa_pass0_post.frag
antialiasing/OpenGL/opengl_smaa_pass0_post.vert
antialiasing/OpenGL/opengl_smaa_pass1_pre.frag
antialiasing/OpenGL/opengl_smaa_pass1_pre.vert
antialiasing/OpenGL/opengl_smaa_pass1_post.frag
antialiasing/OpenGL/opengl_smaa_pass1_post.vert
antialiasing/OpenGL/opengl_smaa_pass2_pre.frag
antialiasing/OpenGL/opengl_smaa_pass2_pre.vert
antialiasing/OpenGL/opengl_smaa_pass2_post.frag
antialiasing/OpenGL/opengl_smaa_pass2_post.vert
antialiasing/OpenGL/opengl_smaa.hlsl
antialiasing/Vulkan/vulkan_fxaa.frag
antialiasing/Vulkan/vulkan_fxaa.vert
antialiasing/Vulkan/vulkan_smaa_pass0_pre.frag
antialiasing/Vulkan/vulkan_smaa_pass0_pre.vert
antialiasing/Vulkan/vulkan_smaa_pass0_post.frag
antialiasing/Vulkan/vulkan_smaa_pass0_post.vert
antialiasing/Vulkan/vulkan_smaa_pass1_pre.frag
antialiasing/Vulkan/vulkan_smaa_pass1_pre.vert
antialiasing/Vulkan/vulkan_smaa_pass1_post.frag
antialiasing/Vulkan/vulkan_smaa_pass1_post.vert
antialiasing/Vulkan/vulkan_smaa_pass2_pre.frag
antialiasing/Vulkan/vulkan_smaa_pass2_pre.vert
antialiasing/Vulkan/vulkan_smaa_pass2_post.frag
antialiasing/Vulkan/vulkan_smaa_pass2_post.vert
antialiasing/Vulkan/vulkan_smaa.hlsl
scaling/opengl_area_sampling.frag
scaling/opengl_area_sampling.vert
scaling/vulkan_area_sampling.frag
scaling/vulkan_area_sampling.vert
full_screen_triangle.vert
opengl_present.frag
opengl_present.vert
opengl_present_anaglyph.frag
opengl_present_interlaced.frag
opengl_simple_present.frag
opengl_simple_present.vert
vulkan_depth_to_buffer.comp
vulkan_present.frag
vulkan_present.vert
vulkan_present_anaglyph.frag
vulkan_present_interlaced.frag
vulkan_blit_depth_stencil.frag
vulkan_simple_present.frag
vulkan_simple_present.vert
vulkan_cursor.frag
vulkan_cursor.vert
)

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,256 @@
/**
* @license
* Copyright (c) 2011 NVIDIA Corporation. All rights reserved.
*
* TO THE MAXIMUM EXTENT PERMITTED BY APPLICABLE LAW, THIS SOFTWARE IS PROVIDED
* *AS IS* AND NVIDIA AND ITS SUPPLIERS DISCLAIM ALL WARRANTIES, EITHER EXPRESS
* OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, NONINFRINGEMENT,IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL NVIDIA
* OR ITS SUPPLIERS BE LIABLE FOR ANY DIRECT, SPECIAL, INCIDENTAL, INDIRECT, OR
* CONSEQUENTIAL DAMAGES WHATSOEVER (INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOSS
* OF BUSINESS PROFITS, BUSINESS INTERRUPTION, LOSS OF BUSINESS INFORMATION, OR ANY
* OTHER PECUNIARY LOSS) ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE,
* EVEN IF NVIDIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
*/
/*
FXAA_PRESET - Choose compile-in knob preset 0-5.
------------------------------------------------------------------------------
FXAA_EDGE_THRESHOLD - The minimum amount of local contrast required
to apply algorithm.
1.0/3.0 - too little
1.0/4.0 - good start
1.0/8.0 - applies to more edges
1.0/16.0 - overkill
------------------------------------------------------------------------------
FXAA_EDGE_THRESHOLD_MIN - Trims the algorithm from processing darks.
Perf optimization.
1.0/32.0 - visible limit (smaller isn't visible)
1.0/16.0 - good compromise
1.0/12.0 - upper limit (seeing artifacts)
------------------------------------------------------------------------------
FXAA_SEARCH_STEPS - Maximum number of search steps for end of span.
------------------------------------------------------------------------------
FXAA_SEARCH_THRESHOLD - Controls when to stop searching.
1.0/4.0 - seems to be the best quality wise
------------------------------------------------------------------------------
FXAA_SUBPIX_TRIM - Controls sub-pixel aliasing removal.
1.0/2.0 - low removal
1.0/3.0 - medium removal
1.0/4.0 - default removal
1.0/8.0 - high removal
0.0 - complete removal
------------------------------------------------------------------------------
FXAA_SUBPIX_CAP - Insures fine detail is not completely removed.
This is important for the transition of sub-pixel detail,
like fences and wires.
3.0/4.0 - default (medium amount of filtering)
7.0/8.0 - high amount of filtering
1.0 - no capping of sub-pixel aliasing removal
*/
//? #version 450
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 int convert_colors;
#ifndef FXAA_PRESET
#define FXAA_PRESET 5
#endif
#if (FXAA_PRESET == 3)
#define FXAA_EDGE_THRESHOLD (1.0/8.0)
#define FXAA_EDGE_THRESHOLD_MIN (1.0/16.0)
#define FXAA_SEARCH_STEPS 16
#define FXAA_SEARCH_THRESHOLD (1.0/4.0)
#define FXAA_SUBPIX_CAP (3.0/4.0)
#define FXAA_SUBPIX_TRIM (1.0/4.0)
#endif
#if (FXAA_PRESET == 4)
#define FXAA_EDGE_THRESHOLD (1.0/8.0)
#define FXAA_EDGE_THRESHOLD_MIN (1.0/24.0)
#define FXAA_SEARCH_STEPS 24
#define FXAA_SEARCH_THRESHOLD (1.0/4.0)
#define FXAA_SUBPIX_CAP (3.0/4.0)
#define FXAA_SUBPIX_TRIM (1.0/4.0)
#endif
#if (FXAA_PRESET == 5)
#define FXAA_EDGE_THRESHOLD (1.0/8.0)
#define FXAA_EDGE_THRESHOLD_MIN (1.0/24.0)
#define FXAA_SEARCH_STEPS 32
#define FXAA_SEARCH_THRESHOLD (1.0/4.0)
#define FXAA_SUBPIX_CAP (3.0/4.0)
#define FXAA_SUBPIX_TRIM (1.0/4.0)
#endif
#define FXAA_SUBPIX_TRIM_SCALE (1.0/(1.0 - FXAA_SUBPIX_TRIM))
// Return the luma, the estimation of luminance from rgb inputs.
// This approximates luma using one FMA instruction,
// skipping normalization and tossing out blue.
// FxaaLuma() will range 0.0 to 2.963210702.
float FxaaLuma(vec3 rgb) {
return rgb.y * (0.587/0.299) + rgb.x;
}
vec3 FxaaLerp3(vec3 a, vec3 b, float amountOfA) {
return (vec3(-amountOfA) * b) + ((a * vec3(amountOfA)) + b);
}
vec4 FxaaTexOff(sampler2D tex, vec2 pos, ivec2 off, vec2 rcpFrame) {
float x = pos.x + float(off.x) * rcpFrame.x;
float y = pos.y + float(off.y) * rcpFrame.y;
return texture(tex, vec2(x, y));
}
// pos is the output of FxaaVertexShader interpolated across screen.
// xy -> actual texture position {0.0 to 1.0}
// rcpFrame should be a uniform equal to {1.0/frameWidth, 1.0/frameHeight}
vec3 FxaaPixelShader(vec2 pos, sampler2D tex, vec2 rcpFrame)
{
vec3 rgbN = FxaaTexOff(tex, pos.xy, ivec2( 0,-1), rcpFrame).xyz;
vec3 rgbW = FxaaTexOff(tex, pos.xy, ivec2(-1, 0), rcpFrame).xyz;
vec3 rgbM = FxaaTexOff(tex, pos.xy, ivec2( 0, 0), rcpFrame).xyz;
vec3 rgbE = FxaaTexOff(tex, pos.xy, ivec2( 1, 0), rcpFrame).xyz;
vec3 rgbS = FxaaTexOff(tex, pos.xy, ivec2( 0, 1), rcpFrame).xyz;
float lumaN = FxaaLuma(rgbN);
float lumaW = FxaaLuma(rgbW);
float lumaM = FxaaLuma(rgbM);
float lumaE = FxaaLuma(rgbE);
float lumaS = FxaaLuma(rgbS);
float rangeMin = min(lumaM, min(min(lumaN, lumaW), min(lumaS, lumaE)));
float rangeMax = max(lumaM, max(max(lumaN, lumaW), max(lumaS, lumaE)));
float range = rangeMax - rangeMin;
if(range < max(FXAA_EDGE_THRESHOLD_MIN, rangeMax * FXAA_EDGE_THRESHOLD))
{
return rgbM;
}
vec3 rgbL = rgbN + rgbW + rgbM + rgbE + rgbS;
float lumaL = (lumaN + lumaW + lumaE + lumaS) * 0.25;
float rangeL = abs(lumaL - lumaM);
float blendL = max(0.0, (rangeL / range) - FXAA_SUBPIX_TRIM) * FXAA_SUBPIX_TRIM_SCALE;
blendL = min(FXAA_SUBPIX_CAP, blendL);
vec3 rgbNW = FxaaTexOff(tex, pos.xy, ivec2(-1,-1), rcpFrame).xyz;
vec3 rgbNE = FxaaTexOff(tex, pos.xy, ivec2( 1,-1), rcpFrame).xyz;
vec3 rgbSW = FxaaTexOff(tex, pos.xy, ivec2(-1, 1), rcpFrame).xyz;
vec3 rgbSE = FxaaTexOff(tex, pos.xy, ivec2( 1, 1), rcpFrame).xyz;
rgbL += (rgbNW + rgbNE + rgbSW + rgbSE);
rgbL *= vec3(1.0/9.0);
float lumaNW = FxaaLuma(rgbNW);
float lumaNE = FxaaLuma(rgbNE);
float lumaSW = FxaaLuma(rgbSW);
float lumaSE = FxaaLuma(rgbSE);
float edgeVert =
abs((0.25 * lumaNW) + (-0.5 * lumaN) + (0.25 * lumaNE)) +
abs((0.50 * lumaW ) + (-1.0 * lumaM) + (0.50 * lumaE )) +
abs((0.25 * lumaSW) + (-0.5 * lumaS) + (0.25 * lumaSE));
float edgeHorz =
abs((0.25 * lumaNW) + (-0.5 * lumaW) + (0.25 * lumaSW)) +
abs((0.50 * lumaN ) + (-1.0 * lumaM) + (0.50 * lumaS )) +
abs((0.25 * lumaNE) + (-0.5 * lumaE) + (0.25 * lumaSE));
bool horzSpan = edgeHorz >= edgeVert;
float lengthSign = horzSpan ? -rcpFrame.y : -rcpFrame.x;
if(!horzSpan)
{
lumaN = lumaW;
lumaS = lumaE;
}
float gradientN = abs(lumaN - lumaM);
float gradientS = abs(lumaS - lumaM);
lumaN = (lumaN + lumaM) * 0.5;
lumaS = (lumaS + lumaM) * 0.5;
if (gradientN < gradientS)
{
lumaN = lumaS;
lumaN = lumaS;
gradientN = gradientS;
lengthSign *= -1.0;
}
vec2 posN;
posN.x = pos.x + (horzSpan ? 0.0 : lengthSign * 0.5);
posN.y = pos.y + (horzSpan ? lengthSign * 0.5 : 0.0);
gradientN *= FXAA_SEARCH_THRESHOLD;
vec2 posP = posN;
vec2 offNP = horzSpan ? vec2(rcpFrame.x, 0.0) : vec2(0.0, rcpFrame.y);
float lumaEndN = lumaN;
float lumaEndP = lumaN;
bool doneN = false;
bool doneP = false;
posN += offNP * vec2(-1.0, -1.0);
posP += offNP * vec2( 1.0, 1.0);
for(int i = 0; i < FXAA_SEARCH_STEPS; i++) {
if(!doneN)
{
lumaEndN = FxaaLuma(texture(tex, posN.xy).xyz);
}
if(!doneP)
{
lumaEndP = FxaaLuma(texture(tex, posP.xy).xyz);
}
doneN = doneN || (abs(lumaEndN - lumaN) >= gradientN);
doneP = doneP || (abs(lumaEndP - lumaN) >= gradientN);
if(doneN && doneP)
{
break;
}
if(!doneN)
{
posN -= offNP;
}
if(!doneP)
{
posP += offNP;
}
}
float dstN = horzSpan ? pos.x - posN.x : pos.y - posN.y;
float dstP = horzSpan ? posP.x - pos.x : posP.y - pos.y;
bool directionN = dstN < dstP;
lumaEndN = directionN ? lumaEndN : lumaEndP;
if(((lumaM - lumaN) < 0.0) == ((lumaEndN - lumaN) < 0.0))
{
lengthSign = 0.0;
}
float spanLength = (dstP + dstN);
dstN = directionN ? dstN : dstP;
float subPixelOffset = (0.5 + (dstN * (-1.0/spanLength))) * lengthSign;
vec3 rgbF = texture(tex, vec2(
pos.x + (horzSpan ? 0.0 : subPixelOffset),
pos.y + (horzSpan ? subPixelOffset : 0.0))).xyz;
return FxaaLerp3(rgbL, rgbF, blendL);
}
vec3 sRGBToLinear(vec3 c) {
return mix(c / 12.92, pow((c + 0.055) / 1.055, vec3(2.4)), step(0.04045, c));
}
void main()
{
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);
}
color = pixel;
}

View file

@ -0,0 +1,13 @@
//? #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;
uniform vec4 i_resolution;
void main()
{
gl_Position = vec4(vert_position, 0.0, 1.0);
frag_tex_coord = vert_tex_coord;
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,7 @@
void main() {
if (SMAA_EDT == 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, color_texture), 0.0, 0.0);
}
}

View file

@ -0,0 +1,5 @@
void main() {
gl_Position = vec4(vert_position, 0.0, 1.0);
frag_tex_coord = vert_tex_coord;
SMAAEdgeDetectionVS(vert_tex_coord, offset);
}

View file

@ -0,0 +1,25 @@
//? #version 450
// SPDX-License-Identifier: Unlicense
//-----------------------------------------------------------------------------
// Edge Detection Shaders (First Pass)
uniform vec4 i_resolution;
#define SMAA_RT_METRICS vec4(i_resolution.z, i_resolution.w, i_resolution.x, i_resolution.y)
#define SMAA_GLSL_4
#define SMAA_FLIP_Y 1
#define SMAA_FLIP_Y 1
#define SMAA_FLIP_Y 1
#define SMAA_FLIP_Y 1
#define SMAA_FLIP_Y 1
#define SMAA_FLIP_Y 1
#define SMAA_FLIP_Y 1
#define SMAA_PRESET_ULTRA
#define SMAA_EDT 1.0
layout(location = 0) in vec2 frag_tex_coord;
layout(location = 1) in vec4 offset[3];
layout(location = 0) out vec4 color;
layout(binding = 0) uniform sampler2D color_texture;
#define SMAA_INCLUDE_VS 0
//#include "SMAA.hlsl"

View file

@ -0,0 +1,19 @@
//? #version 450
// SPDX-License-Identifier: Unlicense
//-----------------------------------------------------------------------------
// Edge Detection Shaders (First Pass)
uniform vec4 i_resolution;
#define SMAA_RT_METRICS vec4(i_resolution.z, i_resolution.w, i_resolution.x, i_resolution.y)
#define SMAA_GLSL_4
#define SMAA_FLIP_Y 1
#define SMAA_PRESET_ULTRA
#define SMAA_EDT 1.0
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 vec4 offset[3];
#define SMAA_INCLUDE_PS 0
//#include "SMAA.hlsl"

View file

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

View file

@ -0,0 +1,5 @@
void main() {
gl_Position = vec4(vert_position, 0.0, 1.0);
frag_tex_coord = vert_tex_coord;
SMAABlendingWeightCalculationVS(vert_tex_coord, pixcoord, offset);
}

View file

@ -0,0 +1,22 @@
//? #version 450
// SPDX-License-Identifier: Unlicense
//-----------------------------------------------------------------------------
// Blending Weight Calculation Shader (Second Pass)
uniform vec4 i_resolution;
#define SMAA_RT_METRICS vec4(i_resolution.z, i_resolution.w, i_resolution.x, i_resolution.y)
#define SMAA_GLSL_4
#define SMAA_FLIP_Y 1
#define SMAA_PRESET_ULTRA
#define SMAA_EDT 1.0
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(binding = 0) uniform sampler2D color_texture;
uniform sampler2D areaTex;
uniform sampler2D searchTex;
#define SMAA_INCLUDE_VS 0
//#include "SMAA.hlsl"

View file

@ -0,0 +1,20 @@
//? #version 450
// SPDX-License-Identifier: Unlicense
//-----------------------------------------------------------------------------
// Blending Weight Calculation Shader (Second Pass)
uniform vec4 i_resolution;
#define SMAA_RT_METRICS vec4(i_resolution.z, i_resolution.w, i_resolution.x, i_resolution.y)
#define SMAA_GLSL_4
#define SMAA_FLIP_Y 1
#define SMAA_PRESET_ULTRA
#define SMAA_EDT 1.0
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 pixcoord;
layout(location = 2) out vec4 offset[3];
#define SMAA_INCLUDE_PS 0
//#include "SMAA.hlsl"

View file

@ -0,0 +1,11 @@
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() {
vec4 pixel = SMAANeighborhoodBlendingPS(frag_tex_coord, offset, SMAA_Input, color_texture);
if (convert_colors == 2){
pixel = vec4(LinearTosRGB(pixel.rgb), pixel.a);
}
color = pixel;
}

View file

@ -0,0 +1,5 @@
void main() {
gl_Position = vec4(vert_position, 0.0, 1.0);
frag_tex_coord = vert_tex_coord;
SMAANeighborhoodBlendingVS(vert_tex_coord, offset);
}

View file

@ -0,0 +1,19 @@
//? #version 450
// SPDX-License-Identifier: Unlicense
//-----------------------------------------------------------------------------
// Neighborhood Blending Shader (Third Pass)
uniform vec4 i_resolution;
uniform int convert_colors;
#define SMAA_RT_METRICS vec4(i_resolution.z, i_resolution.w, i_resolution.x, i_resolution.y)
#define SMAA_GLSL_4
#define SMAA_FLIP_Y 1
layout(location = 0) in vec2 frag_tex_coord;
layout(location = 1) in vec4 offset;
layout(location = 0) out vec4 color;
layout(binding = 0) uniform sampler2D color_texture;
uniform sampler2D SMAA_Input;
#define SMAA_INCLUDE_VS 0
//#include "SMAA.hlsl"

View file

@ -0,0 +1,17 @@
//? #version 450
// SPDX-License-Identifier: Unlicense
//-----------------------------------------------------------------------------
// Neighborhood Blending Shader (Third Pass)
uniform vec4 i_resolution;
#define SMAA_RT_METRICS vec4(i_resolution.z, i_resolution.w, i_resolution.x, i_resolution.y)
#define SMAA_GLSL_4
#define SMAA_FLIP_Y 1
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 vec4 offset;
#define SMAA_INCLUDE_PS 0
//#include "SMAA.hlsl"

View file

@ -0,0 +1,132 @@
/**
* Copyright (C) 2013 Jorge Jimenez (jorge@iryoku.com)
* Copyright (C) 2013 Jose I. Echevarria (joseignacioechevarria@gmail.com)
* Copyright (C) 2013 Belen Masia (bmasia@unizar.es)
* Copyright (C) 2013 Fernando Navarro (fernandn@microsoft.com)
* Copyright (C) 2013 Diego Gutierrez (diegog@unizar.es)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
* of the Software, and to permit persons to whom the Software is furnished to
* do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software. As clarification, there
* is no requirement that the copyright notice and permission be included in
* binary distributions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#ifndef SEARCHTEX_H
#define SEARCHTEX_H
#define SEARCHTEX_WIDTH 64
#define SEARCHTEX_HEIGHT 16
#define SEARCHTEX_PITCH SEARCHTEX_WIDTH
#define SEARCHTEX_SIZE (SEARCHTEX_HEIGHT * SEARCHTEX_PITCH)
/**
* Stored in R8 format. Load it in the following format:
* - DX9: D3DFMT_L8
* - DX10: DXGI_FORMAT_R8_UNORM
*/
static const unsigned char searchTexBytes[] = {
0xfe, 0xfe, 0x00, 0x7f, 0x7f, 0x00, 0x00, 0xfe, 0xfe, 0x00, 0x7f, 0x7f,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x7f, 0x00,
0x7f, 0x7f, 0x00, 0x00, 0x7f, 0x7f, 0x00, 0x7f, 0x7f, 0xfe, 0x7f, 0x00,
0x00, 0x00, 0x00, 0x00, 0x7f, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0xfe, 0xfe, 0x00, 0x7f, 0x7f, 0x00, 0x00, 0xfe,
0xfe, 0x00, 0x7f, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x7f, 0x7f, 0x00, 0x7f, 0x7f, 0x00, 0x00, 0x7f, 0x7f, 0x00, 0x7f,
0x7f, 0xfe, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x7f, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xfe, 0xfe, 0x00, 0x7f, 0x7f, 0x00, 0x00, 0xfe, 0xfe, 0x00, 0x7f, 0x7f,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x7f, 0x00,
0x7f, 0x7f, 0x00, 0x00, 0x7f, 0x7f, 0x00, 0x7f, 0x7f, 0xfe, 0x7f, 0x00,
0x00, 0x00, 0x00, 0x00, 0x7f, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0xfe, 0xfe, 0x00, 0x7f, 0x7f, 0x00, 0x00, 0xfe,
0xfe, 0x00, 0x7f, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x7f, 0x7f, 0x00, 0x7f, 0x7f, 0x00, 0x00, 0x7f, 0x7f, 0x00, 0x7f,
0x7f, 0xfe, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x7f, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x7f, 0x7f, 0x00, 0x7f, 0x7f, 0x00, 0x00, 0x7f,
0x7f, 0x00, 0x7f, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x7f, 0x7f, 0x00, 0x7f, 0x7f, 0x00, 0x00, 0x7f, 0x7f, 0x00, 0x7f,
0x7f, 0x7f, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x7f, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x7f, 0x00, 0x7f,
0x7f, 0x00, 0x00, 0x7f, 0x7f, 0x00, 0x7f, 0x7f, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x7f, 0x00, 0x7f, 0x7f, 0x00, 0x00,
0x7f, 0x7f, 0x00, 0x7f, 0x7f, 0x7f, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00,
0x7f, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x7f, 0x7f, 0x00, 0x7f, 0x7f, 0x00, 0x00, 0x7f,
0x7f, 0x00, 0x7f, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x7f, 0x7f, 0x00, 0x7f, 0x7f, 0x00, 0x00, 0x7f, 0x7f, 0x00, 0x7f,
0x7f, 0x7f, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x7f, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x7f, 0x00, 0x7f,
0x7f, 0x00, 0x00, 0x7f, 0x7f, 0x00, 0x7f, 0x7f, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x7f, 0x00, 0x7f, 0x7f, 0x00, 0x00,
0x7f, 0x7f, 0x00, 0x7f, 0x7f, 0x7f, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00,
0x7f, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
};
#endif

View file

@ -0,0 +1,271 @@
/**
* @license
* Copyright (c) 2011 NVIDIA Corporation. All rights reserved.
*
* TO THE MAXIMUM EXTENT PERMITTED BY APPLICABLE LAW, THIS SOFTWARE IS PROVIDED
* *AS IS* AND NVIDIA AND ITS SUPPLIERS DISCLAIM ALL WARRANTIES, EITHER EXPRESS
* OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, NONINFRINGEMENT,IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL NVIDIA
* OR ITS SUPPLIERS BE LIABLE FOR ANY DIRECT, SPECIAL, INCIDENTAL, INDIRECT, OR
* CONSEQUENTIAL DAMAGES WHATSOEVER (INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOSS
* OF BUSINESS PROFITS, BUSINESS INTERRUPTION, LOSS OF BUSINESS INFORMATION, OR ANY
* OTHER PECUNIARY LOSS) ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE,
* EVEN IF NVIDIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
*/
/*
FXAA_PRESET - Choose compile-in knob preset 0-5.
------------------------------------------------------------------------------
FXAA_EDGE_THRESHOLD - The minimum amount of local contrast required
to apply algorithm.
1.0/3.0 - too little
1.0/4.0 - good start
1.0/8.0 - applies to more edges
1.0/16.0 - overkill
------------------------------------------------------------------------------
FXAA_EDGE_THRESHOLD_MIN - Trims the algorithm from processing darks.
Perf optimization.
1.0/32.0 - visible limit (smaller isn't visible)
1.0/16.0 - good compromise
1.0/12.0 - upper limit (seeing artifacts)
------------------------------------------------------------------------------
FXAA_SEARCH_STEPS - Maximum number of search steps for end of span.
------------------------------------------------------------------------------
FXAA_SEARCH_THRESHOLD - Controls when to stop searching.
1.0/4.0 - seems to be the best quality wise
------------------------------------------------------------------------------
FXAA_SUBPIX_TRIM - Controls sub-pixel aliasing removal.
1.0/2.0 - low removal
1.0/3.0 - medium removal
1.0/4.0 - default removal
1.0/8.0 - high removal
0.0 - complete removal
------------------------------------------------------------------------------
FXAA_SUBPIX_CAP - Insures fine detail is not completely removed.
This is important for the transition of sub-pixel detail,
like fences and wires.
3.0/4.0 - default (medium amount of filtering)
7.0/8.0 - high amount of filtering
1.0 - no capping of sub-pixel aliasing removal
*/
#version 450 core
#extension GL_ARB_separate_shader_objects : enable
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 (push_constant, std140) uniform DrawInfo {
mat4 modelview_matrix;
vec4 i_resolution;
vec4 o_resolution;
int screen_id_l;
int screen_id_r;
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
#if (FXAA_PRESET == 3)
#define FXAA_EDGE_THRESHOLD (1.0/8.0)
#define FXAA_EDGE_THRESHOLD_MIN (1.0/16.0)
#define FXAA_SEARCH_STEPS 16
#define FXAA_SEARCH_THRESHOLD (1.0/4.0)
#define FXAA_SUBPIX_CAP (3.0/4.0)
#define FXAA_SUBPIX_TRIM (1.0/4.0)
#endif
#if (FXAA_PRESET == 4)
#define FXAA_EDGE_THRESHOLD (1.0/8.0)
#define FXAA_EDGE_THRESHOLD_MIN (1.0/24.0)
#define FXAA_SEARCH_STEPS 24
#define FXAA_SEARCH_THRESHOLD (1.0/4.0)
#define FXAA_SUBPIX_CAP (3.0/4.0)
#define FXAA_SUBPIX_TRIM (1.0/4.0)
#endif
#if (FXAA_PRESET == 5)
#define FXAA_EDGE_THRESHOLD (1.0/8.0)
#define FXAA_EDGE_THRESHOLD_MIN (1.0/24.0)
#define FXAA_SEARCH_STEPS 32
#define FXAA_SEARCH_THRESHOLD (1.0/4.0)
#define FXAA_SUBPIX_CAP (3.0/4.0)
#define FXAA_SUBPIX_TRIM (1.0/4.0)
#endif
#define FXAA_SUBPIX_TRIM_SCALE (1.0/(1.0 - FXAA_SUBPIX_TRIM))
// Return the luma, the estimation of luminance from rgb inputs.
// This approximates luma using one FMA instruction,
// skipping normalization and tossing out blue.
// FxaaLuma() will range 0.0 to 2.963210702.
float FxaaLuma(vec3 rgb) {
return rgb.y * (0.587/0.299) + rgb.x;
}
vec3 FxaaLerp3(vec3 a, vec3 b, float amountOfA) {
return (vec3(-amountOfA) * b) + ((a * vec3(amountOfA)) + b);
}
vec4 FxaaTexOff(sampler2D tex, vec2 pos, ivec2 off, vec2 rcpFrame) {
float x = pos.x + float(off.x) * rcpFrame.x;
float y = pos.y + float(off.y) * rcpFrame.y;
return texture(tex, vec2(x, y));
}
// pos is the output of FxaaVertexShader interpolated across screen.
// xy -> actual texture position {0.0 to 1.0}
// rcpFrame should be a uniform equal to {1.0/frameWidth, 1.0/frameHeight}
vec3 FxaaPixelShader(vec2 pos, sampler2D tex, vec2 rcpFrame)
{
vec3 rgbN = FxaaTexOff(tex, pos.xy, ivec2( 0,-1), rcpFrame).xyz;
vec3 rgbW = FxaaTexOff(tex, pos.xy, ivec2(-1, 0), rcpFrame).xyz;
vec3 rgbM = FxaaTexOff(tex, pos.xy, ivec2( 0, 0), rcpFrame).xyz;
vec3 rgbE = FxaaTexOff(tex, pos.xy, ivec2( 1, 0), rcpFrame).xyz;
vec3 rgbS = FxaaTexOff(tex, pos.xy, ivec2( 0, 1), rcpFrame).xyz;
float lumaN = FxaaLuma(rgbN);
float lumaW = FxaaLuma(rgbW);
float lumaM = FxaaLuma(rgbM);
float lumaE = FxaaLuma(rgbE);
float lumaS = FxaaLuma(rgbS);
float rangeMin = min(lumaM, min(min(lumaN, lumaW), min(lumaS, lumaE)));
float rangeMax = max(lumaM, max(max(lumaN, lumaW), max(lumaS, lumaE)));
float range = rangeMax - rangeMin;
if(range < max(FXAA_EDGE_THRESHOLD_MIN, rangeMax * FXAA_EDGE_THRESHOLD))
{
return rgbM;
}
vec3 rgbL = rgbN + rgbW + rgbM + rgbE + rgbS;
float lumaL = (lumaN + lumaW + lumaE + lumaS) * 0.25;
float rangeL = abs(lumaL - lumaM);
float blendL = max(0.0, (rangeL / range) - FXAA_SUBPIX_TRIM) * FXAA_SUBPIX_TRIM_SCALE;
blendL = min(FXAA_SUBPIX_CAP, blendL);
vec3 rgbNW = FxaaTexOff(tex, pos.xy, ivec2(-1,-1), rcpFrame).xyz;
vec3 rgbNE = FxaaTexOff(tex, pos.xy, ivec2( 1,-1), rcpFrame).xyz;
vec3 rgbSW = FxaaTexOff(tex, pos.xy, ivec2(-1, 1), rcpFrame).xyz;
vec3 rgbSE = FxaaTexOff(tex, pos.xy, ivec2( 1, 1), rcpFrame).xyz;
rgbL += (rgbNW + rgbNE + rgbSW + rgbSE);
rgbL *= vec3(1.0/9.0);
float lumaNW = FxaaLuma(rgbNW);
float lumaNE = FxaaLuma(rgbNE);
float lumaSW = FxaaLuma(rgbSW);
float lumaSE = FxaaLuma(rgbSE);
float edgeVert =
abs((0.25 * lumaNW) + (-0.5 * lumaN) + (0.25 * lumaNE)) +
abs((0.50 * lumaW ) + (-1.0 * lumaM) + (0.50 * lumaE )) +
abs((0.25 * lumaSW) + (-0.5 * lumaS) + (0.25 * lumaSE));
float edgeHorz =
abs((0.25 * lumaNW) + (-0.5 * lumaW) + (0.25 * lumaSW)) +
abs((0.50 * lumaN ) + (-1.0 * lumaM) + (0.50 * lumaS )) +
abs((0.25 * lumaNE) + (-0.5 * lumaE) + (0.25 * lumaSE));
bool horzSpan = edgeHorz >= edgeVert;
float lengthSign = horzSpan ? -rcpFrame.y : -rcpFrame.x;
if(!horzSpan)
{
lumaN = lumaW;
lumaS = lumaE;
}
float gradientN = abs(lumaN - lumaM);
float gradientS = abs(lumaS - lumaM);
lumaN = (lumaN + lumaM) * 0.5;
lumaS = (lumaS + lumaM) * 0.5;
if (gradientN < gradientS)
{
lumaN = lumaS;
lumaN = lumaS;
gradientN = gradientS;
lengthSign *= -1.0;
}
vec2 posN;
posN.x = pos.x + (horzSpan ? 0.0 : lengthSign * 0.5);
posN.y = pos.y + (horzSpan ? lengthSign * 0.5 : 0.0);
gradientN *= FXAA_SEARCH_THRESHOLD;
vec2 posP = posN;
vec2 offNP = horzSpan ? vec2(rcpFrame.x, 0.0) : vec2(0.0, rcpFrame.y);
float lumaEndN = lumaN;
float lumaEndP = lumaN;
bool doneN = false;
bool doneP = false;
posN += offNP * vec2(-1.0, -1.0);
posP += offNP * vec2( 1.0, 1.0);
for(int i = 0; i < FXAA_SEARCH_STEPS; i++) {
if(!doneN)
{
lumaEndN = FxaaLuma(texture(tex, posN.xy).xyz);
}
if(!doneP)
{
lumaEndP = FxaaLuma(texture(tex, posP.xy).xyz);
}
doneN = doneN || (abs(lumaEndN - lumaN) >= gradientN);
doneP = doneP || (abs(lumaEndP - lumaN) >= gradientN);
if(doneN && doneP)
{
break;
}
if(!doneN)
{
posN -= offNP;
}
if(!doneP)
{
posP += offNP;
}
}
float dstN = horzSpan ? pos.x - posN.x : pos.y - posN.y;
float dstP = horzSpan ? posP.x - pos.x : posP.y - pos.y;
bool directionN = dstN < dstP;
lumaEndN = directionN ? lumaEndN : lumaEndP;
if(((lumaM - lumaN) < 0.0) == ((lumaEndN - lumaN) < 0.0))
{
lengthSign = 0.0;
}
float spanLength = (dstP + dstN);
dstN = directionN ? dstN : dstP;
float subPixelOffset = (0.5 + (dstN * (-1.0/spanLength))) * lengthSign;
vec3 rgbF = texture(tex, vec2(
pos.x + (horzSpan ? 0.0 : subPixelOffset),
pos.y + (horzSpan ? subPixelOffset : 0.0))).xyz;
return FxaaLerp3(rgbL, rgbF, blendL);
}
vec3 sRGBToLinear(vec3 c) {
return mix(c / 12.92, pow((c + 0.055) / 1.055, vec3(2.4)), step(0.04045, c));
}
void main()
{
vec4 pixel = vec4(FxaaPixelShader(frag_tex_coord, screen_textures[0], vec2(i_resolution.z, i_resolution.w)), 1.0) * 1.0;
if (convert_colors == 1){
pixel = vec4(sRGBToLinear(pixel.rgb), pixel.a);
}
color = pixel;
}

View file

@ -0,0 +1,30 @@
#version 450 core
#extension GL_ARB_separate_shader_objects : enable
layout (push_constant, std140) uniform DrawInfo {
mat4 modelview_matrix;
vec4 i_resolution;
vec4 o_resolution;
int screen_id_l;
int screen_id_r;
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);
frag_tex_coord = vert_tex_coord;
}

File diff suppressed because it is too large Load diff

View file

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

View file

@ -0,0 +1,5 @@
void main() {
gl_Position = vec4(vert_position, 0.0, 1.0);
frag_tex_coord = vert_tex_coord;
SMAAEdgeDetectionVS(vert_tex_coord, offset);
}

View file

@ -0,0 +1,35 @@
#version 450 core
#extension GL_ARB_separate_shader_objects : enable
// SPDX-License-Identifier: Unlicense
//-----------------------------------------------------------------------------
// Edge Detection Shaders (First Pass)
layout (push_constant, std140) uniform DrawInfo {
mat4 modelview_matrix;
vec4 i_resolution;
vec4 o_resolution;
int screen_id_l;
int screen_id_r;
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)
#define SMAA_GLSL_4
#define SMAA_FLIP_Y 0
#define SMAA_PRESET_ULTRA
#define SMAA_EDT 1.0
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
*/
#define SMAA_INCLUDE_VS 0
//#include "SMAA.hlsl"

View file

@ -0,0 +1,33 @@
#version 450 core
#extension GL_ARB_separate_shader_objects : enable
// SPDX-License-Identifier: Unlicense
//-----------------------------------------------------------------------------
// Edge Detection Shaders (First Pass)
layout (push_constant, std140) uniform DrawInfo {
mat4 modelview_matrix;
vec4 i_resolution;
vec4 o_resolution;
int screen_id_l;
int screen_id_r;
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)
#define SMAA_GLSL_4
#define SMAA_FLIP_Y 0
#define SMAA_PRESET_ULTRA
#define SMAA_EDT 1.0
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 vec4 offset[3];
#define SMAA_INCLUDE_PS 0
//#include "SMAA.hlsl"

View file

@ -0,0 +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);
}

View file

@ -0,0 +1,5 @@
void main() {
gl_Position = vec4(vert_position, 0.0, 1.0);
frag_tex_coord = vert_tex_coord;
SMAABlendingWeightCalculationVS(vert_tex_coord, pixcoord, offset);
}

View file

@ -0,0 +1,38 @@
#version 450 core
#extension GL_ARB_separate_shader_objects : enable
// SPDX-License-Identifier: Unlicense
//-----------------------------------------------------------------------------
// Blending Weight Calculation Shader (Second Pass)
layout (push_constant, std140) uniform DrawInfo {
mat4 modelview_matrix;
vec4 i_resolution;
vec4 o_resolution;
int screen_id_l;
int screen_id_r;
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)
#define SMAA_GLSL_4
#define SMAA_FLIP_Y 0
#define SMAA_PRESET_ULTRA
#define SMAA_EDT 1.0
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;
*/
#define SMAA_INCLUDE_VS 0
//#include "SMAA.hlsl"

View file

@ -0,0 +1,34 @@
#version 450 core
#extension GL_ARB_separate_shader_objects : enable
// SPDX-License-Identifier: Unlicense
//-----------------------------------------------------------------------------
// Blending Weight Calculation Shader (Second Pass)
layout (push_constant, std140) uniform DrawInfo {
mat4 modelview_matrix;
vec4 i_resolution;
vec4 o_resolution;
int screen_id_l;
int screen_id_r;
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)
#define SMAA_GLSL_4
#define SMAA_FLIP_Y 0
#define SMAA_PRESET_ULTRA
#define SMAA_EDT 1.0
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 pixcoord;
layout(location = 2) out vec4 offset[3];
#define SMAA_INCLUDE_PS 0
//#include "SMAA.hlsl"

View file

@ -0,0 +1,11 @@
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() {
vec4 pixel = SMAANeighborhoodBlendingPS(frag_tex_coord, offset, screen_textures[1], screen_textures[0]);
if (convert_colors == 2){
pixel = vec4(LinearTosRGB(pixel.rgb), pixel.a);
}
color = pixel;
}

View file

@ -0,0 +1,5 @@
void main() {
gl_Position = vec4(vert_position, 0.0, 1.0);
frag_tex_coord = vert_tex_coord;
SMAANeighborhoodBlendingVS(vert_tex_coord, offset);
}

View file

@ -0,0 +1,34 @@
#version 450 core
#extension GL_ARB_separate_shader_objects : enable
// SPDX-License-Identifier: Unlicense
//-----------------------------------------------------------------------------
// Neighborhood Blending Shader (Third Pass)
layout (push_constant, std140) uniform DrawInfo {
mat4 modelview_matrix;
vec4 i_resolution;
vec4 o_resolution;
int screen_id_l;
int screen_id_r;
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)
#define SMAA_GLSL_4
#define SMAA_FLIP_Y 0
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;
*/
#define SMAA_INCLUDE_VS 0
//#include "SMAA.hlsl"

View file

@ -0,0 +1,31 @@
#version 450 core
#extension GL_ARB_separate_shader_objects : enable
// SPDX-License-Identifier: Unlicense
//-----------------------------------------------------------------------------
// Neighborhood Blending Shader (Third Pass)
layout (push_constant, std140) uniform DrawInfo {
mat4 modelview_matrix;
vec4 i_resolution;
vec4 o_resolution;
int screen_id_l;
int screen_id_r;
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)
#define SMAA_GLSL_4
#define SMAA_FLIP_Y 0
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 vec4 offset;
#define SMAA_INCLUDE_PS 0
//#include "SMAA.hlsl"

View file

@ -9,10 +9,22 @@ layout(location = 0) out vec4 color;
layout(binding = 0) uniform sampler2D color_texture;
uniform vec4 i_resolution;
uniform vec4 o_resolution;
uniform int layer;
uniform int convert_colors;
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 = texture(color_texture, frag_tex_coord);
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

@ -0,0 +1,28 @@
// Copyright 2023 Citra Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
//? #version 430 core
layout(location = 0) in vec2 frag_tex_coord;
layout(location = 0) out vec4 color;
layout(binding = 0) uniform sampler2D color_texture;
uniform int convert_colors;
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() {
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

@ -0,0 +1,13 @@
// Copyright 2023 Citra Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
//? #version 430 core
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,93 @@
//? #version 460 core
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;
uniform int convert_colors;
/***** Area Sampling *****/
// By Sam Belliveau and Filippo Tarpini. Public Domain license.
// Effectively a more accurate sharp bilinear filter when upscaling,
// that also works as a mathematically perfect downscale filter.
// https://entropymine.com/imageworsener/pixelmixing/
// https://github.com/obsproject/obs-studio/pull/1715
// https://legacy.imagemagick.org/Usage/filter/
vec4 AreaSampling(sampler2D textureSampler, vec2 texCoords) {
// Determine the sizes of the source and target images.
vec2 source_size = i_resolution.xy;
vec2 inverted_target_size = o_resolution.zw;
// Determine the range of the source image that the target pixel will cover.
vec2 range = source_size * inverted_target_size;
vec2 beg = (texCoords.xy * source_size) - (range * 0.5);
vec2 end = beg + range;
// Compute the top-left and bottom-right corners of the pixel box.
ivec2 f_beg = ivec2(floor(beg));
ivec2 f_end = ivec2(floor(end));
// Compute how much of the start and end pixels are covered horizontally & vertically.
float area_w = 1.0 - fract(beg.x);
float area_n = 1.0 - fract(beg.y);
float area_e = fract(end.x);
float area_s = fract(end.y);
// Compute the areas of the corner pixels in the pixel box.
float area_nw = area_n * area_w;
float area_ne = area_n * area_e;
float area_sw = area_s * area_w;
float area_se = area_s * area_e;
// Initialize the color accumulator.
vec4 avg_color = vec4(0.0, 0.0, 0.0, 0.0);
// Accumulate corner pixels.
avg_color += area_nw * texelFetch(textureSampler, ivec2(f_beg.x, f_beg.y), 0);
avg_color += area_ne * texelFetch(textureSampler, ivec2(f_end.x, f_beg.y), 0);
avg_color += area_sw * texelFetch(textureSampler, ivec2(f_beg.x, f_end.y), 0);
avg_color += area_se * texelFetch(textureSampler, ivec2(f_end.x, f_end.y), 0);
// Determine the size of the pixel box.
int x_range = int(f_end.x - f_beg.x - 0.5);
int y_range = int(f_end.y - f_beg.y - 0.5);
// Accumulate top and bottom edge pixels.
for (int x = f_beg.x + 1; x <= f_beg.x + x_range; ++x) {
avg_color += area_n * texelFetch(textureSampler, ivec2(x, f_beg.y), 0);
avg_color += area_s * texelFetch(textureSampler, ivec2(x, f_end.y), 0);
}
// Accumulate left and right edge pixels and all the pixels in between.
for (int y = f_beg.y + 1; y <= f_beg.y + y_range; ++y) {
avg_color += area_w * texelFetch(textureSampler, ivec2(f_beg.x, y), 0);
avg_color += area_e * texelFetch(textureSampler, ivec2(f_end.x, y), 0);
for (int x = f_beg.x + 1; x <= f_beg.x + x_range; ++x) {
avg_color += texelFetch(textureSampler, ivec2(x, y), 0);
}
}
// Compute the area of the pixel box that was sampled.
float area_corners = area_nw + area_ne + area_sw + area_se;
float area_edges = float(x_range) * (area_n + area_s) + float(y_range) * (area_w + area_e);
float area_center = float(x_range) * float(y_range);
// Return the normalized average color.
return avg_color / (area_corners + area_edges + area_center);
}
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() {
vec4 pixel = AreaSampling(color_texture, frag_tex_coord);
if (convert_colors == 2){
pixel = vec4(LinearTosRGB(pixel.rgb), pixel.a);
}
color = pixel;
}

View file

@ -0,0 +1,11 @@
//? #version 460
layout(location = 0) in vec2 vert_position;
layout(location = 1) in vec2 vert_tex_coord;
layout(location = 0) out vec2 frag_tex_coord;
uniform mat3x2 modelview_matrix;
void main()
{
gl_Position = vec4(mat2(modelview_matrix) * vert_position + modelview_matrix[2], 0.0, 1.0);
frag_tex_coord = vert_tex_coord;
}

View file

@ -0,0 +1,105 @@
//? #version 460 core
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 (push_constant, std140) uniform DrawInfo {
mat4 modelview_matrix;
vec4 i_resolution;
vec4 o_resolution;
int screen_id_l;
int screen_id_r;
int layer;
int reverse_interlaced;
int convert_colors;
int areatex;
int searchtex;
int smaa_input;
};
/***** Area Sampling *****/
// By Sam Belliveau and Filippo Tarpini. Public Domain license.
// Effectively a more accurate sharp bilinear filter when upscaling,
// that also works as a mathematically perfect downscale filter.
// https://entropymine.com/imageworsener/pixelmixing/
// https://github.com/obsproject/obs-studio/pull/1715
// https://legacy.imagemagick.org/Usage/filter/
vec4 AreaSampling(sampler2D textureSampler, vec2 texCoords) {
// Determine the sizes of the source and target images.
vec2 source_size = i_resolution.xy;
vec2 inverted_target_size = o_resolution.zw;
// Determine the range of the source image that the target pixel will cover.
vec2 range = source_size * inverted_target_size;
vec2 beg = (texCoords.xy * source_size) - (range * 0.5);
vec2 end = beg + range;
// Compute the top-left and bottom-right corners of the pixel box.
ivec2 f_beg = ivec2(floor(beg));
ivec2 f_end = ivec2(floor(end));
// Compute how much of the start and end pixels are covered horizontally & vertically.
float area_w = 1.0 - fract(beg.x);
float area_n = 1.0 - fract(beg.y);
float area_e = fract(end.x);
float area_s = fract(end.y);
// Compute the areas of the corner pixels in the pixel box.
float area_nw = area_n * area_w;
float area_ne = area_n * area_e;
float area_sw = area_s * area_w;
float area_se = area_s * area_e;
// Initialize the color accumulator.
vec4 avg_color = vec4(0.0, 0.0, 0.0, 0.0);
// Accumulate corner pixels.
avg_color += area_nw * texelFetch(textureSampler, ivec2(f_beg.x, f_beg.y), 0);
avg_color += area_ne * texelFetch(textureSampler, ivec2(f_end.x, f_beg.y), 0);
avg_color += area_sw * texelFetch(textureSampler, ivec2(f_beg.x, f_end.y), 0);
avg_color += area_se * texelFetch(textureSampler, ivec2(f_end.x, f_end.y), 0);
// Determine the size of the pixel box.
int x_range = int(f_end.x - f_beg.x - 0.5);
int y_range = int(f_end.y - f_beg.y - 0.5);
// Accumulate top and bottom edge pixels.
for (int x = f_beg.x + 1; x <= f_beg.x + x_range; ++x) {
avg_color += area_n * texelFetch(textureSampler, ivec2(x, f_beg.y), 0);
avg_color += area_s * texelFetch(textureSampler, ivec2(x, f_end.y), 0);
}
// Accumulate left and right edge pixels and all the pixels in between.
for (int y = f_beg.y + 1; y <= f_beg.y + y_range; ++y) {
avg_color += area_w * texelFetch(textureSampler, ivec2(f_beg.x, y), 0);
avg_color += area_e * texelFetch(textureSampler, ivec2(f_end.x, y), 0);
for (int x = f_beg.x + 1; x <= f_beg.x + x_range; ++x) {
avg_color += texelFetch(textureSampler, ivec2(x, y), 0);
}
}
// Compute the area of the pixel box that was sampled.
float area_corners = area_nw + area_ne + area_sw + area_se;
float area_edges = float(x_range) * (area_n + area_s) + float(y_range) * (area_w + area_e);
float area_center = float(x_range) * float(y_range);
// Return the normalized average color.
return avg_color / (area_corners + area_edges + area_center);
}
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() {
vec4 pixel = AreaSampling(screen_textures[0], frag_tex_coord);
if (convert_colors == 2){
pixel = vec4(LinearTosRGB(pixel.rgb), pixel.a);
}
color = pixel;
}

View file

@ -0,0 +1,24 @@
//? #version 460
layout(location = 0) in vec2 vert_position;
layout(location = 1) in vec2 vert_tex_coord;
layout(location = 0) out vec2 frag_tex_coord;
layout (push_constant, std140) uniform DrawInfo {
mat4 modelview_matrix;
vec4 i_resolution;
vec4 o_resolution;
int screen_id_l;
int screen_id_r;
int layer;
int reverse_interlaced;
int convert_colors;
int areatex;
int searchtex;
int smaa_input;
};
void main()
{
vec4 position = vec4(vert_position, 0.0, 1.0) * modelview_matrix;
gl_Position = vec4(position.x, position.y, 0.0, 1.0);
frag_tex_coord = vert_tex_coord;
}

View file

@ -1,7 +1,6 @@
// Copyright 2022 Citra Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#version 450 core
#extension GL_ARB_separate_shader_objects : enable

View file

@ -0,0 +1,55 @@
// Copyright 2022 Citra Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#version 450 core
#extension GL_ARB_separate_shader_objects : enable
layout (location = 0) in vec2 frag_tex_coord;
layout (location = 0) out vec4 color;
layout (push_constant, std140) uniform DrawInfo {
mat4 modelview_matrix;
vec4 i_resolution;
vec4 o_resolution;
int screen_id_l;
int screen_id_r;
int layer;
int reverse_interlaced;
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
}
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() {
vec4 pixel = GetScreen(screen_id_l);
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

@ -0,0 +1,23 @@
// Copyright 2022 Citra Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#version 450 core
#extension GL_ARB_separate_shader_objects : enable
layout (location = 0) in vec2 vert_position;
layout (location = 1) in vec2 vert_tex_coord;
layout (location = 0) out vec2 frag_tex_coord;
layout (push_constant, std140) uniform DrawInfo {
mat4 modelview_matrix;
vec4 i_resolution;
vec4 o_resolution;
int screen_id_l;
int screen_id_r;
int layer;
};
void main() {
gl_Position = vec4(vert_position, 0.0, 1.0);
frag_tex_coord = vert_tex_coord;
}

View file

@ -75,7 +75,7 @@ void OGLTexture::Allocate(GLenum target, GLsizei levels, GLenum internalformat,
glTexStorage3D(target, levels, internalformat, width, height, depth);
break;
}
glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);

View file

@ -9,7 +9,9 @@
#include "core/frontend/emu_window.h"
#include "core/frontend/framebuffer_layout.h"
#include "core/memory.h"
#include "gl_state.h"
#include "video_core/pica/pica_core.h"
#include "video_core/renderer_opengl/gl_resource_manager.h"
#include "video_core/renderer_opengl/gl_state.h"
#include "video_core/renderer_opengl/gl_texture_mailbox.h"
#include "video_core/renderer_opengl/post_processing_opengl.h"
@ -20,6 +22,28 @@
#include "video_core/host_shaders/opengl_present_frag.h"
#include "video_core/host_shaders/opengl_present_interlaced_frag.h"
#include "video_core/host_shaders/opengl_present_vert.h"
#include "video_core/host_shaders/opengl_simple_present_frag.h"
#include "video_core/host_shaders/opengl_simple_present_vert.h"
#include "video_core/host_shaders/antialiasing/OpenGL/opengl_fxaa_frag.h"
#include "video_core/host_shaders/antialiasing/OpenGL/opengl_fxaa_vert.h"
#include "video_core/host_shaders/antialiasing/OpenGL/opengl_smaa_pass0_pre_frag.h"
#include "video_core/host_shaders/antialiasing/OpenGL/opengl_smaa_pass0_pre_vert.h"
#include "video_core/host_shaders/antialiasing/OpenGL/opengl_smaa_pass0_post_frag.h"
#include "video_core/host_shaders/antialiasing/OpenGL/opengl_smaa_pass0_post_vert.h"
#include "video_core/host_shaders/antialiasing/OpenGL/opengl_smaa_pass1_pre_frag.h"
#include "video_core/host_shaders/antialiasing/OpenGL/opengl_smaa_pass1_pre_vert.h"
#include "video_core/host_shaders/antialiasing/OpenGL/opengl_smaa_pass1_post_frag.h"
#include "video_core/host_shaders/antialiasing/OpenGL/opengl_smaa_pass1_post_vert.h"
#include "video_core/host_shaders/antialiasing/OpenGL/opengl_smaa_pass2_pre_frag.h"
#include "video_core/host_shaders/antialiasing/OpenGL/opengl_smaa_pass2_pre_vert.h"
#include "video_core/host_shaders/antialiasing/OpenGL/opengl_smaa_pass2_post_frag.h"
#include "video_core/host_shaders/antialiasing/OpenGL/opengl_smaa_pass2_post_vert.h"
#include "video_core/host_shaders/antialiasing/OpenGL/opengl_smaa_hlsl.h"
#include "video_core/host_shaders/antialiasing/AreaTex.h"
#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"
namespace OpenGL {
@ -315,12 +339,72 @@ void RendererOpenGL::LoadFBToScreenInfo(const Pica::FramebufferConfig& framebuff
}
}
std::vector<unsigned char> flipVertically(const unsigned char* data, int width, int height, int channels)
{
int rowSize = width * channels;
std::vector<unsigned char> flipped(width * height * channels);
for (int y = 0; y < height; y++)
{
const unsigned char* src = data + (height - 1 - y) * rowSize;
unsigned char* dst = flipped.data() + y * rowSize;
memcpy(dst, src, rowSize);
}
return flipped;
}
void RendererOpenGL::AllocateSMAATextures(){
//Load AreaTex and SearchTex to OGLTexture Objects
areatex.Create();
searchtex.Create();
std::vector<unsigned char> areaTexBytes_Flipped = flipVertically(areaTexBytes, AREATEX_WIDTH, AREATEX_HEIGHT, 2);
std::vector<unsigned char> searchTexBytes_Flipped = flipVertically(searchTexBytes, SEARCHTEX_WIDTH, SEARCHTEX_HEIGHT, 1);
GLuint old_tex = OpenGLState::GetCurState().texture_units[0].texture_2d;
glBindTexture(GL_TEXTURE_2D, areatex.handle);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RG8, AREATEX_WIDTH, AREATEX_HEIGHT, 0, GL_RG, GL_UNSIGNED_BYTE, areaTexBytes_Flipped.data());
glBindTexture(GL_TEXTURE_2D, searchtex.handle);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexImage2D(GL_TEXTURE_2D, 0, GL_R8, SEARCHTEX_WIDTH, SEARCHTEX_HEIGHT, 0, GL_RED, GL_UNSIGNED_BYTE, searchTexBytes_Flipped.data());
glBindTexture(GL_TEXTURE_2D, old_tex);
}
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");
}
/**
* Initializes the OpenGL state and creates persistent objects.
*/
void RendererOpenGL::InitOpenGLObjects() {
glClearColor(Settings::values.bg_red.GetValue(), Settings::values.bg_green.GetValue(),
Settings::values.bg_blue.GetValue(), 1.0f);
Settings::values.bg_blue.GetValue(), 0.0f);
for (std::size_t i = 0; i < samplers.size(); i++) {
samplers[i].Create();
@ -354,6 +438,10 @@ void RendererOpenGL::InitOpenGLObjects() {
glEnableVertexAttribArray(attrib_position);
glEnableVertexAttribArray(attrib_tex_coord);
// Allocate textures for Post Processing
AllocateSMAATextures();
textureFBO.Create();
// Allocate textures for each screen
for (auto& screen_info : screen_infos) {
screen_info.texture.resource.Create();
@ -373,7 +461,7 @@ void RendererOpenGL::InitOpenGLObjects() {
screen_info.display_texture = screen_info.texture.resource.handle;
}
AllocatePPTextures();
state.texture_units[0].texture_2d = 0;
state.Apply();
}
@ -411,30 +499,68 @@ void RendererOpenGL::ReloadShader(Settings::StereoRenderOption render_3d) {
}
}
}
shader.Create(HostShaders::OPENGL_PRESENT_VERT, shader_data);
state.draw.shader_program = shader.handle;
Present_shader.Create(HostShaders::OPENGL_PRESENT_VERT, shader_data);
state.draw.shader_program = Present_shader.handle;
AttachUniforms();
// Setup FXAA, SMAA and Simple Present Shaders
std::string FXAA_shader_data = fragment_shader_precision_OES;
FXAA_shader_data += HostShaders::OPENGL_FXAA_FRAG;
FXAA_shader.Create(HostShaders::OPENGL_FXAA_VERT, FXAA_shader_data);
std::string AREA_SAMPLING_shader_data = fragment_shader_precision_OES;
AREA_SAMPLING_shader_data += HostShaders::OPENGL_AREA_SAMPLING_FRAG;
AREA_SAMPLING_shader.Create(HostShaders::OPENGL_AREA_SAMPLING_VERT, AREA_SAMPLING_shader_data);
std::string SimplePresent_shader_data = fragment_shader_precision_OES;
SimplePresent_shader_data += HostShaders::OPENGL_SIMPLE_PRESENT_FRAG;
SimplePresent_shader.Create(HostShaders::OPENGL_SIMPLE_PRESENT_VERT, SimplePresent_shader_data);
std::string SMAA_PASS_0_shader_frag_data = fragment_shader_precision_OES;
SMAA_PASS_0_shader_frag_data += HostShaders::OPENGL_SMAA_PASS0_PRE_FRAG;
SMAA_PASS_0_shader_frag_data += HostShaders::OPENGL_SMAA_HLSL;
SMAA_PASS_0_shader_frag_data += HostShaders::OPENGL_SMAA_PASS0_POST_FRAG;
std::string SMAA_PASS_0_shader_vert_data;
SMAA_PASS_0_shader_vert_data += HostShaders::OPENGL_SMAA_PASS0_PRE_VERT;
SMAA_PASS_0_shader_vert_data += HostShaders::OPENGL_SMAA_HLSL;
SMAA_PASS_0_shader_vert_data += HostShaders::OPENGL_SMAA_PASS0_POST_VERT;
SMAA_PASS_0_shader.Create(SMAA_PASS_0_shader_vert_data, SMAA_PASS_0_shader_frag_data);
std::string SMAA_PASS_1_shader_frag_data = fragment_shader_precision_OES;
SMAA_PASS_1_shader_frag_data += HostShaders::OPENGL_SMAA_PASS1_PRE_FRAG;
SMAA_PASS_1_shader_frag_data += HostShaders::OPENGL_SMAA_HLSL;
SMAA_PASS_1_shader_frag_data += HostShaders::OPENGL_SMAA_PASS1_POST_FRAG;
std::string SMAA_PASS_1_shader_vert_data;
SMAA_PASS_1_shader_vert_data += HostShaders::OPENGL_SMAA_PASS1_PRE_VERT;
SMAA_PASS_1_shader_vert_data += HostShaders::OPENGL_SMAA_HLSL;
SMAA_PASS_1_shader_vert_data += HostShaders::OPENGL_SMAA_PASS1_POST_VERT;
SMAA_PASS_1_shader.Create(SMAA_PASS_1_shader_vert_data, SMAA_PASS_1_shader_frag_data);
std::string SMAA_PASS_2_shader_frag_data = fragment_shader_precision_OES;
SMAA_PASS_2_shader_frag_data += HostShaders::OPENGL_SMAA_PASS2_PRE_FRAG;
SMAA_PASS_2_shader_frag_data += HostShaders::OPENGL_SMAA_HLSL;
SMAA_PASS_2_shader_frag_data += HostShaders::OPENGL_SMAA_PASS2_POST_FRAG;
std::string SMAA_PASS_2_shader_vert_data;
SMAA_PASS_2_shader_vert_data += HostShaders::OPENGL_SMAA_PASS2_PRE_VERT;
SMAA_PASS_2_shader_vert_data += HostShaders::OPENGL_SMAA_HLSL;
SMAA_PASS_2_shader_vert_data += HostShaders::OPENGL_SMAA_PASS2_POST_VERT;
SMAA_PASS_2_shader.Create(SMAA_PASS_2_shader_vert_data, SMAA_PASS_2_shader_frag_data);
//
state.Apply();
uniform_modelview_matrix = glGetUniformLocation(shader.handle, "modelview_matrix");
uniform_color_texture = glGetUniformLocation(shader.handle, "color_texture");
if (render_3d == Settings::StereoRenderOption::Anaglyph ||
render_3d == Settings::StereoRenderOption::Interlaced ||
render_3d == Settings::StereoRenderOption::ReverseInterlaced) {
uniform_color_texture_r = glGetUniformLocation(shader.handle, "color_texture_r");
}
if (render_3d == Settings::StereoRenderOption::Interlaced ||
render_3d == Settings::StereoRenderOption::ReverseInterlaced) {
GLuint uniform_reverse_interlaced =
glGetUniformLocation(shader.handle, "reverse_interlaced");
if (render_3d == Settings::StereoRenderOption::ReverseInterlaced)
glUniform1i(uniform_reverse_interlaced, 1);
else
glUniform1i(uniform_reverse_interlaced, 0);
}
uniform_i_resolution = glGetUniformLocation(shader.handle, "i_resolution");
uniform_o_resolution = glGetUniformLocation(shader.handle, "o_resolution");
uniform_layer = glGetUniformLocation(shader.handle, "layer");
attrib_position = glGetAttribLocation(shader.handle, "vert_position");
attrib_tex_coord = glGetAttribLocation(shader.handle, "vert_tex_coord");
}
void RendererOpenGL::ConfigureFramebufferTexture(TextureInfo& texture,
@ -505,69 +631,365 @@ void RendererOpenGL::ConfigureFramebufferTexture(TextureInfo& texture,
state.Apply();
}
void RendererOpenGL::AttachUniforms(){
uniform_modelview_matrix = glGetUniformLocation(state.draw.shader_program, "modelview_matrix");
uniform_color_texture = glGetUniformLocation(state.draw.shader_program, "color_texture");
uniform_color_texture_r = glGetUniformLocation(state.draw.shader_program, "color_texture_r");
uniform_reverse_interlaced = glGetUniformLocation(state.draw.shader_program, "reverse_interlaced");
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_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");
}
/**
* Draws a single texture to the emulator window, rotating the texture to correct for the 3DS's LCD
* rotation.
*/
void RendererOpenGL::DrawSingleScreen(const ScreenInfo& screen_info, float x, float y, float w,
float h, Layout::DisplayOrientation orientation) {
void RendererOpenGL::DrawSingleScreen(const ScreenInfo& screen_info, float screenLeft, float screenTop, float screenWidth,
float screenHeight, Layout::DisplayOrientation orientation) {
const auto& texcoords = screen_info.display_texcoords;
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);
if (textureWidth == currTopTextureWidth && textureHeight == currTopTextureHeight){
currAntialiasFBOTexture = &antialiasFBOTextureTop;
currIntermediateTexture = &intermediateTextureTop;
} else {
currAntialiasFBOTexture = &antialiasFBOTextureBottom;
currIntermediateTexture = &intermediateTextureBottom;
}
// 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 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){
isDownsampling = true;
}
} else {
if (textureWidth > screenHeight){
isDownsampling = true;
}
}
// 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
}};
std::array<ScreenRectVertex, 4> vertices;
// 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
}};
// Vertices for Azahar's Output Layout
std::array<ScreenRectVertex, 4> output_vertices;
switch (orientation) {
case Layout::DisplayOrientation::Landscape:
vertices = {{
ScreenRectVertex(x, y, texcoords.bottom, texcoords.left),
ScreenRectVertex(x + w, y, texcoords.bottom, texcoords.right),
ScreenRectVertex(x, y + h, texcoords.top, texcoords.left),
ScreenRectVertex(x + w, y + h, texcoords.top, texcoords.right),
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
}};
break;
case Layout::DisplayOrientation::Portrait:
vertices = {{
ScreenRectVertex(x, y, texcoords.bottom, texcoords.right),
ScreenRectVertex(x + w, y, texcoords.top, texcoords.right),
ScreenRectVertex(x, y + h, texcoords.bottom, texcoords.left),
ScreenRectVertex(x + w, y + h, texcoords.top, texcoords.left),
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
}};
std::swap(h, w);
std::swap(screenHeight, screenWidth);
break;
case Layout::DisplayOrientation::LandscapeFlipped:
vertices = {{
ScreenRectVertex(x, y, texcoords.top, texcoords.right),
ScreenRectVertex(x + w, y, texcoords.top, texcoords.left),
ScreenRectVertex(x, y + h, texcoords.bottom, texcoords.right),
ScreenRectVertex(x + w, y + h, texcoords.bottom, texcoords.left),
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
}};
break;
case Layout::DisplayOrientation::PortraitFlipped:
vertices = {{
ScreenRectVertex(x, y, texcoords.top, texcoords.left),
ScreenRectVertex(x + w, y, texcoords.bottom, texcoords.left),
ScreenRectVertex(x, y + h, texcoords.top, texcoords.right),
ScreenRectVertex(x + w, y + h, texcoords.bottom, texcoords.right),
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
}};
std::swap(h, w);
std::swap(screenHeight, screenWidth);
break;
default:
LOG_ERROR(Render_OpenGL, "Unknown DisplayOrientation: {}", orientation);
break;
}
const u32 scale_factor = GetResolutionScaleFactor();
const GLuint sampler = samplers[Settings::values.filter_mode.GetValue()].handle;
glUniform4f(uniform_i_resolution, static_cast<float>(screen_info.texture.width * scale_factor),
static_cast<float>(screen_info.texture.height * scale_factor),
1.0f / static_cast<float>(screen_info.texture.width * scale_factor),
1.0f / static_cast<float>(screen_info.texture.height * scale_factor));
glUniform4f(uniform_o_resolution, h, w, 1.0f / h, 1.0f / w);
state.texture_units[0].texture_2d = screen_info.display_texture;
state.texture_units[0].sampler = sampler;
state.Apply();
GLuint originalReadFramebuffer = state.draw.read_framebuffer;
GLuint originalDrawFramebuffer = state.draw.draw_framebuffer;
if (antialiasingMode == 1){
//Pass 1
state.draw.read_framebuffer = textureFBO.handle;
state.draw.draw_framebuffer = textureFBO.handle;
state.Apply();
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, (*currIntermediateTexture)[0].handle, 0);
glClear(GL_COLOR_BUFFER_BIT);
state.draw.shader_program = SimplePresent_shader.handle;
state.Apply();
AttachUniforms();
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, 0);
state.Apply();
glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(rotate_vertices), rotate_vertices.data());
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(vertices), vertices.data());
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
//Pass 2
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, (*currAntialiasFBOTexture).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].sampler = samplers[1].handle;
glUniform1i(uniform_color_texture, 0);
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());
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
} else if (antialiasingMode == 2){
// Landscape Gamma Space Texture
state.draw.read_framebuffer = textureFBO.handle;
state.draw.draw_framebuffer = textureFBO.handle;
state.Apply();
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, (*currIntermediateTexture)[0].handle, 0);
glClear(GL_COLOR_BUFFER_BIT);
state.draw.shader_program = SimplePresent_shader.handle;
state.Apply();
AttachUniforms();
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, 0);
state.Apply();
glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(rotate_vertices), rotate_vertices.data());
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
// Landscape Linear Space Texture
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, (*currIntermediateTexture)[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].sampler = samplers[1].handle;
glUniform1i(uniform_color_texture, 0);
glUniform1i(uniform_convert_colors, 1);
state.Apply();
glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(pass_through_vertices), pass_through_vertices.data());
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
// Edge Detection
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, (*currIntermediateTexture)[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].sampler = samplers[1].handle;
glUniform1i(uniform_color_texture, 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());
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
// Blending Weight Calculation
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, (*currIntermediateTexture)[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].sampler = samplers[1].handle;
state.texture_units[1].texture_2d = areatex.handle;
state.texture_units[1].sampler = samplers[1].handle;
state.texture_units[2].texture_2d = searchtex.handle;
state.texture_units[2].sampler = samplers[1].handle;
GLuint uniform_areatex = glGetUniformLocation(state.draw.shader_program, "areaTex");
GLuint uniform_searchtex = glGetUniformLocation(state.draw.shader_program, "searchTex");
glUniform1i(uniform_color_texture, 0);
glUniform1i(uniform_areatex, 1);
glUniform1i(uniform_searchtex, 2);
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());
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
// Neighborhood Blending
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, (*currAntialiasFBOTexture).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].sampler = samplers[1].handle;
state.texture_units[1].texture_2d = (*currIntermediateTexture)[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);
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());
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
} else {
state.draw.read_framebuffer = textureFBO.handle;
state.draw.draw_framebuffer = textureFBO.handle;
state.Apply();
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, (*currAntialiasFBOTexture).handle, 0);
glClear(GL_COLOR_BUFFER_BIT);
state.draw.shader_program = SimplePresent_shader.handle;
state.Apply();
AttachUniforms();
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);
state.Apply();
glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(rotate_vertices), rotate_vertices.data());
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
}
if (scalingMode == 2){
if (isDownsampling){
//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 = AREA_SAMPLING_shader.handle;
state.Apply();
AttachUniforms();
state.texture_units[0].texture_2d = (*currAntialiasFBOTexture).handle;
state.texture_units[0].sampler = samplers[0].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;
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 = (*currAntialiasFBOTexture).handle;
state.texture_units[0].sampler = samplers[1].handle;
glUniform1i(uniform_color_texture, 0);
glUniform1i(uniform_convert_colors, 2);
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;
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 = (*currAntialiasFBOTexture).handle;
if (scalingMode == 1){
state.texture_units[0].sampler = samplers[1].handle;
} else {
state.texture_units[0].sampler = samplers[0].handle;
}
glUniform1i(uniform_color_texture, 0);
glUniform1i(uniform_convert_colors, 2);
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);
}
state.texture_units[0].texture_2d = 0;
state.texture_units[0].sampler = 0;
state.Apply();
@ -632,6 +1054,7 @@ void RendererOpenGL::DrawSingleScreenStereo(const ScreenInfo& screen_info_l,
1.0f / static_cast<float>(screen_info_l.texture.width * scale_factor),
1.0f / static_cast<float>(screen_info_l.texture.height * scale_factor));
glUniform4f(uniform_o_resolution, h, w, 1.0f / h, 1.0f / w);
glUniformMatrix3x2fv(uniform_modelview_matrix, 1, GL_FALSE, ortho_matrix.data());
state.texture_units[0].texture_2d = screen_info_l.display_texture;
state.texture_units[1].texture_2d = screen_info_r.display_texture;
state.texture_units[0].sampler = sampler;
@ -655,12 +1078,12 @@ void RendererOpenGL::DrawScreens(const Layout::FramebufferLayout& layout, bool f
if (settings.bg_color_update_requested.exchange(false)) {
// Update background color before drawing
glClearColor(Settings::values.bg_red.GetValue(), Settings::values.bg_green.GetValue(),
Settings::values.bg_blue.GetValue(), 1.0f);
Settings::values.bg_blue.GetValue(), 0.0f);
}
if (settings.shader_update_requested.exchange(false)) {
// Update fragment shader before drawing
shader.Release();
Present_shader.Release();
// Link shaders and get variable locations
ReloadShader(layout.render_3d_mode);
}
@ -668,15 +1091,35 @@ void RendererOpenGL::DrawScreens(const Layout::FramebufferLayout& layout, bool f
const auto& top_screen = layout.top_screen;
const auto& bottom_screen = layout.bottom_screen;
glViewport(0, 0, layout.width, layout.height);
// 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();
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;
//Set the Viewport
state.viewport.x = 0;
state.viewport.y = 0;
state.viewport.width = layout.width;
state.viewport.height = layout.height;
originalViewport = {0, 0, static_cast<int>(layout.width), static_cast<int>(layout.height)};
state.Apply();
if (render_window.NeedsClearing()) {
glClear(GL_COLOR_BUFFER_BIT);
}
// Set projection matrix
std::array<GLfloat, 3 * 2> ortho_matrix =
MakeOrthographicMatrix((float)layout.width, (float)layout.height, flipped);
glUniformMatrix3x2fv(uniform_modelview_matrix, 1, GL_FALSE, ortho_matrix.data());
ortho_matrix = MakeOrthographicMatrix((float)layout.width, (float)layout.height, flipped);
// Bind texture in Texture Unit 0
glUniform1i(uniform_color_texture, 0);

View file

@ -5,6 +5,7 @@
#pragma once
#include <array>
#include "gl_resource_manager.h"
#include "video_core/renderer_base.h"
#include "video_core/renderer_opengl/frame_dumper_opengl.h"
#include "video_core/renderer_opengl/gl_driver.h"
@ -57,6 +58,8 @@ public:
private:
void InitOpenGLObjects();
void ReloadShader(Settings::StereoRenderOption render_3d);
void AllocateSMAATextures();
void AllocatePPTextures();
void PrepareRendertarget();
void RenderScreenshot();
void RenderToMailbox(const Layout::FramebufferLayout& layout,
@ -80,6 +83,8 @@ private:
// Loads framebuffer from emulated memory into the display information structure
void LoadFBToScreenInfo(const Pica::FramebufferConfig& framebuffer, ScreenInfo& screen_info,
bool right_eye, const Pica::ColorFill& color_fill);
// Attach Uniforms to the current shader
void AttachUniforms();
private:
Pica::PicaCore& pica;
@ -90,17 +95,40 @@ private:
// OpenGL object IDs
OGLVertexArray vertex_array;
OGLBuffer vertex_buffer;
OGLProgram shader;
OGLProgram Present_shader;
OGLProgram SimplePresent_shader;
OGLProgram FXAA_shader;
OGLProgram SMAA_PASS_0_shader;
OGLProgram SMAA_PASS_1_shader;
OGLProgram SMAA_PASS_2_shader;
OGLProgram AREA_SAMPLING_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;
OGLTexture* currAntialiasFBOTexture;
std::array<OGLTexture, 5>* currIntermediateTexture;
OGLTexture areatex;
OGLTexture searchtex;
// Display information for top and bottom screens respectively
std::array<ScreenInfo, 3> screen_infos;
std::array<GLfloat, 3 * 2> ortho_matrix;
// Shader uniform location indices
GLuint uniform_modelview_matrix;
GLuint uniform_color_texture;
GLuint uniform_color_texture_r;
GLuint uniform_reverse_interlaced;
// Shader Uniform for converting colors. 0 is no conversion, 1 is sRGB -> linear, 2 is Linear -> sRGB
GLuint uniform_convert_colors;
// Shader uniform for Dolphin compatibility
GLuint uniform_i_resolution;
@ -112,6 +140,17 @@ private:
GLuint attrib_tex_coord;
FrameDumperOpenGL frame_dumper;
// Variables tracking texture changes
float prevTopTextureWidth;
float prevTopTextureHeight;
float prevBottomTextureWidth;
float prevBottomTextureHeight;
float currTopTextureWidth;
float currTopTextureHeight;
float currBottomTextureWidth;
float currBottomTextureHeight;
std::array<int, 4> originalViewport;
};
} // namespace OpenGL

View file

@ -23,6 +23,29 @@
#include "video_core/host_shaders/vulkan_cursor_frag.h"
#include "video_core/host_shaders/vulkan_cursor_vert.h"
#include "video_core/host_shaders/vulkan_simple_present_frag.h"
#include "video_core/host_shaders/vulkan_simple_present_vert.h"
#include "video_core/host_shaders/antialiasing/Vulkan/vulkan_fxaa_frag.h"
#include "video_core/host_shaders/antialiasing/Vulkan/vulkan_fxaa_vert.h"
#include "video_core/host_shaders/antialiasing/Vulkan/vulkan_smaa_pass0_pre_frag.h"
#include "video_core/host_shaders/antialiasing/Vulkan/vulkan_smaa_pass0_pre_vert.h"
#include "video_core/host_shaders/antialiasing/Vulkan/vulkan_smaa_pass0_post_frag.h"
#include "video_core/host_shaders/antialiasing/Vulkan/vulkan_smaa_pass0_post_vert.h"
#include "video_core/host_shaders/antialiasing/Vulkan/vulkan_smaa_pass1_pre_frag.h"
#include "video_core/host_shaders/antialiasing/Vulkan/vulkan_smaa_pass1_pre_vert.h"
#include "video_core/host_shaders/antialiasing/Vulkan/vulkan_smaa_pass1_post_frag.h"
#include "video_core/host_shaders/antialiasing/Vulkan/vulkan_smaa_pass1_post_vert.h"
#include "video_core/host_shaders/antialiasing/Vulkan/vulkan_smaa_pass2_pre_frag.h"
#include "video_core/host_shaders/antialiasing/Vulkan/vulkan_smaa_pass2_pre_vert.h"
#include "video_core/host_shaders/antialiasing/Vulkan/vulkan_smaa_pass2_post_frag.h"
#include "video_core/host_shaders/antialiasing/Vulkan/vulkan_smaa_pass2_post_vert.h"
#include "video_core/host_shaders/antialiasing/Vulkan/vulkan_smaa_hlsl.h"
#include "video_core/host_shaders/antialiasing/AreaTex.h"
#include "video_core/host_shaders/antialiasing/SearchTex.h"
#include "video_core/host_shaders/scaling/vulkan_area_sampling_frag.h"
#include "video_core/host_shaders/scaling/vulkan_area_sampling_vert.h"
#include <vk_mem_alloc.h>
#if defined(__APPLE__) && !defined(HAVE_LIBRETRO)
@ -129,6 +152,7 @@ RendererVulkan::RendererVulkan(Core::System& system, Pica::PicaCore& pica_,
present_heap{instance, scheduler.GetMasterSemaphore(), PRESENT_BINDINGS, 32} {
CompileShaders();
BuildLayouts();
CreateTextureRenderPass();
BuildPipelines();
if (secondary_window) {
secondary_present_window_ptr = std::make_unique<PresentWindow>(
@ -148,6 +172,24 @@ RendererVulkan::~RendererVulkan() {
device.destroyShaderModule(present_shaders[i]);
}
for (u32 i = 0; i < POST_PIPELINES_SCREEN; i++) {
device.destroyPipeline(post_pipelines_screen[i]);
}
for (u32 i = 0; i < POST_PIPELINES_TEXTURE; i++) {
device.destroyPipeline(post_pipelines_texture[i]);
}
for (u32 i = 0; i < POST_PIPELINES_SCREEN; i++) {
device.destroyShaderModule(post_vert_shaders_screen[i]);
device.destroyShaderModule(post_frag_shaders_screen[i]);
}
for (u32 i = 0; i < POST_PIPELINES_TEXTURE; i++) {
device.destroyShaderModule(post_vert_shaders_texture[i]);
device.destroyShaderModule(post_frag_shaders_texture[i]);
}
for (auto& sampler : present_samplers) {
device.destroySampler(sampler);
}
@ -186,8 +228,140 @@ void RendererVulkan::PrepareRendertarget() {
}
}
void RendererVulkan::CreateTextureRenderPass(){
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 = vk::Format::eR16G16B16A16Sfloat,
.loadOp = vk::AttachmentLoadOp::eClear,
.storeOp = vk::AttachmentStoreOp::eStore,
.stencilLoadOp = vk::AttachmentLoadOp::eDontCare,
.stencilStoreOp = vk::AttachmentStoreOp::eDontCare,
.initialLayout = vk::ImageLayout::eUndefined,
.finalLayout = vk::ImageLayout::eTransferSrcOptimal,
};
const vk::RenderPassCreateInfo renderpass_info = {
.attachmentCount = 1,
.pAttachments = &color_attachment,
.subpassCount = 1,
.pSubpasses = &subpass,
.dependencyCount = 0,
.pDependencies = nullptr,
};
textureRenderpass = instance.GetDevice().createRenderPass(renderpass_info);
}
void RendererVulkan::AllocateTexture(TextureInfo& texture, int width, int height, vk::Format colorFormat){
vk::Device device = instance.GetDevice();
if (texture.image_view) {
device.destroyImageView(texture.image_view);
}
if (texture.image) {
vmaDestroyImage(instance.GetAllocator(), texture.image, texture.allocation);
}
texture.width = width;
texture.height = height;
const vk::Format format = colorFormat;
const vk::ImageCreateInfo image_info = {
.imageType = vk::ImageType::e2D,
.format = format,
.extent = {texture.width, texture.height, 1},
.mipLevels = 1,
.arrayLayers = 1,
.samples = vk::SampleCountFlagBits::e1,
.usage = vk::ImageUsageFlagBits::eSampled,
};
const VmaAllocationCreateInfo alloc_info = {
.flags = VMA_ALLOCATION_CREATE_WITHIN_BUDGET_BIT,
.usage = VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE,
.requiredFlags = 0,
.preferredFlags = 0,
.pool = VK_NULL_HANDLE,
.pUserData = nullptr,
};
VkImage unsafe_image{};
VkImageCreateInfo unsafe_image_info = static_cast<VkImageCreateInfo>(image_info);
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);
UNREACHABLE();
}
texture.image = vk::Image{unsafe_image};
const vk::ImageViewCreateInfo view_info = {
.image = texture.image,
.viewType = vk::ImageViewType::e2D,
.format = format,
.subresourceRange{
.aspectMask = vk::ImageAspectFlagBits::eColor,
.baseMipLevel = 0,
.levelCount = 1,
.baseArrayLayer = 0,
.layerCount = 1,
},
};
texture.image_view = device.createImageView(view_info);
}
void RendererVulkan::AllocatePPTextures(){
for (int i = 0; i < intermediateTextures[0].size(); i++){
AllocateTexture(intermediateTextures[0][i], currTopTextureWidth, currTopTextureHeight, vk::Format::eR16G16B16A16Sfloat);
}
for (int i = 0; i < intermediateTextures[1].size(); i++){
AllocateTexture(intermediateTextures[1][i], currBottomTextureWidth, currBottomTextureHeight, vk::Format::eR16G16B16A16Sfloat);
}
AllocateTexture(antialiasTextures[0], currTopTextureWidth, currTopTextureHeight, vk::Format::eR16G16B16A16Sfloat);
AllocateTexture(antialiasTextures[1], currBottomTextureWidth, currBottomTextureHeight, vk::Format::eR16G16B16A16Sfloat);
};
void RendererVulkan::CreateTextureFramebuffer(TextureInfo& texture, vk::Framebuffer& framebuffer) {
const vk::FramebufferCreateInfo framebuffer_info = {
.renderPass = textureRenderpass,
.attachmentCount = 1,
.pAttachments = &texture.image_view,
.width = texture.width,
.height = texture.height,
.layers = 1,
};
framebuffer = instance.GetDevice().createFramebuffer(framebuffer_info);
}
void RendererVulkan::CreatePPTextureFramebuffers(){
for (int i = 0; i < intermediateTextures.size(); i++){
for (int j = 0; j < intermediateTextures[0].size(); j++){
CreateTextureFramebuffer(intermediateTextures[i][j], intermediateTextureFBOs[i][j]);
}
}
for (int i = 0; i < antialiasTextures.size(); i++){
CreateTextureFramebuffer(antialiasTextures[i], antialiasTextureFBOs[i]);
}
};
void RendererVulkan::PrepareDraw(Frame* frame, const Layout::FramebufferLayout& layout) {
const auto sampler = present_samplers[!Settings::values.filter_mode.GetValue()];
const auto sampler = present_samplers[Settings::values.filter_mode.GetValue()];
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,
@ -228,7 +402,6 @@ void RendererVulkan::PrepareDraw(Frame* frame, const Layout::FramebufferLayout&
.clearValueCount = 1,
.pClearValues = &clear,
};
cmdbuf.beginRenderPass(renderpass_begin_info, vk::SubpassContents::eInline);
cmdbuf.bindPipeline(vk::PipelineBindPoint::eGraphics, present_pipelines[index]);
cmdbuf.bindDescriptorSets(vk::PipelineBindPoint::eGraphics, layout, 0, present_set, {});
@ -306,9 +479,64 @@ void RendererVulkan::CompileShaders() {
cursor_fragment_shader =
Compile(HostShaders::VULKAN_CURSOR_FRAG, vk::ShaderStageFlagBits::eFragment, device);
// Simple Present Shader
post_vert_shaders_texture[0] =
Compile(HostShaders::VULKAN_SIMPLE_PRESENT_VERT, vk::ShaderStageFlagBits::eVertex, device);
post_frag_shaders_texture[0] =
Compile(HostShaders::VULKAN_SIMPLE_PRESENT_FRAG, vk::ShaderStageFlagBits::eFragment, device, preamble);
// Area Sampling Shader
post_vert_shaders_screen[0] =
Compile(HostShaders::VULKAN_AREA_SAMPLING_VERT, vk::ShaderStageFlagBits::eVertex, device);
post_frag_shaders_screen[0] =
Compile(HostShaders::VULKAN_AREA_SAMPLING_FRAG, vk::ShaderStageFlagBits::eFragment, device);
// FXAA Shader
post_vert_shaders_texture[1] =
Compile(HostShaders::VULKAN_FXAA_VERT, vk::ShaderStageFlagBits::eVertex, device);
post_frag_shaders_texture[1] =
Compile(HostShaders::VULKAN_FXAA_FRAG, vk::ShaderStageFlagBits::eFragment, device);
// SMAA Pass 0 Shader
std::string smaa_pass_0_shader_vert_data = std::string(HostShaders::VULKAN_SMAA_PASS0_PRE_VERT);
smaa_pass_0_shader_vert_data += std::string(HostShaders::VULKAN_SMAA_HLSL);
smaa_pass_0_shader_vert_data += std::string(HostShaders::VULKAN_SMAA_PASS0_POST_VERT);
std::string smaa_pass_0_shader_frag_data = std::string(HostShaders::VULKAN_SMAA_PASS0_PRE_FRAG);
smaa_pass_0_shader_frag_data += std::string(HostShaders::VULKAN_SMAA_HLSL);
smaa_pass_0_shader_frag_data += std::string(HostShaders::VULKAN_SMAA_PASS0_POST_FRAG);
post_vert_shaders_texture[2] =
Compile(smaa_pass_0_shader_vert_data, vk::ShaderStageFlagBits::eVertex, device);
post_frag_shaders_texture[2] =
Compile(smaa_pass_0_shader_frag_data, vk::ShaderStageFlagBits::eFragment, device);
// SMAA Pass 1 Shader
std::string smaa_pass_1_shader_vert_data = std::string(HostShaders::VULKAN_SMAA_PASS1_PRE_VERT);
smaa_pass_1_shader_vert_data += std::string(HostShaders::VULKAN_SMAA_HLSL);
smaa_pass_1_shader_vert_data += std::string(HostShaders::VULKAN_SMAA_PASS1_POST_VERT);
std::string smaa_pass_1_shader_frag_data = std::string(HostShaders::VULKAN_SMAA_PASS1_PRE_FRAG);
smaa_pass_1_shader_frag_data += std::string(HostShaders::VULKAN_SMAA_HLSL);
smaa_pass_1_shader_frag_data += std::string(HostShaders::VULKAN_SMAA_PASS1_POST_FRAG);
post_vert_shaders_texture[3] =
Compile(smaa_pass_1_shader_vert_data, vk::ShaderStageFlagBits::eVertex, device);
post_frag_shaders_texture[3] =
Compile(smaa_pass_1_shader_frag_data, vk::ShaderStageFlagBits::eFragment, device);
// SMAA Pass 2 Shader
std::string smaa_pass_2_shader_vert_data = std::string(HostShaders::VULKAN_SMAA_PASS2_PRE_VERT);
smaa_pass_2_shader_vert_data += std::string(HostShaders::VULKAN_SMAA_HLSL);
smaa_pass_2_shader_vert_data += std::string(HostShaders::VULKAN_SMAA_PASS2_POST_VERT);
std::string smaa_pass_2_shader_frag_data = std::string(HostShaders::VULKAN_SMAA_PASS2_PRE_FRAG);
smaa_pass_2_shader_frag_data += std::string(HostShaders::VULKAN_SMAA_HLSL);
smaa_pass_2_shader_frag_data += std::string(HostShaders::VULKAN_SMAA_PASS2_POST_FRAG);
post_vert_shaders_texture[4] =
Compile(smaa_pass_2_shader_vert_data, vk::ShaderStageFlagBits::eVertex, device);
post_frag_shaders_texture[4] =
Compile(smaa_pass_2_shader_frag_data, vk::ShaderStageFlagBits::eFragment, device);
auto properties = instance.GetPhysicalDevice().getProperties();
for (std::size_t i = 0; i < present_samplers.size(); i++) {
const vk::Filter filter_mode = i == 0 ? vk::Filter::eLinear : vk::Filter::eNearest;
const vk::Filter filter_mode = i == 0 ? vk::Filter::eNearest : vk::Filter::eLinear;
const vk::SamplerCreateInfo sampler_info = {
.magFilter = filter_mode,
.minFilter = filter_mode,
@ -476,6 +704,78 @@ void RendererVulkan::BuildPipelines() {
present_pipelines[i] = pipeline;
}
// Build Post Processing Pipelines for RGBA16F textures
for (u32 i = 0; i < POST_PIPELINES_TEXTURE; i++) {
const std::array shader_stages = {
vk::PipelineShaderStageCreateInfo{
.stage = vk::ShaderStageFlagBits::eVertex,
.module = post_vert_shaders_texture[i],
.pName = "main",
},
vk::PipelineShaderStageCreateInfo{
.stage = vk::ShaderStageFlagBits::eFragment,
.module = post_frag_shaders_texture[i],
.pName = "main",
},
};
const vk::GraphicsPipelineCreateInfo pipeline_info = {
.stageCount = static_cast<u32>(shader_stages.size()),
.pStages = shader_stages.data(),
.pVertexInputState = &vertex_input_info,
.pInputAssemblyState = &input_assembly,
.pViewportState = &viewport_info,
.pRasterizationState = &raster_state,
.pMultisampleState = &multisampling,
.pDepthStencilState = &depth_info,
.pColorBlendState = &color_blending,
.pDynamicState = &dynamic_info,
.layout = *present_pipeline_layout,
.renderPass = textureRenderpass,
};
const auto [result, pipeline] =
instance.GetDevice().createGraphicsPipeline({}, pipeline_info);
ASSERT_MSG(result == vk::Result::eSuccess, "Unable to build post processing pipelines");
post_pipelines_texture[i] = pipeline;
}
// Build Post Processing Pipelines for presenting
for (u32 i = 0; i < POST_PIPELINES_SCREEN; i++) {
const std::array shader_stages = {
vk::PipelineShaderStageCreateInfo{
.stage = vk::ShaderStageFlagBits::eVertex,
.module = post_vert_shaders_screen[i],
.pName = "main",
},
vk::PipelineShaderStageCreateInfo{
.stage = vk::ShaderStageFlagBits::eFragment,
.module = post_frag_shaders_screen[i],
.pName = "main",
},
};
const vk::GraphicsPipelineCreateInfo pipeline_info = {
.stageCount = static_cast<u32>(shader_stages.size()),
.pStages = shader_stages.data(),
.pVertexInputState = &vertex_input_info,
.pInputAssemblyState = &input_assembly,
.pViewportState = &viewport_info,
.pRasterizationState = &raster_state,
.pMultisampleState = &multisampling,
.pDepthStencilState = &depth_info,
.pColorBlendState = &color_blending,
.pDynamicState = &dynamic_info,
.layout = *present_pipeline_layout,
.renderPass = main_present_window.Renderpass(),
};
const auto [result, pipeline] =
instance.GetDevice().createGraphicsPipeline({}, pipeline_info);
ASSERT_MSG(result == vk::Result::eSuccess, "Unable to build post processing pipelines");
post_pipelines_screen[i] = pipeline;
}
// Build cursor pipeline (simple position-only, inverted color blending)
{
const vk::VertexInputBindingDescription cursor_binding = {
@ -730,64 +1030,103 @@ void RendererVulkan::ReloadPipeline(Settings::StereoRenderOption render_3d) {
}
}
void RendererVulkan::DrawSingleScreen(u32 screen_id, float x, float y, float w, float h,
void RendererVulkan::DrawSingleScreen(u32 screen_id, float screenLeft, float screenTop, float screenWidth, float screenHeight,
Layout::DisplayOrientation orientation) {
const ScreenInfo& screen_info = screen_infos[screen_id];
const auto& texcoords = screen_info.texcoords;
std::array<ScreenRectVertex, 4> vertices;
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);
// 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 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){
isDownsampling = true;
}
} else {
if (textureWidth > screenHeight){
isDownsampling = true;
}
}
// 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
}};
// 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
}};
// Vertices for Azahar's Output Layout
std::array<ScreenRectVertex, 4> output_vertices;
switch (orientation) {
case Layout::DisplayOrientation::Landscape:
vertices = {{
ScreenRectVertex(x, y, texcoords.bottom, texcoords.left),
ScreenRectVertex(x + w, y, texcoords.bottom, texcoords.right),
ScreenRectVertex(x, y + h, texcoords.top, texcoords.left),
ScreenRectVertex(x + w, y + h, texcoords.top, texcoords.right),
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
}};
break;
case Layout::DisplayOrientation::Portrait:
vertices = {{
ScreenRectVertex(x, y, texcoords.bottom, texcoords.right),
ScreenRectVertex(x + w, y, texcoords.top, texcoords.right),
ScreenRectVertex(x, y + h, texcoords.bottom, texcoords.left),
ScreenRectVertex(x + w, y + h, texcoords.top, texcoords.left),
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
}};
std::swap(h, w);
std::swap(screenHeight, screenWidth);
break;
case Layout::DisplayOrientation::LandscapeFlipped:
vertices = {{
ScreenRectVertex(x, y, texcoords.top, texcoords.right),
ScreenRectVertex(x + w, y, texcoords.top, texcoords.left),
ScreenRectVertex(x, y + h, texcoords.bottom, texcoords.right),
ScreenRectVertex(x + w, y + h, texcoords.bottom, texcoords.left),
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
}};
break;
case Layout::DisplayOrientation::PortraitFlipped:
vertices = {{
ScreenRectVertex(x, y, texcoords.top, texcoords.left),
ScreenRectVertex(x + w, y, texcoords.bottom, texcoords.left),
ScreenRectVertex(x, y + h, texcoords.top, texcoords.right),
ScreenRectVertex(x + w, y + h, texcoords.bottom, texcoords.right),
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
}};
std::swap(h, w);
std::swap(screenHeight, screenWidth);
break;
default:
LOG_ERROR(Render_Vulkan, "Unknown DisplayOrientation: {}", orientation);
LOG_ERROR(Render_OpenGL, "Unknown DisplayOrientation: {}", orientation);
break;
}
const u64 size = sizeof(ScreenRectVertex) * vertices.size();
const u64 size = sizeof(ScreenRectVertex) * output_vertices.size();
auto [data, offset, invalidate] = vertex_buffer.Map(size, 16);
std::memcpy(data, vertices.data(), size);
std::memcpy(data, output_vertices.data(), size);
vertex_buffer.Commit(size);
const u32 scale_factor = GetResolutionScaleFactor();
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(h, w, 1.0f / h, 1.0f / w);
draw_info.o_resolution = Common::MakeVec(screenWidth, screenHeight, 1.0f / screenWidth, 1.0f / screenHeight);
draw_info.screen_id_l = screen_id;
scheduler.Record([this, offset = offset, info = draw_info](vk::CommandBuffer cmdbuf) {

View file

@ -62,13 +62,19 @@ struct PresentUniformData {
int screen_id_r = 0;
int layer = 0;
int reverse_interlaced = 0;
int convert_colors;
int areatex;
int searchtex;
int smaa_input;
};
static_assert(sizeof(PresentUniformData) == 112,
static_assert(sizeof(PresentUniformData) == 128,
"PresentUniformData does not structure in shader!");
class RendererVulkan : public VideoCore::RendererBase {
static constexpr std::size_t PRESENT_PIPELINES = 3;
static constexpr std::size_t POST_PIPELINES_SCREEN = 1;
static constexpr std::size_t POST_PIPELINES_TEXTURE = 5;
static constexpr std::size_t POST_SHADERS = 6;
public:
explicit RendererVulkan(Core::System& system, Pica::PicaCore& pica, Frontend::EmuWindow& window,
Frontend::EmuWindow* secondary_window);
@ -96,6 +102,7 @@ private:
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);
void RenderToWindow(PresentWindow& window, const Layout::FramebufferLayout& layout,
bool flipped);
@ -118,6 +125,17 @@ private:
bool right_eye);
void FillScreen(Common::Vec3<u8> color, const TextureInfo& texture);
void AllocateTexture(TextureInfo& texture, int width, int height, vk::Format colorFormat);
void CreateTextureFramebuffer(TextureInfo& texture, vk::Framebuffer& framebuffer);
// Create Renderpass used for Textures
void CreateTextureRenderPass();
// Allocate Post Processing Textures
void AllocatePPTextures();
// Create Framebuffers that are attached to the Post Processing Textures
void CreatePPTextureFramebuffers();
void AllocateSMAATextures();
private:
Memory::MemorySystem& memory;
Pica::PicaCore& pica;
@ -138,15 +156,52 @@ private:
DescriptorHeap present_heap;
vk::UniquePipelineLayout present_pipeline_layout;
std::array<vk::Pipeline, PRESENT_PIPELINES> present_pipelines;
// Post Processing Pipelines for use with RGBA16F Textures. Contains: Simple Present, FXAA, SMAA Pass 0, SMAA Pass 1, SMAA Pass 2
std::array<vk::Pipeline, POST_PIPELINES_TEXTURE> post_pipelines_texture;
// Post Processing Pipelines for presenting to screen. Contains: Area
std::array<vk::Pipeline, POST_PIPELINES_SCREEN> post_pipelines_screen;
std::array<vk::ShaderModule, PRESENT_PIPELINES> present_shaders;
// Post Processing Shaders for use with RGBA16F Textures. Contains: Simple Present, FXAA, SMAA Pass 0, SMAA Pass 1, SMAA Pass 2
std::array<vk::ShaderModule, POST_PIPELINES_TEXTURE> post_vert_shaders_texture;
std::array<vk::ShaderModule, POST_PIPELINES_TEXTURE> post_frag_shaders_texture;
// Post Processing Shaders for presenting to screen. Contains: Area
std::array<vk::ShaderModule, POST_PIPELINES_SCREEN> post_vert_shaders_screen;
std::array<vk::ShaderModule, POST_PIPELINES_SCREEN> post_frag_shaders_screen;
// Linear and Nearest Sampler Respectively
std::array<vk::Sampler, 2> present_samplers;
vk::ShaderModule present_vertex_shader;
vk::ShaderModule simplepresent_vertex_shader;
vk::ShaderModule simplepresent_frag_shader;
vk::ShaderModule area_sampling_vertex_shader;
vk::ShaderModule area_sampling_frag_shader;
vk::ShaderModule fxaa_vertex_shader;
vk::ShaderModule fxaa_frag_shader;
vk::ShaderModule smaa_pass_0_vertex_shader;
vk::ShaderModule smaa_pass_0_frag_shader;
vk::ShaderModule smaa_pass_1_vertex_shader;
vk::ShaderModule smaa_pass_1_frag_shader;
vk::ShaderModule smaa_pass_2_vertex_shader;
vk::ShaderModule smaa_pass_2_frag_shader;
// Renderpass for RGBA16F Textures
vk::RenderPass textureRenderpass;
// Array of textures. 0 is top screen, 1 is bottom screen.
std::array<std::array<TextureInfo, 5>, 2> intermediateTextures;
std::array<TextureInfo, 2> antialiasTextures;
// 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;
u32 current_pipeline = 0;
std::array<ScreenInfo, 3> screen_infos{};
PresentUniformData draw_info{};
vk::ClearColorValue clear_color{};
vk::ShaderModule cursor_vertex_shader{};
vk::ShaderModule cursor_fragment_shader{};
vk::Pipeline cursor_pipeline{};