diff options
| author | Stenzek <stenzek@gmail.com> | 2019-08-02 19:20:36 +1000 |
|---|---|---|
| committer | Stenzek <stenzek@gmail.com> | 2019-08-04 14:06:08 +1000 |
| commit | f6f9dc0cacb0dcbbd09d31acbb6e3a3ece764541 (patch) | |
| tree | 049bab9cb6e1b2f22627c3820e44c5b6098e49b2 /Source/Core | |
| parent | 4ccb4ef74fc8fd88b8fc62a2ec05ddb3fc84a94e (diff) | |
RenderState: Approximate logic op with blending if unsupported
This is a giant hack which was previously removed because it causes
broken rendering. However, it seems that some devices still do not
support logical operations (looking at you, Adreno/Mali). Therefore, for
a handful of cases where the hack actually makes things slightly better,
we can use it.
... but not without spamming the log with warnings. With my warning
message PR, we can inform the users before emulation starts anyway.
Diffstat (limited to 'Source/Core')
| -rw-r--r-- | Source/Core/VideoCommon/RenderState.cpp | 36 | ||||
| -rw-r--r-- | Source/Core/VideoCommon/RenderState.h | 4 | ||||
| -rw-r--r-- | Source/Core/VideoCommon/ShaderCache.cpp | 7 |
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; } |
