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/.
|
// 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);
|
||||||
|
|
|
@ -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_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue