2021-11-20 13:11:52 -08:00
|
|
|
// Copyright (c) 2021- PPSSPP Project.
|
|
|
|
|
|
|
|
// This program is free software: you can redistribute it and/or modify
|
|
|
|
// it under the terms of the GNU General Public License as published by
|
|
|
|
// the Free Software Foundation, version 2.0 or later versions.
|
|
|
|
|
|
|
|
// This program is distributed in the hope that it will be useful,
|
|
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
// GNU General Public License 2.0 for more details.
|
|
|
|
|
|
|
|
// A copy of the GPL 2.0 should have been included with the program.
|
|
|
|
// If not, see http://www.gnu.org/licenses/
|
|
|
|
|
|
|
|
// Official git repository and contact information can be found at
|
|
|
|
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
|
|
|
|
|
2021-11-21 08:21:59 -08:00
|
|
|
#include "Common/StringUtils.h"
|
2021-11-20 13:11:52 -08:00
|
|
|
#include "GPU/Software/FuncId.h"
|
|
|
|
#include "GPU/GPUState.h"
|
|
|
|
|
2021-11-21 09:39:14 -08:00
|
|
|
static_assert(sizeof(SamplerID) == sizeof(SamplerID::fullKey), "Bad sampler ID size");
|
|
|
|
static_assert(sizeof(PixelFuncID) == sizeof(PixelFuncID::fullKey), "Bad pixel func ID size");
|
|
|
|
|
2021-11-20 13:11:52 -08:00
|
|
|
void ComputePixelFuncID(PixelFuncID *id) {
|
|
|
|
id->fullKey = 0;
|
|
|
|
|
|
|
|
// TODO: Could this be minz > 0x0000 || maxz < 0xFFFF? Maybe unsafe, depending on verts...
|
|
|
|
id->applyDepthRange = !gstate.isModeThrough();
|
|
|
|
// Dither happens even in clear mode.
|
|
|
|
id->dithering = gstate.isDitherEnabled();
|
|
|
|
id->fbFormat = gstate.FrameBufFormat();
|
|
|
|
id->useStandardStride = gstate.FrameBufStride() == 512 && gstate.DepthBufStride() == 512;
|
|
|
|
id->applyColorWriteMask = gstate.getColorMask() != 0;
|
|
|
|
|
|
|
|
id->clearMode = gstate.isModeClear();
|
|
|
|
if (id->clearMode) {
|
2021-11-21 09:39:14 -08:00
|
|
|
id->colorTest = gstate.isClearModeColorMask();
|
|
|
|
id->stencilTest = gstate.isClearModeAlphaMask();
|
|
|
|
id->depthWrite = gstate.isClearModeDepthMask();
|
2021-11-21 17:52:51 -08:00
|
|
|
id->depthTestFunc = GE_COMP_ALWAYS;
|
|
|
|
id->alphaTestFunc = GE_COMP_ALWAYS;
|
2021-11-20 13:11:52 -08:00
|
|
|
} else {
|
|
|
|
id->colorTest = gstate.isColorTestEnabled() && gstate.getColorTestFunction() != GE_COMP_ALWAYS;
|
|
|
|
if (gstate.isStencilTestEnabled() && gstate.getStencilTestFunction() == GE_COMP_ALWAYS) {
|
|
|
|
// If stencil always passes, force off when we won't write any stencil bits.
|
|
|
|
bool stencilWrite = (gstate.pmska & 0xFF) != 0xFF && gstate.FrameBufFormat() != GE_FORMAT_565;
|
|
|
|
if (gstate.isDepthTestEnabled() && gstate.getDepthTestFunction() != GE_COMP_ALWAYS)
|
|
|
|
id->stencilTest = stencilWrite && (gstate.getStencilOpZPass() != GE_STENCILOP_KEEP || gstate.getStencilOpZFail() != GE_STENCILOP_KEEP);
|
|
|
|
else
|
|
|
|
id->stencilTest = stencilWrite && gstate.getStencilOpZPass() != GE_STENCILOP_KEEP;
|
|
|
|
} else {
|
|
|
|
id->stencilTest = gstate.isStencilTestEnabled();
|
|
|
|
}
|
|
|
|
id->depthWrite = gstate.isDepthTestEnabled() && gstate.isDepthWriteEnabled();
|
|
|
|
|
|
|
|
if (id->stencilTest) {
|
|
|
|
id->stencilTestFunc = gstate.getStencilTestFunction();
|
|
|
|
id->stencilTestRef = gstate.getStencilTestRef() & gstate.getStencilTestMask();
|
|
|
|
id->hasStencilTestMask = gstate.getStencilTestMask() != 0xFF;
|
|
|
|
id->sFail = gstate.getStencilOpSFail();
|
|
|
|
id->zFail = gstate.isDepthTestEnabled() ? gstate.getStencilOpZFail() : GE_STENCILOP_KEEP;
|
|
|
|
id->zPass = gstate.getStencilOpZPass();
|
|
|
|
}
|
|
|
|
|
|
|
|
id->depthTestFunc = gstate.isDepthTestEnabled() ? gstate.getDepthTestFunction() : GE_COMP_ALWAYS;
|
|
|
|
id->alphaTestFunc = gstate.isAlphaTestEnabled() ? gstate.getAlphaTestFunction() : GE_COMP_ALWAYS;
|
2021-11-21 09:39:14 -08:00
|
|
|
if (id->AlphaTestFunc() != GE_COMP_ALWAYS) {
|
2021-11-20 13:11:52 -08:00
|
|
|
id->alphaTestRef = gstate.getAlphaTestRef() & gstate.getAlphaTestMask();
|
|
|
|
id->hasAlphaTestMask = gstate.getAlphaTestMask() != 0xFF;
|
|
|
|
}
|
|
|
|
|
|
|
|
id->alphaBlend = gstate.isAlphaBlendEnabled();
|
2021-11-20 14:52:51 -08:00
|
|
|
// Force it off if the factors are constant and don't blend. Some games use this...
|
|
|
|
if (id->alphaBlend && gstate.getBlendEq() == GE_BLENDMODE_MUL_AND_ADD) {
|
|
|
|
bool srcFixedOne = gstate.getBlendFuncA() == GE_SRCBLEND_FIXA && gstate.getFixA() == 0x00FFFFFF;
|
|
|
|
bool dstFixedZero = gstate.getBlendFuncB() == GE_DSTBLEND_FIXB && gstate.getFixB() == 0x00000000;
|
|
|
|
if (srcFixedOne && dstFixedZero)
|
|
|
|
id->alphaBlend = false;
|
|
|
|
}
|
2021-11-20 13:11:52 -08:00
|
|
|
if (id->alphaBlend) {
|
|
|
|
id->alphaBlendEq = gstate.getBlendEq();
|
|
|
|
id->alphaBlendSrc = gstate.getBlendFuncA();
|
|
|
|
id->alphaBlendDst = gstate.getBlendFuncB();
|
|
|
|
}
|
|
|
|
|
|
|
|
id->applyLogicOp = gstate.isLogicOpEnabled() && gstate.getLogicOp() != GE_LOGIC_COPY;
|
|
|
|
id->applyFog = gstate.isFogEnabled() && !gstate.isModeThrough();
|
|
|
|
}
|
|
|
|
}
|
2021-11-21 08:21:59 -08:00
|
|
|
|
|
|
|
std::string DescribePixelFuncID(const PixelFuncID &id) {
|
|
|
|
std::string desc;
|
|
|
|
if (id.clearMode) {
|
|
|
|
desc = "Clear";
|
2021-11-21 09:39:14 -08:00
|
|
|
if (id.ColorClear())
|
2021-11-21 08:21:59 -08:00
|
|
|
desc += "C";
|
2021-11-21 09:39:14 -08:00
|
|
|
if (id.StencilClear())
|
2021-11-21 08:21:59 -08:00
|
|
|
desc += "S";
|
2021-11-21 09:39:14 -08:00
|
|
|
if (id.DepthClear())
|
2021-11-21 08:21:59 -08:00
|
|
|
desc += "D";
|
|
|
|
desc += ":";
|
|
|
|
}
|
|
|
|
if (id.applyDepthRange)
|
|
|
|
desc += "DepthR:";
|
|
|
|
if (id.useStandardStride)
|
|
|
|
desc += "Str512:";
|
|
|
|
if (id.dithering)
|
|
|
|
desc += "Dith:";
|
|
|
|
if (id.applyColorWriteMask)
|
|
|
|
desc += "Msk:";
|
|
|
|
|
2021-11-22 05:57:54 -08:00
|
|
|
switch (id.fbFormat) {
|
2021-11-21 08:21:59 -08:00
|
|
|
case GE_FORMAT_565: desc += "5650:"; break;
|
|
|
|
case GE_FORMAT_5551: desc += "5551:"; break;
|
|
|
|
case GE_FORMAT_4444: desc += "4444:"; break;
|
|
|
|
case GE_FORMAT_8888: desc += "8888:"; break;
|
|
|
|
}
|
|
|
|
|
2021-11-21 09:39:14 -08:00
|
|
|
if (id.AlphaTestFunc() != GE_COMP_ALWAYS) {
|
|
|
|
switch (id.AlphaTestFunc()) {
|
2021-11-21 08:21:59 -08:00
|
|
|
case GE_COMP_NEVER: desc += "ANever"; break;
|
|
|
|
case GE_COMP_ALWAYS: break;
|
|
|
|
case GE_COMP_EQUAL: desc += "AEQ"; break;
|
|
|
|
case GE_COMP_NOTEQUAL: desc += "ANE"; break;
|
|
|
|
case GE_COMP_LESS: desc += "ALT"; break;
|
|
|
|
case GE_COMP_LEQUAL: desc += "ALE"; break;
|
|
|
|
case GE_COMP_GREATER: desc += "AGT"; break;
|
|
|
|
case GE_COMP_GEQUAL: desc += "AGE"; break;
|
|
|
|
}
|
|
|
|
if (id.hasAlphaTestMask)
|
|
|
|
desc += "Msk";
|
|
|
|
desc += StringFromFormat("%02X:", id.alphaTestRef);
|
|
|
|
}
|
|
|
|
|
2021-11-21 09:39:14 -08:00
|
|
|
if (id.DepthTestFunc() != GE_COMP_ALWAYS) {
|
|
|
|
switch (id.DepthTestFunc()) {
|
2021-11-21 08:21:59 -08:00
|
|
|
case GE_COMP_NEVER: desc += "ZNever:"; break;
|
|
|
|
case GE_COMP_ALWAYS: break;
|
|
|
|
case GE_COMP_EQUAL: desc += "ZEQ:"; break;
|
|
|
|
case GE_COMP_NOTEQUAL: desc += "ZNE:"; break;
|
|
|
|
case GE_COMP_LESS: desc += "ZLT:"; break;
|
|
|
|
case GE_COMP_LEQUAL: desc += "ZLE:"; break;
|
|
|
|
case GE_COMP_GREATER: desc += "ZGT:"; break;
|
|
|
|
case GE_COMP_GEQUAL: desc += "ZGE:"; break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (id.depthWrite && !id.clearMode)
|
|
|
|
desc += "ZWr:";
|
|
|
|
|
|
|
|
if (id.colorTest && !id.clearMode)
|
|
|
|
desc += "CTest:";
|
|
|
|
|
|
|
|
if (id.stencilTest && !id.clearMode) {
|
2021-11-21 09:39:14 -08:00
|
|
|
switch (id.StencilTestFunc()) {
|
2021-11-21 08:21:59 -08:00
|
|
|
case GE_COMP_NEVER: desc += "SNever"; break;
|
|
|
|
case GE_COMP_ALWAYS: desc += "SAlways"; break;
|
|
|
|
case GE_COMP_EQUAL: desc += "SEQ"; break;
|
|
|
|
case GE_COMP_NOTEQUAL: desc += "SNE"; break;
|
|
|
|
case GE_COMP_LESS: desc += "SLT"; break;
|
|
|
|
case GE_COMP_LEQUAL: desc += "SLE"; break;
|
|
|
|
case GE_COMP_GREATER: desc += "SGT"; break;
|
|
|
|
case GE_COMP_GEQUAL: desc += "SGE"; break;
|
|
|
|
}
|
|
|
|
if (id.hasStencilTestMask)
|
|
|
|
desc += "Msk";
|
|
|
|
desc += StringFromFormat("%02X:", id.stencilTestRef);
|
|
|
|
}
|
|
|
|
|
2021-11-21 09:39:14 -08:00
|
|
|
switch (id.SFail()) {
|
2021-11-21 08:21:59 -08:00
|
|
|
case GE_STENCILOP_KEEP: break;
|
|
|
|
case GE_STENCILOP_ZERO: desc += "STstF0:"; break;
|
|
|
|
case GE_STENCILOP_REPLACE: desc += "STstFRpl:"; break;
|
|
|
|
case GE_STENCILOP_INVERT: desc += "STstFXor:"; break;
|
|
|
|
case GE_STENCILOP_INCR: desc += "STstFInc:"; break;
|
|
|
|
case GE_STENCILOP_DECR: desc += "STstFDec:"; break;
|
|
|
|
}
|
2021-11-21 09:39:14 -08:00
|
|
|
switch (id.ZFail()) {
|
2021-11-21 08:21:59 -08:00
|
|
|
case GE_STENCILOP_KEEP: break;
|
|
|
|
case GE_STENCILOP_ZERO: desc += "ZTstF0:"; break;
|
|
|
|
case GE_STENCILOP_REPLACE: desc += "ZTstFRpl:"; break;
|
|
|
|
case GE_STENCILOP_INVERT: desc += "ZTstFXor:"; break;
|
|
|
|
case GE_STENCILOP_INCR: desc += "ZTstFInc:"; break;
|
|
|
|
case GE_STENCILOP_DECR: desc += "ZTstFDec:"; break;
|
|
|
|
}
|
2021-11-21 09:39:14 -08:00
|
|
|
switch (id.ZPass()) {
|
2021-11-21 08:21:59 -08:00
|
|
|
case GE_STENCILOP_KEEP: break;
|
|
|
|
case GE_STENCILOP_ZERO: desc += "ZTstT0:"; break;
|
|
|
|
case GE_STENCILOP_REPLACE: desc += "ZTstTRpl:"; break;
|
|
|
|
case GE_STENCILOP_INVERT: desc += "ZTstTXor:"; break;
|
|
|
|
case GE_STENCILOP_INCR: desc += "ZTstTInc:"; break;
|
|
|
|
case GE_STENCILOP_DECR: desc += "ZTstTDec:"; break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (id.alphaBlend) {
|
2021-11-21 09:39:14 -08:00
|
|
|
switch (id.AlphaBlendEq()) {
|
2021-11-21 08:21:59 -08:00
|
|
|
case GE_BLENDMODE_MUL_AND_ADD: desc += "BlendAdd<"; break;
|
|
|
|
case GE_BLENDMODE_MUL_AND_SUBTRACT: desc += "BlendSub<"; break;
|
|
|
|
case GE_BLENDMODE_MUL_AND_SUBTRACT_REVERSE: desc += "BlendRSub<"; break;
|
|
|
|
case GE_BLENDMODE_MIN: desc += "BlendMin<"; break;
|
|
|
|
case GE_BLENDMODE_MAX: desc += "BlendMax<"; break;
|
|
|
|
case GE_BLENDMODE_ABSDIFF: desc += "BlendDiff<"; break;
|
|
|
|
}
|
2021-11-21 09:39:14 -08:00
|
|
|
switch (id.AlphaBlendSrc()) {
|
2021-11-21 08:21:59 -08:00
|
|
|
case GE_SRCBLEND_DSTCOLOR: desc += "DstRGB,"; break;
|
|
|
|
case GE_SRCBLEND_INVDSTCOLOR: desc += "1-DstRGB,"; break;
|
|
|
|
case GE_SRCBLEND_SRCALPHA: desc += "SrcA,"; break;
|
|
|
|
case GE_SRCBLEND_INVSRCALPHA: desc += "1-SrcA,"; break;
|
|
|
|
case GE_SRCBLEND_DSTALPHA: desc += "DstA,"; break;
|
|
|
|
case GE_SRCBLEND_INVDSTALPHA: desc += "1-DstA,"; break;
|
|
|
|
case GE_SRCBLEND_DOUBLESRCALPHA: desc += "2*SrcA,"; break;
|
|
|
|
case GE_SRCBLEND_DOUBLEINVSRCALPHA: desc += "1-2*SrcA,"; break;
|
|
|
|
case GE_SRCBLEND_DOUBLEDSTALPHA: desc += "2*DstA,"; break;
|
|
|
|
case GE_SRCBLEND_DOUBLEINVDSTALPHA: desc += "1-2*DstA,"; break;
|
|
|
|
case GE_SRCBLEND_FIXA: desc += "Fix,"; break;
|
|
|
|
}
|
2021-11-21 09:39:14 -08:00
|
|
|
switch (id.AlphaBlendDst()) {
|
2021-11-21 08:21:59 -08:00
|
|
|
case GE_DSTBLEND_SRCCOLOR: desc += "SrcRGB>:"; break;
|
|
|
|
case GE_DSTBLEND_INVSRCCOLOR: desc += "1-SrcRGB>:"; break;
|
|
|
|
case GE_DSTBLEND_SRCALPHA: desc += "SrcA>:"; break;
|
|
|
|
case GE_DSTBLEND_INVSRCALPHA: desc += "1-SrcA>:"; break;
|
|
|
|
case GE_DSTBLEND_DSTALPHA: desc += "DstA>:"; break;
|
|
|
|
case GE_DSTBLEND_INVDSTALPHA: desc += "1-DstA>:"; break;
|
|
|
|
case GE_DSTBLEND_DOUBLESRCALPHA: desc += "2*SrcA>:"; break;
|
|
|
|
case GE_DSTBLEND_DOUBLEINVSRCALPHA: desc += "1-2*SrcA>:"; break;
|
|
|
|
case GE_DSTBLEND_DOUBLEDSTALPHA: desc += "2*DstA>:"; break;
|
|
|
|
case GE_DSTBLEND_DOUBLEINVDSTALPHA: desc += "1-2*DstA>:"; break;
|
|
|
|
case GE_DSTBLEND_FIXB: desc += "Fix>:"; break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (id.applyLogicOp)
|
|
|
|
desc += "Logic:";
|
|
|
|
if (id.applyFog)
|
|
|
|
desc += "Fog:";
|
|
|
|
|
|
|
|
if (desc.empty())
|
|
|
|
return desc;
|
|
|
|
desc.resize(desc.size() - 1);
|
|
|
|
return desc;
|
|
|
|
}
|