Centralize the majority of texture decode.
This commit is contained in:
parent
339f065a5c
commit
5962093ef5
8 changed files with 306 additions and 723 deletions
|
@ -16,6 +16,7 @@
|
|||
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
|
||||
|
||||
#include <algorithm>
|
||||
#include "Common/ColorConv.h"
|
||||
#include "Common/MemoryUtil.h"
|
||||
#include "Core/Config.h"
|
||||
#include "Core/Host.h"
|
||||
|
@ -38,7 +39,8 @@
|
|||
|
||||
TextureCacheCommon::TextureCacheCommon()
|
||||
: 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.
|
||||
clutBufRaw_ = (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);
|
||||
}
|
||||
|
||||
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) {
|
||||
const u32 bpp = gstate.getClutPaletteFormat() == GE_CMODE_32BIT_ABGR8888 ? 4 : 2;
|
||||
const u32 pixels = 1024 / bpp;
|
||||
|
@ -467,6 +452,265 @@ u32 TextureCacheCommon::EstimateTexMemoryUsage(const TexCacheEntry *entry) {
|
|||
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) {
|
||||
int w = gstate.getTextureWidth(level);
|
||||
int h = gstate.getTextureHeight(level);
|
||||
|
|
|
@ -152,8 +152,8 @@ protected:
|
|||
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 *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);
|
||||
|
||||
template <typename T>
|
||||
|
@ -200,6 +200,10 @@ protected:
|
|||
u32 clutMaxBytes_;
|
||||
u32 clutRenderAddress_;
|
||||
u32 clutRenderOffset_;
|
||||
// True if the clut is just alpha values in the same order (RGBA4444-bit only.)
|
||||
bool clutAlphaLinear_;
|
||||
u16 clutAlphaLinearColor_;
|
||||
|
||||
int standardScaleFactor_;
|
||||
};
|
||||
|
||||
|
|
|
@ -364,8 +364,6 @@ D3DFORMAT getClutDestFormat(GEPaletteFormat format) {
|
|||
return D3DFMT_A8R8G8B8;
|
||||
}
|
||||
|
||||
static const u8 texByteAlignMap[] = {2, 2, 2, 4};
|
||||
|
||||
static const u8 MinFilt[8] = {
|
||||
D3DTEXF_POINT,
|
||||
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 *finalBuf = NULL;
|
||||
|
||||
void *TextureCacheDX9::DecodeTextureLevelOld(GETextureFormat format, GEPaletteFormat clutformat, int level, u32 &dstFmt, int *bufwout) {
|
||||
void *finalBuf = nullptr;
|
||||
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);
|
||||
if (bufwout)
|
||||
*bufwout = bufw;
|
||||
|
||||
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;
|
||||
int decPitch = 0;
|
||||
int pixelSize = dstFmt == D3DFMT_A8R8G8B8 ? 4 : 2;
|
||||
if (!(standardScaleFactor_ == 1 && gstate_c.Supports(GPU_SUPPORTS_UNPACK_SUBIMAGE)) && w != bufw) {
|
||||
decPitch = w * pixelSize;
|
||||
} else {
|
||||
decPitch = bufw * pixelSize;
|
||||
}
|
||||
|
||||
switch (clutformat) {
|
||||
case GE_CMODE_16BIT_BGR5650:
|
||||
case GE_CMODE_16BIT_ABGR5551:
|
||||
case GE_CMODE_16BIT_ABGR4444:
|
||||
{
|
||||
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;
|
||||
tmpTexBufRearrange.resize(std::max(w, bufw) * h);
|
||||
if (DecodeTextureLevel((u8 *)tmpTexBufRearrange.data(), decPitch, format, clutformat, texaddr, level, bufw, false)) {
|
||||
finalBuf = tmpTexBufRearrange.data();
|
||||
} else {
|
||||
finalBuf = nullptr;
|
||||
}
|
||||
|
||||
if (!finalBuf) {
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -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) {
|
||||
// TODO: only do this once
|
||||
u32 texByteAlign = 1;
|
||||
|
||||
int w = gstate.getTextureWidth(level);
|
||||
int h = gstate.getTextureHeight(level);
|
||||
int bufw;
|
||||
|
@ -1659,7 +1427,7 @@ void TextureCacheDX9::LoadTextureLevel(TexCacheEntry &entry, ReplacedTexture &re
|
|||
dstFmt = ToD3D9Format(replaced.Format(level));
|
||||
} else {
|
||||
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) {
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -81,7 +81,7 @@ private:
|
|||
void UpdateSamplingParams(TexCacheEntry &entry, bool force);
|
||||
void LoadTextureLevel(TexCacheEntry &entry, ReplacedTexture &replaced, int level, int maxLevel, bool replaceImages, int scaleFactor, u32 dstFmt);
|
||||
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);
|
||||
u32 GetCurrentClutHash();
|
||||
void UpdateCurrentClut(GEPaletteFormat clutFormat, u32 clutBase, bool clutIndexIsSimple);
|
||||
|
@ -112,9 +112,6 @@ private:
|
|||
TextureScalerDX9 scaler;
|
||||
|
||||
u32 clutHash_;
|
||||
// True if the clut is just alpha values in the same order (RGBA4444-bit only.)
|
||||
bool clutAlphaLinear_;
|
||||
u16 clutAlphaLinearColor_;
|
||||
|
||||
LPDIRECT3DTEXTURE9 lastBoundTexture;
|
||||
float maxAnisotropyLevel;
|
||||
|
|
|
@ -359,8 +359,6 @@ GLenum getClutDestFormat(GEPaletteFormat format) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
static const u8 texByteAlignMap[] = {2, 2, 2, 4};
|
||||
|
||||
static const GLuint MinFiltGL[8] = {
|
||||
GL_NEAREST,
|
||||
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 *finalBuf = NULL;
|
||||
|
||||
void *TextureCache::DecodeTextureLevelOld(GETextureFormat format, GEPaletteFormat clutformat, int level, GLenum dstFmt, int scaleFactor, int *bufwout) {
|
||||
void *finalBuf = nullptr;
|
||||
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);
|
||||
if (bufwout)
|
||||
*bufwout = bufw;
|
||||
|
||||
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;
|
||||
int decPitch = 0;
|
||||
int pixelSize = dstFmt == GL_UNSIGNED_BYTE ? 4 : 2;
|
||||
if (!(scaleFactor == 1 && gstate_c.Supports(GPU_SUPPORTS_UNPACK_SUBIMAGE)) && w != bufw) {
|
||||
decPitch = w * pixelSize;
|
||||
} else {
|
||||
decPitch = bufw * pixelSize;
|
||||
}
|
||||
|
||||
switch (clutformat) {
|
||||
case GE_CMODE_16BIT_BGR5650:
|
||||
case GE_CMODE_16BIT_ABGR5551:
|
||||
case GE_CMODE_16BIT_ABGR4444:
|
||||
{
|
||||
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;
|
||||
tmpTexBufRearrange.resize(std::max(w, bufw) * h);
|
||||
if (DecodeTextureLevel((u8 *)tmpTexBufRearrange.data(), decPitch, format, clutformat, texaddr, level, bufw, true, UseBGRA8888())) {
|
||||
finalBuf = tmpTexBufRearrange.data();
|
||||
} else {
|
||||
finalBuf = nullptr;
|
||||
}
|
||||
|
||||
if (!finalBuf) {
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -1784,12 +1546,11 @@ void TextureCache::LoadTextureLevel(TexCacheEntry &entry, ReplacedTexture &repla
|
|||
texByteAlign = bpp;
|
||||
useBGRA = false;
|
||||
} else {
|
||||
|
||||
PROFILE_THIS_SCOPE("decodetex");
|
||||
|
||||
GEPaletteFormat clutformat = gstate.getClutPaletteFormat();
|
||||
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) {
|
||||
return;
|
||||
}
|
||||
|
@ -1800,6 +1561,8 @@ void TextureCache::LoadTextureLevel(TexCacheEntry &entry, ReplacedTexture &repla
|
|||
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;
|
||||
|
||||
pixelData = (u32 *)finalBuf;
|
||||
|
@ -1882,7 +1645,6 @@ bool TextureCache::DecodeTexture(u8* output, const GPUgstate &state) {
|
|||
return false;
|
||||
}
|
||||
|
||||
u32 texByteAlign = 1;
|
||||
GLenum dstFmt = 0;
|
||||
|
||||
GETextureFormat format = gstate.getTextureFormat();
|
||||
|
@ -1893,7 +1655,7 @@ bool TextureCache::DecodeTexture(u8* output, const GPUgstate &state) {
|
|||
int w = gstate.getTextureWidth(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) {
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -96,7 +96,7 @@ private:
|
|||
void UpdateSamplingParams(TexCacheEntry &entry, bool force);
|
||||
void LoadTextureLevel(TexCacheEntry &entry, ReplacedTexture &replaced, int level, bool replaceImages, int scaleFactor, GLenum dstFmt);
|
||||
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);
|
||||
u32 GetCurrentClutHash();
|
||||
void UpdateCurrentClut(GEPaletteFormat clutFormat, u32 clutBase, bool clutIndexIsSimple);
|
||||
|
@ -118,9 +118,6 @@ private:
|
|||
TextureScalerGL scaler;
|
||||
|
||||
u32 clutHash_;
|
||||
// True if the clut is just alpha values in the same order (RGBA4444-bit only.)
|
||||
bool clutAlphaLinear_;
|
||||
u16 clutAlphaLinearColor_;
|
||||
|
||||
u32 lastBoundTexture;
|
||||
float maxAnisotropyLevel;
|
||||
|
|
|
@ -131,8 +131,7 @@ VkSampler SamplerCache::GetOrCreateSampler(const SamplerCacheKey &key) {
|
|||
|
||||
TextureCacheVulkan::TextureCacheVulkan(VulkanContext *vulkan)
|
||||
: vulkan_(vulkan), samplerCache_(vulkan), secondCacheSizeEstimate_(0),
|
||||
clearCacheNextFrame_(false), lowMemoryMode_(false), texelsScaledThisFrame_(0),
|
||||
clutAlphaLinear_(false) {
|
||||
clearCacheNextFrame_(false), lowMemoryMode_(false), texelsScaledThisFrame_(0) {
|
||||
timesInvalidatedAllThisFrame_ = 0;
|
||||
lastBoundTexture = nullptr;
|
||||
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) {
|
||||
CheckAlphaResult res;
|
||||
switch (dstFmt) {
|
||||
|
@ -1605,7 +1420,7 @@ void TextureCacheVulkan::LoadTextureLevel(TexCacheEntry &entry, uint8_t *writePt
|
|||
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) {
|
||||
memset(writePtr, 0, rowPitch * h);
|
||||
return;
|
||||
|
|
|
@ -129,7 +129,6 @@ private:
|
|||
void UpdateSamplingParams(TexCacheEntry &entry, SamplerCacheKey &key);
|
||||
void LoadTextureLevel(TexCacheEntry &entry, uint8_t *writePtr, int rowPitch, int level, int scaleFactor, VkFormat dstFmt);
|
||||
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);
|
||||
u32 GetCurrentClutHash();
|
||||
void UpdateCurrentClut(GEPaletteFormat clutFormat, u32 clutBase, bool clutIndexIsSimple);
|
||||
|
@ -156,9 +155,6 @@ private:
|
|||
TextureScalerVulkan scaler;
|
||||
|
||||
u32 clutHash_;
|
||||
// True if the clut is just alpha values in the same order (RGBA4444-bit only.)
|
||||
bool clutAlphaLinear_;
|
||||
u16 clutAlphaLinearColor_;
|
||||
|
||||
CachedTextureVulkan *lastBoundTexture;
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue