VideoCommon: Always use fbfetch in ubershaders if available

Reduce the number of different pipelines needed.  Also works around drivers that break when you combine fbfetch with dual source blending
This commit is contained in:
TellowKrinkle
2022-06-12 21:27:11 -05:00
parent 6ab24e6c17
commit 991024173e
2 changed files with 30 additions and 29 deletions

View File

@ -743,9 +743,17 @@ static GXUberPipelineUid ApplyDriverBugs(const GXUberPipelineUid& in)
{ {
GXUberPipelineUid out; GXUberPipelineUid out;
memcpy(&out, &in, sizeof(out)); // Copy padding memcpy(&out, &in, sizeof(out)); // Copy padding
if (!g_ActiveConfig.backend_info.bSupportsDualSourceBlend || if (g_ActiveConfig.backend_info.bSupportsFramebufferFetch)
(DriverDetails::HasBug(DriverDetails::BUG_BROKEN_DUAL_SOURCE_BLENDING) && {
!out.blending_state.RequiresDualSrc())) // Always blend in shader
out.blending_state.hex = 0;
out.blending_state.colorupdate = in.blending_state.colorupdate.Value();
out.blending_state.alphaupdate = in.blending_state.alphaupdate.Value();
out.ps_uid.GetUidData()->no_dual_src = true;
}
else if (!g_ActiveConfig.backend_info.bSupportsDualSourceBlend ||
(DriverDetails::HasBug(DriverDetails::BUG_BROKEN_DUAL_SOURCE_BLENDING) &&
!out.blending_state.RequiresDualSrc()))
{ {
out.blending_state.usedualsrc = false; out.blending_state.usedualsrc = false;
out.ps_uid.GetUidData()->no_dual_src = true; out.ps_uid.GetUidData()->no_dual_src = true;

View File

@ -3,6 +3,8 @@
#include "VideoCommon/UberShaderPixel.h" #include "VideoCommon/UberShaderPixel.h"
#include "Common/Assert.h"
#include "VideoCommon/BPMemory.h" #include "VideoCommon/BPMemory.h"
#include "VideoCommon/DriverDetails.h" #include "VideoCommon/DriverDetails.h"
#include "VideoCommon/NativeVertexFormat.h" #include "VideoCommon/NativeVertexFormat.h"
@ -39,8 +41,11 @@ void ClearUnusedPixelShaderUidBits(APIType api_type, const ShaderHostConfig& hos
{ {
pixel_ubershader_uid_data* const uid_data = uid->GetUidData(); pixel_ubershader_uid_data* const uid_data = uid->GetUidData();
// With fbfetch, ubershaders always blend using that and don't use dual src
if (host_config.backend_shader_framebuffer_fetch || !host_config.backend_dual_source_blend)
uid_data->no_dual_src = 1;
// Dual source is always enabled in the shader if this bug is not present // Dual source is always enabled in the shader if this bug is not present
if (!DriverDetails::HasBug(DriverDetails::BUG_BROKEN_DUAL_SOURCE_BLENDING)) else if (!DriverDetails::HasBug(DriverDetails::BUG_BROKEN_DUAL_SOURCE_BLENDING))
uid_data->no_dual_src = 0; uid_data->no_dual_src = 0;
// OpenGL and Vulkan convert implicitly normalized color outputs to their uint representation. // OpenGL and Vulkan convert implicitly normalized color outputs to their uint representation.
@ -57,20 +62,17 @@ ShaderCode GenPixelShader(APIType api_type, const ShaderHostConfig& host_config,
const bool msaa = host_config.msaa; const bool msaa = host_config.msaa;
const bool ssaa = host_config.ssaa; const bool ssaa = host_config.ssaa;
const bool stereo = host_config.stereo; const bool stereo = host_config.stereo;
const bool use_framebuffer_fetch = host_config.backend_shader_framebuffer_fetch;
const bool use_dual_source = host_config.backend_dual_source_blend && !uid_data->no_dual_src; const bool use_dual_source = host_config.backend_dual_source_blend && !uid_data->no_dual_src;
const bool use_shader_blend = !host_config.backend_dual_source_blend &&
host_config.backend_shader_framebuffer_fetch;
const bool use_shader_logic_op =
!host_config.backend_logic_op && host_config.backend_shader_framebuffer_fetch;
const bool use_framebuffer_fetch =
use_shader_blend || use_shader_logic_op ||
DriverDetails::HasBug(DriverDetails::BUG_BROKEN_DISCARD_WITH_EARLY_Z);
const bool early_depth = uid_data->early_depth != 0; const bool early_depth = uid_data->early_depth != 0;
const bool per_pixel_depth = uid_data->per_pixel_depth != 0; const bool per_pixel_depth = uid_data->per_pixel_depth != 0;
const bool bounding_box = host_config.bounding_box; const bool bounding_box = host_config.bounding_box;
const u32 numTexgen = uid_data->num_texgens; const u32 numTexgen = uid_data->num_texgens;
ShaderCode out; ShaderCode out;
ASSERT_MSG(VIDEO, !(use_dual_source && use_framebuffer_fetch),
"If you're using framebuffer fetch, you shouldn't need dual source blend!");
out.Write("// {}\n", *uid_data); out.Write("// {}\n", *uid_data);
WriteBitfieldExtractHeader(out, api_type, host_config); WriteBitfieldExtractHeader(out, api_type, host_config);
WritePixelShaderCommonHeader(out, api_type, host_config, bounding_box); WritePixelShaderCommonHeader(out, api_type, host_config, bounding_box);
@ -84,9 +86,8 @@ ShaderCode GenPixelShader(APIType api_type, const ShaderHostConfig& host_config,
{ {
if (use_dual_source) if (use_dual_source)
{ {
out.Write("FRAGMENT_OUTPUT_LOCATION_INDEXED(0, 0) out vec4 {};\n" out.Write("FRAGMENT_OUTPUT_LOCATION_INDEXED(0, 0) out vec4 ocol0;\n"
"FRAGMENT_OUTPUT_LOCATION_INDEXED(0, 1) out vec4 ocol1;\n", "FRAGMENT_OUTPUT_LOCATION_INDEXED(0, 1) out vec4 ocol1;\n");
use_framebuffer_fetch ? "real_ocol0" : "ocol0");
} }
else else
{ {
@ -525,12 +526,8 @@ ShaderCode GenPixelShader(APIType api_type, const ShaderHostConfig& host_config,
// intermediate value with multiple reads & modifications, so we pull out the "real" output // intermediate value with multiple reads & modifications, so we pull out the "real" output
// value above and use a temporary for calculations, then set the output value once at the // value above and use a temporary for calculations, then set the output value once at the
// end of the shader. // end of the shader.
out.Write(" float4 ocol0;\n"); out.Write(" float4 ocol0;\n"
} " float4 ocol1;\n");
if (use_shader_blend)
{
out.Write(" float4 ocol1;\n");
} }
if (host_config.backend_geometry_shaders && stereo) if (host_config.backend_geometry_shaders && stereo)
@ -948,8 +945,8 @@ ShaderCode GenPixelShader(APIType api_type, const ShaderHostConfig& host_config,
{ {
// Instead of using discard, fetch the framebuffer's color value and use it as the output // Instead of using discard, fetch the framebuffer's color value and use it as the output
// for this fragment. // for this fragment.
out.Write(" #define discard_fragment {{ {} = float4(initial_ocol0.xyz, 1.0); return; }}\n", out.Write(
use_shader_blend ? "real_ocol0" : "ocol0"); " #define discard_fragment {{ real_ocol0 = float4(initial_ocol0.xyz, 1.0); return; }}\n");
} }
else else
{ {
@ -1060,7 +1057,7 @@ ShaderCode GenPixelShader(APIType api_type, const ShaderHostConfig& host_config,
" }}\n" " }}\n"
"\n"); "\n");
if (use_shader_logic_op) if (use_framebuffer_fetch)
{ {
static constexpr std::array<const char*, 16> logic_op_mode{ static constexpr std::array<const char*, 16> logic_op_mode{
"int4(0, 0, 0, 0)", // CLEAR "int4(0, 0, 0, 0)", // CLEAR
@ -1117,7 +1114,7 @@ ShaderCode GenPixelShader(APIType api_type, const ShaderHostConfig& host_config,
" ocol0.a = float(TevResult.a >> 2) / 63.0;\n" " ocol0.a = float(TevResult.a >> 2) / 63.0;\n"
" \n"); " \n");
if (use_dual_source || use_shader_blend) if (use_dual_source || use_framebuffer_fetch)
{ {
out.Write(" // Dest alpha override (dual source blending)\n" out.Write(" // Dest alpha override (dual source blending)\n"
" // Colors will be blended against the alpha from ocol1 and\n" " // Colors will be blended against the alpha from ocol1 and\n"
@ -1133,7 +1130,7 @@ ShaderCode GenPixelShader(APIType api_type, const ShaderHostConfig& host_config,
" }}\n"); " }}\n");
} }
if (use_shader_blend) if (use_framebuffer_fetch)
{ {
using Common::EnumMap; using Common::EnumMap;
@ -1212,10 +1209,6 @@ ShaderCode GenPixelShader(APIType api_type, const ShaderHostConfig& host_config,
" real_ocol0 = ocol0;\n" " real_ocol0 = ocol0;\n"
" }}\n"); " }}\n");
} }
else if (use_framebuffer_fetch)
{
out.Write(" real_ocol0 = ocol0;\n");
}
out.Write("}}\n" out.Write("}}\n"
"\n" "\n"