mirror of
https://github.com/hrydgard/ppsspp.git
synced 2025-02-03 12:12:06 +00:00
Merge pull request #1694 from unknownbrackets/font-fix
Match PSP error behavior in some sceFont functions
This commit is contained in:
commit
87a78f2e65
@ -25,6 +25,9 @@
|
||||
#include "Core/Font/PGF.h"
|
||||
#include "Core/HLE/HLE.h"
|
||||
|
||||
#include "GPU/GPUInterface.h"
|
||||
#include "GPU/GPUState.h"
|
||||
|
||||
// These fonts, created by ttf2pgf, don't have complete glyph info and need to be identified.
|
||||
static bool isJPCSPFont(const char *fontName) {
|
||||
return !strcmp(fontName, "Liberation") || !strcmp(fontName, "Sazanami") || !strcmp(fontName, "UnDotum");
|
||||
@ -241,11 +244,12 @@ int PGF::GetCharIndex(int charCode, const std::vector<int> &charmapCompressed) {
|
||||
|
||||
bool PGF::GetCharInfo(int charCode, PGFCharInfo *charInfo) {
|
||||
Glyph glyph;
|
||||
memset(charInfo, 0, sizeof(*charInfo));
|
||||
|
||||
if (!GetCharGlyph(charCode, FONT_PGF_CHARGLYPH, glyph)) {
|
||||
// Character not in font, return zeroed charInfo as on real PSP.
|
||||
return false;
|
||||
}
|
||||
memset(charInfo, 0, sizeof(*charInfo));
|
||||
|
||||
charInfo->bitmapWidth = glyph.w;
|
||||
charInfo->bitmapHeight = glyph.h;
|
||||
@ -408,7 +412,7 @@ bool PGF::GetCharGlyph(int charCode, int glyphType, Glyph &glyph) {
|
||||
return true;
|
||||
}
|
||||
|
||||
void PGF::DrawCharacter(u32 base, int bpl, int bufWidth, int bufHeight, int x, int y, int clipX, int clipY, int clipWidth, int clipHeight, int pixelformat, int charCode, int altCharCode, int glyphType) {
|
||||
void PGF::DrawCharacter(const GlyphImage *image, int clipX, int clipY, int clipWidth, int clipHeight, int charCode, int altCharCode, int glyphType) {
|
||||
Glyph glyph;
|
||||
if (!GetCharGlyph(charCode, glyphType, glyph)) {
|
||||
// No Glyph available for this charCode, try to use the alternate char.
|
||||
@ -431,6 +435,9 @@ void PGF::DrawCharacter(u32 base, int bpl, int bufWidth, int bufHeight, int x, i
|
||||
int numberPixels = glyph.w * glyph.h;
|
||||
int pixelIndex = 0;
|
||||
|
||||
int x = image->xPos64 >> 6;
|
||||
int y = image->yPos64 >> 6;
|
||||
|
||||
while (pixelIndex < numberPixels && bitPtr + 8 < fontDataSize * 8) {
|
||||
// This is some kind of nibble based RLE compression.
|
||||
int nibble = getBits(4, fontData, bitPtr);
|
||||
@ -466,7 +473,7 @@ void PGF::DrawCharacter(u32 base, int bpl, int bufWidth, int bufHeight, int x, i
|
||||
if (pixelX >= clipX && pixelX < clipX + clipWidth && pixelY >= clipY && pixelY < clipY + clipHeight) {
|
||||
// 4-bit color value
|
||||
int pixelColor = value;
|
||||
switch (pixelformat) {
|
||||
switch (image->pixelFormat) {
|
||||
case PSP_FONT_PIXELFORMAT_8:
|
||||
// 8-bit color value
|
||||
pixelColor |= pixelColor << 4;
|
||||
@ -485,12 +492,14 @@ void PGF::DrawCharacter(u32 base, int bpl, int bufWidth, int bufHeight, int x, i
|
||||
break;
|
||||
}
|
||||
|
||||
SetFontPixel(base, bpl, bufWidth, bufHeight, pixelX, pixelY, pixelColor, pixelformat);
|
||||
SetFontPixel(image->bufferPtr, image->bytesPerLine, image->bufWidth, image->bufHeight, pixelX, pixelY, pixelColor, image->pixelFormat);
|
||||
}
|
||||
|
||||
pixelIndex++;
|
||||
}
|
||||
}
|
||||
|
||||
gpu->InvalidateCache(image->bufferPtr, image->bytesPerLine * image->bufHeight, GPU_INVALIDATE_SAFE);
|
||||
}
|
||||
|
||||
void PGF::SetFontPixel(u32 base, int bpl, int bufWidth, int bufHeight, int x, int y, int pixelColor, int pixelformat) {
|
||||
|
@ -108,6 +108,17 @@ struct Glyph {
|
||||
u32 ptr;
|
||||
};
|
||||
|
||||
struct GlyphImage {
|
||||
FontPixelFormat pixelFormat;
|
||||
s32 xPos64;
|
||||
s32 yPos64;
|
||||
u16 bufWidth;
|
||||
u16 bufHeight;
|
||||
u16 bytesPerLine;
|
||||
u16 pad;
|
||||
u32 bufferPtr;
|
||||
};
|
||||
|
||||
#pragma pack(push,1)
|
||||
struct PGFHeader
|
||||
{
|
||||
@ -243,7 +254,7 @@ public:
|
||||
|
||||
bool GetCharInfo(int charCode, PGFCharInfo *ci);
|
||||
void GetFontInfo(PGFFontInfo *fi);
|
||||
void DrawCharacter(u32 base, int bpl, int bufWidth, int bufHeight, int x, int y, int clipX, int clipY, int clipWidth, int clipHeight, int pixelformat, int charCode, int altCharCode, int glyphType);
|
||||
void DrawCharacter(const GlyphImage *image, int clipX, int clipY, int clipWidth, int clipHeight, int charCode, int altCharCode, int glyphType);
|
||||
|
||||
void DoState(PointerWrap &p);
|
||||
|
||||
|
@ -57,17 +57,6 @@ struct FontNewLibParams {
|
||||
u32 ioFinishFuncAddr;
|
||||
};
|
||||
|
||||
struct GlyphImage {
|
||||
FontPixelFormat pixelFormat;
|
||||
s32 xPos64;
|
||||
s32 yPos64;
|
||||
u16 bufWidth;
|
||||
u16 bufHeight;
|
||||
u16 bytesPerLine;
|
||||
u16 pad;
|
||||
u32 bufferPtr;
|
||||
};
|
||||
|
||||
struct FontRegistryEntry {
|
||||
int hSize;
|
||||
int vSize;
|
||||
@ -231,6 +220,7 @@ public:
|
||||
: fontLibID_(fontLibID), font_(font), handle_(handle) {}
|
||||
|
||||
Font *GetFont() { return font_; }
|
||||
PGF *GetPGF() { return font_->GetPGF(); }
|
||||
FontLib *GetFontLib() { if (!IsOpen()) return NULL; return fontLibList[fontLibID_]; }
|
||||
u32 Handle() const { return handle_; }
|
||||
|
||||
@ -615,13 +605,18 @@ int sceFontDoneLib(u32 fontLibHandle) {
|
||||
|
||||
// Open internal font into a FontLib
|
||||
u32 sceFontOpen(u32 libHandle, u32 index, u32 mode, u32 errorCodePtr) {
|
||||
INFO_LOG(HLE, "sceFontOpen(%x, %x, %x, %x)", libHandle, index, mode, errorCodePtr);
|
||||
if (!Memory::IsValidAddress(errorCodePtr)) {
|
||||
Memory::Write_U32(ERROR_FONT_INVALID_PARAMETER, errorCodePtr);
|
||||
// Would crash on the PSP.
|
||||
ERROR_LOG(HLE, "sceFontOpen(%x, %x, %x, %x): invalid pointer", libHandle, index, mode, errorCodePtr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
INFO_LOG(HLE, "sceFontOpen(%x, %x, %x, %x)", libHandle, index, mode, errorCodePtr);
|
||||
FontLib *fontLib = GetFontLib(libHandle);
|
||||
if (fontLib == NULL) {
|
||||
Memory::Write_U32(ERROR_FONT_INVALID_LIBID, errorCodePtr);
|
||||
return 0;
|
||||
}
|
||||
if (index >= internalFonts.size()) {
|
||||
Memory::Write_U32(ERROR_FONT_INVALID_PARAMETER, errorCodePtr);
|
||||
return 0;
|
||||
@ -763,21 +758,21 @@ int sceFontFindFont(u32 libHandlePtr, u32 fontStylePtr, u32 errorCodePtr) {
|
||||
}
|
||||
|
||||
int sceFontGetFontInfo(u32 fontHandle, u32 fontInfoPtr) {
|
||||
ERROR_LOG(HLE, "sceFontGetFontInfo(%x, %x)", fontHandle, fontInfoPtr);
|
||||
|
||||
PGFFontInfo fi;
|
||||
memset (&fi, 0, sizeof(fi));
|
||||
if (!Memory::IsValidAddress(fontInfoPtr))
|
||||
return 0;
|
||||
|
||||
if (!Memory::IsValidAddress(fontInfoPtr)) {
|
||||
ERROR_LOG(HLE, "sceFontGetFontInfo(%x, %x): bad fontInfo pointer", fontHandle, fontInfoPtr);
|
||||
return ERROR_FONT_INVALID_PARAMETER;
|
||||
}
|
||||
LoadedFont *font = GetLoadedFont(fontHandle, true);
|
||||
if (!font)
|
||||
return 0;
|
||||
PGF *pgf = font->GetFont()->GetPGF();
|
||||
pgf->GetFontInfo(&fi);
|
||||
fi.fontStyle = font->GetFont()->GetFontStyle();
|
||||
if (!font) {
|
||||
ERROR_LOG(HLE, "sceFontGetFontInfo(%x, %x): bad font", fontHandle, fontInfoPtr);
|
||||
return ERROR_FONT_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
INFO_LOG(HLE, "sceFontGetFontInfo(%x, %x)", fontHandle, fontInfoPtr);
|
||||
auto fi = Memory::GetStruct<PGFFontInfo>(fontInfoPtr);
|
||||
font->GetPGF()->GetFontInfo(fi);
|
||||
fi->fontStyle = font->GetFont()->GetFontStyle();
|
||||
|
||||
Memory::WriteStruct(fontInfoPtr, &fi);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -789,19 +784,21 @@ int sceFontGetFontInfoByIndexNumber(u32 libHandle, u32 fontInfoPtr, u32 unknown,
|
||||
}
|
||||
|
||||
int sceFontGetCharInfo(u32 fontHandle, u32 charCode, u32 charInfoPtr) {
|
||||
INFO_LOG(HLE, "sceFontGetCharInfo(%08x, %i, %08x)", fontHandle, charCode, charInfoPtr);
|
||||
if (!Memory::IsValidAddress(charInfoPtr))
|
||||
return -1;
|
||||
|
||||
PGFCharInfo charInfo;
|
||||
memset(&charInfo, 0, sizeof(charInfo));
|
||||
LoadedFont *font = GetLoadedFont(fontHandle, false);
|
||||
if (font) {
|
||||
font->GetFont()->GetPGF()->GetCharInfo(charCode, &charInfo);
|
||||
} else {
|
||||
ERROR_LOG(HLE, "sceFontGetCharInfo - invalid font");
|
||||
if (!Memory::IsValidAddress(charInfoPtr)) {
|
||||
ERROR_LOG(HLE, "sceFontGetCharInfo(%08x, %i, %08x): bad charInfo pointer", fontHandle, charCode, charInfoPtr);
|
||||
return ERROR_FONT_INVALID_PARAMETER;
|
||||
}
|
||||
Memory::WriteStruct(charInfoPtr, &charInfo);
|
||||
LoadedFont *font = GetLoadedFont(fontHandle, false);
|
||||
if (!font) {
|
||||
// The PSP crashes, but we assume it'd work like sceFontGetFontInfo(), and not touch charInfo.
|
||||
ERROR_LOG(HLE, "sceFontGetCharInfo(%08x, %i, %08x): bad font", fontHandle, charCode, charInfoPtr);
|
||||
return ERROR_FONT_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
DEBUG_LOG(HLE, "sceFontGetCharInfo(%08x, %i, %08x)", fontHandle, charCode, charInfoPtr);
|
||||
auto charInfo = Memory::GetStruct<PGFCharInfo>(charInfoPtr);
|
||||
font->GetPGF()->GetCharInfo(charCode, charInfo);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -820,7 +817,7 @@ int sceFontGetCharImageRect(u32 fontHandle, u32 charCode, u32 charRectPtr) {
|
||||
PGFCharInfo charInfo;
|
||||
LoadedFont *font = GetLoadedFont(fontHandle, false);
|
||||
if (font) {
|
||||
font->GetFont()->GetPGF()->GetCharInfo(charCode, &charInfo);
|
||||
font->GetPGF()->GetCharInfo(charCode, &charInfo);
|
||||
Memory::Write_U16(charInfo.bitmapWidth, charRectPtr); // character bitmap width in pixels
|
||||
Memory::Write_U16(charInfo.bitmapHeight, charRectPtr + 2); // character bitmap height in pixels
|
||||
} else {
|
||||
@ -835,44 +832,38 @@ int sceFontGetShadowImageRect(u32 fontHandle, u32 charCode, u32 charRectPtr) {
|
||||
}
|
||||
|
||||
int sceFontGetCharGlyphImage(u32 fontHandle, u32 charCode, u32 glyphImagePtr) {
|
||||
INFO_LOG(HLE, "sceFontGetCharGlyphImage(%x, %x, %x)", fontHandle, charCode, glyphImagePtr);
|
||||
|
||||
int pixelFormat = Memory::Read_U32(glyphImagePtr);
|
||||
int xPos64 = Memory::Read_U32(glyphImagePtr+4);
|
||||
int yPos64 = Memory::Read_U32(glyphImagePtr+8);
|
||||
int bufWidth = Memory::Read_U16(glyphImagePtr+12);
|
||||
int bufHeight = Memory::Read_U16(glyphImagePtr+14);
|
||||
int bytesPerLine = Memory::Read_U16(glyphImagePtr+16);
|
||||
int buffer = Memory::Read_U32(glyphImagePtr+20);
|
||||
|
||||
if (!Memory::IsValidAddress(glyphImagePtr)) {
|
||||
ERROR_LOG(HLE, "sceFontGetCharGlyphImage(%x, %x, %x): bad glyphImage pointer", fontHandle, charCode, glyphImagePtr);
|
||||
return ERROR_FONT_INVALID_PARAMETER;
|
||||
}
|
||||
LoadedFont *font = GetLoadedFont(fontHandle, false);
|
||||
if (!font) {
|
||||
ERROR_LOG(HLE, "%08x is not a valid font handle!", fontHandle);
|
||||
return 0;
|
||||
ERROR_LOG(HLE, "sceFontGetCharGlyphImage(%x, %x, %x): bad font", fontHandle, charCode, glyphImagePtr);
|
||||
return ERROR_FONT_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
INFO_LOG(HLE, "sceFontGetCharGlyphImage(%x, %x, %x)", fontHandle, charCode, glyphImagePtr);
|
||||
auto glyph = Memory::GetStruct<const GlyphImage>(glyphImagePtr);
|
||||
int altCharCode = font->GetFontLib()->GetAltCharCode();
|
||||
font->GetFont()->GetPGF()->DrawCharacter(buffer, bytesPerLine, bufWidth, bufHeight, xPos64 >> 6, yPos64 >> 6, 0, 0, 8192, 8192, pixelFormat, charCode, altCharCode, FONT_PGF_CHARGLYPH);
|
||||
font->GetPGF()->DrawCharacter(glyph, 0, 0, 8192, 8192, charCode, altCharCode, FONT_PGF_CHARGLYPH);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sceFontGetCharGlyphImage_Clip(u32 fontHandle, u32 charCode, u32 glyphImagePtr, int clipXPos, int clipYPos, int clipWidth, int clipHeight) {
|
||||
INFO_LOG(HLE, "sceFontGetCharGlyphImage_Clip(%08x, %i, %08x, %i, %i, %i, %i)", fontHandle, charCode, glyphImagePtr, clipXPos, clipYPos, clipWidth, clipHeight);
|
||||
|
||||
int pixelFormat = Memory::Read_U32(glyphImagePtr);
|
||||
int xPos64 = Memory::Read_U32(glyphImagePtr+4);
|
||||
int yPos64 = Memory::Read_U32(glyphImagePtr+8);
|
||||
int bufWidth = Memory::Read_U16(glyphImagePtr+12);
|
||||
int bufHeight = Memory::Read_U16(glyphImagePtr+14);
|
||||
int bytesPerLine = Memory::Read_U16(glyphImagePtr+16);
|
||||
int buffer = Memory::Read_U32(glyphImagePtr+20);
|
||||
|
||||
if (!Memory::IsValidAddress(glyphImagePtr)) {
|
||||
ERROR_LOG(HLE, "sceFontGetCharGlyphImage_Clip(%08x, %i, %08x, %i, %i, %i, %i): bad glyphImage pointer", fontHandle, charCode, glyphImagePtr, clipXPos, clipYPos, clipWidth, clipHeight);
|
||||
return ERROR_FONT_INVALID_PARAMETER;
|
||||
}
|
||||
LoadedFont *font = GetLoadedFont(fontHandle, false);
|
||||
if (!font) {
|
||||
ERROR_LOG(HLE, "%08x is not a valid font handle!", fontHandle);
|
||||
return 0;
|
||||
ERROR_LOG(HLE, "sceFontGetCharGlyphImage_Clip(%08x, %i, %08x, %i, %i, %i, %i): bad font", fontHandle, charCode, glyphImagePtr, clipXPos, clipYPos, clipWidth, clipHeight);
|
||||
return ERROR_FONT_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
INFO_LOG(HLE, "sceFontGetCharGlyphImage_Clip(%08x, %i, %08x, %i, %i, %i, %i)", fontHandle, charCode, glyphImagePtr, clipXPos, clipYPos, clipWidth, clipHeight);
|
||||
auto glyph = Memory::GetStruct<const GlyphImage>(glyphImagePtr);
|
||||
int altCharCode = font->GetFontLib()->GetAltCharCode();
|
||||
font->GetFont()->GetPGF()->DrawCharacter(buffer, bytesPerLine, bufWidth, bufHeight, xPos64 >> 6, yPos64 >> 6, clipXPos, clipYPos, clipXPos + clipWidth, clipYPos + clipHeight, pixelFormat, charCode, altCharCode, FONT_PGF_CHARGLYPH);
|
||||
font->GetPGF()->DrawCharacter(glyph, clipXPos, clipYPos, clipXPos + clipWidth, clipYPos + clipHeight, charCode, altCharCode, FONT_PGF_CHARGLYPH);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -307,7 +307,7 @@ int sceKernelDcacheInvalidateRange(u32 addr, int size)
|
||||
return SCE_KERNEL_ERROR_CACHE_ALIGNMENT;
|
||||
|
||||
if (addr != 0)
|
||||
gpu->InvalidateCache(addr, size);
|
||||
gpu->InvalidateCache(addr, size, GPU_INVALIDATE_HINT);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@ -325,7 +325,7 @@ int sceKernelDcacheWritebackAll()
|
||||
#endif
|
||||
// Some games seem to use this a lot, it doesn't make sense
|
||||
// to zap the whole texture cache.
|
||||
gpu->InvalidateCacheHint(0, -1);
|
||||
gpu->InvalidateCache(0, -1, GPU_INVALIDATE_ALL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -338,7 +338,7 @@ int sceKernelDcacheWritebackRange(u32 addr, int size)
|
||||
return SCE_KERNEL_ERROR_INVALID_SIZE;
|
||||
|
||||
if (size > 0 && addr != 0) {
|
||||
gpu->InvalidateCache(addr, size);
|
||||
gpu->InvalidateCache(addr, size, GPU_INVALIDATE_HINT);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@ -351,7 +351,7 @@ int sceKernelDcacheWritebackInvalidateRange(u32 addr, int size)
|
||||
return SCE_KERNEL_ERROR_INVALID_SIZE;
|
||||
|
||||
if (size > 0 && addr != 0) {
|
||||
gpu->InvalidateCache(addr, size);
|
||||
gpu->InvalidateCache(addr, size, GPU_INVALIDATE_HINT);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@ -360,7 +360,7 @@ int sceKernelDcacheWritebackInvalidateAll()
|
||||
#ifdef LOG_CACHE
|
||||
NOTICE_LOG(HLE,"sceKernelDcacheInvalidateAll()");
|
||||
#endif
|
||||
gpu->InvalidateCacheHint(0, -1);
|
||||
gpu->InvalidateCache(0, -1, GPU_INVALIDATE_ALL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -980,21 +980,14 @@ void GLES_GPU::DoBlockTransfer() {
|
||||
|
||||
// TODO: Notify all overlapping FBOs that they need to reload.
|
||||
|
||||
textureCache_.Invalidate(dstBasePtr + dstY * dstStride + dstX, height * dstStride + width * bpp, true);
|
||||
textureCache_.Invalidate(dstBasePtr + dstY * dstStride + dstX, height * dstStride + width * bpp, GPU_INVALIDATE_HINT);
|
||||
}
|
||||
|
||||
void GLES_GPU::InvalidateCache(u32 addr, int size) {
|
||||
void GLES_GPU::InvalidateCache(u32 addr, int size, GPUInvalidationType type) {
|
||||
if (size > 0)
|
||||
textureCache_.Invalidate(addr, size, true);
|
||||
textureCache_.Invalidate(addr, size, type);
|
||||
else
|
||||
textureCache_.InvalidateAll(true);
|
||||
}
|
||||
|
||||
void GLES_GPU::InvalidateCacheHint(u32 addr, int size) {
|
||||
if (size > 0)
|
||||
textureCache_.Invalidate(addr, size, false);
|
||||
else
|
||||
textureCache_.InvalidateAll(false);
|
||||
textureCache_.InvalidateAll(type);
|
||||
}
|
||||
|
||||
void GLES_GPU::ClearCacheNextFrame() {
|
||||
|
@ -44,8 +44,7 @@ public:
|
||||
virtual void CopyDisplayToOutput();
|
||||
virtual void BeginFrame();
|
||||
virtual void UpdateStats();
|
||||
virtual void InvalidateCache(u32 addr, int size);
|
||||
virtual void InvalidateCacheHint(u32 addr, int size);
|
||||
virtual void InvalidateCache(u32 addr, int size, GPUInvalidationType type);
|
||||
virtual void ClearCacheNextFrame();
|
||||
virtual void DeviceLost(); // Only happens on Android. Drop all textures and shaders.
|
||||
|
||||
|
@ -108,7 +108,7 @@ void TextureCache::Decimate() {
|
||||
}
|
||||
}
|
||||
|
||||
void TextureCache::Invalidate(u32 addr, int size, bool force) {
|
||||
void TextureCache::Invalidate(u32 addr, int size, GPUInvalidationType type) {
|
||||
addr &= 0xFFFFFFF;
|
||||
u32 addr_end = addr + size;
|
||||
|
||||
@ -125,10 +125,10 @@ void TextureCache::Invalidate(u32 addr, int size, bool force) {
|
||||
if (iter->second.status == TexCacheEntry::STATUS_RELIABLE) {
|
||||
iter->second.status = TexCacheEntry::STATUS_HASHING;
|
||||
}
|
||||
if (force) {
|
||||
if (type != GPU_INVALIDATE_ALL) {
|
||||
gpuStats.numTextureInvalidations++;
|
||||
// Start it over from 0.
|
||||
iter->second.numFrames = 0;
|
||||
// Start it over from 0 (unless it's safe.)
|
||||
iter->second.numFrames = type == GPU_INVALIDATE_SAFE ? 256 : 0;
|
||||
iter->second.framesUntilNextFullHash = 0;
|
||||
} else {
|
||||
iter->second.invalidHint++;
|
||||
@ -137,8 +137,8 @@ void TextureCache::Invalidate(u32 addr, int size, bool force) {
|
||||
}
|
||||
}
|
||||
|
||||
void TextureCache::InvalidateAll(bool force) {
|
||||
Invalidate(0, 0xFFFFFFFF, force);
|
||||
void TextureCache::InvalidateAll(GPUInvalidationType type) {
|
||||
Invalidate(0, 0xFFFFFFFF, type);
|
||||
}
|
||||
|
||||
void TextureCache::ClearNextFrame() {
|
||||
@ -318,12 +318,39 @@ inline void DeIndexTexture4(ClutT *dest, const u8 *indexed, int length, const Cl
|
||||
}
|
||||
}
|
||||
|
||||
template <typename ClutT>
|
||||
inline void DeIndexTexture4Optimal(ClutT *dest, const u8 *indexed, int length, ClutT color) {
|
||||
for (int i = 0; i < length; i += 2) {
|
||||
u8 index = *indexed++;
|
||||
dest[i + 0] = color | ((index >> 0) & 0xf);
|
||||
dest[i + 1] = color | ((index >> 4) & 0xf);
|
||||
}
|
||||
}
|
||||
|
||||
template <>
|
||||
inline void DeIndexTexture4Optimal<u16>(u16 *dest, const u8 *indexed, int length, u16 color) {
|
||||
const u16 *indexed16 = (const u16 *)indexed;
|
||||
const u32 color32 = (color << 16) | color;
|
||||
u32 *dest32 = (u32 *)dest;
|
||||
for (int i = 0; i < length / 2; i += 2) {
|
||||
u16 index = *indexed16++;
|
||||
dest32[i + 0] = color32 | ((index & 0x00f0) << 12) | ((index & 0x000f) >> 0);
|
||||
dest32[i + 1] = color32 | ((index & 0xf000) << 4) | ((index & 0x0f00) >> 8);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename ClutT>
|
||||
inline void DeIndexTexture4(ClutT *dest, const u32 texaddr, int length, const ClutT *clut) {
|
||||
const u8 *indexed = (const u8 *) Memory::GetPointer(texaddr);
|
||||
DeIndexTexture4(dest, indexed, length, clut);
|
||||
}
|
||||
|
||||
template <typename ClutT>
|
||||
inline void DeIndexTexture4Optimal(ClutT *dest, const u32 texaddr, int length, ClutT color) {
|
||||
const u8 *indexed = (const u8 *) Memory::GetPointer(texaddr);
|
||||
DeIndexTexture4Optimal(dest, indexed, length, color);
|
||||
}
|
||||
|
||||
void *TextureCache::readIndexedTex(int level, u32 texaddr, int bytesPerIndex, GLuint dstFmt) {
|
||||
// Special rules for kernel textures (PPGe):
|
||||
int mask = 0x3FF;
|
||||
@ -1036,12 +1063,41 @@ void *TextureCache::DecodeTextureLevel(u8 format, u8 clutformat, int level, u32
|
||||
const u16 *clut = clutBuf16;
|
||||
u32 clutSharingOffset = 0; //(gstate.mipmapShareClut & 1) ? 0 : level * 16;
|
||||
texByteAlign = 2;
|
||||
|
||||
// Special optimization: fonts typically draw clut4 with just alpha values in a single color.
|
||||
bool linearClut = false;
|
||||
u16 linearColor = 0;
|
||||
if (gstate.clutformat == (0xC500FF00 | GE_CMODE_16BIT_ABGR4444)) {
|
||||
// TODO: Do this check once per CLUT load?
|
||||
linearClut = true;
|
||||
linearColor = clut[clutSharingOffset + 15] & 0xFFF0;
|
||||
for (int i = 0; i < 16; ++i) {
|
||||
if ((clut[clutSharingOffset + i] & 0xf) != i) {
|
||||
linearClut = false;
|
||||
break;
|
||||
}
|
||||
// Alpha 0 doesn't matter.
|
||||
if (i != 0 && (clut[clutSharingOffset + i] & 0xFFF0) != linearColor) {
|
||||
linearClut = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!(gstate.texmode & 1)) {
|
||||
DeIndexTexture4(tmpTexBuf16.data(), texaddr, bufw * h, clut + clutSharingOffset);
|
||||
if (linearClut) {
|
||||
DeIndexTexture4Optimal(tmpTexBuf16.data(), texaddr, bufw * h, linearColor);
|
||||
} else {
|
||||
DeIndexTexture4(tmpTexBuf16.data(), texaddr, bufw * h, clut + clutSharingOffset);
|
||||
}
|
||||
} else {
|
||||
tmpTexBuf32.resize(std::max(bufw, w) * h);
|
||||
UnswizzleFromMem(texaddr, bufw, 0, level);
|
||||
DeIndexTexture4(tmpTexBuf16.data(), (u8 *)tmpTexBuf32.data(), bufw * h, clut + clutSharingOffset);
|
||||
if (linearClut) {
|
||||
DeIndexTexture4Optimal(tmpTexBuf16.data(), (u8 *)tmpTexBuf32.data(), bufw * h, linearColor);
|
||||
} else {
|
||||
DeIndexTexture4(tmpTexBuf16.data(), (u8 *)tmpTexBuf32.data(), bufw * h, clut + clutSharingOffset);
|
||||
}
|
||||
}
|
||||
finalBuf = tmpTexBuf16.data();
|
||||
}
|
||||
|
@ -19,6 +19,7 @@
|
||||
|
||||
#include "../Globals.h"
|
||||
#include "gfx_es2/fbo.h"
|
||||
#include "GPU/GPUInterface.h"
|
||||
#include "GPU/GPUState.h"
|
||||
#include "TextureScaler.h"
|
||||
|
||||
@ -34,8 +35,8 @@ public:
|
||||
|
||||
void Clear(bool delete_them);
|
||||
void StartFrame();
|
||||
void Invalidate(u32 addr, int size, bool force);
|
||||
void InvalidateAll(bool force);
|
||||
void Invalidate(u32 addr, int size, GPUInvalidationType type);
|
||||
void InvalidateAll(GPUInvalidationType type);
|
||||
void ClearNextFrame();
|
||||
|
||||
// FramebufferManager keeps TextureCache updated about what regions of memory
|
||||
|
@ -132,6 +132,15 @@ struct DisplayList
|
||||
u64 waitTicks;
|
||||
};
|
||||
|
||||
enum GPUInvalidationType {
|
||||
// Affects all memory. Not considered highly.
|
||||
GPU_INVALIDATE_ALL,
|
||||
// Indicates some memory may have changed.
|
||||
GPU_INVALIDATE_HINT,
|
||||
// Reliable invalidation (where any hashing, etc. is unneeded, it'll always invalidate.)
|
||||
GPU_INVALIDATE_SAFE,
|
||||
};
|
||||
|
||||
class GPUInterface
|
||||
{
|
||||
public:
|
||||
@ -171,8 +180,7 @@ public:
|
||||
|
||||
// Invalidate any cached content sourced from the specified range.
|
||||
// If size = -1, invalidate everything.
|
||||
virtual void InvalidateCache(u32 addr, int size) = 0;
|
||||
virtual void InvalidateCacheHint(u32 addr, int size) = 0;
|
||||
virtual void InvalidateCache(u32 addr, int size, GPUInvalidationType type) = 0;
|
||||
|
||||
// Will cause the texture cache to be cleared at the start of the next frame.
|
||||
virtual void ClearCacheNextFrame() = 0;
|
||||
|
@ -674,12 +674,7 @@ void NullGPU::UpdateStats()
|
||||
gpuStats.numTextures = 0;
|
||||
}
|
||||
|
||||
void NullGPU::InvalidateCache(u32 addr, int size)
|
||||
{
|
||||
// Nothing to invalidate.
|
||||
}
|
||||
|
||||
void NullGPU::InvalidateCacheHint(u32 addr, int size)
|
||||
void NullGPU::InvalidateCache(u32 addr, int size, GPUInvalidationType type)
|
||||
{
|
||||
// Nothing to invalidate.
|
||||
}
|
||||
|
@ -34,8 +34,7 @@ public:
|
||||
virtual void SetDisplayFramebuffer(u32 framebuf, u32 stride, int format) {}
|
||||
virtual void CopyDisplayToOutput() {}
|
||||
virtual void UpdateStats();
|
||||
virtual void InvalidateCache(u32 addr, int size);
|
||||
virtual void InvalidateCacheHint(u32 addr, int size);
|
||||
virtual void InvalidateCache(u32 addr, int size, GPUInvalidationType type);
|
||||
virtual void ClearCacheNextFrame() {};
|
||||
virtual void Flush() {}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user