mirror of https://github.com/PCSX2/pcsx2.git
GS/Vulkan: Implement FXAA
This commit is contained in:
parent
486764be03
commit
3067bef82d
|
@ -1,8 +1,11 @@
|
||||||
#if defined(SHADER_MODEL) || defined(FXAA_GLSL_130)
|
#if defined(SHADER_MODEL) || defined(FXAA_GLSL_130) || defined(FXAA_GLSL_VK)
|
||||||
|
|
||||||
#ifndef FXAA_GLSL_130
|
#ifndef FXAA_GLSL_130
|
||||||
#define FXAA_GLSL_130 0
|
#define FXAA_GLSL_130 0
|
||||||
#endif
|
#endif
|
||||||
|
#ifndef FXAA_GLSL_VK
|
||||||
|
#define FXAA_GLSL_VK 0
|
||||||
|
#endif
|
||||||
|
|
||||||
#define UHQ_FXAA 1 //High Quality Fast Approximate Anti Aliasing. Adapted for GS from Timothy Lottes FXAA 3.11.
|
#define UHQ_FXAA 1 //High Quality Fast Approximate Anti Aliasing. Adapted for GS from Timothy Lottes FXAA 3.11.
|
||||||
#define FxaaSubpixMax 0.0 //[0.00 to 1.00] Amount of subpixel aliasing removal. 0.00: Edge only antialiasing (no blurring)
|
#define FxaaSubpixMax 0.0 //[0.00 to 1.00] Amount of subpixel aliasing removal. 0.00: Edge only antialiasing (no blurring)
|
||||||
|
@ -17,6 +20,12 @@ in vec2 PSin_t;
|
||||||
|
|
||||||
layout(location = 0) out vec4 SV_Target0;
|
layout(location = 0) out vec4 SV_Target0;
|
||||||
|
|
||||||
|
#elif (FXAA_GLSL_VK == 1)
|
||||||
|
|
||||||
|
layout(location = 0) in vec2 PSin_t;
|
||||||
|
layout(location = 0) out vec4 SV_Target0;
|
||||||
|
layout(set = 0, binding = 0) uniform sampler2D TextureSampler;
|
||||||
|
|
||||||
#elif (SHADER_MODEL >= 0x400)
|
#elif (SHADER_MODEL >= 0x400)
|
||||||
Texture2D Texture : register(t0);
|
Texture2D Texture : register(t0);
|
||||||
SamplerState TextureSampler : register(s0);
|
SamplerState TextureSampler : register(s0);
|
||||||
|
@ -52,7 +61,7 @@ struct PS_OUTPUT
|
||||||
#define FXAA_HLSL_4 1
|
#define FXAA_HLSL_4 1
|
||||||
#define FXAA_GATHER4_ALPHA 0
|
#define FXAA_GATHER4_ALPHA 0
|
||||||
|
|
||||||
#elif (FXAA_GLSL_130 == 1)
|
#elif (FXAA_GLSL_130 == 1 || FXAA_GLSL_VK == 1)
|
||||||
#define FXAA_GATHER4_ALPHA 1
|
#define FXAA_GATHER4_ALPHA 1
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -72,7 +81,7 @@ struct FxaaTex { SamplerState smpl; Texture2D tex; };
|
||||||
#define FxaaDiscard clip(-1)
|
#define FxaaDiscard clip(-1)
|
||||||
#define FxaaSat(x) saturate(x)
|
#define FxaaSat(x) saturate(x)
|
||||||
|
|
||||||
#elif (FXAA_GLSL_130 == 1)
|
#elif (FXAA_GLSL_130 == 1 || FXAA_GLSL_VK == 1)
|
||||||
#define int2 ivec2
|
#define int2 ivec2
|
||||||
#define float2 vec2
|
#define float2 vec2
|
||||||
#define float3 vec3
|
#define float3 vec3
|
||||||
|
@ -470,7 +479,7 @@ float4 FxaaPixelShader(float2 pos, FxaaTex tex, float2 fxaaRcpFrame, float fxaaS
|
||||||
return float4(FxaaTexTop(tex, posM).xyz, lumaM);
|
return float4(FxaaTexTop(tex, posM).xyz, lumaM);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if (FXAA_GLSL_130 == 1)
|
#if (FXAA_GLSL_130 == 1 || FXAA_GLSL_VK == 1)
|
||||||
float4 FxaaPass(float4 FxaaColor, float2 uv0)
|
float4 FxaaPass(float4 FxaaColor, float2 uv0)
|
||||||
#elif (SHADER_MODEL >= 0x400)
|
#elif (SHADER_MODEL >= 0x400)
|
||||||
float4 FxaaPass(float4 FxaaColor : COLOR0, float2 uv0 : TEXCOORD0)
|
float4 FxaaPass(float4 FxaaColor : COLOR0, float2 uv0 : TEXCOORD0)
|
||||||
|
@ -486,7 +495,7 @@ float4 FxaaPass(float4 FxaaColor : COLOR0, float2 uv0 : TEXCOORD0)
|
||||||
Texture.GetDimensions(PixelSize.x, PixelSize.y);
|
Texture.GetDimensions(PixelSize.x, PixelSize.y);
|
||||||
FxaaColor = FxaaPixelShader(uv0, tex, 1.0/PixelSize.xy, FxaaSubpixMax, FxaaEdgeThreshold, FxaaEdgeThresholdMin);
|
FxaaColor = FxaaPixelShader(uv0, tex, 1.0/PixelSize.xy, FxaaSubpixMax, FxaaEdgeThreshold, FxaaEdgeThresholdMin);
|
||||||
|
|
||||||
#elif (FXAA_GLSL_130 == 1)
|
#elif (FXAA_GLSL_130 == 1 || FXAA_GLSL_VK == 1)
|
||||||
vec2 PixelSize = textureSize(TextureSampler, 0);
|
vec2 PixelSize = textureSize(TextureSampler, 0);
|
||||||
FxaaColor = FxaaPixelShader(uv0, TextureSampler, 1.0/PixelSize.xy, FxaaSubpixMax, FxaaEdgeThreshold, FxaaEdgeThresholdMin);
|
FxaaColor = FxaaPixelShader(uv0, TextureSampler, 1.0/PixelSize.xy, FxaaSubpixMax, FxaaEdgeThreshold, FxaaEdgeThresholdMin);
|
||||||
#endif
|
#endif
|
||||||
|
@ -497,9 +506,9 @@ float4 FxaaPass(float4 FxaaColor : COLOR0, float2 uv0 : TEXCOORD0)
|
||||||
/*------------------------------------------------------------------------------
|
/*------------------------------------------------------------------------------
|
||||||
[MAIN() & COMBINE PASS CODE SECTION]
|
[MAIN() & COMBINE PASS CODE SECTION]
|
||||||
------------------------------------------------------------------------------*/
|
------------------------------------------------------------------------------*/
|
||||||
#if (FXAA_GLSL_130 == 1)
|
#if (FXAA_GLSL_130 == 1 || FXAA_GLSL_VK == 1)
|
||||||
|
|
||||||
void ps_main()
|
void main()
|
||||||
{
|
{
|
||||||
vec4 color = texture(TextureSampler, PSin_t);
|
vec4 color = texture(TextureSampler, PSin_t);
|
||||||
color = PreGammaPass(color, PSin_t);
|
color = PreGammaPass(color, PSin_t);
|
||||||
|
|
|
@ -121,7 +121,7 @@ bool GSDeviceVK::Create(HostDisplay* display)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (!CompileConvertPipelines() || !CompileInterlacePipelines() ||
|
if (!CompileConvertPipelines() || !CompileInterlacePipelines() ||
|
||||||
!CompileMergePipelines() || !CompileShadeBoostPipeline())
|
!CompileMergePipelines() || !CompilePostProcessingPipelines())
|
||||||
{
|
{
|
||||||
Host::ReportErrorAsync("GS", "Failed to compile utility pipelines");
|
Host::ReportErrorAsync("GS", "Failed to compile utility pipelines");
|
||||||
return false;
|
return false;
|
||||||
|
@ -883,6 +883,21 @@ void GSDeviceVK::DoShadeBoost(GSTexture* sTex, GSTexture* dTex, const float para
|
||||||
static_cast<GSTextureVK*>(dTex)->TransitionToLayout(VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
|
static_cast<GSTextureVK*>(dTex)->TransitionToLayout(VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GSDeviceVK::DoFXAA(GSTexture* sTex, GSTexture* dTex)
|
||||||
|
{
|
||||||
|
const GSVector4 sRect(0.0f, 0.0f, 1.0f, 1.0f);
|
||||||
|
const GSVector4i dRect(0, 0, dTex->GetWidth(), dTex->GetHeight());
|
||||||
|
EndRenderPass();
|
||||||
|
OMSetRenderTargets(dTex, nullptr, dRect, false);
|
||||||
|
SetUtilityTexture(sTex, m_linear_sampler);
|
||||||
|
BeginRenderPass(m_utility_color_render_pass_discard, dRect);
|
||||||
|
SetPipeline(m_fxaa_pipeline);
|
||||||
|
DrawStretchRect(sRect, GSVector4(dRect), dTex->GetSize());
|
||||||
|
EndRenderPass();
|
||||||
|
|
||||||
|
static_cast<GSTextureVK*>(dTex)->TransitionToLayout(VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
|
||||||
|
}
|
||||||
|
|
||||||
void GSDeviceVK::IASetVertexBuffer(const void* vertex, size_t stride, size_t count)
|
void GSDeviceVK::IASetVertexBuffer(const void* vertex, size_t stride, size_t count)
|
||||||
{
|
{
|
||||||
const u32 size = static_cast<u32>(stride) * static_cast<u32>(count);
|
const u32 size = static_cast<u32>(stride) * static_cast<u32>(count);
|
||||||
|
@ -1626,29 +1641,13 @@ bool GSDeviceVK::CompileMergePipelines()
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GSDeviceVK::CompileShadeBoostPipeline()
|
bool GSDeviceVK::CompilePostProcessingPipelines()
|
||||||
{
|
{
|
||||||
std::optional<std::string> shader = Host::ReadResourceFileToString("shaders/vulkan/shadeboost.glsl");
|
|
||||||
if (!shader)
|
|
||||||
{
|
|
||||||
Host::ReportErrorAsync("GS", "Failed to read shaders/vulkan/shadeboost.glsl.");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
VkRenderPass rp = g_vulkan_context->GetRenderPass(
|
VkRenderPass rp = g_vulkan_context->GetRenderPass(
|
||||||
LookupNativeFormat(GSTexture::Format::Color), VK_FORMAT_UNDEFINED, VK_ATTACHMENT_LOAD_OP_LOAD);
|
LookupNativeFormat(GSTexture::Format::Color), VK_FORMAT_UNDEFINED, VK_ATTACHMENT_LOAD_OP_LOAD);
|
||||||
if (!rp)
|
if (!rp)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
VkShaderModule vs = GetUtilityVertexShader(*shader);
|
|
||||||
VkShaderModule ps = GetUtilityFragmentShader(*shader);
|
|
||||||
ScopedGuard shader_guard([&vs, &ps]() {
|
|
||||||
Vulkan::Util::SafeDestroyShaderModule(vs);
|
|
||||||
Vulkan::Util::SafeDestroyShaderModule(ps);
|
|
||||||
});
|
|
||||||
if (vs == VK_NULL_HANDLE || ps == VK_NULL_HANDLE)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
Vulkan::GraphicsPipelineBuilder gpb;
|
Vulkan::GraphicsPipelineBuilder gpb;
|
||||||
AddUtilityVertexAttributes(gpb);
|
AddUtilityVertexAttributes(gpb);
|
||||||
gpb.SetPipelineLayout(m_utility_pipeline_layout);
|
gpb.SetPipelineLayout(m_utility_pipeline_layout);
|
||||||
|
@ -1658,18 +1657,74 @@ bool GSDeviceVK::CompileShadeBoostPipeline()
|
||||||
gpb.SetNoDepthTestState();
|
gpb.SetNoDepthTestState();
|
||||||
gpb.SetNoBlendingState();
|
gpb.SetNoBlendingState();
|
||||||
gpb.SetRenderPass(rp, 0);
|
gpb.SetRenderPass(rp, 0);
|
||||||
gpb.SetVertexShader(vs);
|
|
||||||
gpb.SetFragmentShader(ps);
|
|
||||||
|
|
||||||
// we enable provoking vertex here anyway, in case it doesn't support multiple modes in the same pass
|
// we enable provoking vertex here anyway, in case it doesn't support multiple modes in the same pass
|
||||||
if (m_features.provoking_vertex_last)
|
if (m_features.provoking_vertex_last)
|
||||||
gpb.SetProvokingVertex(VK_PROVOKING_VERTEX_MODE_LAST_VERTEX_EXT);
|
gpb.SetProvokingVertex(VK_PROVOKING_VERTEX_MODE_LAST_VERTEX_EXT);
|
||||||
|
|
||||||
m_shadeboost_pipeline = gpb.Create(g_vulkan_context->GetDevice(), g_vulkan_shader_cache->GetPipelineCache(true), false);
|
{
|
||||||
if (!m_shadeboost_pipeline)
|
std::optional<std::string> vshader = Host::ReadResourceFileToString("shaders/vulkan/convert.glsl");
|
||||||
return false;
|
if (!vshader)
|
||||||
|
{
|
||||||
|
Host::ReportErrorAsync("GS", "Failed to read shaders/vulkan/convert.glsl.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<std::string> pshader = Host::ReadResourceFileToString("shaders/common/fxaa.fx");
|
||||||
|
if (!pshader)
|
||||||
|
{
|
||||||
|
Host::ReportErrorAsync("GS", "Failed to read shaders/common/fxaa.fx.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::string psource = "#define FXAA_GLSL_VK 1\n" + *pshader;
|
||||||
|
|
||||||
|
VkShaderModule vs = GetUtilityVertexShader(*vshader);
|
||||||
|
VkShaderModule ps = GetUtilityFragmentShader(psource, "ps_main");
|
||||||
|
ScopedGuard shader_guard([&vs, &ps]() {
|
||||||
|
Vulkan::Util::SafeDestroyShaderModule(vs);
|
||||||
|
Vulkan::Util::SafeDestroyShaderModule(ps);
|
||||||
|
});
|
||||||
|
if (vs == VK_NULL_HANDLE || ps == VK_NULL_HANDLE)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
gpb.SetVertexShader(vs);
|
||||||
|
gpb.SetFragmentShader(ps);
|
||||||
|
|
||||||
|
m_fxaa_pipeline = gpb.Create(g_vulkan_context->GetDevice(), g_vulkan_shader_cache->GetPipelineCache(true), false);
|
||||||
|
if (!m_fxaa_pipeline)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
Vulkan::Util::SetObjectName(g_vulkan_context->GetDevice(), m_fxaa_pipeline, "FXAA pipeline");
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
std::optional<std::string> shader = Host::ReadResourceFileToString("shaders/vulkan/shadeboost.glsl");
|
||||||
|
if (!shader)
|
||||||
|
{
|
||||||
|
Host::ReportErrorAsync("GS", "Failed to read shaders/vulkan/shadeboost.glsl.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
VkShaderModule vs = GetUtilityVertexShader(*shader);
|
||||||
|
VkShaderModule ps = GetUtilityFragmentShader(*shader);
|
||||||
|
ScopedGuard shader_guard([&vs, &ps]() {
|
||||||
|
Vulkan::Util::SafeDestroyShaderModule(vs);
|
||||||
|
Vulkan::Util::SafeDestroyShaderModule(ps);
|
||||||
|
});
|
||||||
|
if (vs == VK_NULL_HANDLE || ps == VK_NULL_HANDLE)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
gpb.SetVertexShader(vs);
|
||||||
|
gpb.SetFragmentShader(ps);
|
||||||
|
|
||||||
|
m_shadeboost_pipeline = gpb.Create(g_vulkan_context->GetDevice(), g_vulkan_shader_cache->GetPipelineCache(true), false);
|
||||||
|
if (!m_shadeboost_pipeline)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
Vulkan::Util::SetObjectName(g_vulkan_context->GetDevice(), m_shadeboost_pipeline, "Shadeboost pipeline");
|
||||||
|
}
|
||||||
|
|
||||||
Vulkan::Util::SetObjectName(g_vulkan_context->GetDevice(), m_shadeboost_pipeline, "Shadeboost pipeline");
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1755,6 +1810,7 @@ void GSDeviceVK::DestroyResources()
|
||||||
Vulkan::Util::SafeDestroyPipeline(m_date_image_setup_pipelines[ds][datm]);
|
Vulkan::Util::SafeDestroyPipeline(m_date_image_setup_pipelines[ds][datm]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Vulkan::Util::SafeDestroyPipeline(m_fxaa_pipeline);
|
||||||
Vulkan::Util::SafeDestroyPipeline(m_shadeboost_pipeline);
|
Vulkan::Util::SafeDestroyPipeline(m_shadeboost_pipeline);
|
||||||
|
|
||||||
for (auto& it : m_samplers)
|
for (auto& it : m_samplers)
|
||||||
|
|
|
@ -124,6 +124,7 @@ private:
|
||||||
VkPipeline m_hdr_finish_pipelines[2][2] = {}; // [depth][feedback_loop]
|
VkPipeline m_hdr_finish_pipelines[2][2] = {}; // [depth][feedback_loop]
|
||||||
VkRenderPass m_date_image_setup_render_passes[2][2] = {}; // [depth][clear]
|
VkRenderPass m_date_image_setup_render_passes[2][2] = {}; // [depth][clear]
|
||||||
VkPipeline m_date_image_setup_pipelines[2][2] = {}; // [depth][datm]
|
VkPipeline m_date_image_setup_pipelines[2][2] = {}; // [depth][datm]
|
||||||
|
VkPipeline m_fxaa_pipeline = {};
|
||||||
VkPipeline m_shadeboost_pipeline = {};
|
VkPipeline m_shadeboost_pipeline = {};
|
||||||
|
|
||||||
std::unordered_map<u32, VkShaderModule> m_tfx_vertex_shaders;
|
std::unordered_map<u32, VkShaderModule> m_tfx_vertex_shaders;
|
||||||
|
@ -155,6 +156,7 @@ private:
|
||||||
const GSRegEXTBUF& EXTBUF, const GSVector4& c) final;
|
const GSRegEXTBUF& EXTBUF, const GSVector4& c) final;
|
||||||
void DoInterlace(GSTexture* sTex, GSTexture* dTex, int shader, bool linear, float yoffset = 0) final;
|
void DoInterlace(GSTexture* sTex, GSTexture* dTex, int shader, bool linear, float yoffset = 0) final;
|
||||||
void DoShadeBoost(GSTexture* sTex, GSTexture* dTex, const float params[4]) final;
|
void DoShadeBoost(GSTexture* sTex, GSTexture* dTex, const float params[4]) final;
|
||||||
|
void DoFXAA(GSTexture* sTex, GSTexture* dTex) final;
|
||||||
|
|
||||||
VkSampler GetSampler(GSHWDrawConfig::SamplerSelector ss);
|
VkSampler GetSampler(GSHWDrawConfig::SamplerSelector ss);
|
||||||
void ClearSamplerCache() final;
|
void ClearSamplerCache() final;
|
||||||
|
@ -177,7 +179,7 @@ private:
|
||||||
bool CompileConvertPipelines();
|
bool CompileConvertPipelines();
|
||||||
bool CompileInterlacePipelines();
|
bool CompileInterlacePipelines();
|
||||||
bool CompileMergePipelines();
|
bool CompileMergePipelines();
|
||||||
bool CompileShadeBoostPipeline();
|
bool CompilePostProcessingPipelines();
|
||||||
|
|
||||||
bool CheckStagingBufferSize(u32 required_size);
|
bool CheckStagingBufferSize(u32 required_size);
|
||||||
void DestroyStagingBuffer();
|
void DestroyStagingBuffer();
|
||||||
|
|
|
@ -454,7 +454,7 @@ PostTab::PostTab(wxWindow* parent)
|
||||||
auto not_vk_prereq = [this] { return !m_is_vk_hw; };
|
auto not_vk_prereq = [this] { return !m_is_vk_hw; };
|
||||||
|
|
||||||
m_ui.addCheckBox(shader_box.inner, "Texture Filtering of Display", "linear_present", IDC_LINEAR_PRESENT);
|
m_ui.addCheckBox(shader_box.inner, "Texture Filtering of Display", "linear_present", IDC_LINEAR_PRESENT);
|
||||||
m_ui.addCheckBox(shader_box.inner, "FXAA Shader (PgUp)", "fxaa", IDC_FXAA, not_vk_prereq);
|
m_ui.addCheckBox(shader_box.inner, "FXAA Shader (PgUp)", "fxaa", IDC_FXAA);
|
||||||
|
|
||||||
CheckboxPrereq shade_boost_check(m_ui.addCheckBox(shader_box.inner, "Enable Shade Boost", "ShadeBoost", IDC_SHADEBOOST));
|
CheckboxPrereq shade_boost_check(m_ui.addCheckBox(shader_box.inner, "Enable Shade Boost", "ShadeBoost", IDC_SHADEBOOST));
|
||||||
|
|
||||||
|
@ -462,7 +462,7 @@ PostTab::PostTab(wxWindow* parent)
|
||||||
auto* shader_boost_grid = new wxFlexGridSizer(2, space, space);
|
auto* shader_boost_grid = new wxFlexGridSizer(2, space, space);
|
||||||
shader_boost_grid->AddGrowableCol(1);
|
shader_boost_grid->AddGrowableCol(1);
|
||||||
|
|
||||||
auto shader_boost_prereq = [shade_boost_check, this] { return !m_is_vk_hw && shade_boost_check.box->GetValue(); };
|
auto shader_boost_prereq = [shade_boost_check, this] { return shade_boost_check.box->GetValue(); };
|
||||||
m_ui.addSliderAndLabel(shader_boost_grid, "Brightness:", "ShadeBoost_Brightness", 0, 100, 50, -1, shader_boost_prereq);
|
m_ui.addSliderAndLabel(shader_boost_grid, "Brightness:", "ShadeBoost_Brightness", 0, 100, 50, -1, shader_boost_prereq);
|
||||||
m_ui.addSliderAndLabel(shader_boost_grid, "Contrast:", "ShadeBoost_Contrast", 0, 100, 50, -1, shader_boost_prereq);
|
m_ui.addSliderAndLabel(shader_boost_grid, "Contrast:", "ShadeBoost_Contrast", 0, 100, 50, -1, shader_boost_prereq);
|
||||||
m_ui.addSliderAndLabel(shader_boost_grid, "Saturation:", "ShadeBoost_Saturation", 0, 100, 50, -1, shader_boost_prereq);
|
m_ui.addSliderAndLabel(shader_boost_grid, "Saturation:", "ShadeBoost_Saturation", 0, 100, 50, -1, shader_boost_prereq);
|
||||||
|
|
Loading…
Reference in New Issue