Skip to content

Commit

Permalink
Merge pull request #15962 from hrydgard/logic-op-followups
Browse files Browse the repository at this point in the history
Fix the new logic-op-in-shader on OpenGL ES and D3D11
  • Loading branch information
unknownbrackets authored Sep 4, 2022
2 parents 026040b + b15c655 commit eeffc98
Show file tree
Hide file tree
Showing 8 changed files with 35 additions and 23 deletions.
2 changes: 1 addition & 1 deletion GPU/Common/FragmentShaderGenerator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1103,7 +1103,7 @@ bool GenerateFragmentShader(const FShaderID &id, char *buffer, const ShaderLangu
case GE_LOGIC_EQUIV: p.C(" v32 = (~(v32 ^ d32) & 0x00FFFFFFu) | (v32 & 0xFF000000u);\n"); break;
case GE_LOGIC_INVERTED: p.C(" v32 = (~d32 & 0x00FFFFFFu) | (v32 & 0xFF000000u);\n"); break;
case GE_LOGIC_OR_REVERSE: p.C(" v32 = v32 | (~d32 & 0x00FFFFFFu);\n"); break;
case GE_LOGIC_COPY_INVERTED: p.C(" v32 = (~v32 & 0x00FFFFFFu) | (v32 &0xFF000000u);\n"); break;
case GE_LOGIC_COPY_INVERTED: p.C(" v32 = (~v32 & 0x00FFFFFFu) | (v32 & 0xFF000000u);\n"); break;
case GE_LOGIC_OR_INVERTED: p.C(" v32 = ((~v32 | d32) & 0x00FFFFFFu) | (v32 & 0xFF000000u);\n"); break;
case GE_LOGIC_NAND: p.C(" v32 = (~(v32 & d32) & 0x00FFFFFFu) | (v32 & 0xFF000000u);\n"); break;
case GE_LOGIC_SET: p.C(" v32 |= 0x00FFFFFF;\n"); break;
Expand Down
33 changes: 26 additions & 7 deletions GPU/Common/GPUStateUtils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1011,7 +1011,7 @@ static void ConvertMaskState(GenericMaskState &maskState, bool shaderBitOpsSuppo
maskState.applyFramebufferRead = false;
maskState.channelMask = 0;
for (int i = 0; i < 4; i++) {
int channelMask = colorMask & 0xFF;
uint32_t channelMask = (colorMask >> (i * 8)) & 0xFF;
switch (channelMask) {
case 0x0:
break;
Expand All @@ -1030,7 +1030,6 @@ static void ConvertMaskState(GenericMaskState &maskState, bool shaderBitOpsSuppo
}
}
}
colorMask >>= 8;
}

// Let's not write to alpha if stencil isn't enabled.
Expand Down Expand Up @@ -1087,6 +1086,7 @@ static void ConvertBlendState(GenericBlendState &blendState, bool forceReplaceBl
case REPLACE_BLEND_READ_FRAMEBUFFER:
blendState.blendEnabled = true;
blendState.applyFramebufferRead = true;
blendState.simulateLogicOpType = LOGICOPTYPE_NORMAL;
break;

case REPLACE_BLEND_PRE_SRC:
Expand Down Expand Up @@ -1251,7 +1251,9 @@ static void ConvertBlendState(GenericBlendState &blendState, bool forceReplaceBl
}

// Attempt to apply simulated logic ops, if any and if needed.
SimulateLogicOpIfNeeded(glBlendFuncA, glBlendFuncB, colorEq);
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
Expand Down Expand Up @@ -1337,7 +1339,15 @@ static void ConvertBlendState(GenericBlendState &blendState, bool forceReplaceBl
static void ConvertLogicOpState(GenericLogicState &logicOpState, bool logicSupported, bool shaderBitOpsSupported, bool forceApplyFramebuffer) {
// TODO: We can get more detailed with checks here. Some logic ops don't involve the destination at all.
// Several can be trivially supported even without any bitwise logic.
if (gstate.isLogicOpEnabled() && gstate.getLogicOp() != GE_LOGIC_COPY && forceApplyFramebuffer && shaderBitOpsSupported) {
if (!gstate.isLogicOpEnabled() || gstate.getLogicOp() == GE_LOGIC_COPY) {
// No matter what, don't need to do anything.
logicOpState.logicOpEnabled = false;
logicOpState.logicOp = GE_LOGIC_COPY;
logicOpState.applyFramebufferRead = forceApplyFramebuffer;
return;
}

if (forceApplyFramebuffer && shaderBitOpsSupported) {
// We have to emulate logic ops in the shader.
logicOpState.logicOpEnabled = false; // Don't use any hardware logic op, supported or not.
logicOpState.applyFramebufferRead = true;
Expand All @@ -1352,6 +1362,13 @@ static void ConvertLogicOpState(GenericLogicState &logicOpState, bool logicSuppo
logicOpState.logicOpEnabled = false;
logicOpState.logicOp = GE_LOGIC_COPY;
}
} else if (shaderBitOpsSupported) {
// D3D11 and some OpenGL versions will end up here.
// Logic ops not support, bitops supported. Let's punt to the shader.
// We should possibly always do this and never use the hardware ops, since they'll mishandle the alpha channel..
logicOpState.logicOpEnabled = false; // Don't use any hardware logic op, supported or not.
logicOpState.applyFramebufferRead = true;
logicOpState.logicOp = gstate.getLogicOp();
} else {
// In this case, the SIMULATE fallback should kick in.
// Need to make sure this is checking for the same things though...
Expand Down Expand Up @@ -1551,13 +1568,15 @@ void GenericBlendState::Log() {
}

void ComputedPipelineState::Convert(bool shaderBitOpsSuppported) {
// Passing on the previous applyFramebufferRead as forceFrameBuffer read in the next one,
// thus propagating forward.
ConvertMaskState(maskState, shaderBitOpsSuppported);
ConvertLogicOpState(logicState, gstate_c.Supports(GPU_SUPPORTS_LOGIC_OP), shaderBitOpsSuppported, maskState.applyFramebufferRead);
ConvertBlendState(blendState, maskState.applyFramebufferRead);
ConvertBlendState(blendState, logicState.applyFramebufferRead);

// Note: If the blend state decided it had to use framebuffer reads,
// we need to switch mask and logic over to also use it, otherwise things will go wrong.
if (blendState.applyFramebufferRead) {
// we need to make sure that both mask and logic also use it, otherwise things will go wrong.
if (blendState.applyFramebufferRead || logicState.applyFramebufferRead) {
maskState.ConvertToShaderBlend();
logicState.ConvertToShaderBlend();
}
Expand Down
4 changes: 4 additions & 0 deletions GPU/Common/GPUStateUtils.h
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,10 @@ struct ComputedPipelineState {
GenericLogicState logicState;

void Convert(bool shaderBitOpsSupported);

bool FramebufferRead() const {
return blendState.applyFramebufferRead;
}
};

// See issue #15898
Expand Down
2 changes: 1 addition & 1 deletion GPU/D3D11/StateMappingD3D11.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ void DrawEngineD3D11::ApplyDrawState(int prim) {
GenericBlendState &blendState = pipelineState_.blendState;
// We ignore the logicState on D3D since there's no support, the emulation of it is blend-and-shader only.

if (blendState.applyFramebufferRead || maskState.applyFramebufferRead) {
if (pipelineState_.FramebufferRead()) {
bool fboTexNeedsBind = false;
ApplyFramebufferRead(&fboTexNeedsBind);
// The shader takes over the responsibility for blending, so recompute.
Expand Down
2 changes: 1 addition & 1 deletion GPU/Directx9/StateMappingDX9.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ void DrawEngineDX9::ApplyDrawState(int prim) {
GenericBlendState &blendState = pipelineState_.blendState;
// We ignore the logicState on D3D since there's no support, the emulation of it is blend-and-shader only.

if (blendState.applyFramebufferRead || maskState.applyFramebufferRead) {
if (pipelineState_.FramebufferRead()) {
bool fboTexNeedsBind = false;
ApplyFramebufferRead(&fboTexNeedsBind);
// The shader takes over the responsibility for blending, so recompute.
Expand Down
2 changes: 1 addition & 1 deletion GPU/GLES/StateMappingGLES.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ void DrawEngineGLES::ApplyDrawState(int prim) {
GenericBlendState &blendState = pipelineState_.blendState;
GenericLogicState &logicState = pipelineState_.logicState;

if (blendState.applyFramebufferRead || maskState.applyFramebufferRead) {
if (pipelineState_.FramebufferRead()) {
bool fboTexNeedsBind = false;
ApplyFramebufferRead(&fboTexNeedsBind);
// The shader takes over the responsibility for blending, so recompute.
Expand Down
2 changes: 1 addition & 1 deletion GPU/Vulkan/StateMappingVulkan.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ void DrawEngineVulkan::ConvertStateToVulkanKey(FramebufferManagerVulkan &fbManag
GenericBlendState &blendState = pipelineState_.blendState;
GenericLogicState &logicState = pipelineState_.logicState;

if (blendState.applyFramebufferRead || maskState.applyFramebufferRead) {
if (pipelineState_.FramebufferRead()) {
ApplyFramebufferRead(&fboTexNeedsBind_);
// The shader takes over the responsibility for blending, so recompute.
// We might still end up using blend to write something to alpha.
Expand Down
11 changes: 0 additions & 11 deletions assets/compat.ini
Original file line number Diff line number Diff line change
Expand Up @@ -1119,17 +1119,6 @@ ULUS10513 = true
ULJM05812 = true
NPJH50371 = true

# Colin McRae's DiRT 2 - issue #13012 (car lighting)
ULUS10471 = true
ULJM05533 = true
NPJH50006 = true
ULES01301 = true

# Outrun 2006: Coast to Coast - issue #11358 (car reflections)
ULES00262 = true
ULUS10064 = true
ULKS46087 = true

[DateLimited]
# Car Jack Streets - issue #12698
NPUZ00043 = true
Expand Down

0 comments on commit eeffc98

Please sign in to comment.