GS/Vulkan: Implement shadeboost

This commit is contained in:
Connor McLaughlin 2022-03-27 04:16:46 +10:00 committed by lightningterror
parent 5e336138d0
commit 486764be03
4 changed files with 150 additions and 7 deletions

View File

@ -0,0 +1,71 @@
//#version 420 // Keep it for editor detection
#ifdef VERTEX_SHADER
layout(location = 0) in vec4 a_pos;
layout(location = 1) in vec2 a_tex;
layout(location = 0) out vec2 v_tex;
void main()
{
gl_Position = vec4(a_pos.x, -a_pos.y, a_pos.z, a_pos.w);
v_tex = a_tex;
}
#endif
/*
** Contrast, saturation, brightness
** Code of this function is from TGM's shader pack
** http://irrlicht.sourceforge.net/phpBB2/viewtopic.php?t=21057
** TGM's author comment about the license (included in the previous link)
** "do with it, what you want! its total free!
** (but would be nice, if you say that you used my shaders :wink: ) but not necessary"
*/
#ifdef FRAGMENT_SHADER
layout(push_constant) uniform cb0
{
vec4 params;
};
layout(set = 0, binding = 0) uniform sampler2D samp0;
layout(location = 0) in vec2 v_tex;
layout(location = 0) out vec4 o_col0;
// For all settings: 1.0 = 100% 0.5=50% 1.5 = 150%
vec4 ContrastSaturationBrightness(vec4 color)
{
float brt = params.x;
float con = params.y;
float sat = params.z;
// Increase or decrease these values to adjust r, g and b color channels separately
const float AvgLumR = 0.5;
const float AvgLumG = 0.5;
const float AvgLumB = 0.5;
const vec3 LumCoeff = vec3(0.2125, 0.7154, 0.0721);
vec3 AvgLumin = vec3(AvgLumR, AvgLumG, AvgLumB);
vec3 brtColor = color.rgb * brt;
float dot_intensity = dot(brtColor, LumCoeff);
vec3 intensity = vec3(dot_intensity, dot_intensity, dot_intensity);
vec3 satColor = mix(intensity, brtColor, sat);
vec3 conColor = mix(AvgLumin, satColor, con);
color.rgb = conColor;
return color;
}
void main()
{
vec4 c = texture(samp0, v_tex);
o_col0 = ContrastSaturationBrightness(c);
}
#endif

View File

@ -120,7 +120,8 @@ bool GSDeviceVK::Create(HostDisplay* display)
if (!CreateBuffers())
return false;
if (!CompileConvertPipelines() || !CompileInterlacePipelines() || !CompileMergePipelines())
if (!CompileConvertPipelines() || !CompileInterlacePipelines() ||
!CompileMergePipelines() || !CompileShadeBoostPipeline())
{
Host::ReportErrorAsync("GS", "Failed to compile utility pipelines");
return false;
@ -147,9 +148,15 @@ void GSDeviceVK::Destroy()
GSDevice::Destroy();
}
void GSDeviceVK::ResetAPIState() { EndRenderPass(); }
void GSDeviceVK::ResetAPIState()
{
EndRenderPass();
}
void GSDeviceVK::RestoreAPIState() { InvalidateCachedState(); }
void GSDeviceVK::RestoreAPIState()
{
InvalidateCachedState();
}
#ifdef ENABLE_OGL_DEBUG
static std::array<float, 3> Palette(float phase, const std::array<float, 3>& a, const std::array<float, 3>& b,
@ -860,6 +867,22 @@ void GSDeviceVK::DoInterlace(GSTexture* sTex, GSTexture* dTex, int shader, bool
static_cast<GSTextureVK*>(dTex)->TransitionToLayout(VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
}
void GSDeviceVK::DoShadeBoost(GSTexture* sTex, GSTexture* dTex, const float params[4])
{
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_point_sampler);
BeginRenderPass(m_utility_color_render_pass_discard, dRect);
SetPipeline(m_shadeboost_pipeline);
SetUtilityPushConstants(params, sizeof(float) * 4);
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)
{
const u32 size = static_cast<u32>(stride) * static_cast<u32>(count);
@ -1603,6 +1626,53 @@ bool GSDeviceVK::CompileMergePipelines()
return true;
}
bool GSDeviceVK::CompileShadeBoostPipeline()
{
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(
LookupNativeFormat(GSTexture::Format::Color), VK_FORMAT_UNDEFINED, VK_ATTACHMENT_LOAD_OP_LOAD);
if (!rp)
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;
AddUtilityVertexAttributes(gpb);
gpb.SetPipelineLayout(m_utility_pipeline_layout);
gpb.SetDynamicViewportAndScissorState();
gpb.AddDynamicState(VK_DYNAMIC_STATE_BLEND_CONSTANTS);
gpb.SetNoCullRasterizationState();
gpb.SetNoDepthTestState();
gpb.SetNoBlendingState();
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
if (m_features.provoking_vertex_last)
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)
return false;
Vulkan::Util::SetObjectName(g_vulkan_context->GetDevice(), m_shadeboost_pipeline, "Shadeboost pipeline");
return true;
}
bool GSDeviceVK::CheckStagingBufferSize(u32 required_size)
{
if (m_readback_staging_buffer_size >= required_size)
@ -1685,6 +1755,8 @@ void GSDeviceVK::DestroyResources()
Vulkan::Util::SafeDestroyPipeline(m_date_image_setup_pipelines[ds][datm]);
}
}
Vulkan::Util::SafeDestroyPipeline(m_shadeboost_pipeline);
for (auto& it : m_samplers)
Vulkan::Util::SafeDestroySampler(it.second);

View File

@ -124,6 +124,7 @@ private:
VkPipeline m_hdr_finish_pipelines[2][2] = {}; // [depth][feedback_loop]
VkRenderPass m_date_image_setup_render_passes[2][2] = {}; // [depth][clear]
VkPipeline m_date_image_setup_pipelines[2][2] = {}; // [depth][datm]
VkPipeline m_shadeboost_pipeline = {};
std::unordered_map<u32, VkShaderModule> m_tfx_vertex_shaders;
std::unordered_map<u32, VkShaderModule> m_tfx_geometry_shaders;
@ -153,6 +154,7 @@ private:
void DoMerge(GSTexture* sTex[3], GSVector4* sRect, GSTexture* dTex, GSVector4* dRect, const GSRegPMODE& PMODE,
const GSRegEXTBUF& EXTBUF, const GSVector4& c) 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;
VkSampler GetSampler(GSHWDrawConfig::SamplerSelector ss);
void ClearSamplerCache() final;
@ -175,6 +177,7 @@ private:
bool CompileConvertPipelines();
bool CompileInterlacePipelines();
bool CompileMergePipelines();
bool CompileShadeBoostPipeline();
bool CheckStagingBufferSize(u32 required_size);
void DestroyStagingBuffer();
@ -218,9 +221,6 @@ public:
bool DownloadTexture(GSTexture* src, const GSVector4i& rect, GSTexture::GSMap& out_map) override;
void DownloadTextureComplete() override;
GSTexture* DrawForReadback(GSTexture* src, const GSVector4& sRect, int w, int h, int format = 0, int ps_shader = 0);
bool ReadbackTexture(GSTexture* src, const GSVector4i& rect, u32 level, GSTexture::GSMap* dst);
void CopyRect(GSTexture* sTex, GSTexture* dTex, const GSVector4i& r) override;
void DoCopyRect(GSTexture* sTex, GSTexture* dTex, const GSVector4i& r, const GSVector4i& dst_rc);

View File

@ -456,7 +456,7 @@ PostTab::PostTab(wxWindow* parent)
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);
CheckboxPrereq shade_boost_check(m_ui.addCheckBox(shader_box.inner, "Enable Shade Boost", "ShadeBoost", IDC_SHADEBOOST, not_vk_prereq));
CheckboxPrereq shade_boost_check(m_ui.addCheckBox(shader_box.inner, "Enable Shade Boost", "ShadeBoost", IDC_SHADEBOOST));
PaddedBoxSizer<wxStaticBoxSizer> shade_boost_box(wxVERTICAL, this, "Shade Boost");
auto* shader_boost_grid = new wxFlexGridSizer(2, space, space);