mirror of
https://github.com/hrydgard/ppsspp.git
synced 2025-04-02 11:01:50 -04:00
Implement the stencil/alpha reverse trick for all backends
This commit is contained in:
parent
59053e7815
commit
880ea48e2d
4 changed files with 96 additions and 6 deletions
|
@ -293,6 +293,34 @@ void DrawEngineD3D11::ApplyDrawState(int prim) {
|
|||
keys_.depthStencil.stencilWriteMask = stencilState.writeMask;
|
||||
dynState_.useStencil = true;
|
||||
dynState_.stencilRef = stencilState.testRef;
|
||||
|
||||
// Nasty special case for Spongebob and similar where it tries to write zeros to alpha/stencil during
|
||||
// depth-fail. We can't write to alpha then because the pixel is killed. However, we can invert the depth
|
||||
// test and modify the alpha function...
|
||||
if (gstate.isDepthTestEnabled() && !gstate.isDepthWriteEnabled() && stencilState.zFail == GE_STENCILOP_ZERO &&
|
||||
stencilState.sFail == GE_STENCILOP_KEEP && stencilState.zPass == GE_STENCILOP_KEEP &&
|
||||
stencilState.testFunc == GE_COMP_ALWAYS &&
|
||||
stencilState.writeMask == 0xFF && stencilState.testMask == 0xFF && stencilState.testRef == 0xFF) {
|
||||
keys_.blend.blendEnable = true;
|
||||
keys_.blend.blendOpAlpha = D3D11_BLEND_OP_ADD;
|
||||
keys_.blend.blendOpColor = D3D11_BLEND_OP_ADD;
|
||||
keys_.blend.srcColor = D3D11_BLEND_ZERO;
|
||||
keys_.blend.destColor = D3D11_BLEND_ZERO;
|
||||
keys_.blend.logicOpEnable = false;
|
||||
keys_.blend.srcAlpha = D3D11_BLEND_ZERO;
|
||||
keys_.blend.destAlpha = D3D11_BLEND_ZERO;
|
||||
keys_.blend.colorWriteMask = D3D11_COLOR_WRITE_ENABLE_ALPHA;
|
||||
|
||||
keys_.depthStencil.depthCompareOp = D3D11_COMPARISON_LESS; // Inverse of GREATER_EQUAL
|
||||
keys_.depthStencil.stencilCompareFunc = D3D11_COMPARISON_ALWAYS;
|
||||
// Invert
|
||||
keys_.depthStencil.stencilPassOp = D3D11_STENCIL_OP_ZERO;
|
||||
keys_.depthStencil.stencilFailOp = D3D11_STENCIL_OP_ZERO;
|
||||
keys_.depthStencil.stencilDepthFailOp = D3D11_STENCIL_OP_KEEP;
|
||||
|
||||
// TODO: Need to set in a way that carries over to the next draw..
|
||||
gstate_c.Dirty(DIRTY_BLEND_STATE);
|
||||
}
|
||||
} else {
|
||||
keys_.depthStencil.stencilTestEnable = false;
|
||||
dynState_.useStencil = false;
|
||||
|
|
|
@ -247,6 +247,28 @@ void DrawEngineDX9::ApplyDrawState(int prim) {
|
|||
dxstate.stencilCompareMask.set(stencilState.testMask);
|
||||
dxstate.stencilOp.set(stencilOps[stencilState.sFail], stencilOps[stencilState.zFail], stencilOps[stencilState.zPass]);
|
||||
dxstate.stencilWriteMask.set(stencilState.writeMask);
|
||||
|
||||
// Nasty special case for Spongebob and similar where it tries to write zeros to alpha/stencil during
|
||||
// depth-fail. We can't write to alpha then because the pixel is killed. However, we can invert the depth
|
||||
// test and modify the alpha function...
|
||||
if (gstate.isDepthTestEnabled() && !gstate.isDepthWriteEnabled() && stencilState.zFail == GE_STENCILOP_ZERO &&
|
||||
stencilState.sFail == GE_STENCILOP_KEEP && stencilState.zPass == GE_STENCILOP_KEEP &&
|
||||
stencilState.testFunc == GE_COMP_ALWAYS &&
|
||||
stencilState.writeMask == 0xFF && stencilState.testMask == 0xFF && stencilState.testRef == 0xFF) {
|
||||
|
||||
dxstate.blend.set(true);
|
||||
dxstate.blendEquation.set(D3DBLENDOP_ADD, D3DBLENDOP_ADD);
|
||||
dxstate.blendFunc.set(D3DBLEND_ZERO, D3DBLEND_ZERO, D3DBLEND_ZERO, D3DBLEND_ZERO);
|
||||
dxstate.colorMask.set(8);
|
||||
|
||||
dxstate.depthFunc.set(D3DCMP_LESS);
|
||||
dxstate.stencilFunc.set(D3DCMP_ALWAYS);
|
||||
// Invert
|
||||
dxstate.stencilOp.set(D3DSTENCILOP_ZERO, D3DSTENCILOP_KEEP, D3DSTENCILOP_ZERO);
|
||||
|
||||
// TODO: Need to set in a way that carries over to the next draw..
|
||||
gstate_c.Dirty(DIRTY_BLEND_STATE);
|
||||
}
|
||||
} else {
|
||||
dxstate.stencilTest.disable();
|
||||
}
|
||||
|
|
|
@ -144,7 +144,6 @@ void DrawEngineGLES::ApplyDrawState(int prim) {
|
|||
bool useBufferedRendering = framebufferManager_->UseBufferedRendering();
|
||||
|
||||
if (gstate_c.IsDirty(DIRTY_BLEND_STATE)) {
|
||||
gstate_c.Clean(DIRTY_BLEND_STATE);
|
||||
gstate_c.SetAllowFramebufferRead(!g_Config.bDisableSlowFramebufEffects);
|
||||
|
||||
if (gstate.isModeClear()) {
|
||||
|
@ -208,7 +207,6 @@ void DrawEngineGLES::ApplyDrawState(int prim) {
|
|||
} else {
|
||||
renderManager->SetNoBlendAndMask(mask);
|
||||
}
|
||||
|
||||
#ifndef USING_GLES2
|
||||
if (gstate_c.Supports(GPU_SUPPORTS_LOGIC_OP)) {
|
||||
renderManager->SetLogicOp(gstate.isLogicOpEnabled() && gstate.getLogicOp() != GE_LOGIC_COPY,
|
||||
|
@ -219,8 +217,6 @@ void DrawEngineGLES::ApplyDrawState(int prim) {
|
|||
}
|
||||
|
||||
if (gstate_c.IsDirty(DIRTY_RASTER_STATE)) {
|
||||
gstate_c.Clean(DIRTY_RASTER_STATE);
|
||||
|
||||
// Dither
|
||||
bool dither = gstate.isDitherEnabled();
|
||||
bool cullEnable;
|
||||
|
@ -247,7 +243,6 @@ void DrawEngineGLES::ApplyDrawState(int prim) {
|
|||
}
|
||||
|
||||
if (gstate_c.IsDirty(DIRTY_DEPTHSTENCIL_STATE)) {
|
||||
gstate_c.Clean(DIRTY_DEPTHSTENCIL_STATE);
|
||||
GenericStencilFuncState stencilState;
|
||||
ConvertStencilFuncState(stencilState);
|
||||
|
||||
|
@ -265,13 +260,29 @@ void DrawEngineGLES::ApplyDrawState(int prim) {
|
|||
renderManager->SetStencilFunc(stencilState.enabled, compareOps[stencilState.testFunc], stencilState.testRef, stencilState.testMask);
|
||||
renderManager->SetStencilOp(stencilState.writeMask, stencilOps[stencilState.sFail], stencilOps[stencilState.zFail], stencilOps[stencilState.zPass]);
|
||||
} else {
|
||||
// Nasty special case for Spongebob and similar where it tries to write zeros to alpha/stencil during
|
||||
// depth-fail. We can't write to alpha then because the pixel is killed. However, we can invert the depth
|
||||
// test and modify the alpha function...
|
||||
if (gstate.isDepthTestEnabled() && !gstate.isDepthWriteEnabled() && stencilState.zFail == GE_STENCILOP_ZERO &&
|
||||
stencilState.sFail == GE_STENCILOP_KEEP && stencilState.zPass == GE_STENCILOP_KEEP &&
|
||||
stencilState.testFunc == GE_COMP_ALWAYS &&
|
||||
stencilState.writeMask == 0xFF && stencilState.testMask == 0xFF && stencilState.testRef == 0xFF) {
|
||||
|
||||
renderManager->SetBlendAndMask(0x8, true, GL_ZERO, GL_ZERO, GL_ZERO, GL_ZERO, GL_ADD, GL_ADD);
|
||||
renderManager->SetDepth(true, false, GL_LESS);
|
||||
renderManager->SetStencilFunc(true, GL_ALWAYS, 0xFF, 0xFF);
|
||||
renderManager->SetStencilOp(0xFF, GL_ZERO, GL_KEEP, GL_ZERO);
|
||||
|
||||
// TODO: Need to set in a way that carries over to the next draw..
|
||||
gstate_c.Dirty(DIRTY_BLEND_STATE);
|
||||
}
|
||||
|
||||
renderManager->SetStencilDisabled();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (gstate_c.IsDirty(DIRTY_VIEWPORTSCISSOR_STATE)) {
|
||||
gstate_c.Clean(DIRTY_VIEWPORTSCISSOR_STATE);
|
||||
ConvertViewportAndScissor(useBufferedRendering,
|
||||
framebufferManager_->GetRenderWidth(), framebufferManager_->GetRenderHeight(),
|
||||
framebufferManager_->GetTargetBufferWidth(), framebufferManager_->GetTargetBufferHeight(),
|
||||
|
@ -284,6 +295,8 @@ void DrawEngineGLES::ApplyDrawState(int prim) {
|
|||
vpAndScissor.viewportW, vpAndScissor.viewportH,
|
||||
vpAndScissor.depthRangeMin, vpAndScissor.depthRangeMax });
|
||||
}
|
||||
|
||||
gstate_c.Clean(DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_DEPTHSTENCIL_STATE | DIRTY_RASTER_STATE | DIRTY_BLEND_STATE);
|
||||
}
|
||||
|
||||
void DrawEngineGLES::ApplyDrawStateLate(bool setStencilValue, int stencilValue) {
|
||||
|
|
|
@ -301,6 +301,33 @@ void DrawEngineVulkan::ConvertStateToVulkanKey(FramebufferManagerVulkan &fbManag
|
|||
dynState.stencilRef = stencilState.testRef;
|
||||
dynState.stencilCompareMask = stencilState.testMask;
|
||||
dynState.stencilWriteMask = stencilState.writeMask;
|
||||
|
||||
// Nasty special case for Spongebob and similar where it tries to write zeros to alpha/stencil during
|
||||
// depth-fail. We can't write to alpha then because the pixel is killed. However, we can invert the depth
|
||||
// test and modify the alpha function...
|
||||
if (gstate.isDepthTestEnabled() && !gstate.isDepthWriteEnabled() && stencilState.zFail == GE_STENCILOP_ZERO &&
|
||||
stencilState.sFail == GE_STENCILOP_KEEP && stencilState.zPass == GE_STENCILOP_KEEP &&
|
||||
stencilState.testFunc == GE_COMP_ALWAYS &&
|
||||
stencilState.writeMask == 0xFF && stencilState.testMask == 0xFF && stencilState.testRef == 0xFF) {
|
||||
key.blendEnable = true;
|
||||
key.blendOpAlpha = VK_BLEND_OP_ADD;
|
||||
key.blendOpColor = VK_BLEND_OP_ADD;
|
||||
key.srcColor = VK_BLEND_FACTOR_ZERO;
|
||||
key.destColor = VK_BLEND_FACTOR_ZERO;
|
||||
key.logicOpEnable = false;
|
||||
key.srcAlpha = VK_BLEND_FACTOR_ZERO;
|
||||
key.destAlpha = VK_BLEND_FACTOR_ZERO;
|
||||
key.colorWriteMask = VK_COLOR_COMPONENT_A_BIT;
|
||||
key.depthCompareOp = VK_COMPARE_OP_LESS; // Inverse of GREATER_EQUAL
|
||||
key.stencilCompareOp = VK_COMPARE_OP_ALWAYS;
|
||||
// Invert
|
||||
key.stencilPassOp = VK_STENCIL_OP_ZERO;
|
||||
key.stencilFailOp = VK_STENCIL_OP_ZERO;
|
||||
key.stencilDepthFailOp = VK_STENCIL_OP_KEEP;
|
||||
|
||||
// TODO: Need to set in a way that carries over to the next draw..
|
||||
gstate_c.Dirty(DIRTY_BLEND_STATE);
|
||||
}
|
||||
} else {
|
||||
key.stencilTestEnable = false;
|
||||
key.stencilCompareOp = VK_COMPARE_OP_ALWAYS;
|
||||
|
|
Loading…
Add table
Reference in a new issue