Merge pull request #16024 from unknownbrackets/logicop-simulate
GPU: Fix simulating logicop with blend and shader
This commit is contained in:
commit
cf2ad5ceaf
3 changed files with 27 additions and 13 deletions
|
@ -1081,7 +1081,7 @@ bool FramebufferManagerCommon::BindFramebufferAsColorTexture(int stage, VirtualF
|
|||
|
||||
// currentRenderVfb_ will always be set when this is called, except from the GE debugger.
|
||||
// Let's just not bother with the copy in that case.
|
||||
bool skipCopy = !(flags & BINDFBCOLOR_MAY_COPY) || GPUStepping::IsStepping();
|
||||
bool skipCopy = !(flags & BINDFBCOLOR_MAY_COPY);
|
||||
|
||||
// Currently rendering to this framebuffer. Need to make a copy.
|
||||
if (!skipCopy && framebuffer == currentRenderVfb_) {
|
||||
|
|
|
@ -856,7 +856,7 @@ static inline bool blendColorSimilar(uint32_t a, uint32_t b, int margin = 25) {
|
|||
// Try to simulate some common logic ops by using blend, if needed.
|
||||
// The shader might also need modification, the below function SimulateLogicOpShaderTypeIfNeeded
|
||||
// takes care of that.
|
||||
static void SimulateLogicOpIfNeeded(BlendFactor &srcBlend, BlendFactor &dstBlend, BlendEq &blendEq) {
|
||||
static bool SimulateLogicOpIfNeeded(BlendFactor &srcBlend, BlendFactor &dstBlend, BlendEq &blendEq) {
|
||||
// Note: our shader solution applies logic ops BEFORE blending, not correctly after.
|
||||
// This is however fine for the most common ones, like CLEAR/NOOP/SET, etc.
|
||||
if (!gstate_c.Supports(GPU_SUPPORTS_LOGIC_OP)) {
|
||||
|
@ -866,7 +866,7 @@ static void SimulateLogicOpIfNeeded(BlendFactor &srcBlend, BlendFactor &dstBlend
|
|||
srcBlend = BlendFactor::ZERO;
|
||||
dstBlend = BlendFactor::ZERO;
|
||||
blendEq = BlendEq::ADD;
|
||||
break;
|
||||
return true;
|
||||
case GE_LOGIC_AND:
|
||||
case GE_LOGIC_AND_REVERSE:
|
||||
WARN_LOG_REPORT_ONCE(d3dLogicOpAnd, G3D, "Unsupported AND logic op: %x", gstate.getLogicOp());
|
||||
|
@ -889,21 +889,23 @@ static void SimulateLogicOpIfNeeded(BlendFactor &srcBlend, BlendFactor &dstBlend
|
|||
dstBlend = BlendFactor::ONE;
|
||||
blendEq = BlendEq::SUBTRACT;
|
||||
WARN_LOG_REPORT_ONCE(d3dLogicOpInverted, G3D, "Attempted inverse for logic op: %x", gstate.getLogicOp());
|
||||
break;
|
||||
return true;
|
||||
case GE_LOGIC_NOOP:
|
||||
srcBlend = BlendFactor::ZERO;
|
||||
dstBlend = BlendFactor::ONE;
|
||||
blendEq = BlendEq::ADD;
|
||||
break;
|
||||
return true;
|
||||
case GE_LOGIC_XOR:
|
||||
WARN_LOG_REPORT_ONCE(d3dLogicOpOrXor, G3D, "Unsupported XOR logic op: %x", gstate.getLogicOp());
|
||||
break;
|
||||
case GE_LOGIC_OR:
|
||||
case GE_LOGIC_OR_INVERTED:
|
||||
// Inverted in shader.
|
||||
srcBlend = BlendFactor::ONE;
|
||||
dstBlend = BlendFactor::ONE;
|
||||
blendEq = BlendEq::ADD;
|
||||
WARN_LOG_REPORT_ONCE(d3dLogicOpOr, G3D, "Attempted or for logic op: %x", gstate.getLogicOp());
|
||||
break;
|
||||
return true;
|
||||
case GE_LOGIC_OR_REVERSE:
|
||||
WARN_LOG_REPORT_ONCE(d3dLogicOpOrReverse, G3D, "Unsupported OR REVERSE logic op: %x", gstate.getLogicOp());
|
||||
break;
|
||||
|
@ -912,10 +914,12 @@ static void SimulateLogicOpIfNeeded(BlendFactor &srcBlend, BlendFactor &dstBlend
|
|||
dstBlend = BlendFactor::ONE;
|
||||
blendEq = BlendEq::ADD;
|
||||
WARN_LOG_REPORT_ONCE(d3dLogicOpSet, G3D, "Attempted set for logic op: %x", gstate.getLogicOp());
|
||||
break;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Choose the shader part of the above logic op fallback simulation.
|
||||
|
@ -950,7 +954,6 @@ void ApplyStencilReplaceAndLogicOpIgnoreBlend(ReplaceAlphaType replaceAlphaWithS
|
|||
BlendFactor srcBlend = BlendFactor::ONE;
|
||||
BlendFactor dstBlend = BlendFactor::ZERO;
|
||||
BlendEq blendEq = BlendEq::ADD;
|
||||
SimulateLogicOpIfNeeded(srcBlend, dstBlend, blendEq);
|
||||
|
||||
// We're not blending, but we may still want to "blend" for stencil.
|
||||
// This is only useful for INCR/DECR/INVERT. Others can write directly.
|
||||
|
@ -1252,11 +1255,6 @@ static void ConvertBlendState(GenericBlendState &blendState, bool forceReplaceBl
|
|||
colorEq = eqLookupNoMinMax[blendFuncEq];
|
||||
}
|
||||
|
||||
// Attempt to apply simulated logic ops, if any and if needed.
|
||||
if (!forceReplaceBlend) {
|
||||
SimulateLogicOpIfNeeded(glBlendFuncA, glBlendFuncB, colorEq);
|
||||
}
|
||||
|
||||
// The stencil-to-alpha in fragment shader doesn't apply here (blending is enabled), and we shouldn't
|
||||
// do any blending in the alpha channel as that doesn't seem to happen on PSP. So, we attempt to
|
||||
// apply the stencil to the alpha, since that's what should be stored.
|
||||
|
@ -1581,5 +1579,20 @@ void ComputedPipelineState::Convert(bool shaderBitOpsSuppported) {
|
|||
if (blendState.applyFramebufferRead || logicState.applyFramebufferRead) {
|
||||
maskState.ConvertToShaderBlend();
|
||||
logicState.ConvertToShaderBlend();
|
||||
} else {
|
||||
// If it isn't a read, we may need to change blending to apply the logic op.
|
||||
logicState.ApplyToBlendState(blendState);
|
||||
}
|
||||
}
|
||||
|
||||
void GenericLogicState::ApplyToBlendState(GenericBlendState &blendState) {
|
||||
if (SimulateLogicOpIfNeeded(blendState.srcColor, blendState.dstColor, blendState.eqColor)) {
|
||||
if (!blendState.blendEnabled) {
|
||||
// If it wasn't turned on, make sure it is now.
|
||||
blendState.blendEnabled = true;
|
||||
blendState.srcAlpha = BlendFactor::ONE;
|
||||
blendState.dstAlpha = BlendFactor::ZERO;
|
||||
blendState.eqAlpha = BlendEq::ADD;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -226,6 +226,7 @@ struct GenericLogicState {
|
|||
// Hardware and shader generation
|
||||
GELogicOp logicOp;
|
||||
|
||||
void ApplyToBlendState(GenericBlendState &blendState);
|
||||
void ConvertToShaderBlend() {
|
||||
if (logicOp != GE_LOGIC_COPY) {
|
||||
logicOpEnabled = false;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue