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.
|
// 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.
|
// 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.
|
// Currently rendering to this framebuffer. Need to make a copy.
|
||||||
if (!skipCopy && framebuffer == currentRenderVfb_) {
|
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.
|
// Try to simulate some common logic ops by using blend, if needed.
|
||||||
// The shader might also need modification, the below function SimulateLogicOpShaderTypeIfNeeded
|
// The shader might also need modification, the below function SimulateLogicOpShaderTypeIfNeeded
|
||||||
// takes care of that.
|
// 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.
|
// 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.
|
// This is however fine for the most common ones, like CLEAR/NOOP/SET, etc.
|
||||||
if (!gstate_c.Supports(GPU_SUPPORTS_LOGIC_OP)) {
|
if (!gstate_c.Supports(GPU_SUPPORTS_LOGIC_OP)) {
|
||||||
|
@ -866,7 +866,7 @@ static void SimulateLogicOpIfNeeded(BlendFactor &srcBlend, BlendFactor &dstBlend
|
||||||
srcBlend = BlendFactor::ZERO;
|
srcBlend = BlendFactor::ZERO;
|
||||||
dstBlend = BlendFactor::ZERO;
|
dstBlend = BlendFactor::ZERO;
|
||||||
blendEq = BlendEq::ADD;
|
blendEq = BlendEq::ADD;
|
||||||
break;
|
return true;
|
||||||
case GE_LOGIC_AND:
|
case GE_LOGIC_AND:
|
||||||
case GE_LOGIC_AND_REVERSE:
|
case GE_LOGIC_AND_REVERSE:
|
||||||
WARN_LOG_REPORT_ONCE(d3dLogicOpAnd, G3D, "Unsupported AND logic op: %x", gstate.getLogicOp());
|
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;
|
dstBlend = BlendFactor::ONE;
|
||||||
blendEq = BlendEq::SUBTRACT;
|
blendEq = BlendEq::SUBTRACT;
|
||||||
WARN_LOG_REPORT_ONCE(d3dLogicOpInverted, G3D, "Attempted inverse for logic op: %x", gstate.getLogicOp());
|
WARN_LOG_REPORT_ONCE(d3dLogicOpInverted, G3D, "Attempted inverse for logic op: %x", gstate.getLogicOp());
|
||||||
break;
|
return true;
|
||||||
case GE_LOGIC_NOOP:
|
case GE_LOGIC_NOOP:
|
||||||
srcBlend = BlendFactor::ZERO;
|
srcBlend = BlendFactor::ZERO;
|
||||||
dstBlend = BlendFactor::ONE;
|
dstBlend = BlendFactor::ONE;
|
||||||
blendEq = BlendEq::ADD;
|
blendEq = BlendEq::ADD;
|
||||||
break;
|
return true;
|
||||||
case GE_LOGIC_XOR:
|
case GE_LOGIC_XOR:
|
||||||
WARN_LOG_REPORT_ONCE(d3dLogicOpOrXor, G3D, "Unsupported XOR logic op: %x", gstate.getLogicOp());
|
WARN_LOG_REPORT_ONCE(d3dLogicOpOrXor, G3D, "Unsupported XOR logic op: %x", gstate.getLogicOp());
|
||||||
break;
|
break;
|
||||||
case GE_LOGIC_OR:
|
case GE_LOGIC_OR:
|
||||||
case GE_LOGIC_OR_INVERTED:
|
case GE_LOGIC_OR_INVERTED:
|
||||||
// Inverted in shader.
|
// Inverted in shader.
|
||||||
|
srcBlend = BlendFactor::ONE;
|
||||||
dstBlend = BlendFactor::ONE;
|
dstBlend = BlendFactor::ONE;
|
||||||
|
blendEq = BlendEq::ADD;
|
||||||
WARN_LOG_REPORT_ONCE(d3dLogicOpOr, G3D, "Attempted or for logic op: %x", gstate.getLogicOp());
|
WARN_LOG_REPORT_ONCE(d3dLogicOpOr, G3D, "Attempted or for logic op: %x", gstate.getLogicOp());
|
||||||
break;
|
return true;
|
||||||
case GE_LOGIC_OR_REVERSE:
|
case GE_LOGIC_OR_REVERSE:
|
||||||
WARN_LOG_REPORT_ONCE(d3dLogicOpOrReverse, G3D, "Unsupported OR REVERSE logic op: %x", gstate.getLogicOp());
|
WARN_LOG_REPORT_ONCE(d3dLogicOpOrReverse, G3D, "Unsupported OR REVERSE logic op: %x", gstate.getLogicOp());
|
||||||
break;
|
break;
|
||||||
|
@ -912,10 +914,12 @@ static void SimulateLogicOpIfNeeded(BlendFactor &srcBlend, BlendFactor &dstBlend
|
||||||
dstBlend = BlendFactor::ONE;
|
dstBlend = BlendFactor::ONE;
|
||||||
blendEq = BlendEq::ADD;
|
blendEq = BlendEq::ADD;
|
||||||
WARN_LOG_REPORT_ONCE(d3dLogicOpSet, G3D, "Attempted set for logic op: %x", gstate.getLogicOp());
|
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.
|
// Choose the shader part of the above logic op fallback simulation.
|
||||||
|
@ -950,7 +954,6 @@ void ApplyStencilReplaceAndLogicOpIgnoreBlend(ReplaceAlphaType replaceAlphaWithS
|
||||||
BlendFactor srcBlend = BlendFactor::ONE;
|
BlendFactor srcBlend = BlendFactor::ONE;
|
||||||
BlendFactor dstBlend = BlendFactor::ZERO;
|
BlendFactor dstBlend = BlendFactor::ZERO;
|
||||||
BlendEq blendEq = BlendEq::ADD;
|
BlendEq blendEq = BlendEq::ADD;
|
||||||
SimulateLogicOpIfNeeded(srcBlend, dstBlend, blendEq);
|
|
||||||
|
|
||||||
// We're not blending, but we may still want to "blend" for stencil.
|
// 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.
|
// 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];
|
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
|
// 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
|
// 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.
|
// 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) {
|
if (blendState.applyFramebufferRead || logicState.applyFramebufferRead) {
|
||||||
maskState.ConvertToShaderBlend();
|
maskState.ConvertToShaderBlend();
|
||||||
logicState.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
|
// Hardware and shader generation
|
||||||
GELogicOp logicOp;
|
GELogicOp logicOp;
|
||||||
|
|
||||||
|
void ApplyToBlendState(GenericBlendState &blendState);
|
||||||
void ConvertToShaderBlend() {
|
void ConvertToShaderBlend() {
|
||||||
if (logicOp != GE_LOGIC_COPY) {
|
if (logicOp != GE_LOGIC_COPY) {
|
||||||
logicOpEnabled = false;
|
logicOpEnabled = false;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue