diff options
| author | Jonathan Hamilton <jtrhamilton@gmail.com> | 2017-10-25 22:44:39 -0700 |
|---|---|---|
| committer | Jonathan Hamilton <jtrhamilton@gmail.com> | 2018-01-05 09:56:46 -0800 |
| commit | 29a9ed043bd0946497edf7c4d392ce46041b9817 (patch) | |
| tree | 3104979b668377da1499a3b4afc7ac29c557e3ce /Source/Core/VideoCommon/PixelShaderGen.cpp | |
| parent | 11976526d11f0475a3af126758260cdd69dd2a35 (diff) | |
Implement dual-source blending in shader
For some GLES drivers that don't support dual-source blending, but do
support GL_EXT_shader_framebuffer_fetch, this might be useful.
Diffstat (limited to 'Source/Core/VideoCommon/PixelShaderGen.cpp')
| -rw-r--r-- | Source/Core/VideoCommon/PixelShaderGen.cpp | 120 |
1 files changed, 118 insertions, 2 deletions
diff --git a/Source/Core/VideoCommon/PixelShaderGen.cpp b/Source/Core/VideoCommon/PixelShaderGen.cpp index 0ccfb09679..1a427b70d0 100644 --- a/Source/Core/VideoCommon/PixelShaderGen.cpp +++ b/Source/Core/VideoCommon/PixelShaderGen.cpp @@ -16,6 +16,7 @@ #include "VideoCommon/DriverDetails.h" #include "VideoCommon/LightingShaderGen.h" #include "VideoCommon/NativeVertexFormat.h" +#include "VideoCommon/RenderState.h" #include "VideoCommon/VertexLoaderManager.h" #include "VideoCommon/VideoCommon.h" #include "VideoCommon/VideoConfig.h" @@ -319,6 +320,21 @@ PixelShaderUid GetPixelShaderUid() uid_data->fog_proj = bpmem.fog.c_proj_fsel.proj; uid_data->fog_RangeBaseEnabled = bpmem.fogRange.Base.Enabled; + BlendingState state = {}; + state.Generate(bpmem); + + if (state.usedualsrc && state.dstalpha && g_ActiveConfig.backend_info.bSupportsFramebufferFetch && + !g_ActiveConfig.backend_info.bSupportsDualSourceBlend) + { + uid_data->blend_enable = state.blendenable; + uid_data->blend_src_factor = state.srcfactor; + uid_data->blend_src_factor_alpha = state.srcfactoralpha; + uid_data->blend_dst_factor = state.dstfactor; + uid_data->blend_dst_factor_alpha = state.dstfactoralpha; + uid_data->blend_subtract = state.subtract; + uid_data->blend_subtract_alpha = state.subtractAlpha; + } + return out; } @@ -447,6 +463,7 @@ static void WriteAlphaTest(ShaderCode& out, const pixel_shader_uid_data* uid_dat static void WriteFog(ShaderCode& out, const pixel_shader_uid_data* uid_data); static void WriteColor(ShaderCode& out, APIType api_type, const pixel_shader_uid_data* uid_data, bool use_dual_source); +static void WriteBlend(ShaderCode& out, const pixel_shader_uid_data* uid_data); ShaderCode GeneratePixelShaderCode(APIType ApiType, const ShaderHostConfig& host_config, const pixel_shader_uid_data* uid_data) @@ -519,6 +536,8 @@ ShaderCode GeneratePixelShaderCode(APIType ApiType, const ShaderHostConfig& host host_config.backend_dual_source_blend && (!DriverDetails::HasBug(DriverDetails::BUG_BROKEN_DUAL_SOURCE_BLENDING) || uid_data->useDstAlpha); + const bool use_shader_blend = + !use_dual_source && (uid_data->useDstAlpha && host_config.backend_shader_framebuffer_fetch); if (ApiType == APIType::OpenGL || ApiType == APIType::Vulkan) { @@ -535,6 +554,17 @@ ShaderCode GeneratePixelShaderCode(APIType ApiType, const ShaderHostConfig& host out.Write("FRAGMENT_OUTPUT_LOCATION_INDEXED(0, 1) out vec4 ocol1;\n"); } } + else if (use_shader_blend) + { + if (DriverDetails::HasBug(DriverDetails::BUG_BROKEN_FRAGMENT_SHADER_INDEX_DECORATION)) + { + out.Write("FRAGMENT_OUTPUT_LOCATION(0) FRAGMENT_INOUT vec4 ocol0;\n"); + } + else + { + out.Write("FRAGMENT_OUTPUT_LOCATION_INDEXED(0, 0) FRAGMENT_INOUT vec4 ocol0;\n"); + } + } else { out.Write("FRAGMENT_OUTPUT_LOCATION(0) out vec4 ocol0;\n"); @@ -575,6 +605,11 @@ ShaderCode GeneratePixelShaderCode(APIType ApiType, const ShaderHostConfig& host out.Write("void main()\n{\n"); out.Write("\tfloat4 rawpos = gl_FragCoord;\n"); + if (use_shader_blend) + { + // Store off a copy of the initial fb value for blending + out.Write("\tfloat4 initial_ocol0 = FB_FETCH_VALUE;\n"); + } } else // D3D { @@ -710,7 +745,8 @@ ShaderCode GeneratePixelShaderCode(APIType ApiType, const ShaderHostConfig& host // testing result) if (uid_data->Pretest == AlphaTest::UNDETERMINED || (uid_data->Pretest == AlphaTest::FAIL && uid_data->late_ztest)) - WriteAlphaTest(out, uid_data, ApiType, uid_data->per_pixel_depth, use_dual_source); + WriteAlphaTest(out, uid_data, ApiType, uid_data->per_pixel_depth, + use_dual_source || use_shader_blend); if (uid_data->zfreeze) { @@ -793,7 +829,11 @@ ShaderCode GeneratePixelShaderCode(APIType ApiType, const ShaderHostConfig& host WriteFog(out, uid_data); // Write the color and alpha values to the framebuffer - WriteColor(out, ApiType, uid_data, use_dual_source); + // If using shader blend, we still use the separate alpha + WriteColor(out, ApiType, uid_data, use_dual_source || use_shader_blend); + + if (use_shader_blend) + WriteBlend(out, uid_data); if (uid_data->bounding_box) { @@ -1358,3 +1398,79 @@ static void WriteColor(ShaderCode& out, APIType api_type, const pixel_shader_uid } } } + +static void WriteBlend(ShaderCode& out, const pixel_shader_uid_data* uid_data) +{ + if (uid_data->blend_enable) + { + static const std::array<const char*, 8> blendSrcFactor = { + "float3(0,0,0);", // ZERO + "float3(1,1,1);", // ONE + "initial_ocol0.rgb;", // DSTCLR + "float3(1,1,1) - initial_ocol0.rgb;", // INVDSTCLR + "ocol1.aaa;", // SRCALPHA + "float3(1,1,1) - ocol1.aaa;", // INVSRCALPHA + "initial_ocol0.aaa;", // DSTALPHA + "float3(1,1,1) - initial_ocol0.aaa;", // INVDSTALPHA + }; + static const std::array<const char*, 8> blendSrcFactorAlpha = { + "0.0;", // ZERO + "1.0;", // ONE + "initial_ocol0.a;", // DSTCLR + "1.0 - initial_ocol0.a;", // INVDSTCLR + "ocol1.a;", // SRCALPHA + "1.0 - ocol1.a;", // INVSRCALPHA + "initial_ocol0.a;", // DSTALPHA + "1.0 - initial_ocol0.a;", // INVDSTALPHA + }; + static const std::array<const char*, 8> blendDstFactor = { + "float3(0,0,0);", // ZERO + "float3(1,1,1);", // ONE + "ocol0.rgb;", // SRCCLR + "float3(1,1,1) - ocol0.rgb;", // INVSRCCLR + "ocol1.aaa;", // SRCALHA + "float3(1,1,1) - ocol1.aaa;", // INVSRCALPHA + "initial_ocol0.aaa;", // DSTALPHA + "float3(1,1,1) - initial_ocol0.aaa;", // INVDSTALPHA + }; + static const std::array<const char*, 8> blendDstFactorAlpha = { + "0.0;", // ZERO + "1.0;", // ONE + "ocol0.a;", // SRCCLR + "1.0 - ocol0.a;", // INVSRCCLR + "ocol1.a;", // SRCALPHA + "1.0 - ocol1.a;", // INVSRCALPHA + "initial_ocol0.a;", // DSTALPHA + "1.0 - initial_ocol0.a;", // INVDSTALPHA + }; + out.Write("\tfloat4 blend_src;\n"); + out.Write("\tblend_src.rgb = %s\n", blendSrcFactor[uid_data->blend_src_factor]); + out.Write("\tblend_src.a = %s\n", blendSrcFactorAlpha[uid_data->blend_src_factor_alpha]); + out.Write("\tfloat4 blend_dst;\n"); + out.Write("\tblend_dst.rgb = %s\n", blendDstFactor[uid_data->blend_dst_factor]); + out.Write("\tblend_dst.a = %s\n", blendDstFactorAlpha[uid_data->blend_dst_factor_alpha]); + + out.Write("\tfloat4 blend_result;\n"); + if (uid_data->blend_subtract) + { + out.Write("\tblend_result.rgb = initial_ocol0.rgb * blend_dst.rgb - ocol0.rgb * " + "blend_src.rgb;\n"); + } + else + { + out.Write( + "\tblend_result.rgb = initial_ocol0.rgb * blend_dst.rgb + ocol0.rgb * blend_src.rgb;\n"); + } + + if (uid_data->blend_subtract_alpha) + out.Write("\tblend_result.a = initial_ocol0.a * blend_dst.a - ocol0.a * blend_src.a;\n"); + else + out.Write("\tblend_result.a = initial_ocol0.a * blend_dst.a + ocol0.a * blend_src.a;\n"); + } + else + { + out.Write("\tfloat4 blend_result = ocol0;\n"); + } + + out.Write("\tocol0 = blend_result;\n"); +} |
