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

Workaround for some SOCOM games' misuse of CLUT8 to texture from framebuffer #17297

Merged
merged 1 commit into from
Apr 18, 2023
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
1 change: 1 addition & 0 deletions Core/Compatibility.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,7 @@ void Compatibility::CheckSettings(IniFile &iniFile, const std::string &gameID) {
CheckSetting(iniFile, gameID, "BlockTransferDepth", &flags_.BlockTransferDepth);
CheckSetting(iniFile, gameID, "DaxterRotatedAnalogStick", &flags_.DaxterRotatedAnalogStick);
CheckSetting(iniFile, gameID, "ForceMaxDepthResolution", &flags_.ForceMaxDepthResolution);
CheckSetting(iniFile, gameID, "SOCOMClut8Replacement", &flags_.SOCOMClut8Replacement);
}

void Compatibility::CheckVRSettings(IniFile &iniFile, const std::string &gameID) {
Expand Down
1 change: 1 addition & 0 deletions Core/Compatibility.h
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ struct CompatFlags {
bool BlockTransferDepth;
bool DaxterRotatedAnalogStick;
bool ForceMaxDepthResolution;
bool SOCOMClut8Replacement;
};

struct VRCompat {
Expand Down
7 changes: 7 additions & 0 deletions GPU/Common/DepalettizeShaderCommon.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,13 @@ void GenerateDepalShader300(ShaderWriter &writer, const DepalConfig &config) {
if (shiftedMask & 0x7C00) writer.C(" int b = int(color.b * 31.99);\n"); else writer.C(" int b = 0;\n");
if (shiftedMask & 0x8000) writer.C(" int a = int(color.a);\n"); else writer.C(" int a = 0;\n");
writer.C(" int index = (a << 15) | (b << 10) | (g << 5) | (r);\n");

if (config.textureFormat == GE_TFMT_CLUT8) {
// SOCOM case. #16210
// To debug the issue, remove this shift to see the texture (check for clamping etc).
writer.C(" index >>= 8;\n");
}

break;
case GE_FORMAT_DEPTH16:
// Decode depth buffer.
Expand Down
2 changes: 1 addition & 1 deletion GPU/Common/Draw2D.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -261,7 +261,7 @@ Draw2DPipeline *Draw2D::Create2DPipeline(std::function<Draw2DPipelineInfo (Shade

ShaderModule *fs = draw_->CreateShaderModule(ShaderStage::Fragment, shaderLanguageDesc.shaderLanguage, (const uint8_t *)fsCode, strlen(fsCode), info.tag);

_assert_(fs);
_assert_msg_(fs, "Failed to create shader module!\n%s", fsCode);

// verts have positions in 2D clip coordinates.
static const InputLayoutDesc desc = {
Expand Down
31 changes: 26 additions & 5 deletions GPU/Common/TextureCacheCommon.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1028,18 +1028,28 @@ bool TextureCacheCommon::MatchFramebuffer(
}

// Check works for D16 too.
// These are combinations that we have special-cased handling for. There are more
// ones possible, but rare - we'll add them as we find them used.
const bool matchingClutFormat =
(fb_format == GE_FORMAT_DEPTH16 && entry.format == GE_TFMT_CLUT16) ||
(fb_format == GE_FORMAT_DEPTH16 && entry.format == GE_TFMT_5650) ||
(fb_format == GE_FORMAT_8888 && entry.format == GE_TFMT_CLUT32) ||
(fb_format != GE_FORMAT_8888 && entry.format == GE_TFMT_CLUT16) ||
(fb_format == GE_FORMAT_8888 && entry.format == GE_TFMT_CLUT8);
(fb_format == GE_FORMAT_8888 && entry.format == GE_TFMT_CLUT8) ||
(fb_format == GE_FORMAT_5551 && entry.format == GE_TFMT_CLUT8 && PSP_CoreParameter().compat.flags().SOCOMClut8Replacement);

const int texBitsPerPixel = std::max(1U, (u32)textureBitsPerPixel[entry.format]);
const int texBitsPerPixel = TextureFormatBitsPerPixel(entry.format);
const int byteOffset = texaddr - addr;
if (byteOffset > 0) {
int texbpp = texBitsPerPixel;
if (fb_format == GE_FORMAT_5551 && entry.format == GE_TFMT_CLUT8) {
// In this case we treat CLUT8 as if it were CLUT16, see issue #16210. So we need
// to compute the x offset appropriately.
texbpp = 16;
}

matchInfo->yOffset = byteOffset / fb_stride_in_bytes;
matchInfo->xOffset = 8 * (byteOffset % fb_stride_in_bytes) / texBitsPerPixel;
matchInfo->xOffset = 8 * (byteOffset % fb_stride_in_bytes) / texbpp;
} else if (byteOffset < 0) {
int texelOffset = 8 * byteOffset / texBitsPerPixel;
// We don't support negative Y offsets, and negative X offsets are only for the Killzone workaround.
Expand All @@ -1066,7 +1076,7 @@ bool TextureCacheCommon::MatchFramebuffer(
// Trying to play it safe. Below 0x04110000 is almost always framebuffers.
// TODO: Maybe we can reduce this check and find a better way above 0x04110000?
if (matchInfo->yOffset > MAX_SUBAREA_Y_OFFSET_SAFE && addr > 0x04110000 && !PSP_CoreParameter().compat.flags().AllowLargeFBTextureOffsets) {
WARN_LOG_REPORT_ONCE(subareaIgnored, G3D, "Ignoring possible texturing from framebuffer at %08x +%dx%d / %dx%d", fb_address, matchInfo->xOffset, matchInfo->yOffset, framebuffer->width, framebuffer->height);
WARN_LOG_ONCE(subareaIgnored, G3D, "Ignoring possible texturing from framebuffer at %08x +%dx%d / %dx%d", fb_address, matchInfo->xOffset, matchInfo->yOffset, framebuffer->width, framebuffer->height);
return false;
}

Expand Down Expand Up @@ -1133,6 +1143,11 @@ void TextureCacheCommon::SetTextureFramebuffer(const AttachCandidate &candidate)
gstate_c.curTextureWidth = framebuffer->bufferWidth;
gstate_c.curTextureHeight = framebuffer->bufferHeight;

if (candidate.channel == RASTER_COLOR && gstate.getTextureFormat() == GE_TFMT_CLUT8 && framebuffer->fb_format == GE_FORMAT_5551 && PSP_CoreParameter().compat.flags().SOCOMClut8Replacement) {
// See #16210. UV must be adjusted as if the texture was twice the width.
gstate_c.curTextureWidth *= 2.0f;
}

if (needsDepthXSwizzle) {
gstate_c.curTextureWidth = RoundUpToPowerOf2(gstate_c.curTextureWidth);
}
Expand Down Expand Up @@ -2145,6 +2160,7 @@ void TextureCacheCommon::ApplyTexture() {
}
}

// Can we depalettize at all? This refers to both in-fragment-shader depal and "traditional" depal through a separate pass.
static bool CanDepalettize(GETextureFormat texFormat, GEBufferFormat bufferFormat) {
if (IsClutFormat(texFormat)) {
switch (bufferFormat) {
Expand All @@ -2155,6 +2171,10 @@ static bool CanDepalettize(GETextureFormat texFormat, GEBufferFormat bufferForma
if (texFormat == GE_TFMT_CLUT16) {
return true;
}
if (texFormat == GE_TFMT_CLUT8 && bufferFormat == GE_FORMAT_5551 && PSP_CoreParameter().compat.flags().SOCOMClut8Replacement) {
// Wacky case from issue #16210 (SOCOM etc).
return true;
}
break;
case GE_FORMAT_8888:
if (texFormat == GE_TFMT_CLUT32 || texFormat == GE_TFMT_CLUT8) { // clut8 takes a special depal mode.
Expand Down Expand Up @@ -2214,7 +2234,8 @@ void TextureCacheCommon::ApplyTextureFramebuffer(VirtualFramebuffer *framebuffer
bool useShaderDepal = framebufferManager_->GetCurrentRenderVFB() != framebuffer &&
!depth && clutRenderAddress_ == 0xFFFFFFFF &&
!gstate_c.curTextureIs3D &&
draw_->GetShaderLanguageDesc().bitwiseOps;
draw_->GetShaderLanguageDesc().bitwiseOps &&
!(texFormat == GE_TFMT_CLUT8 && framebuffer->fb_format == GE_FORMAT_5551); // socom

switch (draw_->GetShaderLanguageDesc().shaderLanguage) {
case ShaderLanguage::HLSL_D3D9:
Expand Down
19 changes: 19 additions & 0 deletions GPU/Common/TextureDecoder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,25 @@
#define DO_NOT_VECTORIZE_LOOP
#endif

const u8 textureBitsPerPixel[16] = {
16, //GE_TFMT_5650,
16, //GE_TFMT_5551,
16, //GE_TFMT_4444,
32, //GE_TFMT_8888,
4, //GE_TFMT_CLUT4,
8, //GE_TFMT_CLUT8,
16, //GE_TFMT_CLUT16,
32, //GE_TFMT_CLUT32,
4, //GE_TFMT_DXT1,
8, //GE_TFMT_DXT3,
8, //GE_TFMT_DXT5,
0, // INVALID,
0, // INVALID,
0, // INVALID,
0, // INVALID,
0, // INVALID,
};

#ifdef _M_SSE

static u32 QuickTexHashSSE2(const void *checkp, u32 size) {
Expand Down
25 changes: 7 additions & 18 deletions GPU/Common/TextureDecoder.h
Original file line number Diff line number Diff line change
Expand Up @@ -73,27 +73,16 @@ uint32_t GetDXT1Texel(const DXT1Block *src, int x, int y);
uint32_t GetDXT3Texel(const DXT3Block *src, int x, int y);
uint32_t GetDXT5Texel(const DXT5Block *src, int x, int y);

static const u8 textureBitsPerPixel[16] = {
16, //GE_TFMT_5650,
16, //GE_TFMT_5551,
16, //GE_TFMT_4444,
32, //GE_TFMT_8888,
4, //GE_TFMT_CLUT4,
8, //GE_TFMT_CLUT8,
16, //GE_TFMT_CLUT16,
32, //GE_TFMT_CLUT32,
4, //GE_TFMT_DXT1,
8, //GE_TFMT_DXT3,
8, //GE_TFMT_DXT5,
0, // INVALID,
0, // INVALID,
0, // INVALID,
0, // INVALID,
0, // INVALID,
};
extern const u8 textureBitsPerPixel[16];

u32 GetTextureBufw(int level, u32 texaddr, GETextureFormat format);

// WARNING: Bits not bytes, this is needed due to the presence of 4 - bit formats.
inline u32 TextureFormatBitsPerPixel(GETextureFormat format) {
u32 bits = textureBitsPerPixel[(int)format];
return bits != 0 ? bits : 1; // Best to return 1 here to survive divisions in case of invalid data.
}

inline bool AlphaSumIsFull(u32 alphaSum, u32 fullAlphaMask) {
return fullAlphaMask != 0 && (alphaSum & fullAlphaMask) == fullAlphaMask;
}
Expand Down
2 changes: 1 addition & 1 deletion GPU/GLES/ShaderManagerGLES.h
Original file line number Diff line number Diff line change
Expand Up @@ -209,7 +209,7 @@ class ShaderManagerGLES : public ShaderManagerCommon {
GLRenderManager *render_;
LinkedShaderCache linkedShaderCache_;

bool lastVShaderSame_;
bool lastVShaderSame_ = false;

FShaderID lastFSID_;
VShaderID lastVSID_;
Expand Down
13 changes: 13 additions & 0 deletions assets/compat.ini
Original file line number Diff line number Diff line change
Expand Up @@ -1555,3 +1555,16 @@ UCET00844 = true
UCUS98705 = true
UCED00971 = true
UCUS98713 = true

[SOCOMClut8Replacement]
# SOCOM and other games use CLUT8 with crafty sampling as if it was CLUT16. Issue #16210
UCES00855 = true
UCUS98649 = true
NPUG70003 = true # demo
UCUS98714 = true # demo

# SOCOM Fireteam Bravo 3
UCES01242 = true
NPHG00032 = true
UCUS98716 = true
NPEG90024 = true # demo