summaryrefslogtreecommitdiff
path: root/Source/Core
diff options
context:
space:
mode:
Diffstat (limited to 'Source/Core')
-rw-r--r--Source/Core/VideoCommon/RenderState.cpp36
-rw-r--r--Source/Core/VideoCommon/RenderState.h4
-rw-r--r--Source/Core/VideoCommon/ShaderCache.cpp7
3 files changed, 47 insertions, 0 deletions
diff --git a/Source/Core/VideoCommon/RenderState.cpp b/Source/Core/VideoCommon/RenderState.cpp
index 04d8804f0c..6d6f892979 100644
--- a/Source/Core/VideoCommon/RenderState.cpp
+++ b/Source/Core/VideoCommon/RenderState.cpp
@@ -167,6 +167,42 @@ void BlendingState::Generate(const BPMemory& bp)
}
}
+void BlendingState::ApproximateLogicOpWithBlending()
+{
+ // Any of these which use SRC as srcFactor or DST as dstFactor won't be correct.
+ // This is because the two are aliased to one another (see the enum).
+ struct LogicOpApproximation
+ {
+ bool subtract;
+ BlendMode::BlendFactor srcfactor;
+ BlendMode::BlendFactor dstfactor;
+ };
+ static constexpr std::array<LogicOpApproximation, 16> approximations = {{
+ {false, BlendMode::ZERO, BlendMode::ZERO}, // CLEAR
+ {false, BlendMode::DSTCLR, BlendMode::ZERO}, // AND
+ {true, BlendMode::ONE, BlendMode::INVSRCCLR}, // AND_REVERSE
+ {false, BlendMode::ONE, BlendMode::ZERO}, // COPY
+ {true, BlendMode::DSTCLR, BlendMode::ONE}, // AND_INVERTED
+ {false, BlendMode::ZERO, BlendMode::ONE}, // NOOP
+ {false, BlendMode::INVDSTCLR, BlendMode::INVSRCCLR}, // XOR
+ {false, BlendMode::INVDSTCLR, BlendMode::ONE}, // OR
+ {false, BlendMode::INVSRCCLR, BlendMode::INVDSTCLR}, // NOR
+ {false, BlendMode::INVSRCCLR, BlendMode::ZERO}, // EQUIV
+ {false, BlendMode::INVDSTCLR, BlendMode::INVDSTCLR}, // INVERT
+ {false, BlendMode::ONE, BlendMode::INVDSTALPHA}, // OR_REVERSE
+ {false, BlendMode::INVSRCCLR, BlendMode::INVSRCCLR}, // COPY_INVERTED
+ {false, BlendMode::INVSRCCLR, BlendMode::ONE}, // OR_INVERTED
+ {false, BlendMode::INVDSTCLR, BlendMode::INVSRCCLR}, // NAND
+ {false, BlendMode::ONE, BlendMode::ONE}, // SET
+ }};
+
+ logicopenable = false;
+ blendenable = true;
+ subtract = approximations[logicmode].subtract;
+ srcfactor = approximations[logicmode].srcfactor;
+ dstfactor = approximations[logicmode].dstfactor;
+}
+
BlendingState& BlendingState::operator=(const BlendingState& rhs)
{
hex = rhs.hex;
diff --git a/Source/Core/VideoCommon/RenderState.h b/Source/Core/VideoCommon/RenderState.h
index dc0676ccc4..f5bf085d72 100644
--- a/Source/Core/VideoCommon/RenderState.h
+++ b/Source/Core/VideoCommon/RenderState.h
@@ -68,6 +68,10 @@ union BlendingState
{
void Generate(const BPMemory& bp);
+ // HACK: Replaces logical operations with blend operations.
+ // Will not be bit-correct, and in some cases not even remotely in the same ballpark.
+ void ApproximateLogicOpWithBlending();
+
BlendingState& operator=(const BlendingState& rhs);
bool operator==(const BlendingState& rhs) const { return hex == rhs.hex; }
diff --git a/Source/Core/VideoCommon/ShaderCache.cpp b/Source/Core/VideoCommon/ShaderCache.cpp
index 3d4f286b68..e3066520fb 100644
--- a/Source/Core/VideoCommon/ShaderCache.cpp
+++ b/Source/Core/VideoCommon/ShaderCache.cpp
@@ -558,6 +558,13 @@ AbstractPipelineConfig ShaderCache::GetGXPipelineConfig(
config.depth_state = depth_state;
config.blending_state = blending_state;
config.framebuffer_state = g_framebuffer_manager->GetEFBFramebufferState();
+
+ if (config.blending_state.logicopenable && !g_ActiveConfig.backend_info.bSupportsLogicOp)
+ {
+ WARN_LOG(VIDEO, "Approximating logic op with blending, this will produce incorrect rendering.");
+ config.blending_state.ApproximateLogicOpWithBlending();
+ }
+
return config;
}