Centralize the majority of texture decode.

This commit is contained in:
Unknown W. Brackets 2016-06-19 07:55:38 -07:00
parent 339f065a5c
commit 5962093ef5
8 changed files with 306 additions and 723 deletions

View file

@ -16,6 +16,7 @@
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. // https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
#include <algorithm> #include <algorithm>
#include "Common/ColorConv.h"
#include "Common/MemoryUtil.h" #include "Common/MemoryUtil.h"
#include "Core/Config.h" #include "Core/Config.h"
#include "Core/Host.h" #include "Core/Host.h"
@ -38,7 +39,8 @@
TextureCacheCommon::TextureCacheCommon() TextureCacheCommon::TextureCacheCommon()
: cacheSizeEstimate_(0), nextTexture_(nullptr), : cacheSizeEstimate_(0), nextTexture_(nullptr),
clutLastFormat_(0xFFFFFFFF), clutTotalBytes_(0), clutMaxBytes_(0), clutRenderAddress_(0xFFFFFFFF) { clutLastFormat_(0xFFFFFFFF), clutTotalBytes_(0), clutMaxBytes_(0), clutRenderAddress_(0xFFFFFFFF),
clutAlphaLinear_(false) {
// TODO: Clamp down to 256/1KB? Need to check mipmapShareClut and clamp loadclut. // TODO: Clamp down to 256/1KB? Need to check mipmapShareClut and clamp loadclut.
clutBufRaw_ = (u32 *)AllocateAlignedMemory(1024 * sizeof(u32), 16); // 4KB clutBufRaw_ = (u32 *)AllocateAlignedMemory(1024 * sizeof(u32), 16); // 4KB
clutBufConverted_ = (u32 *)AllocateAlignedMemory(1024 * sizeof(u32), 16); // 4KB clutBufConverted_ = (u32 *)AllocateAlignedMemory(1024 * sizeof(u32), 16); // 4KB
@ -409,23 +411,6 @@ void TextureCacheCommon::UnswizzleFromMem(u32 *dest, u32 destPitch, const u8 *te
DoUnswizzleTex16(texptr, dest, bxc, byc, destPitch); DoUnswizzleTex16(texptr, dest, bxc, byc, destPitch);
} }
void *TextureCacheCommon::RearrangeBuf(void *inBuf, u32 inRowBytes, u32 outRowBytes, int h, bool allowInPlace) {
const u8 *read = (const u8 *)inBuf;
void *outBuf = inBuf;
u8 *write = (u8 *)inBuf;
if (outRowBytes > inRowBytes || !allowInPlace) {
write = (u8 *)tmpTexBufRearrange.data();
outBuf = tmpTexBufRearrange.data();
}
for (int y = 0; y < h; y++) {
memmove(write, read, outRowBytes);
read += inRowBytes;
write += outRowBytes;
}
return outBuf;
}
bool TextureCacheCommon::GetCurrentClutBuffer(GPUDebugBuffer &buffer) { bool TextureCacheCommon::GetCurrentClutBuffer(GPUDebugBuffer &buffer) {
const u32 bpp = gstate.getClutPaletteFormat() == GE_CMODE_32BIT_ABGR8888 ? 4 : 2; const u32 bpp = gstate.getClutPaletteFormat() == GE_CMODE_32BIT_ABGR8888 ? 4 : 2;
const u32 pixels = 1024 / bpp; const u32 pixels = 1024 / bpp;
@ -467,6 +452,265 @@ u32 TextureCacheCommon::EstimateTexMemoryUsage(const TexCacheEntry *entry) {
return pixelSize << (dimW + dimH); return pixelSize << (dimW + dimH);
} }
static void ReverseColors(void *dstBuf, const void *srcBuf, GETextureFormat fmt, int numPixels, bool useBGRA) {
switch (fmt) {
case GE_TFMT_4444:
ConvertRGBA4444ToABGR4444((u16 *)dstBuf, (const u16 *)srcBuf, numPixels);
break;
// Final Fantasy 2 uses this heavily in animated textures.
case GE_TFMT_5551:
ConvertRGBA5551ToABGR1555((u16 *)dstBuf, (const u16 *)srcBuf, numPixels);
break;
case GE_TFMT_5650:
ConvertRGB565ToBGR565((u16 *)dstBuf, (const u16 *)srcBuf, numPixels);
break;
default:
if (useBGRA) {
ConvertRGBA8888ToBGRA8888((u32 *)dstBuf, (const u32 *)srcBuf, numPixels);
} else {
// No need to convert RGBA8888, right order already
if (dstBuf != srcBuf)
memcpy(dstBuf, srcBuf, numPixels * sizeof(u32));
}
break;
}
}
bool TextureCacheCommon::DecodeTextureLevel(u8 *out, int outPitch, GETextureFormat format, GEPaletteFormat clutformat, uint32_t texaddr, int level, int bufw, bool reverseColors, bool useBGRA) {
bool swizzled = gstate.isTextureSwizzled();
if ((texaddr & 0x00600000) != 0 && Memory::IsVRAMAddress(texaddr)) {
// This means it's in a mirror, possibly a swizzled mirror. Let's report.
WARN_LOG_REPORT_ONCE(texmirror, G3D, "Decoding texture from VRAM mirror at %08x swizzle=%d", texaddr, swizzled ? 1 : 0);
if ((texaddr & 0x00200000) == 0x00200000) {
// Technically 2 and 6 are slightly different, but this is better than nothing probably.
swizzled = !swizzled;
}
// Note that (texaddr & 0x00600000) == 0x00600000 is very likely to be depth texturing.
}
int w = gstate.getTextureWidth(level);
int h = gstate.getTextureHeight(level);
const u8 *texptr = Memory::GetPointer(texaddr);
switch (format) {
case GE_TFMT_CLUT4:
{
const bool mipmapShareClut = gstate.isClutSharedForMipmaps();
const int clutSharingOffset = mipmapShareClut ? 0 : level * 16;
if (swizzled) {
tmpTexBuf32.resize(bufw * ((h + 7) & ~7));
UnswizzleFromMem(tmpTexBuf32.data(), bufw / 2, texptr, bufw, h, 0);
texptr = (u8 *)tmpTexBuf32.data();
}
switch (clutformat) {
case GE_CMODE_16BIT_BGR5650:
case GE_CMODE_16BIT_ABGR5551:
case GE_CMODE_16BIT_ABGR4444:
{
const u16 *clut = GetCurrentClut<u16>() + clutSharingOffset;
if (clutAlphaLinear_ && mipmapShareClut) {
// Here, reverseColors means the CLUT is already reversed.
if (reverseColors) {
for (int y = 0; y < h; ++y) {
DeIndexTexture4Optimal((u16 *)(out + outPitch * y), texptr + (bufw * y) / 2, w, clutAlphaLinearColor_);
}
} else {
for (int y = 0; y < h; ++y) {
DeIndexTexture4OptimalRev((u16 *)(out + outPitch * y), texptr + (bufw * y) / 2, w, clutAlphaLinearColor_);
}
}
} else {
for (int y = 0; y < h; ++y) {
DeIndexTexture4((u16 *)(out + outPitch * y), texptr + (bufw * y) / 2, w, clut);
}
}
}
break;
case GE_CMODE_32BIT_ABGR8888:
{
const u32 *clut = GetCurrentClut<u32>() + clutSharingOffset;
for (int y = 0; y < h; ++y) {
DeIndexTexture4((u32 *)(out + outPitch * y), texptr + (bufw * y) / 2, w, clut);
}
}
break;
default:
ERROR_LOG_REPORT(G3D, "Unknown CLUT4 texture mode %d", gstate.getClutPaletteFormat());
return false;
}
}
break;
case GE_TFMT_CLUT8:
if (!ReadIndexedTex(out, outPitch, level, texptr, 1, bufw)) {
return false;
}
break;
case GE_TFMT_CLUT16:
if (!ReadIndexedTex(out, outPitch, level, texptr, 2, bufw)) {
return false;
}
break;
case GE_TFMT_CLUT32:
if (!ReadIndexedTex(out, outPitch, level, texptr, 4, bufw)) {
return false;
}
break;
case GE_TFMT_4444:
case GE_TFMT_5551:
case GE_TFMT_5650:
if (!swizzled) {
// Just a simple copy, we swizzle the color format.
if (reverseColors) {
for (int y = 0; y < h; ++y) {
ReverseColors(out + outPitch * y, texptr + bufw * sizeof(u16) * y, format, w, useBGRA);
}
} else {
for (int y = 0; y < h; ++y) {
memcpy(out + outPitch * y, texptr + bufw * sizeof(u16) * y, w * sizeof(u16));
}
}
} else if (h >= 8) {
UnswizzleFromMem((u32 *)out, outPitch, texptr, bufw, h, 2);
if (reverseColors) {
ReverseColors(out, out, format, h * outPitch / 2, useBGRA);
}
} else {
// We don't have enough space for all rows in out, so use a temp buffer.
tmpTexBuf32.resize(bufw * ((h + 7) & ~7));
UnswizzleFromMem(tmpTexBuf32.data(), bufw * 2, texptr, bufw, h, 2);
const u8 *unswizzled = (u8 *)tmpTexBuf32.data();
if (reverseColors) {
for (int y = 0; y < h; ++y) {
ReverseColors(out + outPitch * y, unswizzled + bufw * sizeof(u16) * y, format, w, useBGRA);
}
} else {
for (int y = 0; y < h; ++y) {
memcpy(out + outPitch * y, unswizzled + bufw * sizeof(u16) * y, w * sizeof(u16));
}
}
}
break;
case GE_TFMT_8888:
if (!swizzled) {
if (reverseColors) {
for (int y = 0; y < h; ++y) {
ReverseColors(out + outPitch * y, texptr + bufw * sizeof(u32) * y, format, w, useBGRA);
}
} else {
for (int y = 0; y < h; ++y) {
memcpy(out + outPitch * y, texptr + bufw * sizeof(u32) * y, w * sizeof(u32));
}
}
} else if (h >= 8) {
UnswizzleFromMem((u32 *)out, outPitch, texptr, bufw, h, 4);
if (reverseColors) {
ReverseColors(out, out, format, h * outPitch / 4, useBGRA);
}
} else {
// We don't have enough space for all rows in out, so use a temp buffer.
tmpTexBuf32.resize(bufw * ((h + 7) & ~7));
UnswizzleFromMem(tmpTexBuf32.data(), bufw * 4, texptr, bufw, h, 4);
const u8 *unswizzled = (u8 *)tmpTexBuf32.data();
if (reverseColors) {
for (int y = 0; y < h; ++y) {
ReverseColors(out + outPitch * y, unswizzled + bufw * sizeof(u32) * y, format, w, useBGRA);
}
} else {
for (int y = 0; y < h; ++y) {
memcpy(out + outPitch * y, unswizzled + bufw * sizeof(u32) * y, w * sizeof(u32));
}
}
}
break;
case GE_TFMT_DXT1:
{
int minw = std::min(bufw, w);
u32 *dst = (u32 *)out;
int outPitch32 = outPitch / sizeof(u32);
DXT1Block *src = (DXT1Block*)texptr;
for (int y = 0; y < h; y += 4) {
u32 blockIndex = (y / 4) * (bufw / 4);
for (int x = 0; x < minw; x += 4) {
DecodeDXT1Block(dst + outPitch32 * y + x, src + blockIndex, outPitch32);
blockIndex++;
}
}
// TODO: Not height also?
w = (w + 3) & ~3;
if (reverseColors) {
ReverseColors(out, out, GE_TFMT_8888, outPitch32 * h, useBGRA);
}
}
break;
case GE_TFMT_DXT3:
{
int minw = std::min(bufw, w);
u32 *dst = (u32 *)out;
int outPitch32 = outPitch / sizeof(u32);
DXT3Block *src = (DXT3Block*)texptr;
for (int y = 0; y < h; y += 4) {
u32 blockIndex = (y / 4) * (bufw / 4);
for (int x = 0; x < minw; x += 4) {
DecodeDXT3Block(dst + outPitch32 * y + x, src + blockIndex, outPitch32);
blockIndex++;
}
}
// TODO: Not height also?
w = (w + 3) & ~3;
if (reverseColors) {
ReverseColors(out, out, GE_TFMT_8888, outPitch32 * h, useBGRA);
}
}
break;
case GE_TFMT_DXT5:
{
int minw = std::min(bufw, w);
u32 *dst = (u32 *)out;
int outPitch32 = outPitch / sizeof(u32);
DXT5Block *src = (DXT5Block*)texptr;
for (int y = 0; y < h; y += 4) {
u32 blockIndex = (y / 4) * (bufw / 4);
for (int x = 0; x < minw; x += 4) {
DecodeDXT5Block(dst + outPitch32 * y + x, src + blockIndex, outPitch32);
blockIndex++;
}
}
// TODO: Not height also?
w = (w + 3) & ~3;
if (reverseColors) {
ReverseColors(out, out, GE_TFMT_8888, outPitch32 * h, useBGRA);
}
}
break;
default:
ERROR_LOG_REPORT(G3D, "Unknown Texture Format %d!!!", format);
return false;
}
return true;
}
bool TextureCacheCommon::ReadIndexedTex(u8 *out, int outPitch, int level, const u8 *texptr, int bytesPerIndex, int bufw) { bool TextureCacheCommon::ReadIndexedTex(u8 *out, int outPitch, int level, const u8 *texptr, int bytesPerIndex, int bufw) {
int w = gstate.getTextureWidth(level); int w = gstate.getTextureWidth(level);
int h = gstate.getTextureHeight(level); int h = gstate.getTextureHeight(level);

View file

@ -152,8 +152,8 @@ protected:
u32 yOffset; u32 yOffset;
}; };
bool DecodeTextureLevel(u8 *out, int outPitch, GETextureFormat format, GEPaletteFormat clutformat, uint32_t texaddr, int level, int bufw, bool reverseColors, bool useBGRA = false);
void UnswizzleFromMem(u32 *dest, u32 destPitch, const u8 *texptr, u32 bufw, u32 height, u32 bytesPerPixel); void UnswizzleFromMem(u32 *dest, u32 destPitch, const u8 *texptr, u32 bufw, u32 height, u32 bytesPerPixel);
void *RearrangeBuf(void *inBuf, u32 inRowBytes, u32 outRowBytes, int h, bool allowInPlace = true);
bool ReadIndexedTex(u8 *out, int outPitch, int level, const u8 *texptr, int bytesPerIndex, int bufw); bool ReadIndexedTex(u8 *out, int outPitch, int level, const u8 *texptr, int bytesPerIndex, int bufw);
template <typename T> template <typename T>
@ -200,6 +200,10 @@ protected:
u32 clutMaxBytes_; u32 clutMaxBytes_;
u32 clutRenderAddress_; u32 clutRenderAddress_;
u32 clutRenderOffset_; u32 clutRenderOffset_;
// True if the clut is just alpha values in the same order (RGBA4444-bit only.)
bool clutAlphaLinear_;
u16 clutAlphaLinearColor_;
int standardScaleFactor_; int standardScaleFactor_;
}; };

View file

@ -364,8 +364,6 @@ D3DFORMAT getClutDestFormat(GEPaletteFormat format) {
return D3DFMT_A8R8G8B8; return D3DFMT_A8R8G8B8;
} }
static const u8 texByteAlignMap[] = {2, 2, 2, 4};
static const u8 MinFilt[8] = { static const u8 MinFilt[8] = {
D3DTEXF_POINT, D3DTEXF_POINT,
D3DTEXF_LINEAR, D3DTEXF_LINEAR,
@ -1306,262 +1304,35 @@ D3DFORMAT TextureCacheDX9::GetDestFormat(GETextureFormat format, GEPaletteFormat
} }
} }
void *TextureCacheDX9::DecodeTextureLevel(GETextureFormat format, GEPaletteFormat clutformat, int level, u32 &texByteAlign, u32 &dstFmt, int *bufwout) { void *TextureCacheDX9::DecodeTextureLevelOld(GETextureFormat format, GEPaletteFormat clutformat, int level, u32 &dstFmt, int *bufwout) {
void *finalBuf = NULL; void *finalBuf = nullptr;
u32 texaddr = gstate.getTextureAddress(level); u32 texaddr = gstate.getTextureAddress(level);
bool swizzled = gstate.isTextureSwizzled();
if ((texaddr & 0x00600000) != 0 && Memory::IsVRAMAddress(texaddr)) {
// This means it's in a mirror, possibly a swizzled mirror. Let's report.
WARN_LOG_REPORT_ONCE(texmirror, G3D, "Decoding texture from VRAM mirror at %08x swizzle=%d", texaddr, swizzled ? 1 : 0);
if ((texaddr & 0x00200000) == 0x00200000) {
// Technically 2 and 6 are slightly different, but this is better than nothing probably.
swizzled = !swizzled;
}
// Note that (texaddr & 0x00600000) == 0x00600000 is very likely to be depth texturing.
}
int bufw = GetTextureBufw(level, texaddr, format); int bufw = GetTextureBufw(level, texaddr, format);
if (bufwout) if (bufwout)
*bufwout = bufw; *bufwout = bufw;
int w = gstate.getTextureWidth(level); int w = gstate.getTextureWidth(level);
int h = gstate.getTextureHeight(level); int h = gstate.getTextureHeight(level);
const u8 *texptr = Memory::GetPointer(texaddr);
switch (format) { int decPitch = 0;
case GE_TFMT_CLUT4: int pixelSize = dstFmt == D3DFMT_A8R8G8B8 ? 4 : 2;
{ if (!(standardScaleFactor_ == 1 && gstate_c.Supports(GPU_SUPPORTS_UNPACK_SUBIMAGE)) && w != bufw) {
const bool mipmapShareClut = gstate.isClutSharedForMipmaps(); decPitch = w * pixelSize;
const int clutSharingOffset = mipmapShareClut ? 0 : level * 16; } else {
decPitch = bufw * pixelSize;
}
switch (clutformat) { tmpTexBufRearrange.resize(std::max(w, bufw) * h);
case GE_CMODE_16BIT_BGR5650: if (DecodeTextureLevel((u8 *)tmpTexBufRearrange.data(), decPitch, format, clutformat, texaddr, level, bufw, false)) {
case GE_CMODE_16BIT_ABGR5551: finalBuf = tmpTexBufRearrange.data();
case GE_CMODE_16BIT_ABGR4444: } else {
{ finalBuf = nullptr;
tmpTexBuf16.resize(std::max(bufw, w) * h);
tmpTexBufRearrange.resize(std::max(bufw, w) * h);
const u16 *clut = GetCurrentClut<u16>() + clutSharingOffset;
texByteAlign = 2;
if (!swizzled) {
if (clutAlphaLinear_ && mipmapShareClut) {
DeIndexTexture4OptimalRev(tmpTexBuf16.data(), texptr, bufw * h, clutAlphaLinearColor_);
} else {
DeIndexTexture4(tmpTexBuf16.data(), texptr, bufw * h, clut);
}
} else {
tmpTexBuf32.resize(std::max(bufw, w) * h);
UnswizzleFromMem(tmpTexBuf32.data(), bufw / 2, texptr, bufw, h, 0);
if (clutAlphaLinear_ && mipmapShareClut) {
DeIndexTexture4OptimalRev(tmpTexBuf16.data(), (const u8 *)tmpTexBuf32.data(), bufw * h, clutAlphaLinearColor_);
} else {
DeIndexTexture4(tmpTexBuf16.data(), (const u8 *)tmpTexBuf32.data(), bufw * h, clut);
}
}
finalBuf = tmpTexBuf16.data();
}
break;
case GE_CMODE_32BIT_ABGR8888:
{
tmpTexBuf32.resize(std::max(bufw, w) * h);
tmpTexBufRearrange.resize(std::max(bufw, w) * h);
const u32 *clut = GetCurrentClut<u32>() + clutSharingOffset;
if (!swizzled) {
DeIndexTexture4(tmpTexBuf32.data(), texptr, bufw * h, clut);
finalBuf = tmpTexBuf32.data();
} else {
UnswizzleFromMem(tmpTexBuf32.data(), bufw / 2, texptr, bufw, h, 0);
// Let's reuse tmpTexBuf16, just need double the space.
tmpTexBuf16.resize(std::max(bufw, w) * h * 2);
DeIndexTexture4((u32 *)tmpTexBuf16.data(), (u8 *)tmpTexBuf32.data(), bufw * h, clut);
finalBuf = tmpTexBuf16.data();
}
}
break;
default:
ERROR_LOG_REPORT(G3D, "Unknown CLUT4 texture mode %d", gstate.getClutPaletteFormat());
return NULL;
}
}
break;
case GE_TFMT_CLUT8:
texByteAlign = texByteAlignMap[gstate.getClutPaletteFormat()];
{
int w = gstate.getTextureWidth(level);
int h = gstate.getTextureHeight(level);
int length = bufw * h;
int bpp = gstate.getClutPaletteFormat() == GE_CMODE_32BIT_ABGR8888 ? 4 : 2;
tmpTexBuf16.resize(std::max(bufw, w) * h * bpp / 2);
tmpTexBufRearrange.resize(std::max(bufw, w) * h * bpp / 2);
finalBuf = nullptr;
if (ReadIndexedTex((u8 *)tmpTexBuf16.data(), bufw * bpp, level, texptr, 1, bufw)) {
finalBuf = tmpTexBuf16.data();
}
}
break;
case GE_TFMT_CLUT16:
texByteAlign = texByteAlignMap[gstate.getClutPaletteFormat()];
{
int w = gstate.getTextureWidth(level);
int h = gstate.getTextureHeight(level);
int length = bufw * h;
int bpp = gstate.getClutPaletteFormat() == GE_CMODE_32BIT_ABGR8888 ? 4 : 2;
tmpTexBuf16.resize(std::max(bufw, w) * h * bpp / 2);
tmpTexBufRearrange.resize(std::max(bufw, w) * h * bpp / 2);
finalBuf = nullptr;
if (ReadIndexedTex((u8 *)tmpTexBuf16.data(), bufw * bpp, level, texptr, 2, bufw)) {
finalBuf = tmpTexBuf16.data();
}
}
break;
case GE_TFMT_CLUT32:
texByteAlign = texByteAlignMap[gstate.getClutPaletteFormat()];
{
int w = gstate.getTextureWidth(level);
int h = gstate.getTextureHeight(level);
int length = bufw * h;
int bpp = gstate.getClutPaletteFormat() == GE_CMODE_32BIT_ABGR8888 ? 4 : 2;
tmpTexBuf16.resize(std::max(bufw, w) * h * bpp / 2);
tmpTexBufRearrange.resize(std::max(bufw, w) * h * bpp / 2);
finalBuf = nullptr;
if (ReadIndexedTex((u8 *)tmpTexBuf16.data(), bufw * bpp, level, texptr, 4, bufw)) {
finalBuf = tmpTexBuf16.data();
}
}
break;
case GE_TFMT_4444:
case GE_TFMT_5551:
case GE_TFMT_5650:
texByteAlign = 2;
if (!swizzled) {
int len = std::max(bufw, w) * h;
tmpTexBuf16.resize(len);
tmpTexBufRearrange.resize(len);
Memory::MemcpyUnchecked(tmpTexBuf16.data(), texaddr, len * sizeof(u16));
finalBuf = tmpTexBuf16.data();
}
else {
tmpTexBuf32.resize(std::max(bufw, w) * h);
UnswizzleFromMem(tmpTexBuf32.data(), bufw * 2, texptr, bufw, h, 2);
finalBuf = tmpTexBuf32.data();
}
break;
case GE_TFMT_8888:
if (!swizzled) {
// Special case: if we don't need to deal with packing, we don't need to copy.
//if (w == bufw) {
// finalBuf = Memory::GetPointer(texaddr);
//} else
{
int len = bufw * h;
tmpTexBuf32.resize(std::max(bufw, w) * h);
tmpTexBufRearrange.resize(std::max(bufw, w) * h);
Memory::MemcpyUnchecked(tmpTexBuf32.data(), texaddr, len * sizeof(u32));
finalBuf = tmpTexBuf32.data();
}
} else {
tmpTexBuf32.resize(std::max(bufw, w) * h);
UnswizzleFromMem(tmpTexBuf32.data(), bufw * 4, texptr, bufw, h, 4);
finalBuf = tmpTexBuf32.data();
}
break;
case GE_TFMT_DXT1:
{
int minw = std::min(bufw, w);
tmpTexBuf32.resize(std::max(bufw, w) * h);
tmpTexBufRearrange.resize(std::max(bufw, w) * h);
u32 *dst = tmpTexBuf32.data();
DXT1Block *src = (DXT1Block*)texptr;
for (int y = 0; y < h; y += 4) {
u32 blockIndex = (y / 4) * (bufw / 4);
for (int x = 0; x < minw; x += 4) {
DecodeDXT1Block(dst + bufw * y + x, src + blockIndex, bufw);
blockIndex++;
}
}
finalBuf = tmpTexBuf32.data();
w = (w + 3) & ~3;
}
break;
case GE_TFMT_DXT3:
{
int minw = std::min(bufw, w);
tmpTexBuf32.resize(std::max(bufw, w) * h);
tmpTexBufRearrange.resize(std::max(bufw, w) * h);
u32 *dst = tmpTexBuf32.data();
DXT3Block *src = (DXT3Block*)texptr;
for (int y = 0; y < h; y += 4) {
u32 blockIndex = (y / 4) * (bufw / 4);
for (int x = 0; x < minw; x += 4) {
DecodeDXT3Block(dst + bufw * y + x, src + blockIndex, bufw);
blockIndex++;
}
}
w = (w + 3) & ~3;
finalBuf = tmpTexBuf32.data();
}
break;
case GE_TFMT_DXT5:
{
int minw = std::min(bufw, w);
tmpTexBuf32.resize(std::max(bufw, w) * h);
tmpTexBufRearrange.resize(std::max(bufw, w) * h);
u32 *dst = tmpTexBuf32.data();
DXT5Block *src = (DXT5Block*)texptr;
for (int y = 0; y < h; y += 4) {
u32 blockIndex = (y / 4) * (bufw / 4);
for (int x = 0; x < minw; x += 4) {
DecodeDXT5Block(dst + bufw * y + x, src + blockIndex, bufw);
blockIndex++;
}
}
w = (w + 3) & ~3;
finalBuf = tmpTexBuf32.data();
}
break;
default:
ERROR_LOG_REPORT(G3D, "Unknown Texture Format %d!!!", format);
return NULL;
} }
if (!finalBuf) { if (!finalBuf) {
ERROR_LOG_REPORT(G3D, "NO finalbuf! Will crash!"); ERROR_LOG_REPORT(G3D, "NO finalbuf! Will crash!");
} }
if (!(standardScaleFactor_ == 1 && gstate_c.Supports(GPU_SUPPORTS_UNPACK_SUBIMAGE)) && w != bufw) {
int pixelSize;
switch (dstFmt) {
case D3DFMT_A4R4G4B4:
case D3DFMT_A1R5G5B5:
case D3DFMT_R5G6B5:
pixelSize = 2;
break;
default:
pixelSize = 4;
break;
}
// Need to rearrange the buffer to simulate GL_UNPACK_ROW_LENGTH etc.
finalBuf = RearrangeBuf(finalBuf, bufw * pixelSize, w * pixelSize, h);
}
return finalBuf; return finalBuf;
} }
@ -1640,9 +1411,6 @@ u32 ToD3D9Format(ReplacedTextureFormat fmt) {
} }
void TextureCacheDX9::LoadTextureLevel(TexCacheEntry &entry, ReplacedTexture &replaced, int level, int maxLevel, bool replaceImages, int scaleFactor, u32 dstFmt) { void TextureCacheDX9::LoadTextureLevel(TexCacheEntry &entry, ReplacedTexture &replaced, int level, int maxLevel, bool replaceImages, int scaleFactor, u32 dstFmt) {
// TODO: only do this once
u32 texByteAlign = 1;
int w = gstate.getTextureWidth(level); int w = gstate.getTextureWidth(level);
int h = gstate.getTextureHeight(level); int h = gstate.getTextureHeight(level);
int bufw; int bufw;
@ -1659,7 +1427,7 @@ void TextureCacheDX9::LoadTextureLevel(TexCacheEntry &entry, ReplacedTexture &re
dstFmt = ToD3D9Format(replaced.Format(level)); dstFmt = ToD3D9Format(replaced.Format(level));
} else { } else {
GEPaletteFormat clutformat = gstate.getClutPaletteFormat(); GEPaletteFormat clutformat = gstate.getClutPaletteFormat();
void *finalBuf = DecodeTextureLevel(GETextureFormat(entry.format), clutformat, level, texByteAlign, dstFmt, &bufw); void *finalBuf = DecodeTextureLevelOld(GETextureFormat(entry.format), clutformat, level, dstFmt, &bufw);
if (finalBuf == NULL) { if (finalBuf == NULL) {
return; return;
} }

View file

@ -81,7 +81,7 @@ private:
void UpdateSamplingParams(TexCacheEntry &entry, bool force); void UpdateSamplingParams(TexCacheEntry &entry, bool force);
void LoadTextureLevel(TexCacheEntry &entry, ReplacedTexture &replaced, int level, int maxLevel, bool replaceImages, int scaleFactor, u32 dstFmt); void LoadTextureLevel(TexCacheEntry &entry, ReplacedTexture &replaced, int level, int maxLevel, bool replaceImages, int scaleFactor, u32 dstFmt);
D3DFORMAT GetDestFormat(GETextureFormat format, GEPaletteFormat clutFormat) const; D3DFORMAT GetDestFormat(GETextureFormat format, GEPaletteFormat clutFormat) const;
void *DecodeTextureLevel(GETextureFormat format, GEPaletteFormat clutformat, int level, u32 &texByteAlign, u32 &dstFmt, int *bufw = 0); void *DecodeTextureLevelOld(GETextureFormat format, GEPaletteFormat clutformat, int level, u32 &dstFmt, int *bufw = 0);
TexCacheEntry::Status CheckAlpha(const u32 *pixelData, u32 dstFmt, int stride, int w, int h); TexCacheEntry::Status CheckAlpha(const u32 *pixelData, u32 dstFmt, int stride, int w, int h);
u32 GetCurrentClutHash(); u32 GetCurrentClutHash();
void UpdateCurrentClut(GEPaletteFormat clutFormat, u32 clutBase, bool clutIndexIsSimple); void UpdateCurrentClut(GEPaletteFormat clutFormat, u32 clutBase, bool clutIndexIsSimple);
@ -112,9 +112,6 @@ private:
TextureScalerDX9 scaler; TextureScalerDX9 scaler;
u32 clutHash_; u32 clutHash_;
// True if the clut is just alpha values in the same order (RGBA4444-bit only.)
bool clutAlphaLinear_;
u16 clutAlphaLinearColor_;
LPDIRECT3DTEXTURE9 lastBoundTexture; LPDIRECT3DTEXTURE9 lastBoundTexture;
float maxAnisotropyLevel; float maxAnisotropyLevel;

View file

@ -359,8 +359,6 @@ GLenum getClutDestFormat(GEPaletteFormat format) {
return 0; return 0;
} }
static const u8 texByteAlignMap[] = {2, 2, 2, 4};
static const GLuint MinFiltGL[8] = { static const GLuint MinFiltGL[8] = {
GL_NEAREST, GL_NEAREST,
GL_LINEAR, GL_LINEAR,
@ -1470,271 +1468,35 @@ GLenum TextureCache::GetDestFormat(GETextureFormat format, GEPaletteFormat clutF
} }
} }
void *TextureCache::DecodeTextureLevel(GETextureFormat format, GEPaletteFormat clutformat, int level, u32 &texByteAlign, GLenum dstFmt, int scaleFactor, int *bufwout) { void *TextureCache::DecodeTextureLevelOld(GETextureFormat format, GEPaletteFormat clutformat, int level, GLenum dstFmt, int scaleFactor, int *bufwout) {
void *finalBuf = NULL; void *finalBuf = nullptr;
u32 texaddr = gstate.getTextureAddress(level); u32 texaddr = gstate.getTextureAddress(level);
bool swizzled = gstate.isTextureSwizzled();
if ((texaddr & 0x00600000) != 0 && Memory::IsVRAMAddress(texaddr)) {
// This means it's in a mirror, possibly a swizzled mirror. Let's report.
WARN_LOG_REPORT_ONCE(texmirror, G3D, "Decoding texture from VRAM mirror at %08x swizzle=%d", texaddr, swizzled ? 1 : 0);
if ((texaddr & 0x00200000) == 0x00200000) {
// Technically 2 and 6 are slightly different, but this is better than nothing probably.
swizzled = !swizzled;
}
// Note that (texaddr & 0x00600000) == 0x00600000 is very likely to be depth texturing.
}
int bufw = GetTextureBufw(level, texaddr, format); int bufw = GetTextureBufw(level, texaddr, format);
if (bufwout) if (bufwout)
*bufwout = bufw; *bufwout = bufw;
int w = gstate.getTextureWidth(level); int w = gstate.getTextureWidth(level);
int h = gstate.getTextureHeight(level); int h = gstate.getTextureHeight(level);
const u8 *texptr = Memory::GetPointer(texaddr);
switch (format) { int decPitch = 0;
case GE_TFMT_CLUT4: int pixelSize = dstFmt == GL_UNSIGNED_BYTE ? 4 : 2;
{ if (!(scaleFactor == 1 && gstate_c.Supports(GPU_SUPPORTS_UNPACK_SUBIMAGE)) && w != bufw) {
const bool mipmapShareClut = gstate.isClutSharedForMipmaps(); decPitch = w * pixelSize;
const int clutSharingOffset = mipmapShareClut ? 0 : level * 16; } else {
decPitch = bufw * pixelSize;
}
switch (clutformat) { tmpTexBufRearrange.resize(std::max(w, bufw) * h);
case GE_CMODE_16BIT_BGR5650: if (DecodeTextureLevel((u8 *)tmpTexBufRearrange.data(), decPitch, format, clutformat, texaddr, level, bufw, true, UseBGRA8888())) {
case GE_CMODE_16BIT_ABGR5551: finalBuf = tmpTexBufRearrange.data();
case GE_CMODE_16BIT_ABGR4444: } else {
{ finalBuf = nullptr;
tmpTexBuf16.resize(std::max(bufw, w) * h);
tmpTexBufRearrange.resize(std::max(bufw, w) * h);
const u16 *clut = GetCurrentClut<u16>() + clutSharingOffset;
texByteAlign = 2;
if (!swizzled) {
if (clutAlphaLinear_ && mipmapShareClut) {
DeIndexTexture4Optimal(tmpTexBuf16.data(), texptr, bufw * h, clutAlphaLinearColor_);
} else {
DeIndexTexture4(tmpTexBuf16.data(), texptr, bufw * h, clut);
}
} else {
tmpTexBuf32.resize(std::max(bufw, w) * h);
UnswizzleFromMem(tmpTexBuf32.data(), bufw / 2, texptr, bufw, h, 0);
if (clutAlphaLinear_ && mipmapShareClut) {
DeIndexTexture4Optimal(tmpTexBuf16.data(), (const u8 *)tmpTexBuf32.data(), bufw * h, clutAlphaLinearColor_);
} else {
DeIndexTexture4(tmpTexBuf16.data(), (const u8 *)tmpTexBuf32.data(), bufw * h, clut);
}
}
finalBuf = tmpTexBuf16.data();
}
break;
case GE_CMODE_32BIT_ABGR8888:
{
tmpTexBuf32.resize(std::max(bufw, w) * h);
tmpTexBufRearrange.resize(std::max(bufw, w) * h);
const u32 *clut = GetCurrentClut<u32>() + clutSharingOffset;
if (!swizzled) {
DeIndexTexture4(tmpTexBuf32.data(), texptr, bufw * h, clut);
finalBuf = tmpTexBuf32.data();
} else {
UnswizzleFromMem(tmpTexBuf32.data(), bufw / 2, texptr, bufw, h, 0);
// Let's reuse tmpTexBuf16, just need double the space.
tmpTexBuf16.resize(std::max(bufw, w) * h * 2);
DeIndexTexture4((u32 *)tmpTexBuf16.data(), (u8 *)tmpTexBuf32.data(), bufw * h, clut);
finalBuf = tmpTexBuf16.data();
}
}
break;
default:
ERROR_LOG_REPORT(G3D, "Unknown CLUT4 texture mode %d", gstate.getClutPaletteFormat());
return NULL;
}
}
break;
case GE_TFMT_CLUT8:
texByteAlign = texByteAlignMap[gstate.getClutPaletteFormat()];
{
int w = gstate.getTextureWidth(level);
int h = gstate.getTextureHeight(level);
int length = bufw * h;
int bpp = gstate.getClutPaletteFormat() == GE_CMODE_32BIT_ABGR8888 ? 4 : 2;
tmpTexBuf16.resize(std::max(bufw, w) * h * bpp / 2);
tmpTexBufRearrange.resize(std::max(bufw, w) * h * bpp / 2);
finalBuf = nullptr;
if (ReadIndexedTex((u8 *)tmpTexBuf16.data(), bufw * bpp, level, texptr, 1, bufw)) {
finalBuf = tmpTexBuf16.data();
}
}
break;
case GE_TFMT_CLUT16:
texByteAlign = texByteAlignMap[gstate.getClutPaletteFormat()];
{
int w = gstate.getTextureWidth(level);
int h = gstate.getTextureHeight(level);
int length = bufw * h;
int bpp = gstate.getClutPaletteFormat() == GE_CMODE_32BIT_ABGR8888 ? 4 : 2;
tmpTexBuf16.resize(std::max(bufw, w) * h * bpp / 2);
tmpTexBufRearrange.resize(std::max(bufw, w) * h * bpp / 2);
finalBuf = nullptr;
if (ReadIndexedTex((u8 *)tmpTexBuf16.data(), bufw * bpp, level, texptr, 2, bufw)) {
finalBuf = tmpTexBuf16.data();
}
}
break;
case GE_TFMT_CLUT32:
texByteAlign = texByteAlignMap[gstate.getClutPaletteFormat()];
{
int w = gstate.getTextureWidth(level);
int h = gstate.getTextureHeight(level);
int length = bufw * h;
int bpp = gstate.getClutPaletteFormat() == GE_CMODE_32BIT_ABGR8888 ? 4 : 2;
tmpTexBuf16.resize(std::max(bufw, w) * h * bpp / 2);
tmpTexBufRearrange.resize(std::max(bufw, w) * h * bpp / 2);
finalBuf = nullptr;
if (ReadIndexedTex((u8 *)tmpTexBuf16.data(), bufw * bpp, level, texptr, 4, bufw)) {
finalBuf = tmpTexBuf16.data();
}
}
break;
case GE_TFMT_4444:
case GE_TFMT_5551:
case GE_TFMT_5650:
texByteAlign = 2;
if (!swizzled) {
int len = std::max(bufw, w) * h;
tmpTexBuf16.resize(len);
tmpTexBufRearrange.resize(len);
finalBuf = tmpTexBuf16.data();
ConvertColors(finalBuf, texptr, dstFmt, bufw * h);
} else {
tmpTexBuf32.resize(std::max(bufw, w) * h);
UnswizzleFromMem(tmpTexBuf32.data(), bufw * 2, texptr, bufw, h, 2);
finalBuf = tmpTexBuf32.data();
ConvertColors(finalBuf, finalBuf, dstFmt, bufw * h);
}
break;
case GE_TFMT_8888:
if (!swizzled) {
// Special case: if we don't need to deal with packing, we don't need to copy.
if ((scaleFactor == 1 && gstate_c.Supports(GPU_SUPPORTS_UNPACK_SUBIMAGE)) || w == bufw) {
if (UseBGRA8888()) {
tmpTexBuf32.resize(std::max(bufw, w) * h);
finalBuf = tmpTexBuf32.data();
ConvertColors(finalBuf, texptr, dstFmt, bufw * h);
} else {
finalBuf = (void *)texptr;
}
} else {
tmpTexBuf32.resize(std::max(bufw, w) * h);
tmpTexBufRearrange.resize(std::max(bufw, w) * h);
finalBuf = tmpTexBuf32.data();
ConvertColors(finalBuf, texptr, dstFmt, bufw * h);
}
} else {
tmpTexBuf32.resize(std::max(bufw, w) * h);
UnswizzleFromMem(tmpTexBuf32.data(), bufw * 4, texptr, bufw, h, 4);
finalBuf = tmpTexBuf32.data();
ConvertColors(finalBuf, finalBuf, dstFmt, bufw * h);
}
break;
case GE_TFMT_DXT1:
{
int minw = std::min(bufw, w);
tmpTexBuf32.resize(std::max(bufw, w) * h);
tmpTexBufRearrange.resize(std::max(bufw, w) * h);
u32 *dst = tmpTexBuf32.data();
DXT1Block *src = (DXT1Block*)texptr;
for (int y = 0; y < h; y += 4) {
u32 blockIndex = (y / 4) * (bufw / 4);
for (int x = 0; x < minw; x += 4) {
DecodeDXT1Block(dst + bufw * y + x, src + blockIndex, bufw);
blockIndex++;
}
}
finalBuf = tmpTexBuf32.data();
ConvertColors(finalBuf, finalBuf, dstFmt, bufw * h);
w = (w + 3) & ~3;
}
break;
case GE_TFMT_DXT3:
{
int minw = std::min(bufw, w);
tmpTexBuf32.resize(std::max(bufw, w) * h);
tmpTexBufRearrange.resize(std::max(bufw, w) * h);
u32 *dst = tmpTexBuf32.data();
DXT3Block *src = (DXT3Block*)texptr;
for (int y = 0; y < h; y += 4) {
u32 blockIndex = (y / 4) * (bufw / 4);
for (int x = 0; x < minw; x += 4) {
DecodeDXT3Block(dst + bufw * y + x, src + blockIndex, bufw);
blockIndex++;
}
}
w = (w + 3) & ~3;
finalBuf = tmpTexBuf32.data();
ConvertColors(finalBuf, finalBuf, dstFmt, bufw * h);
}
break;
case GE_TFMT_DXT5:
{
int minw = std::min(bufw, w);
tmpTexBuf32.resize(std::max(bufw, w) * h);
tmpTexBufRearrange.resize(std::max(bufw, w) * h);
u32 *dst = tmpTexBuf32.data();
DXT5Block *src = (DXT5Block*)texptr;
for (int y = 0; y < h; y += 4) {
u32 blockIndex = (y / 4) * (bufw / 4);
for (int x = 0; x < minw; x += 4) {
DecodeDXT5Block(dst + bufw * y + x, src + blockIndex, bufw);
blockIndex++;
}
}
w = (w + 3) & ~3;
finalBuf = tmpTexBuf32.data();
ConvertColors(finalBuf, finalBuf, dstFmt, bufw * h);
}
break;
default:
ERROR_LOG_REPORT(G3D, "Unknown Texture Format %d!!!", format);
return NULL;
} }
if (!finalBuf) { if (!finalBuf) {
ERROR_LOG_REPORT(G3D, "NO finalbuf! Will crash!"); ERROR_LOG_REPORT(G3D, "NO finalbuf! Will crash!");
} }
if (!(scaleFactor == 1 && gstate_c.Supports(GPU_SUPPORTS_UNPACK_SUBIMAGE)) && w != bufw) {
int pixelSize;
switch (dstFmt) {
case GL_UNSIGNED_SHORT_4_4_4_4:
case GL_UNSIGNED_SHORT_5_5_5_1:
case GL_UNSIGNED_SHORT_5_6_5:
pixelSize = 2;
break;
default:
pixelSize = 4;
break;
}
// Need to rearrange the buffer to simulate GL_UNPACK_ROW_LENGTH etc.
finalBuf = RearrangeBuf(finalBuf, bufw * pixelSize, w * pixelSize, h);
}
return finalBuf; return finalBuf;
} }
@ -1784,12 +1546,11 @@ void TextureCache::LoadTextureLevel(TexCacheEntry &entry, ReplacedTexture &repla
texByteAlign = bpp; texByteAlign = bpp;
useBGRA = false; useBGRA = false;
} else { } else {
PROFILE_THIS_SCOPE("decodetex"); PROFILE_THIS_SCOPE("decodetex");
GEPaletteFormat clutformat = gstate.getClutPaletteFormat(); GEPaletteFormat clutformat = gstate.getClutPaletteFormat();
int bufw; int bufw;
void *finalBuf = DecodeTextureLevel(GETextureFormat(entry.format), clutformat, level, texByteAlign, dstFmt, scaleFactor, &bufw); void *finalBuf = DecodeTextureLevelOld(GETextureFormat(entry.format), clutformat, level, dstFmt, scaleFactor, &bufw);
if (finalBuf == NULL) { if (finalBuf == NULL) {
return; return;
} }
@ -1800,6 +1561,8 @@ void TextureCache::LoadTextureLevel(TexCacheEntry &entry, ReplacedTexture &repla
useUnpack = true; useUnpack = true;
} }
// Textures are always aligned to 16 bytes bufw, so this could safely be 4 always.
texByteAlign = dstFmt == GL_UNSIGNED_BYTE ? 4 : 2;
useBGRA = UseBGRA8888() && dstFmt == GL_UNSIGNED_BYTE; useBGRA = UseBGRA8888() && dstFmt == GL_UNSIGNED_BYTE;
pixelData = (u32 *)finalBuf; pixelData = (u32 *)finalBuf;
@ -1882,7 +1645,6 @@ bool TextureCache::DecodeTexture(u8* output, const GPUgstate &state) {
return false; return false;
} }
u32 texByteAlign = 1;
GLenum dstFmt = 0; GLenum dstFmt = 0;
GETextureFormat format = gstate.getTextureFormat(); GETextureFormat format = gstate.getTextureFormat();
@ -1893,7 +1655,7 @@ bool TextureCache::DecodeTexture(u8* output, const GPUgstate &state) {
int w = gstate.getTextureWidth(level); int w = gstate.getTextureWidth(level);
int h = gstate.getTextureHeight(level); int h = gstate.getTextureHeight(level);
void *finalBuf = DecodeTextureLevel(format, clutformat, level, texByteAlign, dstFmt, 1); void *finalBuf = DecodeTextureLevelOld(format, clutformat, level, dstFmt, 1);
if (finalBuf == NULL) { if (finalBuf == NULL) {
return false; return false;
} }

View file

@ -96,7 +96,7 @@ private:
void UpdateSamplingParams(TexCacheEntry &entry, bool force); void UpdateSamplingParams(TexCacheEntry &entry, bool force);
void LoadTextureLevel(TexCacheEntry &entry, ReplacedTexture &replaced, int level, bool replaceImages, int scaleFactor, GLenum dstFmt); void LoadTextureLevel(TexCacheEntry &entry, ReplacedTexture &replaced, int level, bool replaceImages, int scaleFactor, GLenum dstFmt);
GLenum GetDestFormat(GETextureFormat format, GEPaletteFormat clutFormat) const; GLenum GetDestFormat(GETextureFormat format, GEPaletteFormat clutFormat) const;
void *DecodeTextureLevel(GETextureFormat format, GEPaletteFormat clutformat, int level, u32 &texByteAlign, GLenum dstFmt, int scaleFactor, int *bufw = 0); void *DecodeTextureLevelOld(GETextureFormat format, GEPaletteFormat clutformat, int level, GLenum dstFmt, int scaleFactor, int *bufw = 0);
TexCacheEntry::Status CheckAlpha(const u32 *pixelData, GLenum dstFmt, int stride, int w, int h); TexCacheEntry::Status CheckAlpha(const u32 *pixelData, GLenum dstFmt, int stride, int w, int h);
u32 GetCurrentClutHash(); u32 GetCurrentClutHash();
void UpdateCurrentClut(GEPaletteFormat clutFormat, u32 clutBase, bool clutIndexIsSimple); void UpdateCurrentClut(GEPaletteFormat clutFormat, u32 clutBase, bool clutIndexIsSimple);
@ -118,9 +118,6 @@ private:
TextureScalerGL scaler; TextureScalerGL scaler;
u32 clutHash_; u32 clutHash_;
// True if the clut is just alpha values in the same order (RGBA4444-bit only.)
bool clutAlphaLinear_;
u16 clutAlphaLinearColor_;
u32 lastBoundTexture; u32 lastBoundTexture;
float maxAnisotropyLevel; float maxAnisotropyLevel;

View file

@ -131,8 +131,7 @@ VkSampler SamplerCache::GetOrCreateSampler(const SamplerCacheKey &key) {
TextureCacheVulkan::TextureCacheVulkan(VulkanContext *vulkan) TextureCacheVulkan::TextureCacheVulkan(VulkanContext *vulkan)
: vulkan_(vulkan), samplerCache_(vulkan), secondCacheSizeEstimate_(0), : vulkan_(vulkan), samplerCache_(vulkan), secondCacheSizeEstimate_(0),
clearCacheNextFrame_(false), lowMemoryMode_(false), texelsScaledThisFrame_(0), clearCacheNextFrame_(false), lowMemoryMode_(false), texelsScaledThisFrame_(0) {
clutAlphaLinear_(false) {
timesInvalidatedAllThisFrame_ = 0; timesInvalidatedAllThisFrame_ = 0;
lastBoundTexture = nullptr; lastBoundTexture = nullptr;
decimationCounter_ = TEXCACHE_DECIMATION_INTERVAL; decimationCounter_ = TEXCACHE_DECIMATION_INTERVAL;
@ -1375,190 +1374,6 @@ VkFormat TextureCacheVulkan::GetDestFormat(GETextureFormat format, GEPaletteForm
} }
} }
bool TextureCacheVulkan::DecodeTextureLevel(u8 *out, int outPitch, GETextureFormat format, GEPaletteFormat clutformat, uint32_t texaddr, int level, VkFormat dstFmt, int scaleFactor, int bufw) {
bool swizzled = gstate.isTextureSwizzled();
if ((texaddr & 0x00600000) != 0 && Memory::IsVRAMAddress(texaddr)) {
// This means it's in a mirror, possibly a swizzled mirror. Let's report.
WARN_LOG_REPORT_ONCE(texmirror, G3D, "Decoding texture from VRAM mirror at %08x swizzle=%d", texaddr, swizzled ? 1 : 0);
if ((texaddr & 0x00200000) == 0x00200000) {
// Technically 2 and 6 are slightly different, but this is better than nothing probably.
swizzled = !swizzled;
}
// Note that (texaddr & 0x00600000) == 0x00600000 is very likely to be depth texturing.
}
int w = gstate.getTextureWidth(level);
int h = gstate.getTextureHeight(level);
const u8 *texptr = Memory::GetPointer(texaddr);
switch (format) {
case GE_TFMT_CLUT4:
{
const bool mipmapShareClut = gstate.isClutSharedForMipmaps();
const int clutSharingOffset = mipmapShareClut ? 0 : level * 16;
if (swizzled) {
tmpTexBuf32.resize(bufw * ((h + 7) & ~7));
UnswizzleFromMem(tmpTexBuf32.data(), bufw / 2, texptr, bufw, h, 0);
texptr = (u8 *)tmpTexBuf32.data();
}
switch (clutformat) {
case GE_CMODE_16BIT_BGR5650:
case GE_CMODE_16BIT_ABGR5551:
case GE_CMODE_16BIT_ABGR4444:
{
const u16 *clut = GetCurrentClut<u16>() + clutSharingOffset;
if (clutAlphaLinear_ && mipmapShareClut) {
for (int y = 0; y < h; ++y) {
DeIndexTexture4OptimalRev((u16 *)(out + outPitch * y), texptr + (bufw * y) / 2, w, clutAlphaLinearColor_);
}
} else {
for (int y = 0; y < h; ++y) {
DeIndexTexture4((u16 *)(out + outPitch * y), texptr + (bufw * y) / 2, w, clut);
}
}
}
break;
case GE_CMODE_32BIT_ABGR8888:
{
const u32 *clut = GetCurrentClut<u32>() + clutSharingOffset;
for (int y = 0; y < h; ++y) {
DeIndexTexture4((u32 *)(out + outPitch * y), texptr + (bufw * y) / 2, w, clut);
}
}
break;
default:
ERROR_LOG_REPORT(G3D, "Unknown CLUT4 texture mode %d", gstate.getClutPaletteFormat());
return false;
}
}
break;
case GE_TFMT_CLUT8:
if (!ReadIndexedTex(out, outPitch, level, texptr, 1, bufw)) {
return false;
}
break;
case GE_TFMT_CLUT16:
if (!ReadIndexedTex(out, outPitch, level, texptr, 2, bufw)) {
return false;
}
break;
case GE_TFMT_CLUT32:
if (!ReadIndexedTex(out, outPitch, level, texptr, 4, bufw)) {
return false;
}
break;
case GE_TFMT_4444:
case GE_TFMT_5551:
case GE_TFMT_5650:
if (!swizzled) {
// Just a simple copy, we swizzle the color format.
for (int y = 0; y < h; ++y) {
memcpy(out + outPitch * y, texptr + bufw * sizeof(u16) * y, w * sizeof(u16));
}
} else if (h >= 8) {
UnswizzleFromMem((u32 *)out, outPitch, texptr, bufw, h, 2);
} else {
// We don't have enough space for all rows in out, so use a temp buffer.
tmpTexBuf32.resize(bufw * ((h + 7) & ~7));
UnswizzleFromMem(tmpTexBuf32.data(), bufw * 2, texptr, bufw, h, 2);
const u8 *unswizzled = (u8 *)tmpTexBuf32.data();
for (int y = 0; y < h; ++y) {
memcpy(out + outPitch * y, unswizzled + bufw * sizeof(u16) * y, w * sizeof(u16));
}
}
break;
case GE_TFMT_8888:
if (!swizzled) {
for (int y = 0; y < h; ++y) {
memcpy(out + outPitch * y, texptr + bufw * sizeof(u32) * y, w * sizeof(u32));
}
} else if (h >= 8) {
UnswizzleFromMem((u32 *)out, outPitch, texptr, bufw, h, 4);
} else {
// We don't have enough space for all rows in out, so use a temp buffer.
tmpTexBuf32.resize(bufw * ((h + 7) & ~7));
UnswizzleFromMem(tmpTexBuf32.data(), bufw * 4, texptr, bufw, h, 4);
const u8 *unswizzled = (u8 *)tmpTexBuf32.data();
for (int y = 0; y < h; ++y) {
memcpy(out + outPitch * y, unswizzled + bufw * sizeof(u32) * y, w * sizeof(u32));
}
}
break;
case GE_TFMT_DXT1:
{
int minw = std::min(bufw, w);
u32 *dst = (u32 *)out;
int outPitch32 = outPitch / sizeof(u32);
DXT1Block *src = (DXT1Block*)texptr;
for (int y = 0; y < h; y += 4) {
u32 blockIndex = (y / 4) * (bufw / 4);
for (int x = 0; x < minw; x += 4) {
DecodeDXT1Block(dst + outPitch32 * y + x, src + blockIndex, outPitch32);
blockIndex++;
}
}
// TODO: Not height also?
w = (w + 3) & ~3;
}
break;
case GE_TFMT_DXT3:
{
int minw = std::min(bufw, w);
u32 *dst = (u32 *)out;
int outPitch32 = outPitch / sizeof(u32);
DXT3Block *src = (DXT3Block*)texptr;
for (int y = 0; y < h; y += 4) {
u32 blockIndex = (y / 4) * (bufw / 4);
for (int x = 0; x < minw; x += 4) {
DecodeDXT3Block(dst + outPitch32 * y + x, src + blockIndex, outPitch32);
blockIndex++;
}
}
// TODO: Not height also?
w = (w + 3) & ~3;
}
break;
case GE_TFMT_DXT5:
{
int minw = std::min(bufw, w);
u32 *dst = (u32 *)out;
int outPitch32 = outPitch / sizeof(u32);
DXT5Block *src = (DXT5Block*)texptr;
for (int y = 0; y < h; y += 4) {
u32 blockIndex = (y / 4) * (bufw / 4);
for (int x = 0; x < minw; x += 4) {
DecodeDXT5Block(dst + outPitch32 * y + x, src + blockIndex, outPitch32);
blockIndex++;
}
}
// TODO: Not height also?
w = (w + 3) & ~3;
}
break;
default:
ERROR_LOG_REPORT(G3D, "Unknown Texture Format %d!!!", format);
return false;
}
return true;
}
TextureCacheVulkan::TexCacheEntry::Status TextureCacheVulkan::CheckAlpha(const u32 *pixelData, VkFormat dstFmt, int stride, int w, int h) { TextureCacheVulkan::TexCacheEntry::Status TextureCacheVulkan::CheckAlpha(const u32 *pixelData, VkFormat dstFmt, int stride, int w, int h) {
CheckAlphaResult res; CheckAlphaResult res;
switch (dstFmt) { switch (dstFmt) {
@ -1605,7 +1420,7 @@ void TextureCacheVulkan::LoadTextureLevel(TexCacheEntry &entry, uint8_t *writePt
decPitch = w * bpp; decPitch = w * bpp;
} }
bool decSuccess = DecodeTextureLevel((u8 *)pixelData, decPitch, tfmt, clutformat, texaddr, level, dstFmt, scaleFactor, bufw); bool decSuccess = DecodeTextureLevel((u8 *)pixelData, decPitch, tfmt, clutformat, texaddr, level, bufw, false);
if (!decSuccess) { if (!decSuccess) {
memset(writePtr, 0, rowPitch * h); memset(writePtr, 0, rowPitch * h);
return; return;

View file

@ -129,7 +129,6 @@ private:
void UpdateSamplingParams(TexCacheEntry &entry, SamplerCacheKey &key); void UpdateSamplingParams(TexCacheEntry &entry, SamplerCacheKey &key);
void LoadTextureLevel(TexCacheEntry &entry, uint8_t *writePtr, int rowPitch, int level, int scaleFactor, VkFormat dstFmt); void LoadTextureLevel(TexCacheEntry &entry, uint8_t *writePtr, int rowPitch, int level, int scaleFactor, VkFormat dstFmt);
VkFormat GetDestFormat(GETextureFormat format, GEPaletteFormat clutFormat) const; VkFormat GetDestFormat(GETextureFormat format, GEPaletteFormat clutFormat) const;
bool DecodeTextureLevel(u8 *out, int outPitch, GETextureFormat format, GEPaletteFormat clutformat, uint32_t texaddr, int level, VkFormat dstFmt, int scaleFactor, int bufw);
TexCacheEntry::Status CheckAlpha(const u32 *pixelData, VkFormat dstFmt, int stride, int w, int h); TexCacheEntry::Status CheckAlpha(const u32 *pixelData, VkFormat dstFmt, int stride, int w, int h);
u32 GetCurrentClutHash(); u32 GetCurrentClutHash();
void UpdateCurrentClut(GEPaletteFormat clutFormat, u32 clutBase, bool clutIndexIsSimple); void UpdateCurrentClut(GEPaletteFormat clutFormat, u32 clutBase, bool clutIndexIsSimple);
@ -156,9 +155,6 @@ private:
TextureScalerVulkan scaler; TextureScalerVulkan scaler;
u32 clutHash_; u32 clutHash_;
// True if the clut is just alpha values in the same order (RGBA4444-bit only.)
bool clutAlphaLinear_;
u16 clutAlphaLinearColor_;
CachedTextureVulkan *lastBoundTexture; CachedTextureVulkan *lastBoundTexture;