Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix the new logic-op-in-shader on OpenGL ES and D3D11 #15962

Merged
merged 1 commit into from
Sep 4, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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