mirror of
https://github.com/azahar-emu/azahar.git
synced 2026-06-06 02:33:44 -04:00
Merge b18f8d8b35 into 56f738eb06
This commit is contained in:
commit
b3f5cb04c2
54 changed files with 20468 additions and 108 deletions
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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)));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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><html><head/><body><p>Use Integer Scaling</p><p>Enforces that the larger screen in all layouts is an integer scale of the 240px height of the original 3DS screen.</p></body></html></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><html><head/><body><p>Disable Right Eye Rendering</p><p>Disables rendering the right eye image when not using stereoscopic mode. Greatly improves performance in some applications, but can cause flickering in others.</p></body></html></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>
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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
|
||||
)
|
||||
|
|
|
|||
14980
src/video_core/host_shaders/antialiasing/AreaTex.h
Normal file
14980
src/video_core/host_shaders/antialiasing/AreaTex.h
Normal file
File diff suppressed because it is too large
Load diff
256
src/video_core/host_shaders/antialiasing/OpenGL/opengl_fxaa.frag
Normal file
256
src/video_core/host_shaders/antialiasing/OpenGL/opengl_fxaa.frag
Normal 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;
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
||||
1459
src/video_core/host_shaders/antialiasing/OpenGL/opengl_smaa.hlsl
Normal file
1459
src/video_core/host_shaders/antialiasing/OpenGL/opengl_smaa.hlsl
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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"
|
||||
|
|
@ -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"
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
void main() {
|
||||
vec4 subsampleIndices = vec4(0.0);
|
||||
color = SMAABlendingWeightCalculationPS(frag_tex_coord, pixcoord, offset, color_texture, areaTex, searchTex, subsampleIndices);
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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"
|
||||
|
|
@ -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"
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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"
|
||||
|
|
@ -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"
|
||||
132
src/video_core/host_shaders/antialiasing/SearchTex.h
Normal file
132
src/video_core/host_shaders/antialiasing/SearchTex.h
Normal 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
|
||||
271
src/video_core/host_shaders/antialiasing/Vulkan/vulkan_fxaa.frag
Normal file
271
src/video_core/host_shaders/antialiasing/Vulkan/vulkan_fxaa.frag
Normal 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;
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
||||
1459
src/video_core/host_shaders/antialiasing/Vulkan/vulkan_smaa.hlsl
Normal file
1459
src/video_core/host_shaders/antialiasing/Vulkan/vulkan_smaa.hlsl
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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"
|
||||
|
|
@ -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"
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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"
|
||||
|
|
@ -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"
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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"
|
||||
|
|
@ -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"
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
28
src/video_core/host_shaders/opengl_simple_present.frag
Normal file
28
src/video_core/host_shaders/opengl_simple_present.frag
Normal 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;
|
||||
}
|
||||
13
src/video_core/host_shaders/opengl_simple_present.vert
Normal file
13
src/video_core/host_shaders/opengl_simple_present.vert
Normal 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;
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
||||
105
src/video_core/host_shaders/scaling/vulkan_area_sampling.frag
Normal file
105
src/video_core/host_shaders/scaling/vulkan_area_sampling.frag
Normal 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;
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
55
src/video_core/host_shaders/vulkan_simple_present.frag
Normal file
55
src/video_core/host_shaders/vulkan_simple_present.frag
Normal 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;
|
||||
}
|
||||
23
src/video_core/host_shaders/vulkan_simple_present.vert
Normal file
23
src/video_core/host_shaders/vulkan_simple_present.vert
Normal 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;
|
||||
}
|
||||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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{};
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue