Skip to content

Commit

Permalink
Adjust stencil ops for 5551 and 565 buffers.
Browse files Browse the repository at this point in the history
This attempts to better approximate the operations that actually happen,
where possible.  Expected to help #5278.
  • Loading branch information
unknownbrackets committed Jan 1, 2016
1 parent 337f27d commit c31a8f8
Show file tree
Hide file tree
Showing 4 changed files with 152 additions and 28 deletions.
122 changes: 122 additions & 0 deletions GPU/Common/GPUStateUtils.cpp
Expand Up @@ -1119,3 +1119,125 @@ void ConvertBlendState(GenericBlendState &blendState, bool allowShaderBlend) {
blendState.setEquation(eqLookupNoMinMax[blendFuncEq], alphaEq);
}
}

void ConvertStencilFuncState(GenericStencilFuncState &state) {
state.enabled = gstate.isStencilTestEnabled() && !g_Config.bDisableStencilTest;
if (!state.enabled)
return;

// The PSP's mask is reversed (bits not to write.)
state.writeMask = (~(gstate.pmska >> 0)) & 0xFF;

state.sFail = gstate.getStencilOpSFail();
state.zFail = gstate.getStencilOpZFail();
state.zPass = gstate.getStencilOpZPass();

state.testFunc = gstate.getStencilTestFunction();
state.testRef = gstate.getStencilTestRef();
state.testMask = gstate.getStencilTestMask();

bool usesRef = state.sFail == GE_STENCILOP_REPLACE || state.zFail == GE_STENCILOP_REPLACE || state.zPass == GE_STENCILOP_REPLACE;
switch (gstate.FrameBufFormat()) {
case GE_FORMAT_565:
state.writeMask = 0;
break;

case GE_FORMAT_5551:
state.writeMask = state.writeMask >= 0x80 ? 0xff : 0x00;

// Decrement always zeros, so let's rewrite those to be safe (even if it's not 1.)
if (state.sFail == GE_STENCILOP_DECR)
state.sFail = GE_STENCILOP_ZERO;
if (state.zFail == GE_STENCILOP_DECR)
state.zFail = GE_STENCILOP_ZERO;
if (state.zPass == GE_STENCILOP_DECR)
state.zPass = GE_STENCILOP_ZERO;

if (!usesRef) {
// For 5551, we treat any non-zero value in the buffer as 255. Only zero is treated as zero.
// See: https://github.com/hrydgard/ppsspp/pull/4150#issuecomment-26211193
switch (state.testFunc) {
case GE_COMP_NEVER:
case GE_COMP_ALWAYS:
// Fine as is.
break;
case GE_COMP_EQUAL:
if (state.testRef == 255) {
if (!usesRef) {
state.testFunc = GE_COMP_NOTEQUAL;
state.testRef = 0;
state.testMask = 255;
}
} else if (state.testRef != 0) {
// This should never pass, regardless of buffer value. Only 0 and 255 are directly equal.
state.testFunc = GE_COMP_NEVER;
}
break;
case GE_COMP_NOTEQUAL:
if (state.testRef == 255) {
if (!usesRef) {
state.testFunc = GE_COMP_EQUAL;
state.testRef = 0;
state.testMask = 255;
}
} else if (state.testRef != 0) {
state.testFunc = GE_COMP_ALWAYS;
}
break;
case GE_COMP_LESS:
if (state.testRef == 255) {
state.testFunc = GE_COMP_NEVER;
} else {
if (!usesRef || state.testRef == 0) {
// Any non-zero value in the buffer should be treated as 255.
state.testFunc = GE_COMP_NOTEQUAL;
state.testRef = 0;
state.testMask = 255;
}
}
break;
case GE_COMP_LEQUAL:
if (state.testRef == 0) {
state.testFunc = GE_COMP_ALWAYS;
} else {
if (!usesRef) {
// Everything but 0 in the buffer is "255", so only 0 doesn't match.
state.testFunc = GE_COMP_NOTEQUAL;
state.testRef = 0;
state.testMask = 255;
}
}
break;
case GE_COMP_GREATER:
if (state.testRef > 0) {
if (!usesRef) {
// If we have a 1 in the buffer, it's the same as 255, which > can never match.
state.testFunc = GE_COMP_EQUAL;
state.testRef = 0;
state.testMask = 255;
}
} else {
state.testFunc = GE_COMP_NEVER;
}
break;
case GE_COMP_GEQUAL:
if (state.testRef == 255) {
state.testFunc = GE_COMP_ALWAYS;
} else {
if (!usesRef || state.testRef == 0) {
// If the buffer is non-zero, we treat as 255. So only 0 can match.
state.testFunc = GE_COMP_EQUAL;
state.testRef = 0;
state.testMask = 255;
}
}
break;
}
}
break;

default:
// Hard to do anything useful for 4444, and 8888 is fine.
break;
}
}
13 changes: 13 additions & 0 deletions GPU/Common/GPUStateUtils.h
Expand Up @@ -137,3 +137,16 @@ struct GenericBlendState {

void ConvertBlendState(GenericBlendState &blendState, bool allowShaderBlend);
void ApplyStencilReplaceAndLogicOp(ReplaceAlphaType replaceAlphaWithStencil, GenericBlendState &blendState);

struct GenericStencilFuncState {
bool enabled;
GEComparison testFunc;
u8 testRef;
u8 testMask;
u8 writeMask;
GEStencilOp sFail;
GEStencilOp zFail;
GEStencilOp zPass;
};

void ConvertStencilFuncState(GenericStencilFuncState &stencilFuncState);
23 changes: 9 additions & 14 deletions GPU/Directx9/StateMappingDX9.cpp
Expand Up @@ -243,8 +243,8 @@ void TransformDrawEngineDX9::ApplyDrawState(int prim) {
bool bmask = ((gstate.pmskc >> 16) & 0xFF) < 128;
bool amask = (gstate.pmska & 0xFF) < 128;

u8 abits = (gstate.pmska >> 0) & 0xFF;
#ifndef MOBILE_DEVICE
u8 abits = (gstate.pmska >> 0) & 0xFF;
u8 rbits = (gstate.pmskc >> 0) & 0xFF;
u8 gbits = (gstate.pmskc >> 8) & 0xFF;
u8 bbits = (gstate.pmskc >> 16) & 0xFF;
Expand All @@ -268,21 +268,16 @@ void TransformDrawEngineDX9::ApplyDrawState(int prim) {
}

dxstate.colorMask.set(rmask, gmask, bmask, amask);


GenericStencilFuncState stencilState;
ConvertStencilFuncState(stencilState);

// Stencil Test
if (gstate.isStencilTestEnabled()) {
if (stencilState.enabled) {
dxstate.stencilTest.enable();
dxstate.stencilFunc.set(ztests[gstate.getStencilTestFunction()],
gstate.getStencilTestRef(),
gstate.getStencilTestMask());
dxstate.stencilOp.set(stencilOps[gstate.getStencilOpSFail()], // stencil fail
stencilOps[gstate.getStencilOpZFail()], // depth fail
stencilOps[gstate.getStencilOpZPass()]); // depth pass
if (gstate.FrameBufFormat() == GE_FORMAT_5551) {
dxstate.stencilMask.set(abits <= 0x7f ? 0xff : 0x00);
} else {
dxstate.stencilMask.set(~abits);
}
dxstate.stencilFunc.set(ztests[stencilState.testFunc], stencilState.testRef, stencilState.testMask);
dxstate.stencilOp.set(stencilOps[stencilState.sFail], stencilOps[stencilState.zFail], stencilOps[stencilState.zPass]);
dxstate.stencilMask.set(stencilState.writeMask);
} else {
dxstate.stencilTest.disable();
}
Expand Down
22 changes: 8 additions & 14 deletions GPU/GLES/StateMapping.cpp
Expand Up @@ -312,8 +312,8 @@ void TransformDrawEngine::ApplyDrawState(int prim) {
bool bmask = ((gstate.pmskc >> 16) & 0xFF) < 128;
bool amask = (gstate.pmska & 0xFF) < 128;

u8 abits = (gstate.pmska >> 0) & 0xFF;
#ifndef MOBILE_DEVICE
u8 abits = (gstate.pmska >> 0) & 0xFF;
u8 rbits = (gstate.pmskc >> 0) & 0xFF;
u8 gbits = (gstate.pmskc >> 8) & 0xFF;
u8 bbits = (gstate.pmskc >> 16) & 0xFF;
Expand All @@ -338,21 +338,15 @@ void TransformDrawEngine::ApplyDrawState(int prim) {

glstate.colorMask.set(rmask, gmask, bmask, amask);

GenericStencilFuncState stencilState;
ConvertStencilFuncState(stencilState);

// Stencil Test
if (gstate.isStencilTestEnabled() && enableStencilTest) {
if (stencilState.enabled) {
glstate.stencilTest.enable();
glstate.stencilFunc.set(ztests[gstate.getStencilTestFunction()],
gstate.getStencilTestRef(),
gstate.getStencilTestMask());
glstate.stencilOp.set(stencilOps[gstate.getStencilOpSFail()], // stencil fail
stencilOps[gstate.getStencilOpZFail()], // depth fail
stencilOps[gstate.getStencilOpZPass()]); // depth pass

if (gstate.FrameBufFormat() == GE_FORMAT_5551) {
glstate.stencilMask.set(abits <= 0x7f ? 0xff : 0x00);
} else {
glstate.stencilMask.set(~abits);
}
glstate.stencilFunc.set(ztests[stencilState.testFunc], stencilState.testRef, stencilState.testMask);
glstate.stencilOp.set(stencilOps[stencilState.sFail], stencilOps[stencilState.zFail], stencilOps[stencilState.zPass]);
glstate.stencilMask.set(stencilState.writeMask);
} else {
glstate.stencilTest.disable();
}
Expand Down

0 comments on commit c31a8f8

Please sign in to comment.