mirror of
https://github.com/blawar/GLideN64.git
synced 2024-06-27 23:14:05 +00:00
2194 lines
81 KiB
C++
2194 lines
81 KiB
C++
#include <assert.h>
|
|
#include <memory.h>
|
|
#include <algorithm>
|
|
#include <thread> // std::this_thread::sleep_for
|
|
#include <chrono> // std::chrono::seconds
|
|
#include "Platform.h"
|
|
#include "Textures.h"
|
|
#include "GBI.h"
|
|
#include "RSP.h"
|
|
#include "RDP.h"
|
|
#include "gDP.h"
|
|
#include "gSP.h"
|
|
#include "N64.h"
|
|
#include "convert.h"
|
|
#include "FrameBuffer.h"
|
|
#include "Config.h"
|
|
#include "GLideNHQ/TxFilterExport.h"
|
|
#include "TextureFilterHandler.h"
|
|
#include "DisplayLoadProgress.h"
|
|
#include "Graphics/Context.h"
|
|
#include "Graphics/Parameters.h"
|
|
#include "DisplayWindow.h"
|
|
|
|
#ifdef NATIVE
|
|
#define RDRAM ((u8*)0)
|
|
#endif
|
|
|
|
using namespace std;
|
|
using namespace graphics;
|
|
|
|
u32 GetNone(u16 offset, u16 x, u16 i, u8 palette)
|
|
{
|
|
return 0x00000000;
|
|
}
|
|
|
|
inline u8 Get4BitPaletteColor(u16 offset, u16 x, u16 i)
|
|
{
|
|
u8* tmem8 = reinterpret_cast<u8*>(TMEM);
|
|
return tmem8[((offset << 3) + ((x >> 1) ^ (i << 1))) & 0xFFF];
|
|
}
|
|
|
|
u32 GetCI4_RGBA8888(u16 offset, u16 x, u16 i, u8 palette)
|
|
{
|
|
const u8 color4B = Get4BitPaletteColor(offset, x, i);
|
|
return CI4_RGBA8888((x & 1) ? (palette << 4) | (color4B & 0x0F) : (palette << 4) | (color4B >> 4));
|
|
}
|
|
|
|
u32 GetCI4_RGBA4444(u16 offset, u16 x, u16 i, u8 palette)
|
|
{
|
|
const u8 color4B = Get4BitPaletteColor(offset, x, i);
|
|
return CI4_RGBA4444((x & 1) ? (palette << 4) | (color4B & 0x0F) : (palette << 4) | (color4B >> 4));
|
|
}
|
|
|
|
u32 GetCI4IA_RGBA4444(u16 offset, u16 x, u16 i, u8 palette)
|
|
{
|
|
const u8 color4B = Get4BitPaletteColor(offset, x, i);
|
|
|
|
if (x & 1)
|
|
return IA88_RGBA4444(*(u16*)&TMEM[(0x100 + (palette << 4) + (color4B & 0x0F)) & 0x1FF]);
|
|
else
|
|
return IA88_RGBA4444(*(u16*)&TMEM[(0x100 + (palette << 4) + (color4B >> 4)) & 0x1FF]);
|
|
}
|
|
|
|
u32 GetCI4IA_RGBA8888(u16 offset, u16 x, u16 i, u8 palette)
|
|
{
|
|
const u8 color4B = Get4BitPaletteColor(offset, x, i);
|
|
|
|
if (x & 1)
|
|
return IA88_RGBA8888(*(u16*)&TMEM[(0x100 + (palette << 4) + (color4B & 0x0F)) & 0x1FF]);
|
|
else
|
|
return IA88_RGBA8888(*(u16*)&TMEM[(0x100 + (palette << 4) + (color4B >> 4)) & 0x1FF]);
|
|
}
|
|
|
|
u32 GetCI4RGBA_RGBA5551(u16 offset, u16 x, u16 i, u8 palette)
|
|
{
|
|
const u8 color4B = Get4BitPaletteColor(offset, x, i);
|
|
|
|
if (x & 1)
|
|
return RGBA5551_RGBA5551(*(u16*)&TMEM[(0x100 + (palette << 4) + (color4B & 0x0F)) & 0x1FF]);
|
|
else
|
|
return RGBA5551_RGBA5551(*(u16*)&TMEM[(0x100 + (palette << 4) + (color4B >> 4)) & 0x1FF]);
|
|
}
|
|
|
|
u32 GetCI4RGBA_RGBA8888(u16 offset, u16 x, u16 i, u8 palette)
|
|
{
|
|
const u8 color4B = Get4BitPaletteColor(offset, x, i);
|
|
|
|
if (x & 1)
|
|
return RGBA5551_RGBA8888(*(u16*)&TMEM[(0x100 + (palette << 4) + (color4B & 0x0F)) & 0x1FF]);
|
|
else
|
|
return RGBA5551_RGBA8888(*(u16*)&TMEM[(0x100 + (palette << 4) + (color4B >> 4)) & 0x1FF]);
|
|
}
|
|
|
|
u32 GetIA31_RGBA8888(u16 offset, u16 x, u16 i, u8 palette)
|
|
{
|
|
const u8 color4B = Get4BitPaletteColor(offset, x, i);
|
|
return IA31_RGBA8888((x & 1) ? (color4B & 0x0F) : (color4B >> 4));
|
|
}
|
|
|
|
u32 GetIA31_RGBA4444(u16 offset, u16 x, u16 i, u8 palette)
|
|
{
|
|
const u8 color4B = Get4BitPaletteColor(offset, x, i);
|
|
return IA31_RGBA4444((x & 1) ? (color4B & 0x0F) : (color4B >> 4));
|
|
}
|
|
|
|
u32 GetI4_RGBA8888(u16 offset, u16 x, u16 i, u8 palette)
|
|
{
|
|
const u8 color4B = Get4BitPaletteColor(offset, x, i);
|
|
return I4_RGBA8888((x & 1) ? (color4B & 0x0F) : (color4B >> 4));
|
|
}
|
|
|
|
u32 GetI4_RGBA4444(u16 offset, u16 x, u16 i, u8 palette)
|
|
{
|
|
const u8 color4B = Get4BitPaletteColor(offset, x, i);
|
|
return I4_RGBA4444((x & 1) ? (color4B & 0x0F) : (color4B >> 4));
|
|
}
|
|
|
|
inline u8 Get8BitPaletteColor(u16 offset, u16 x, u16 i)
|
|
{
|
|
u8* tmem8 = reinterpret_cast<u8*>(TMEM);
|
|
return tmem8[((offset << 3) + (x ^ (i << 1))) & 0xFFF];
|
|
}
|
|
|
|
u32 GetCI8IA_RGBA4444(u16 offset, u16 x, u16 i, u8 palette)
|
|
{
|
|
const u8 color = Get8BitPaletteColor(offset, x, i);
|
|
return IA88_RGBA4444(*(u16*)&TMEM[(0x100 + color) & 0x1FF]);
|
|
}
|
|
|
|
u32 GetCI8IA_RGBA8888(u16 offset, u16 x, u16 i, u8 palette)
|
|
{
|
|
const u8 color = Get8BitPaletteColor(offset, x, i);
|
|
return IA88_RGBA8888(*(u16*)&TMEM[(0x100 + color) & 0x1FF]);
|
|
}
|
|
|
|
u32 GetCI8RGBA_RGBA5551(u16 offset, u16 x, u16 i, u8 palette)
|
|
{
|
|
const u8 color = Get8BitPaletteColor(offset, x, i);
|
|
return RGBA5551_RGBA5551(*(u16*)&TMEM[(0x100 + color) & 0x1FF]);
|
|
}
|
|
|
|
u32 GetCI8RGBA_RGBA8888(u16 offset, u16 x, u16 i, u8 palette)
|
|
{
|
|
const u8 color = Get8BitPaletteColor(offset, x, i);
|
|
return RGBA5551_RGBA8888(*(u16*)&TMEM[(0x100 + color) & 0x1FF]);
|
|
}
|
|
|
|
u32 GetIA44_RGBA8888(u16 offset, u16 x, u16 i, u8 palette)
|
|
{
|
|
const u8 color = Get8BitPaletteColor(offset, x, i);
|
|
return IA44_RGBA8888(color);
|
|
}
|
|
|
|
u32 GetIA44_RGBA4444(u16 offset, u16 x, u16 i, u8 palette)
|
|
{
|
|
const u8 color = Get8BitPaletteColor(offset, x, i);
|
|
return IA44_RGBA4444(color);
|
|
}
|
|
|
|
u32 GetI8_RGBA8888(u16 offset, u16 x, u16 i, u8 palette)
|
|
{
|
|
const u8 color = Get8BitPaletteColor(offset, x, i);
|
|
return I8_RGBA8888(color);
|
|
}
|
|
u32 GetI8_RGBA4444(u16 offset, u16 x, u16 i, u8 palette)
|
|
{
|
|
const u8 color = Get8BitPaletteColor(offset, x, i);
|
|
return I8_RGBA4444(color);
|
|
}
|
|
|
|
inline u16 Get16BitColor(u16 offset, u16 x, u16 i)
|
|
{
|
|
u16* tmem16 = reinterpret_cast<u16*>(TMEM);
|
|
return tmem16[((offset << 2) + (x ^ i)) & 0x7FF];
|
|
}
|
|
|
|
u32 GetI16_RGBA8888(u16 offset, u16 x, u16 i, u8 palette)
|
|
{
|
|
const u16 tex = Get16BitColor(offset, x, i);
|
|
u32 r = tex >> 8;
|
|
u32 g = tex & 0xFF;
|
|
u32 b = r;
|
|
u32 a = g;
|
|
return (a << 24) | (b << 16) | (g << 8) | r;
|
|
}
|
|
|
|
u32 GetI16_RGBA4444(u16 offset, u16 x, u16 i, u8 palette)
|
|
{
|
|
const u16 tex = Get16BitColor(offset, x, i);
|
|
u16 r = tex >> 12;
|
|
u16 g = tex & 0x0F;
|
|
u16 b = r;
|
|
u16 a = g;
|
|
return (a << 12) | (b << 8) | (g << 4) | r;
|
|
}
|
|
|
|
u32 GetCI16IA_RGBA8888(u16 offset, u16 x, u16 i, u8 palette)
|
|
{
|
|
const u16 tex = Get16BitColor(offset, x, i);
|
|
const u16 col = (*(u16*)&TMEM[0x100 + (tex & 0xFF)]);
|
|
const u16 c = col >> 8;
|
|
const u16 a = col & 0xFF;
|
|
return (a << 24) | (c << 16) | (c << 8) | c;
|
|
}
|
|
|
|
u32 GetCI16IA_RGBA4444(u16 offset, u16 x, u16 i, u8 palette)
|
|
{
|
|
const u16 tex = Get16BitColor(offset, x, i);
|
|
const u16 col = (*(u16*)&TMEM[0x100 + (tex & 0xFF)]);
|
|
const u16 c = col >> 12;
|
|
const u16 a = col & 0x0F;
|
|
return (a << 12) | (c << 8) | (c << 4) | c;
|
|
}
|
|
|
|
u32 GetCI16RGBA_RGBA8888(u16 offset, u16 x, u16 i, u8 palette)
|
|
{
|
|
const u16 tex = Get16BitColor(offset, x, i) & 0xFF;
|
|
return RGBA5551_RGBA8888(((u16*)&TMEM[0x100])[tex << 2]);
|
|
}
|
|
|
|
u32 GetCI16RGBA_RGBA5551(u16 offset, u16 x, u16 i, u8 palette)
|
|
{
|
|
const u16 tex = Get16BitColor(offset, x, i) & 0xFF;
|
|
return RGBA5551_RGBA5551(((u16*)&TMEM[0x100])[tex << 2]);
|
|
}
|
|
|
|
u32 GetRGBA5551_RGBA8888(u16 offset, u16 x, u16 i, u8 palette)
|
|
{
|
|
const u16 tex = Get16BitColor(offset, x, i);
|
|
return RGBA5551_RGBA8888(tex);
|
|
}
|
|
|
|
u32 GetRGBA5551_RGBA5551(u16 offset, u16 x, u16 i, u8 palette)
|
|
{
|
|
const u16 tex = Get16BitColor(offset, x, i);
|
|
return RGBA5551_RGBA5551(tex);
|
|
}
|
|
|
|
u32 GetIA88_RGBA8888(u16 offset, u16 x, u16 i, u8 palette)
|
|
{
|
|
const u16 tex = Get16BitColor(offset, x, i);
|
|
return IA88_RGBA8888(tex);
|
|
}
|
|
|
|
u32 GetIA88_RGBA4444(u16 offset, u16 x, u16 i, u8 palette)
|
|
{
|
|
const u16 tex = Get16BitColor(offset, x, i);
|
|
return IA88_RGBA4444(tex);
|
|
}
|
|
|
|
inline u32 Get32BitColor(u16 offset, u16 x, u16 i)
|
|
{
|
|
u32* tmem32 = reinterpret_cast<u32*>(TMEM);
|
|
return tmem32[((offset << 1) + (x ^ i)) & LOAD_BLOCK32_MASK];
|
|
}
|
|
|
|
u32 GetRGBA8888_RGBA8888(u16 offset, u16 x, u16 i, u8 palette)
|
|
{
|
|
return Get32BitColor(offset, x, i);
|
|
}
|
|
|
|
u32 GetRGBA8888_RGBA4444(u16 offset, u16 x, u16 i, u8 palette)
|
|
{
|
|
const u32 tex = Get32BitColor(offset, x, i);
|
|
return RGBA8888_RGBA4444(tex);
|
|
}
|
|
|
|
inline u32 YUV_RGBA8888(u8 y, u8 u, u8 v)
|
|
{
|
|
return (0xff << 24) | (y << 16) | (v << 8) | u;
|
|
}
|
|
|
|
void GetYUV_RGBA8888(u64 * src, u32 * dst, u16 x)
|
|
{
|
|
const u32 t = (((u32*)src)[x]);
|
|
u8 y1 = (u8)t & 0xFF;
|
|
u8 v = (u8)(t >> 8) & 0xFF;
|
|
u8 y0 = (u8)(t >> 16) & 0xFF;
|
|
u8 u = (u8)(t >> 24) & 0xFF;
|
|
u32 c = YUV_RGBA8888(y0, u, v);
|
|
*(dst++) = c;
|
|
c = YUV_RGBA8888(y1, u, v);
|
|
*(dst++) = c;
|
|
}
|
|
|
|
u32 GetNoneBG(u64 *src, u16 x, u16 i, u8 palette)
|
|
{
|
|
return 0x00000000;
|
|
}
|
|
|
|
u32 GetCI4_RGBA8888_BG(u64 *src, u16 x, u16 i, u8 palette)
|
|
{
|
|
u8 color4B = ((u8*)src)[(x >> 1) ^ (i << 1)];
|
|
|
|
return CI4_RGBA8888((x & 1) ? (palette << 4) | (color4B & 0x0F) : (palette << 4) | (color4B >> 4));
|
|
}
|
|
|
|
u32 GetCI4_RGBA4444_BG(u64 *src, u16 x, u16 i, u8 palette)
|
|
{
|
|
u8 color4B = ((u8*)src)[(x >> 1) ^ (i << 1)];
|
|
|
|
return CI4_RGBA4444((x & 1) ? (palette << 4) | (color4B & 0x0F) : (palette << 4) | (color4B >> 4));
|
|
}
|
|
|
|
u32 GetCI4IA_RGBA4444_BG(u64 *src, u16 x, u16 i, u8 palette)
|
|
{
|
|
u8 color4B = ((u8*)src)[(x >> 1) ^ (i << 1)];
|
|
|
|
if (x & 1)
|
|
return IA88_RGBA4444(*(u16*)&TMEM[256 + (palette << 4) + (color4B & 0x0F)]);
|
|
else
|
|
return IA88_RGBA4444(*(u16*)&TMEM[256 + (palette << 4) + (color4B >> 4)]);
|
|
}
|
|
|
|
u32 GetCI4IA_RGBA8888_BG(u64 *src, u16 x, u16 i, u8 palette)
|
|
{
|
|
u8 color4B = ((u8*)src)[(x >> 1) ^ (i << 1)];
|
|
|
|
if (x & 1)
|
|
return IA88_RGBA8888(*(u16*)&TMEM[256 + (palette << 4) + (color4B & 0x0F)]);
|
|
else
|
|
return IA88_RGBA8888(*(u16*)&TMEM[256 + (palette << 4) + (color4B >> 4)]);
|
|
}
|
|
|
|
u32 GetCI4RGBA_RGBA5551_BG(u64 *src, u16 x, u16 i, u8 palette)
|
|
{
|
|
u8 color4B = ((u8*)src)[(x >> 1) ^ (i << 1)];
|
|
|
|
if (x & 1)
|
|
return RGBA5551_RGBA5551(*(u16*)&TMEM[256 + (palette << 4) + (color4B & 0x0F)]);
|
|
else
|
|
return RGBA5551_RGBA5551(*(u16*)&TMEM[256 + (palette << 4) + (color4B >> 4)]);
|
|
}
|
|
|
|
u32 GetCI4RGBA_RGBA8888_BG(u64 *src, u16 x, u16 i, u8 palette)
|
|
{
|
|
u8 color4B = ((u8*)src)[(x >> 1) ^ (i << 1)];
|
|
|
|
if (x & 1)
|
|
return RGBA5551_RGBA8888(*(u16*)&TMEM[256 + (palette << 4) + (color4B & 0x0F)]);
|
|
else
|
|
return RGBA5551_RGBA8888(*(u16*)&TMEM[256 + (palette << 4) + (color4B >> 4)]);
|
|
}
|
|
|
|
u32 GetIA31_RGBA8888_BG(u64 *src, u16 x, u16 i, u8 palette)
|
|
{
|
|
u8 color4B = ((u8*)src)[(x >> 1) ^ (i << 1)];
|
|
|
|
return IA31_RGBA8888((x & 1) ? (color4B & 0x0F) : (color4B >> 4));
|
|
}
|
|
|
|
u32 GetIA31_RGBA4444_BG(u64 *src, u16 x, u16 i, u8 palette)
|
|
{
|
|
u8 color4B = ((u8*)src)[(x >> 1) ^ (i << 1)];
|
|
|
|
return IA31_RGBA4444((x & 1) ? (color4B & 0x0F) : (color4B >> 4));
|
|
}
|
|
|
|
u32 GetI4_RGBA8888_BG(u64 *src, u16 x, u16 i, u8 palette)
|
|
{
|
|
u8 color4B = ((u8*)src)[(x >> 1) ^ (i << 1)];
|
|
|
|
return I4_RGBA8888((x & 1) ? (color4B & 0x0F) : (color4B >> 4));
|
|
}
|
|
|
|
u32 GetI4_RGBA4444_BG(u64 *src, u16 x, u16 i, u8 palette)
|
|
{
|
|
u8 color4B = ((u8*)src)[(x >> 1) ^ (i << 1)];
|
|
|
|
return I4_RGBA4444((x & 1) ? (color4B & 0x0F) : (color4B >> 4));
|
|
}
|
|
|
|
u32 GetCI8IA_RGBA4444_BG(u64 *src, u16 x, u16 i, u8 palette)
|
|
{
|
|
return IA88_RGBA4444(*(u16*)&TMEM[256 + ((u8*)src)[x ^ (i << 1)]]);
|
|
}
|
|
|
|
u32 GetCI8IA_RGBA8888_BG(u64 *src, u16 x, u16 i, u8 palette)
|
|
{
|
|
return IA88_RGBA8888(*(u16*)&TMEM[256 + ((u8*)src)[x ^ (i << 1)]]);
|
|
}
|
|
|
|
u32 GetCI8RGBA_RGBA5551_BG(u64 *src, u16 x, u16 i, u8 palette)
|
|
{
|
|
return RGBA5551_RGBA5551(*(u16*)&TMEM[256 + ((u8*)src)[x ^ (i << 1)]]);
|
|
}
|
|
|
|
u32 GetCI8RGBA_RGBA8888_BG(u64 *src, u16 x, u16 i, u8 palette)
|
|
{
|
|
return RGBA5551_RGBA8888(*(u16*)&TMEM[256 + ((u8*)src)[x ^ (i << 1)]]);
|
|
}
|
|
|
|
u32 GetIA44_RGBA8888_BG(u64 *src, u16 x, u16 i, u8 palette)
|
|
{
|
|
return IA44_RGBA8888(((u8*)src)[x ^ (i << 1)]);
|
|
}
|
|
|
|
u32 GetIA44_RGBA4444_BG(u64 *src, u16 x, u16 i, u8 palette)
|
|
{
|
|
return IA44_RGBA4444(((u8*)src)[x ^ (i << 1)]);
|
|
}
|
|
|
|
u32 GetI8_RGBA8888_BG(u64 *src, u16 x, u16 i, u8 palette)
|
|
{
|
|
return I8_RGBA8888(((u8*)src)[x ^ (i << 1)]);
|
|
}
|
|
|
|
u32 GetI8_RGBA4444_BG(u64 *src, u16 x, u16 i, u8 palette)
|
|
{
|
|
return I8_RGBA4444(((u8*)src)[x ^ (i << 1)]);
|
|
}
|
|
|
|
u32 GetI16_RGBA8888_BG(u64 *src, u16 x, u16 i, u8 palette)
|
|
{
|
|
const u16 tex = ((u16*)src)[x^i];
|
|
u32 r = tex >> 8;
|
|
u32 g = tex & 0xFF;
|
|
u32 b = r;
|
|
u32 a = g;
|
|
return (a << 24) | (b << 16) | (g << 8) | r;
|
|
}
|
|
|
|
u32 GetI16_RGBA4444_BG(u64 *src, u16 x, u16 i, u8 palette)
|
|
{
|
|
const u16 tex = ((u16*)src)[x^i];
|
|
u16 r = tex >> 12;
|
|
u16 g = tex & 0x0F;
|
|
u16 b = r;
|
|
u16 a = g;
|
|
return (a << 12) | (b << 8) | (g << 4) | r;
|
|
}
|
|
|
|
u32 GetCI16IA_RGBA8888_BG(u64 *src, u16 x, u16 i, u8 palette)
|
|
{
|
|
const u16 tex = ((u16*)src)[x^i];
|
|
const u16 col = (*(u16*)&TMEM[256 + (tex & 0xFF)]);
|
|
const u16 c = col >> 8;
|
|
const u16 a = col & 0xFF;
|
|
return (a << 24) | (c << 16) | (c << 8) | c;
|
|
}
|
|
|
|
u32 GetCI16IA_RGBA4444_BG(u64 *src, u16 x, u16 i, u8 palette)
|
|
{
|
|
const u16 tex = ((u16*)src)[x^i];
|
|
const u16 col = (*(u16*)&TMEM[256 + (tex & 0xFF)]);
|
|
const u16 c = col >> 12;
|
|
const u16 a = col & 0x0F;
|
|
return (a << 12) | (c << 8) | (c << 4) | c;
|
|
}
|
|
|
|
u32 GetCI16RGBA_RGBA8888_BG(u64 *src, u16 x, u16 i, u8 palette)
|
|
{
|
|
const u16 tex = (((u16*)src)[x^i]) & 0xFF;
|
|
return RGBA5551_RGBA8888(((u16*)&TMEM[256])[tex << 2]);
|
|
}
|
|
|
|
u32 GetCI16RGBA_RGBA5551_BG(u64 *src, u16 x, u16 i, u8 palette)
|
|
{
|
|
const u16 tex = (((u16*)src)[x^i]) & 0xFF;
|
|
return RGBA5551_RGBA5551(((u16*)&TMEM[256])[tex << 2]);
|
|
}
|
|
|
|
u32 GetRGBA5551_RGBA8888_BG(u64 *src, u16 x, u16 i, u8 palette)
|
|
{
|
|
u16 tex = ((u16*)src)[x^i];
|
|
return RGBA5551_RGBA8888(tex);
|
|
}
|
|
|
|
u32 GetRGBA5551_RGBA5551_BG(u64 *src, u16 x, u16 i, u8 palette)
|
|
{
|
|
u16 tex = ((u16*)src)[x^i];
|
|
return RGBA5551_RGBA5551(tex);
|
|
}
|
|
|
|
u32 GetIA88_RGBA8888_BG(u64 *src, u16 x, u16 i, u8 palette)
|
|
{
|
|
return IA88_RGBA8888(((u16*)src)[x^i]);
|
|
}
|
|
|
|
u32 GetIA88_RGBA4444_BG(u64 *src, u16 x, u16 i, u8 palette)
|
|
{
|
|
return IA88_RGBA4444(((u16*)src)[x^i]);
|
|
}
|
|
|
|
u32 GetRGBA8888_RGBA8888_BG(u64 *src, u16 x, u16 i, u8 palette)
|
|
{
|
|
return ((u32*)src)[x^i];
|
|
}
|
|
|
|
u32 GetRGBA8888_RGBA4444_BG(u64 *src, u16 x, u16 i, u8 palette)
|
|
{
|
|
return RGBA8888_RGBA4444(((u32*)src)[x^i]);
|
|
}
|
|
|
|
struct TextureLoadParameters
|
|
{
|
|
GetTexelFunc Get16;
|
|
GetTexelFuncBG Get16BG;
|
|
DatatypeParam glType16;
|
|
InternalColorFormatParam glInternalFormat16;
|
|
GetTexelFunc Get32;
|
|
GetTexelFuncBG Get32BG;
|
|
DatatypeParam glType32;
|
|
InternalColorFormatParam glInternalFormat32;
|
|
InternalColorFormatParam autoFormat;
|
|
u32 lineShift;
|
|
u32 maxTexels;
|
|
};
|
|
|
|
struct ImageFormat {
|
|
ImageFormat();
|
|
|
|
TextureLoadParameters tlp[4][4][5];
|
|
|
|
static ImageFormat & get() {
|
|
static ImageFormat imageFmt;
|
|
return imageFmt;
|
|
}
|
|
};
|
|
|
|
ImageFormat::ImageFormat()
|
|
{
|
|
TextureLoadParameters imageFormat[4][4][5] =
|
|
{ // G_TT_NONE
|
|
{ // Get16 glType16 glInternalFormat16 Get32 glType32 glInternalFormat32 autoFormat
|
|
{ // 4-bit
|
|
{ GetI4_RGBA4444, GetI4_RGBA4444_BG, datatype::UNSIGNED_SHORT_4_4_4_4, internalcolorFormat::RGBA4, GetI4_RGBA8888, GetI4_RGBA8888_BG, datatype::UNSIGNED_BYTE, internalcolorFormat::RGBA8, internalcolorFormat::RGBA4, 4, 8192 }, // RGBA as I
|
|
{ GetNone, GetNoneBG, datatype::UNSIGNED_SHORT_4_4_4_4, internalcolorFormat::RGBA4, GetNone, GetNoneBG, datatype::UNSIGNED_BYTE, internalcolorFormat::RGBA8, internalcolorFormat::RGBA4, 4, 8192 }, // YUV
|
|
{ GetCI4_RGBA4444, GetCI4_RGBA4444_BG, datatype::UNSIGNED_SHORT_4_4_4_4, internalcolorFormat::RGBA4, GetCI4_RGBA8888, GetCI4_RGBA8888_BG, datatype::UNSIGNED_BYTE, internalcolorFormat::RGBA8, internalcolorFormat::RGBA4, 4, 8192 }, // CI without palette
|
|
{ GetIA31_RGBA4444, GetIA31_RGBA4444_BG, datatype::UNSIGNED_SHORT_4_4_4_4, internalcolorFormat::RGBA4, GetIA31_RGBA8888, GetIA31_RGBA8888_BG, datatype::UNSIGNED_BYTE, internalcolorFormat::RGBA8, internalcolorFormat::RGBA4, 4, 8192 }, // IA
|
|
{ GetI4_RGBA4444, GetI4_RGBA4444_BG, datatype::UNSIGNED_SHORT_4_4_4_4, internalcolorFormat::RGBA4, GetI4_RGBA8888, GetI4_RGBA8888_BG, datatype::UNSIGNED_BYTE, internalcolorFormat::RGBA8, internalcolorFormat::RGBA4, 4, 8192 }, // I
|
|
},
|
|
{ // 8-bit
|
|
{ GetI8_RGBA4444, GetI8_RGBA4444_BG, datatype::UNSIGNED_SHORT_4_4_4_4, internalcolorFormat::RGBA4, GetI8_RGBA8888, GetI8_RGBA8888_BG, datatype::UNSIGNED_BYTE, internalcolorFormat::RGBA8, internalcolorFormat::RGBA8, 3, 4096 }, // RGBA as I
|
|
{ GetNone, GetNoneBG, datatype::UNSIGNED_SHORT_4_4_4_4, internalcolorFormat::RGBA4, GetNone, GetNoneBG, datatype::UNSIGNED_BYTE, internalcolorFormat::RGBA8, internalcolorFormat::RGBA4, 0, 4096 }, // YUV
|
|
{ GetI8_RGBA4444, GetI8_RGBA4444_BG, datatype::UNSIGNED_SHORT_4_4_4_4, internalcolorFormat::RGBA4, GetI8_RGBA8888, GetI8_RGBA8888_BG, datatype::UNSIGNED_BYTE, internalcolorFormat::RGBA8, internalcolorFormat::RGBA8, 3, 4096 }, // CI without palette
|
|
{ GetIA44_RGBA4444, GetIA44_RGBA4444_BG, datatype::UNSIGNED_SHORT_4_4_4_4, internalcolorFormat::RGBA4, GetIA44_RGBA8888, GetIA44_RGBA8888_BG, datatype::UNSIGNED_BYTE, internalcolorFormat::RGBA8, internalcolorFormat::RGBA4, 3, 4096 }, // IA
|
|
{ GetI8_RGBA4444, GetI8_RGBA4444_BG, datatype::UNSIGNED_SHORT_4_4_4_4, internalcolorFormat::RGBA4, GetI8_RGBA8888, GetI8_RGBA8888_BG, datatype::UNSIGNED_BYTE, internalcolorFormat::RGBA8, internalcolorFormat::RGBA8, 3, 4096 }, // I
|
|
},
|
|
{ // 16-bit
|
|
{ GetRGBA5551_RGBA5551, GetRGBA5551_RGBA5551_BG, datatype::UNSIGNED_SHORT_5_5_5_1, internalcolorFormat::RGB5_A1, GetRGBA5551_RGBA8888, GetRGBA5551_RGBA8888_BG, datatype::UNSIGNED_BYTE, internalcolorFormat::RGBA8, internalcolorFormat::RGB5_A1, 2, 2048 }, // RGBA
|
|
{ GetNone, GetNoneBG, datatype::UNSIGNED_SHORT_4_4_4_4, internalcolorFormat::RGBA4, GetNone, GetNoneBG, datatype::UNSIGNED_BYTE, internalcolorFormat::RGBA8, internalcolorFormat::RGBA8, 2, 2048 }, // YUV
|
|
{ GetIA88_RGBA4444, GetIA88_RGBA4444_BG, datatype::UNSIGNED_SHORT_4_4_4_4, internalcolorFormat::RGBA4, GetIA88_RGBA8888, GetIA88_RGBA8888_BG, datatype::UNSIGNED_BYTE, internalcolorFormat::RGBA8, internalcolorFormat::RGBA8, 2, 2048 }, // CI as IA
|
|
{ GetIA88_RGBA4444, GetIA88_RGBA4444_BG, datatype::UNSIGNED_SHORT_4_4_4_4, internalcolorFormat::RGBA4, GetIA88_RGBA8888, GetIA88_RGBA8888_BG, datatype::UNSIGNED_BYTE, internalcolorFormat::RGBA8, internalcolorFormat::RGBA8, 2, 2048 }, // IA
|
|
{ GetI16_RGBA4444, GetI16_RGBA4444_BG, datatype::UNSIGNED_SHORT_4_4_4_4, internalcolorFormat::RGBA4, GetI16_RGBA8888, GetI16_RGBA8888_BG, datatype::UNSIGNED_BYTE, internalcolorFormat::RGBA8, internalcolorFormat::RGBA8, 0, 2048 }, // I
|
|
},
|
|
{ // 32-bit
|
|
{ GetRGBA8888_RGBA4444, GetRGBA8888_RGBA4444_BG, datatype::UNSIGNED_SHORT_4_4_4_4, internalcolorFormat::RGBA4, GetRGBA8888_RGBA8888, GetRGBA8888_RGBA8888_BG, datatype::UNSIGNED_BYTE, internalcolorFormat::RGBA8, internalcolorFormat::RGBA8, 2, 1024 }, // RGBA
|
|
{ GetNone, GetNoneBG, datatype::UNSIGNED_SHORT_4_4_4_4, internalcolorFormat::RGBA4, GetNone, GetNoneBG, datatype::UNSIGNED_BYTE, internalcolorFormat::RGBA8, internalcolorFormat::RGBA4, 0, 1024 }, // YUV
|
|
{ GetNone, GetNoneBG, datatype::UNSIGNED_SHORT_4_4_4_4, internalcolorFormat::RGBA4, GetNone, GetNoneBG, datatype::UNSIGNED_BYTE, internalcolorFormat::RGBA8, internalcolorFormat::RGBA4, 0, 1024 }, // CI
|
|
{ GetNone, GetNoneBG, datatype::UNSIGNED_SHORT_4_4_4_4, internalcolorFormat::RGBA4, GetNone, GetNoneBG, datatype::UNSIGNED_BYTE, internalcolorFormat::RGBA8, internalcolorFormat::RGBA4, 0, 1024 }, // IA
|
|
{ GetNone, GetNoneBG, datatype::UNSIGNED_SHORT_4_4_4_4, internalcolorFormat::RGBA4, GetNone, GetNoneBG, datatype::UNSIGNED_BYTE, internalcolorFormat::RGBA8, internalcolorFormat::RGBA4, 0, 1024 }, // I
|
|
}
|
|
},
|
|
// DUMMY
|
|
{ // Get16 glType16 glInternalFormat16 Get32 glType32 glInternalFormat32 autoFormat
|
|
{ // 4-bit
|
|
{ GetCI4RGBA_RGBA5551, GetCI4RGBA_RGBA5551_BG, datatype::UNSIGNED_SHORT_5_5_5_1, internalcolorFormat::RGB5_A1, GetCI4RGBA_RGBA8888, GetCI4RGBA_RGBA8888_BG, datatype::UNSIGNED_BYTE, internalcolorFormat::RGBA8, internalcolorFormat::RGB5_A1, 4, 4096 }, // CI (Banjo-Kazooie uses this, doesn't make sense, but it works...)
|
|
{ GetNone, GetNoneBG, datatype::UNSIGNED_SHORT_4_4_4_4, internalcolorFormat::RGBA4, GetNone, GetNoneBG, datatype::UNSIGNED_BYTE, internalcolorFormat::RGBA8, internalcolorFormat::RGBA4, 4, 8192 }, // YUV
|
|
{ GetCI4RGBA_RGBA5551, GetCI4RGBA_RGBA5551_BG, datatype::UNSIGNED_SHORT_5_5_5_1, internalcolorFormat::RGB5_A1, GetCI4RGBA_RGBA8888, GetCI4RGBA_RGBA8888_BG, datatype::UNSIGNED_BYTE, internalcolorFormat::RGBA8, internalcolorFormat::RGB5_A1, 4, 4096 }, // CI
|
|
{ GetCI4RGBA_RGBA5551, GetCI4RGBA_RGBA5551_BG, datatype::UNSIGNED_SHORT_5_5_5_1, internalcolorFormat::RGB5_A1, GetCI4RGBA_RGBA8888, GetCI4RGBA_RGBA8888_BG, datatype::UNSIGNED_BYTE, internalcolorFormat::RGBA8, internalcolorFormat::RGB5_A1, 4, 4096 }, // IA as CI
|
|
{ GetCI4RGBA_RGBA5551, GetCI4RGBA_RGBA5551_BG, datatype::UNSIGNED_SHORT_5_5_5_1, internalcolorFormat::RGB5_A1, GetCI4RGBA_RGBA8888, GetCI4RGBA_RGBA8888_BG, datatype::UNSIGNED_BYTE, internalcolorFormat::RGBA8, internalcolorFormat::RGB5_A1, 4, 4096 }, // I as CI
|
|
},
|
|
{ // 8-bit
|
|
{ GetCI8RGBA_RGBA5551, GetCI8RGBA_RGBA5551_BG, datatype::UNSIGNED_SHORT_5_5_5_1, internalcolorFormat::RGB5_A1, GetCI8RGBA_RGBA8888, GetCI8RGBA_RGBA8888_BG, datatype::UNSIGNED_BYTE, internalcolorFormat::RGBA8, internalcolorFormat::RGB5_A1, 3, 2048 }, // RGBA
|
|
{ GetNone, GetNoneBG, datatype::UNSIGNED_SHORT_4_4_4_4, internalcolorFormat::RGBA4, GetNone, GetNoneBG, datatype::UNSIGNED_BYTE, internalcolorFormat::RGBA8, internalcolorFormat::RGBA4, 0, 4096 }, // YUV
|
|
{ GetCI8RGBA_RGBA5551, GetCI8RGBA_RGBA5551_BG, datatype::UNSIGNED_SHORT_5_5_5_1, internalcolorFormat::RGB5_A1, GetCI8RGBA_RGBA8888, GetCI8RGBA_RGBA8888_BG, datatype::UNSIGNED_BYTE, internalcolorFormat::RGBA8, internalcolorFormat::RGB5_A1, 3, 2048 }, // CI
|
|
{ GetCI8RGBA_RGBA5551, GetCI8RGBA_RGBA5551_BG, datatype::UNSIGNED_SHORT_5_5_5_1, internalcolorFormat::RGB5_A1, GetCI8RGBA_RGBA8888, GetCI8RGBA_RGBA8888_BG, datatype::UNSIGNED_BYTE, internalcolorFormat::RGBA8, internalcolorFormat::RGB5_A1, 3, 2048 }, // IA as CI
|
|
{ GetCI8RGBA_RGBA5551, GetCI8RGBA_RGBA5551_BG, datatype::UNSIGNED_SHORT_5_5_5_1, internalcolorFormat::RGB5_A1, GetCI8RGBA_RGBA8888, GetCI8RGBA_RGBA8888_BG, datatype::UNSIGNED_BYTE, internalcolorFormat::RGBA8, internalcolorFormat::RGB5_A1, 3, 2048 }, // I as CI
|
|
},
|
|
{ // 16-bit
|
|
{ GetCI16RGBA_RGBA5551, GetCI16RGBA_RGBA5551_BG, datatype::UNSIGNED_SHORT_5_5_5_1, internalcolorFormat::RGB5_A1, GetRGBA5551_RGBA8888, GetRGBA5551_RGBA8888_BG, datatype::UNSIGNED_BYTE, internalcolorFormat::RGBA8, internalcolorFormat::RGB5_A1, 2, 2048 }, // RGBA
|
|
{ GetNone, GetNoneBG, datatype::UNSIGNED_SHORT_4_4_4_4, internalcolorFormat::RGBA4, GetNone, GetNoneBG, datatype::UNSIGNED_BYTE, internalcolorFormat::RGBA8, internalcolorFormat::RGBA8, 2, 2048 }, // YUV
|
|
{ GetNone, GetNoneBG, datatype::UNSIGNED_SHORT_4_4_4_4, internalcolorFormat::RGBA4, GetNone, GetNoneBG, datatype::UNSIGNED_BYTE, internalcolorFormat::RGBA8, internalcolorFormat::RGBA4, 0, 2048 }, // CI
|
|
{ GetCI16RGBA_RGBA5551, GetCI16RGBA_RGBA5551_BG, datatype::UNSIGNED_SHORT_5_5_5_1, internalcolorFormat::RGB5_A1, GetCI16RGBA_RGBA8888, GetCI16RGBA_RGBA8888_BG, datatype::UNSIGNED_BYTE, internalcolorFormat::RGBA8, internalcolorFormat::RGB5_A1, 2, 2048 }, // IA as CI
|
|
{ GetNone, GetNoneBG, datatype::UNSIGNED_SHORT_4_4_4_4, internalcolorFormat::RGBA4, GetNone, GetNoneBG, datatype::UNSIGNED_BYTE, internalcolorFormat::RGBA8, internalcolorFormat::RGBA4, 0, 2048 }, // I
|
|
},
|
|
{ // 32-bit
|
|
{ GetRGBA8888_RGBA4444, GetRGBA8888_RGBA4444_BG, datatype::UNSIGNED_SHORT_4_4_4_4, internalcolorFormat::RGBA4, GetRGBA8888_RGBA8888, GetRGBA8888_RGBA8888_BG, datatype::UNSIGNED_BYTE, internalcolorFormat::RGBA8, internalcolorFormat::RGBA8, 2, 1024 }, // RGBA
|
|
{ GetNone, GetNoneBG, datatype::UNSIGNED_SHORT_4_4_4_4, internalcolorFormat::RGBA4, GetNone, GetNoneBG, datatype::UNSIGNED_BYTE, internalcolorFormat::RGBA8, internalcolorFormat::RGBA4, 0, 1024 }, // YUV
|
|
{ GetNone, GetNoneBG, datatype::UNSIGNED_SHORT_4_4_4_4, internalcolorFormat::RGBA4, GetNone, GetNoneBG, datatype::UNSIGNED_BYTE, internalcolorFormat::RGBA8, internalcolorFormat::RGBA4, 0, 1024 }, // CI
|
|
{ GetNone, GetNoneBG, datatype::UNSIGNED_SHORT_4_4_4_4, internalcolorFormat::RGBA4, GetNone, GetNoneBG, datatype::UNSIGNED_BYTE, internalcolorFormat::RGBA8, internalcolorFormat::RGBA4, 0, 1024 }, // IA
|
|
{ GetNone, GetNoneBG, datatype::UNSIGNED_SHORT_4_4_4_4, internalcolorFormat::RGBA4, GetNone, GetNoneBG, datatype::UNSIGNED_BYTE, internalcolorFormat::RGBA8, internalcolorFormat::RGBA4, 0, 1024 }, // I
|
|
}
|
|
},
|
|
// G_TT_RGBA16
|
|
{ // Get16 glType16 glInternalFormat16 Get32 glType32 glInternalFormat32 autoFormat
|
|
{ // 4-bit
|
|
{ GetCI4RGBA_RGBA5551, GetCI4RGBA_RGBA5551_BG, datatype::UNSIGNED_SHORT_5_5_5_1, internalcolorFormat::RGB5_A1, GetCI4RGBA_RGBA8888, GetCI4RGBA_RGBA8888_BG, datatype::UNSIGNED_BYTE, internalcolorFormat::RGBA8, internalcolorFormat::RGB5_A1, 4, 4096 }, // CI (Banjo-Kazooie uses this, doesn't make sense, but it works...)
|
|
{ GetNone, GetNoneBG, datatype::UNSIGNED_SHORT_4_4_4_4, internalcolorFormat::RGBA4, GetNone, GetNoneBG, datatype::UNSIGNED_BYTE, internalcolorFormat::RGBA8, internalcolorFormat::RGBA4, 4, 8192 }, // YUV
|
|
{ GetCI4RGBA_RGBA5551, GetCI4RGBA_RGBA5551_BG, datatype::UNSIGNED_SHORT_5_5_5_1, internalcolorFormat::RGB5_A1, GetCI4RGBA_RGBA8888, GetCI4RGBA_RGBA8888_BG, datatype::UNSIGNED_BYTE, internalcolorFormat::RGBA8, internalcolorFormat::RGB5_A1, 4, 4096 }, // CI
|
|
{ GetCI4RGBA_RGBA5551, GetCI4RGBA_RGBA5551_BG, datatype::UNSIGNED_SHORT_5_5_5_1, internalcolorFormat::RGB5_A1, GetCI4RGBA_RGBA8888, GetCI4RGBA_RGBA8888_BG, datatype::UNSIGNED_BYTE, internalcolorFormat::RGBA8, internalcolorFormat::RGB5_A1, 4, 4096 }, // IA as CI
|
|
{ GetCI4RGBA_RGBA5551, GetCI4RGBA_RGBA5551_BG, datatype::UNSIGNED_SHORT_5_5_5_1, internalcolorFormat::RGB5_A1, GetCI4RGBA_RGBA8888, GetCI4RGBA_RGBA8888_BG, datatype::UNSIGNED_BYTE, internalcolorFormat::RGBA8, internalcolorFormat::RGB5_A1, 4, 4096 }, // I as CI
|
|
},
|
|
{ // 8-bit
|
|
{ GetCI8RGBA_RGBA5551, GetCI8RGBA_RGBA5551_BG, datatype::UNSIGNED_SHORT_5_5_5_1, internalcolorFormat::RGB5_A1, GetCI8RGBA_RGBA8888, GetCI8RGBA_RGBA8888_BG, datatype::UNSIGNED_BYTE, internalcolorFormat::RGBA8, internalcolorFormat::RGB5_A1, 3, 2048 }, // RGBA
|
|
{ GetNone, GetNoneBG, datatype::UNSIGNED_SHORT_4_4_4_4, internalcolorFormat::RGBA4, GetNone, GetNoneBG, datatype::UNSIGNED_BYTE, internalcolorFormat::RGBA8, internalcolorFormat::RGBA4, 0, 4096 }, // YUV
|
|
{ GetCI8RGBA_RGBA5551, GetCI8RGBA_RGBA5551_BG, datatype::UNSIGNED_SHORT_5_5_5_1, internalcolorFormat::RGB5_A1, GetCI8RGBA_RGBA8888, GetCI8RGBA_RGBA8888_BG, datatype::UNSIGNED_BYTE, internalcolorFormat::RGBA8, internalcolorFormat::RGB5_A1, 3, 2048 }, // CI
|
|
{ GetCI8RGBA_RGBA5551, GetCI8RGBA_RGBA5551_BG, datatype::UNSIGNED_SHORT_5_5_5_1, internalcolorFormat::RGB5_A1, GetCI8RGBA_RGBA8888, GetCI8RGBA_RGBA8888_BG, datatype::UNSIGNED_BYTE, internalcolorFormat::RGBA8, internalcolorFormat::RGB5_A1, 3, 2048 }, // IA as CI
|
|
{ GetCI8RGBA_RGBA5551, GetCI8RGBA_RGBA5551_BG, datatype::UNSIGNED_SHORT_5_5_5_1, internalcolorFormat::RGB5_A1, GetCI8RGBA_RGBA8888, GetCI8RGBA_RGBA8888_BG, datatype::UNSIGNED_BYTE, internalcolorFormat::RGBA8, internalcolorFormat::RGB5_A1, 3, 2048 }, // I as CI
|
|
},
|
|
{ // 16-bit
|
|
{ GetCI16RGBA_RGBA5551, GetCI16RGBA_RGBA5551_BG, datatype::UNSIGNED_SHORT_5_5_5_1, internalcolorFormat::RGB5_A1, GetRGBA5551_RGBA8888, GetRGBA5551_RGBA8888_BG, datatype::UNSIGNED_BYTE, internalcolorFormat::RGBA8, internalcolorFormat::RGB5_A1, 2, 2048 }, // RGBA
|
|
{ GetNone, GetNoneBG, datatype::UNSIGNED_SHORT_4_4_4_4, internalcolorFormat::RGBA4, GetNone, GetNoneBG, datatype::UNSIGNED_BYTE, internalcolorFormat::RGBA8, internalcolorFormat::RGBA8, 2, 2048 }, // YUV
|
|
{ GetNone, GetNoneBG, datatype::UNSIGNED_SHORT_4_4_4_4, internalcolorFormat::RGBA4, GetNone, GetNoneBG, datatype::UNSIGNED_BYTE, internalcolorFormat::RGBA8, internalcolorFormat::RGBA4, 0, 2048 }, // CI
|
|
{ GetCI16RGBA_RGBA5551, GetCI16RGBA_RGBA5551_BG, datatype::UNSIGNED_SHORT_5_5_5_1, internalcolorFormat::RGB5_A1, GetCI16RGBA_RGBA8888, GetCI16RGBA_RGBA8888_BG, datatype::UNSIGNED_BYTE, internalcolorFormat::RGBA8, internalcolorFormat::RGB5_A1, 2, 2048 }, // IA as CI
|
|
{ GetNone, GetNoneBG, datatype::UNSIGNED_SHORT_4_4_4_4, internalcolorFormat::RGBA4, GetNone, GetNoneBG, datatype::UNSIGNED_BYTE, internalcolorFormat::RGBA8, internalcolorFormat::RGBA4, 0, 2048 }, // I
|
|
},
|
|
{ // 32-bit
|
|
{ GetRGBA8888_RGBA4444, GetRGBA8888_RGBA4444_BG, datatype::UNSIGNED_SHORT_4_4_4_4, internalcolorFormat::RGBA4, GetRGBA8888_RGBA8888, GetRGBA8888_RGBA8888_BG, datatype::UNSIGNED_BYTE, internalcolorFormat::RGBA8, internalcolorFormat::RGBA8, 2, 1024 }, // RGBA
|
|
{ GetNone, GetNoneBG, datatype::UNSIGNED_SHORT_4_4_4_4, internalcolorFormat::RGBA4, GetNone, GetNoneBG, datatype::UNSIGNED_BYTE, internalcolorFormat::RGBA8, internalcolorFormat::RGBA4, 0, 1024 }, // YUV
|
|
{ GetNone, GetNoneBG, datatype::UNSIGNED_SHORT_4_4_4_4, internalcolorFormat::RGBA4, GetNone, GetNoneBG, datatype::UNSIGNED_BYTE, internalcolorFormat::RGBA8, internalcolorFormat::RGBA4, 0, 1024 }, // CI
|
|
{ GetNone, GetNoneBG, datatype::UNSIGNED_SHORT_4_4_4_4, internalcolorFormat::RGBA4, GetNone, GetNoneBG, datatype::UNSIGNED_BYTE, internalcolorFormat::RGBA8, internalcolorFormat::RGBA4, 0, 1024 }, // IA
|
|
{ GetNone, GetNoneBG, datatype::UNSIGNED_SHORT_4_4_4_4, internalcolorFormat::RGBA4, GetNone, GetNoneBG, datatype::UNSIGNED_BYTE, internalcolorFormat::RGBA8, internalcolorFormat::RGBA4, 0, 1024 }, // I
|
|
}
|
|
},
|
|
// G_TT_IA16
|
|
{ // Get16 glType16 glInternalFormat16 Get32 glType32 glInternalFormat32 autoFormat
|
|
{ // 4-bit
|
|
{ GetCI4IA_RGBA4444, GetCI4IA_RGBA4444_BG, datatype::UNSIGNED_SHORT_4_4_4_4, internalcolorFormat::RGBA4, GetCI4IA_RGBA8888, GetCI4IA_RGBA8888_BG, datatype::UNSIGNED_BYTE, internalcolorFormat::RGBA8, internalcolorFormat::RGBA8, 4, 4096 }, // IA
|
|
{ GetNone, GetNoneBG, datatype::UNSIGNED_SHORT_4_4_4_4, internalcolorFormat::RGBA4, GetNone, GetNoneBG, datatype::UNSIGNED_BYTE, internalcolorFormat::RGBA8, internalcolorFormat::RGBA8, 4, 8192 }, // YUV
|
|
{ GetCI4IA_RGBA4444, GetCI4IA_RGBA4444_BG, datatype::UNSIGNED_SHORT_4_4_4_4, internalcolorFormat::RGBA4, GetCI4IA_RGBA8888, GetCI4IA_RGBA8888_BG, datatype::UNSIGNED_BYTE, internalcolorFormat::RGBA8, internalcolorFormat::RGBA8, 4, 4096 }, // CI
|
|
{ GetCI4IA_RGBA4444, GetCI4IA_RGBA4444_BG, datatype::UNSIGNED_SHORT_4_4_4_4, internalcolorFormat::RGBA4, GetCI4IA_RGBA8888, GetCI4IA_RGBA8888_BG, datatype::UNSIGNED_BYTE, internalcolorFormat::RGBA8, internalcolorFormat::RGBA8, 4, 4096 }, // IA
|
|
{ GetCI4IA_RGBA4444, GetCI4IA_RGBA4444_BG, datatype::UNSIGNED_SHORT_4_4_4_4, internalcolorFormat::RGBA4, GetCI4IA_RGBA8888, GetCI4IA_RGBA8888_BG, datatype::UNSIGNED_BYTE, internalcolorFormat::RGBA8, internalcolorFormat::RGBA8, 4, 4096 }, // I
|
|
},
|
|
{ // 8-bit
|
|
{ GetCI8IA_RGBA4444, GetCI8IA_RGBA4444_BG, datatype::UNSIGNED_SHORT_4_4_4_4, internalcolorFormat::RGBA4, GetCI8IA_RGBA8888, GetCI8IA_RGBA8888_BG, datatype::UNSIGNED_BYTE, internalcolorFormat::RGBA8, internalcolorFormat::RGBA8, 3, 2048 }, // RGBA
|
|
{ GetNone, GetNoneBG, datatype::UNSIGNED_SHORT_4_4_4_4, internalcolorFormat::RGBA4, GetNone, GetNoneBG, datatype::UNSIGNED_BYTE, internalcolorFormat::RGBA8, internalcolorFormat::RGBA8, 0, 4096 }, // YUV
|
|
{ GetCI8IA_RGBA4444, GetCI8IA_RGBA4444_BG, datatype::UNSIGNED_SHORT_4_4_4_4, internalcolorFormat::RGBA4, GetCI8IA_RGBA8888, GetCI8IA_RGBA8888_BG, datatype::UNSIGNED_BYTE, internalcolorFormat::RGBA8, internalcolorFormat::RGBA8, 3, 2048 }, // CI
|
|
{ GetCI8IA_RGBA4444, GetCI8IA_RGBA4444_BG, datatype::UNSIGNED_SHORT_4_4_4_4, internalcolorFormat::RGBA4, GetCI8IA_RGBA8888, GetCI8IA_RGBA8888_BG, datatype::UNSIGNED_BYTE, internalcolorFormat::RGBA8, internalcolorFormat::RGBA8, 3, 2048 }, // IA
|
|
{ GetCI8IA_RGBA4444, GetCI8IA_RGBA4444_BG, datatype::UNSIGNED_SHORT_4_4_4_4, internalcolorFormat::RGBA4, GetCI8IA_RGBA8888, GetCI8IA_RGBA8888_BG, datatype::UNSIGNED_BYTE, internalcolorFormat::RGBA8, internalcolorFormat::RGBA8, 3, 2048 }, // I
|
|
},
|
|
{ // 16-bit
|
|
{ GetCI16IA_RGBA4444, GetCI16IA_RGBA4444_BG, datatype::UNSIGNED_SHORT_4_4_4_4, internalcolorFormat::RGBA4, GetCI16IA_RGBA8888, GetCI16IA_RGBA8888_BG, datatype::UNSIGNED_BYTE, internalcolorFormat::RGBA8, internalcolorFormat::RGBA8, 2, 2048 }, // RGBA
|
|
{ GetNone, GetNoneBG, datatype::UNSIGNED_SHORT_4_4_4_4, internalcolorFormat::RGBA4, GetNone, GetNoneBG, datatype::UNSIGNED_BYTE, internalcolorFormat::RGBA8, internalcolorFormat::RGBA8, 2, 2048 }, // YUV
|
|
{ GetNone, GetNoneBG, datatype::UNSIGNED_SHORT_4_4_4_4, internalcolorFormat::RGBA4, GetNone, GetNoneBG, datatype::UNSIGNED_BYTE, internalcolorFormat::RGBA8, internalcolorFormat::RGBA8, 0, 2048 }, // CI
|
|
{ GetCI16IA_RGBA4444, GetCI16IA_RGBA4444_BG, datatype::UNSIGNED_SHORT_4_4_4_4, internalcolorFormat::RGBA4, GetCI16IA_RGBA8888, GetCI16IA_RGBA8888_BG, datatype::UNSIGNED_BYTE, internalcolorFormat::RGBA8, internalcolorFormat::RGBA8, 2, 2048 }, // IA
|
|
{ GetNone, GetNoneBG, datatype::UNSIGNED_SHORT_4_4_4_4, internalcolorFormat::RGBA4, GetNone, GetNoneBG, datatype::UNSIGNED_BYTE, internalcolorFormat::RGBA8, internalcolorFormat::RGBA8, 0, 2048 }, // I
|
|
},
|
|
{ // 32-bit
|
|
{ GetRGBA8888_RGBA4444, GetRGBA8888_RGBA4444_BG, datatype::UNSIGNED_SHORT_4_4_4_4, internalcolorFormat::RGBA4, GetRGBA8888_RGBA8888, GetRGBA8888_RGBA8888_BG, datatype::UNSIGNED_BYTE, internalcolorFormat::RGBA8, internalcolorFormat::RGBA8, 2, 1024 }, // RGBA
|
|
{ GetNone, GetNoneBG, datatype::UNSIGNED_SHORT_4_4_4_4, internalcolorFormat::RGBA4, GetNone, GetNoneBG, datatype::UNSIGNED_BYTE, internalcolorFormat::RGBA8, internalcolorFormat::RGBA8, 0, 1024 }, // YUV
|
|
{ GetNone, GetNoneBG, datatype::UNSIGNED_SHORT_4_4_4_4, internalcolorFormat::RGBA4, GetNone, GetNoneBG, datatype::UNSIGNED_BYTE, internalcolorFormat::RGBA8, internalcolorFormat::RGBA8, 0, 1024 }, // CI
|
|
{ GetNone, GetNoneBG, datatype::UNSIGNED_SHORT_4_4_4_4, internalcolorFormat::RGBA4, GetNone, GetNoneBG, datatype::UNSIGNED_BYTE, internalcolorFormat::RGBA8, internalcolorFormat::RGBA8, 0, 1024 }, // IA
|
|
{ GetNone, GetNoneBG, datatype::UNSIGNED_SHORT_4_4_4_4, internalcolorFormat::RGBA4, GetNone, GetNoneBG, datatype::UNSIGNED_BYTE, internalcolorFormat::RGBA8, internalcolorFormat::RGBA8, 0, 1024 }, // I
|
|
}
|
|
}
|
|
};
|
|
|
|
memcpy(tlp, imageFormat, sizeof(tlp));
|
|
}
|
|
|
|
/** cite from RiceVideo */
|
|
inline u32 CalculateDXT(u32 txl2words)
|
|
{
|
|
if (txl2words == 0) return 1;
|
|
else return (2048 + txl2words - 1) / txl2words;
|
|
}
|
|
|
|
u32 sizeBytes[4] = {0, 1, 2, 4};
|
|
|
|
inline u32 Txl2Words(u32 width, u32 size)
|
|
{
|
|
if (size == 0)
|
|
return max(1U, width / 16);
|
|
else
|
|
return max(1U, width*sizeBytes[size] / 8);
|
|
}
|
|
|
|
inline u32 ReverseDXT(u32 val, u32 lrs, u32 width, u32 size)
|
|
{
|
|
if (val == 0x800) return 1;
|
|
|
|
int low = 2047 / val;
|
|
if (CalculateDXT(low) > val) low++;
|
|
int high = 2047 / (val - 1);
|
|
|
|
if (low == high) return low;
|
|
|
|
for (int i = low; i <= high; i++) {
|
|
if (Txl2Words(width, size) == (u32)i)
|
|
return i;
|
|
}
|
|
|
|
return (low + high) / 2;
|
|
}
|
|
/** end RiceVideo cite */
|
|
|
|
TextureCache & TextureCache::get() {
|
|
static TextureCache cache;
|
|
return cache;
|
|
}
|
|
|
|
void TextureCache::_initDummyTexture(CachedTexture * _pDummy)
|
|
{
|
|
_pDummy->address = 0;
|
|
_pDummy->clampS = 1;
|
|
_pDummy->clampT = 1;
|
|
_pDummy->clampWidth = 2;
|
|
_pDummy->clampHeight = 2;
|
|
_pDummy->crc = 0;
|
|
_pDummy->format = 0;
|
|
_pDummy->size = 0;
|
|
_pDummy->frameBufferTexture = CachedTexture::fbNone;
|
|
_pDummy->width = 2;
|
|
_pDummy->height = 2;
|
|
_pDummy->maskS = 0;
|
|
_pDummy->maskT = 0;
|
|
_pDummy->scaleS = 0.5f;
|
|
_pDummy->scaleT = 0.5f;
|
|
_pDummy->hdRatioS = 1.0f;
|
|
_pDummy->hdRatioT = 1.0f;
|
|
_pDummy->shiftScaleS = 1.0f;
|
|
_pDummy->shiftScaleT = 1.0f;
|
|
_pDummy->textureBytes = 2 * 2 * 4;
|
|
_pDummy->tMem = 0;
|
|
}
|
|
|
|
void TextureCache::init()
|
|
{
|
|
m_curUnpackAlignment = 0;
|
|
|
|
u32 dummyTexture[16] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
|
|
|
|
m_pDummy = addFrameBufferTexture(textureTarget::TEXTURE_2D); // we don't want to remove dummy texture
|
|
_initDummyTexture(m_pDummy);
|
|
|
|
Context::InitTextureParams params;
|
|
params.handle = m_pDummy->name;
|
|
params.mipMapLevel = 0;
|
|
params.msaaLevel = 0;
|
|
params.width = m_pDummy->width;
|
|
params.height = m_pDummy->height;
|
|
params.format = colorFormat::RGBA;
|
|
params.internalFormat = gfxContext.convertInternalTextureFormat(u32(internalcolorFormat::RGBA8));
|
|
params.dataType = datatype::UNSIGNED_BYTE;
|
|
params.data = dummyTexture;
|
|
gfxContext.init2DTexture(params);
|
|
|
|
activateDummy( 0 );
|
|
activateDummy(1);
|
|
current[0] = current[1] = nullptr;
|
|
|
|
|
|
m_pMSDummy = nullptr;
|
|
if (config.video.multisampling != 0 && Context::Multisampling) {
|
|
m_pMSDummy = addFrameBufferTexture(textureTarget::TEXTURE_2D_MULTISAMPLE); // we don't want to remove dummy texture
|
|
_initDummyTexture(m_pMSDummy);
|
|
|
|
Context::InitTextureParams msParams;
|
|
msParams.handle = m_pMSDummy->name;
|
|
msParams.mipMapLevel = 0;
|
|
msParams.msaaLevel = config.video.multisampling;
|
|
msParams.width = m_pMSDummy->width;
|
|
msParams.height = m_pMSDummy->height;
|
|
msParams.format = colorFormat::RGBA;
|
|
msParams.internalFormat = gfxContext.convertInternalTextureFormat(u32(internalcolorFormat::RGBA8));
|
|
msParams.dataType = datatype::UNSIGNED_BYTE;
|
|
gfxContext.init2DTexture(msParams);
|
|
|
|
activateMSDummy(0);
|
|
activateMSDummy(1);
|
|
}
|
|
|
|
assert(!gfxContext.isError());
|
|
}
|
|
|
|
void TextureCache::destroy()
|
|
{
|
|
current[0] = current[1] = nullptr;
|
|
|
|
for (Textures::const_iterator cur = m_textures.cbegin(); cur != m_textures.cend(); ++cur)
|
|
gfxContext.deleteTexture(cur->name);
|
|
m_textures.clear();
|
|
m_lruTextureLocations.clear();
|
|
|
|
for (FBTextures::const_iterator cur = m_fbTextures.cbegin(); cur != m_fbTextures.cend(); ++cur)
|
|
gfxContext.deleteTexture(cur->second.name);
|
|
m_fbTextures.clear();
|
|
|
|
m_hdTexCacheSize = 0;
|
|
}
|
|
|
|
void TextureCache::_checkHdTexLimit()
|
|
{
|
|
const u64 maxCacheSize = config.textureFilter.txHiresVramLimit * 1024u * 1024u;
|
|
|
|
// we don't need to do anything,
|
|
// when the limit has been disabled
|
|
if (maxCacheSize == 0u)
|
|
return;
|
|
|
|
// keep removing hd textures until we're below the max size
|
|
for (auto iter = m_textures.rbegin(); iter != m_textures.rend() && m_hdTexCacheSize >= maxCacheSize;)
|
|
{
|
|
if (!iter->bHDTexture) {
|
|
++iter;
|
|
} else {
|
|
assert(m_hdTexCacheSize >= iter->textureBytes);
|
|
m_hdTexCacheSize -= iter->textureBytes;
|
|
gfxContext.deleteTexture(iter->name);
|
|
m_lruTextureLocations.erase(iter->crc);
|
|
iter = decltype(iter)(m_textures.erase(std::next(iter).base()));
|
|
}
|
|
}
|
|
}
|
|
|
|
void TextureCache::_checkCacheSize()
|
|
{
|
|
if (m_textures.size() >= m_maxCacheSize) {
|
|
CachedTexture& clsTex = m_textures.back();
|
|
if (clsTex.bHDTexture)
|
|
m_hdTexCacheSize -= clsTex.textureBytes;
|
|
gfxContext.deleteTexture(clsTex.name);
|
|
m_lruTextureLocations.erase(clsTex.crc);
|
|
m_textures.pop_back();
|
|
}
|
|
}
|
|
|
|
CachedTexture * TextureCache::_addTexture(u64 _crc64)
|
|
{
|
|
if (m_curUnpackAlignment == 0)
|
|
m_curUnpackAlignment = gfxContext.getTextureUnpackAlignment();
|
|
_checkCacheSize();
|
|
m_textures.emplace_front(gfxContext.createTexture(textureTarget::TEXTURE_2D));
|
|
Textures::iterator new_iter = m_textures.begin();
|
|
new_iter->crc = _crc64;
|
|
m_lruTextureLocations.insert(std::pair<u64, Textures::iterator>(_crc64, new_iter));
|
|
return &(*new_iter);
|
|
}
|
|
|
|
void TextureCache::removeFrameBufferTexture(CachedTexture * _pTexture)
|
|
{
|
|
if (_pTexture == nullptr)
|
|
return;
|
|
FBTextures::const_iterator iter = m_fbTextures.find(u32(_pTexture->name));
|
|
assert(iter != m_fbTextures.cend());
|
|
|
|
if (iter != m_fbTextures.cend()) {
|
|
gfxContext.deleteTexture(ObjectHandle(iter->second.name));
|
|
m_fbTextures.erase(iter);
|
|
}
|
|
}
|
|
|
|
CachedTexture * TextureCache::addFrameBufferTexture(graphics::Parameter _target)
|
|
{
|
|
ObjectHandle texName(gfxContext.createTexture(_target));
|
|
m_fbTextures.emplace(u32(texName), texName);
|
|
return &m_fbTextures.at(u32(texName));
|
|
}
|
|
|
|
struct TileSizes
|
|
{
|
|
u32 clampWidth = 0U;
|
|
u32 width = 0U;
|
|
u32 clampHeight = 0U;
|
|
u32 height = 0U;
|
|
u32 bytes = 0U;
|
|
};
|
|
|
|
static
|
|
void _calcTileSizes(u32 _t, TileSizes & _sizes, gDPTile * _pLoadTile)
|
|
{
|
|
gDPTile * pTile = _t < 2 ? gSP.textureTile[_t] : &gDP.tiles[_t];
|
|
pTile->masks = pTile->originalMaskS;
|
|
pTile->maskt = pTile->originalMaskT;
|
|
|
|
u32 tileWidth = ((pTile->lrs - pTile->uls) & LOAD_BLOCK32_MASK) + 1;
|
|
u32 tileHeight = ((pTile->lrt - pTile->ult) & LOAD_BLOCK32_MASK) + 1;
|
|
|
|
const u32 tMemMask = gDP.otherMode.textureLUT == G_TT_NONE ? 0x1FF : 0xFF;
|
|
gDPLoadTileInfo &info = gDP.loadInfo[pTile->tmem & tMemMask];
|
|
if (pTile->tmem == gDP.loadTile->tmem) {
|
|
if (gDP.loadTile->loadWidth != 0 && gDP.loadTile->masks == 0)
|
|
info.width = gDP.loadTile->loadWidth;
|
|
if (gDP.loadTile->loadHeight != 0 && gDP.loadTile->maskt == 0) {
|
|
info.height = gDP.loadTile->loadHeight;
|
|
info.bytes = info.height * (gDP.loadTile->line << 3);
|
|
if (gDP.loadTile->size == G_IM_SIZ_32b)
|
|
// 32 bit texture loaded into lower and upper half of TMEM, thus actual bytes doubled.
|
|
info.bytes *= 2;
|
|
}
|
|
}
|
|
|
|
gDP.loadTile->loadWidth = gDP.loadTile->loadHeight = 0;
|
|
_sizes.bytes = info.bytes;
|
|
|
|
if (tileWidth == 1 && tileHeight == 1 &&
|
|
gDP.otherMode.cycleType == G_CYC_COPY &&
|
|
_pLoadTile != nullptr) {
|
|
const u32 ulx = _SHIFTR(RDP.w1, 14, 10);
|
|
const u32 uly = _SHIFTR(RDP.w1, 2, 10);
|
|
const u32 lrx = _SHIFTR(RDP.w0, 14, 10);
|
|
const u32 lry = _SHIFTR(RDP.w0, 2, 10);
|
|
tileWidth = lrx - ulx + 1;
|
|
tileHeight = lry - uly + 1;
|
|
}
|
|
|
|
u32 width = 0, height = 0;
|
|
if (info.loadType == LOADTYPE_TILE) {
|
|
width = min(info.width, info.texWidth);
|
|
if (width == 0)
|
|
width = tileWidth;
|
|
if (info.size > pTile->size)
|
|
width <<= info.size - pTile->size;
|
|
|
|
height = info.height;
|
|
if (height == 0)
|
|
height = tileHeight;
|
|
if ((config.generalEmulation.hacks & hack_MK64) != 0 && (height % 2) != 0)
|
|
height--;
|
|
} else {
|
|
const TextureLoadParameters & loadParams =
|
|
ImageFormat::get().tlp[gDP.otherMode.textureLUT][pTile->size][pTile->format];
|
|
|
|
int tile_width = pTile->lrs - pTile->uls + 1;
|
|
int tile_height = pTile->lrt - pTile->ult + 1;
|
|
|
|
int mask_width = (pTile->masks == 0) ? (tile_width) : (1 << pTile->masks);
|
|
int mask_height = (pTile->maskt == 0) ? (tile_height) : (1 << pTile->maskt);
|
|
|
|
if (pTile->clamps)
|
|
width = min(mask_width, tile_width);
|
|
else if ((u32)(mask_width * mask_height) <= loadParams.maxTexels)
|
|
width = mask_width;
|
|
else
|
|
width = tileWidth;
|
|
|
|
if (pTile->clampt)
|
|
height = min(mask_height, tile_height);
|
|
else if ((u32)(mask_width * mask_height) <= loadParams.maxTexels)
|
|
height = mask_height;
|
|
else
|
|
height = tileHeight;
|
|
}
|
|
|
|
_sizes.clampWidth = (pTile->clamps && gDP.otherMode.cycleType != G_CYC_COPY) ? tileWidth : width;
|
|
_sizes.clampHeight = (pTile->clampt && gDP.otherMode.cycleType != G_CYC_COPY) ? tileHeight : height;
|
|
|
|
_sizes.width = (info.loadType == LOADTYPE_TILE &&
|
|
pTile->clamps != 0 &&
|
|
pTile->masks == 0) ?
|
|
_sizes.clampWidth :
|
|
width;
|
|
_sizes.height = (info.loadType == LOADTYPE_TILE &&
|
|
pTile->clampt != 0 &&
|
|
pTile->maskt == 0) ?
|
|
_sizes.clampHeight :
|
|
height;
|
|
}
|
|
|
|
void TextureCache::_updateCachedTexture(const GHQTexInfo & _info, CachedTexture *_pTexture, u16 widthOrg, u16 heightOrg)
|
|
{
|
|
_pTexture->textureBytes = _info.width * _info.height;
|
|
|
|
Parameter format(_info.format);
|
|
if (format == internalcolorFormat::RGB8 ||
|
|
format == internalcolorFormat::RGBA4 ||
|
|
format == internalcolorFormat::RGB5_A1) {
|
|
_pTexture->textureBytes <<= 1;
|
|
} else {
|
|
_pTexture->textureBytes <<= 2;
|
|
}
|
|
|
|
_pTexture->scaleS = 1.0f / (_pTexture->maskS ? f32(pow2(widthOrg)) : f32(widthOrg));
|
|
_pTexture->scaleT = 1.0f / (_pTexture->maskT ? f32(pow2(heightOrg)) : f32(heightOrg));
|
|
|
|
_pTexture->hdRatioS = (f32)(_info.width) / (f32)(_pTexture->width);
|
|
_pTexture->hdRatioT = (f32)(_info.height) / (f32)(_pTexture->height);
|
|
|
|
_pTexture->bHDTexture = true;
|
|
|
|
m_hdTexCacheSize += _pTexture->textureBytes;
|
|
_checkHdTexLimit();
|
|
}
|
|
|
|
bool TextureCache::_loadHiresBackground(CachedTexture *_pTexture, u64 & _ricecrc)
|
|
{
|
|
if (!TFH.isInited())
|
|
return false;
|
|
|
|
u8 * addr = (u8*)(RDRAM + gSP.bgImage.address);
|
|
int tile_width = gSP.bgImage.width;
|
|
int tile_height = gSP.bgImage.height;
|
|
int bpl = tile_width << gSP.bgImage.size >> 1;
|
|
|
|
u8 * paladdr = nullptr;
|
|
u16 * palette = nullptr;
|
|
if ((gSP.bgImage.size < G_IM_SIZ_16b) && (gDP.otherMode.textureLUT != G_TT_NONE || gSP.bgImage.format == G_IM_FMT_CI)) {
|
|
if (gSP.bgImage.size == G_IM_SIZ_8b)
|
|
paladdr = (u8*)(gDP.TexFilterPalette);
|
|
else if (config.textureFilter.txHresAltCRC)
|
|
paladdr = (u8*)(gDP.TexFilterPalette + (gSP.bgImage.palette << 5));
|
|
else
|
|
paladdr = (u8*)(gDP.TexFilterPalette + (gSP.bgImage.palette << 4));
|
|
// TODO: fix palette load
|
|
// palette = (rdp.pal_8 + (gSP.textureTile[_t]->palette << 4));
|
|
}
|
|
|
|
_ricecrc = txfilter_checksum(addr, tile_width,
|
|
tile_height, gSP.bgImage.size, bpl, paladdr);
|
|
GHQTexInfo ghqTexInfo;
|
|
// TODO: fix problem with zero texture dimensions on GLideNHQ side.
|
|
if (txfilter_hirestex(_pTexture->crc, _ricecrc, palette, N64FormatSize(_pTexture->format, _pTexture->size), &ghqTexInfo) &&
|
|
ghqTexInfo.width != 0 && ghqTexInfo.height != 0) {
|
|
ghqTexInfo.format = gfxContext.convertInternalTextureFormat(ghqTexInfo.format);
|
|
Context::InitTextureParams params;
|
|
params.handle = _pTexture->name;
|
|
params.mipMapLevel = 0;
|
|
params.msaaLevel = 0;
|
|
params.width = ghqTexInfo.width;
|
|
params.height = ghqTexInfo.height;
|
|
params.format = ColorFormatParam(ghqTexInfo.texture_format);
|
|
params.internalFormat = InternalColorFormatParam(ghqTexInfo.format);
|
|
params.dataType = DatatypeParam(ghqTexInfo.pixel_type);
|
|
params.data = ghqTexInfo.data;
|
|
gfxContext.init2DTexture(params);
|
|
|
|
assert(!gfxContext.isError());
|
|
_updateCachedTexture(ghqTexInfo, _pTexture, tile_width, tile_height);
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
void TextureCache::_loadBackground(CachedTexture *pTexture)
|
|
{
|
|
u64 ricecrc = 0;
|
|
if (_loadHiresBackground(pTexture, ricecrc))
|
|
return;
|
|
|
|
u32 *pDest = nullptr;
|
|
u16 *pDest16 = nullptr;
|
|
|
|
u8 *pSwapped, *pSrc;
|
|
u32 numBytes, bpl;
|
|
u32 x, y, j, tx, ty;
|
|
u16 clampSClamp;
|
|
u16 clampTClamp;
|
|
GetTexelFuncBG GetTexel;
|
|
InternalColorFormatParam glInternalFormat;
|
|
DatatypeParam glType;
|
|
|
|
const TextureLoadParameters & loadParams =
|
|
ImageFormat::get().tlp[pTexture->format == 2 ? G_TT_RGBA16 : G_TT_NONE][pTexture->size][pTexture->format];
|
|
if (loadParams.autoFormat == internalcolorFormat::RGBA8) {
|
|
pTexture->textureBytes = (pTexture->width * pTexture->height) << 2;
|
|
GetTexel = loadParams.Get32BG;
|
|
glInternalFormat = loadParams.glInternalFormat32;
|
|
glType = loadParams.glType32;
|
|
} else {
|
|
pTexture->textureBytes = (pTexture->width * pTexture->height) << 1;
|
|
GetTexel = loadParams.Get16BG;
|
|
glInternalFormat = loadParams.glInternalFormat16;
|
|
glType = loadParams.glType16;
|
|
}
|
|
|
|
bpl = gSP.bgImage.width << gSP.bgImage.size >> 1;
|
|
numBytes = bpl * gSP.bgImage.height;
|
|
pSwapped = (u8*)malloc(numBytes);
|
|
if (pSwapped == nullptr)
|
|
return;
|
|
UnswapCopyWrap(RDRAM, gSP.bgImage.address, pSwapped, 0, RDRAMSize, numBytes);
|
|
pDest = (u32*)malloc(pTexture->textureBytes);
|
|
if (pDest == nullptr) {
|
|
free(pSwapped);
|
|
return;
|
|
}
|
|
pDest16 = reinterpret_cast<u16*>(pDest);
|
|
|
|
clampSClamp = pTexture->width - 1;
|
|
clampTClamp = pTexture->height - 1;
|
|
|
|
j = 0;
|
|
for (y = 0; y < pTexture->height; y++) {
|
|
ty = min(y, (u32)clampTClamp);
|
|
|
|
pSrc = &pSwapped[bpl * ty];
|
|
|
|
for (x = 0; x < pTexture->width; x++) {
|
|
tx = min(x, (u32)clampSClamp);
|
|
|
|
if (glInternalFormat == internalcolorFormat::RGBA8)
|
|
pDest[j++] = GetTexel((u64*)pSrc, tx, 0, pTexture->palette);
|
|
else
|
|
pDest16[j++] = static_cast<u16>(GetTexel((u64*)pSrc, tx, 0, pTexture->palette));
|
|
}
|
|
}
|
|
|
|
if ((config.generalEmulation.hacks&hack_LoadDepthTextures) != 0 && gDP.colorImage.address == gDP.depthImageAddress) {
|
|
_loadDepthTexture(pTexture, (u16*)pDest);
|
|
free(pDest);
|
|
free(pSwapped);
|
|
return;
|
|
}
|
|
|
|
if (m_toggleDumpTex &&
|
|
config.textureFilter.txHiresEnable != 0 &&
|
|
config.hotkeys.enabledKeys[Config::HotKey::hkTexDump] != 0) {
|
|
txfilter_dmptx((u8*)pDest, pTexture->width, pTexture->height,
|
|
pTexture->width, (u16)u32(glInternalFormat),
|
|
N64FormatSize(pTexture->format, pTexture->size),
|
|
ricecrc);
|
|
}
|
|
|
|
bool bLoaded = false;
|
|
if ((config.textureFilter.txEnhancementMode | config.textureFilter.txFilterMode) != 0 &&
|
|
config.textureFilter.txFilterIgnoreBG == 0 &&
|
|
TFH.isInited()) {
|
|
GHQTexInfo ghqTexInfo;
|
|
if (txfilter_filter((u8*)pDest, pTexture->width, pTexture->height,
|
|
(u16)u32(glInternalFormat), pTexture->crc, N64FormatSize(pTexture->format, pTexture->size), &ghqTexInfo) != 0 &&
|
|
ghqTexInfo.data != nullptr) {
|
|
|
|
if (ghqTexInfo.width % 2 != 0 &&
|
|
ghqTexInfo.format != u32(internalcolorFormat::RGBA8) &&
|
|
m_curUnpackAlignment > 1)
|
|
gfxContext.setTextureUnpackAlignment(2);
|
|
|
|
ghqTexInfo.format = gfxContext.convertInternalTextureFormat(ghqTexInfo.format);
|
|
Context::InitTextureParams params;
|
|
params.handle = pTexture->name;
|
|
params.mipMapLevel = 0;
|
|
params.msaaLevel = 0;
|
|
params.width = ghqTexInfo.width;
|
|
params.height = ghqTexInfo.height;
|
|
params.format = ColorFormatParam(ghqTexInfo.texture_format);
|
|
params.internalFormat = InternalColorFormatParam(ghqTexInfo.format);
|
|
params.dataType = DatatypeParam(ghqTexInfo.pixel_type);
|
|
params.data = ghqTexInfo.data;
|
|
gfxContext.init2DTexture(params);
|
|
_updateCachedTexture(ghqTexInfo, pTexture, pTexture->width, pTexture->height);
|
|
bLoaded = true;
|
|
}
|
|
}
|
|
if (!bLoaded) {
|
|
if (pTexture->width % 2 != 0 && glInternalFormat != internalcolorFormat::RGBA8)
|
|
gfxContext.setTextureUnpackAlignment(2);
|
|
Context::InitTextureParams params;
|
|
params.handle = pTexture->name;
|
|
params.mipMapLevel = 0;
|
|
params.msaaLevel = 0;
|
|
params.width = pTexture->width;
|
|
params.height = pTexture->height;
|
|
params.format = colorFormat::RGBA;
|
|
params.internalFormat = gfxContext.convertInternalTextureFormat(u32(glInternalFormat));
|
|
params.dataType = glType;
|
|
params.data = pDest;
|
|
gfxContext.init2DTexture(params);
|
|
}
|
|
if (m_curUnpackAlignment > 1)
|
|
gfxContext.setTextureUnpackAlignment(m_curUnpackAlignment);
|
|
free(pSwapped);
|
|
free(pDest);
|
|
}
|
|
|
|
bool TextureCache::_loadHiresTexture(u32 _tile, CachedTexture *_pTexture, u64 & _ricecrc)
|
|
{
|
|
if (config.textureFilter.txHiresEnable == 0 || !TFH.isInited())
|
|
return false;
|
|
|
|
gDPLoadTileInfo & info = gDP.loadInfo[_pTexture->tMem];
|
|
|
|
// Temporal workaround for crash problem with mip-mapped textures. See #1711 for details.
|
|
// TODO: make proper fix.
|
|
if (info.texAddress == 0)
|
|
return false;
|
|
|
|
int bpl;
|
|
int width, height;
|
|
u8 * addr = (u8*)(RDRAM + info.texAddress);
|
|
if (info.loadType == LOADTYPE_TILE) {
|
|
bpl = info.texWidth << info.size >> 1;
|
|
addr += (info.ult * bpl) + (((info.uls << info.size) + 1) >> 1);
|
|
|
|
width = min(info.width, info.texWidth);
|
|
if (info.size > _pTexture->size)
|
|
width <<= info.size - _pTexture->size;
|
|
|
|
height = info.height;
|
|
if ((config.generalEmulation.hacks & hack_MK64) != 0 && (height % 2) != 0)
|
|
height--;
|
|
} else {
|
|
const gDPTile * pTile = gSP.textureTile[_tile];
|
|
int tile_width = pTile->lrs - pTile->uls + 1;
|
|
int tile_height = pTile->lrt - pTile->ult + 1;
|
|
|
|
int mask_width = (pTile->masks == 0) ? (tile_width) : (1 << pTile->masks);
|
|
int mask_height = (pTile->maskt == 0) ? (tile_height) : (1 << pTile->maskt);
|
|
|
|
if ((pTile->clamps && tile_width <= 256))
|
|
width = min(mask_width, tile_width);
|
|
else
|
|
width = mask_width;
|
|
|
|
if ((pTile->clampt && tile_height <= 256) || (mask_height > 256))
|
|
height = min(mask_height, tile_height);
|
|
else
|
|
height = mask_height;
|
|
|
|
if (pTile->size == G_IM_SIZ_32b)
|
|
bpl = pTile->line << 4;
|
|
else if (info.dxt == 0)
|
|
bpl = pTile->line << 3;
|
|
else {
|
|
u32 dxt = info.dxt;
|
|
if (dxt > 1)
|
|
dxt = ReverseDXT(dxt, info.width, _pTexture->width, _pTexture->size);
|
|
bpl = dxt << 3;
|
|
}
|
|
}
|
|
|
|
u8 * paladdr = nullptr;
|
|
u16 * palette = nullptr;
|
|
if ((_pTexture->size < G_IM_SIZ_16b) && (gDP.otherMode.textureLUT != G_TT_NONE || _pTexture->format == G_IM_FMT_CI)) {
|
|
if (_pTexture->size == G_IM_SIZ_8b)
|
|
paladdr = (u8*)(gDP.TexFilterPalette);
|
|
else if (config.textureFilter.txHresAltCRC)
|
|
paladdr = (u8*)(gDP.TexFilterPalette + (_pTexture->palette << 5));
|
|
else
|
|
paladdr = (u8*)(gDP.TexFilterPalette + (_pTexture->palette << 4));
|
|
// TODO: fix palette load
|
|
// palette = (rdp.pal_8 + (gSP.textureTile[_t]->palette << 4));
|
|
}
|
|
|
|
_ricecrc = txfilter_checksum(addr, width, height, _pTexture->size, bpl, paladdr);
|
|
GHQTexInfo ghqTexInfo;
|
|
// TODO: fix problem with zero texture dimensions on GLideNHQ side.
|
|
if (txfilter_hirestex(_pTexture->crc, _ricecrc, palette, N64FormatSize(_pTexture->format, _pTexture->size), &ghqTexInfo) &&
|
|
ghqTexInfo.width != 0 && ghqTexInfo.height != 0) {
|
|
ghqTexInfo.format = gfxContext.convertInternalTextureFormat(ghqTexInfo.format);
|
|
Context::InitTextureParams params;
|
|
params.handle = _pTexture->name;
|
|
params.mipMapLevel = 0;
|
|
params.msaaLevel = 0;
|
|
params.width = ghqTexInfo.width;
|
|
params.height = ghqTexInfo.height;
|
|
params.internalFormat = InternalColorFormatParam(ghqTexInfo.format);
|
|
params.format = ColorFormatParam(ghqTexInfo.texture_format);
|
|
params.dataType = DatatypeParam(ghqTexInfo.pixel_type);
|
|
params.data = ghqTexInfo.data;
|
|
params.textureUnitIndex = textureIndices::Tex[_tile];
|
|
gfxContext.init2DTexture(params);
|
|
assert(!gfxContext.isError());
|
|
_updateCachedTexture(ghqTexInfo, _pTexture, width, height);
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
void TextureCache::_loadDepthTexture(CachedTexture * _pTexture, u16* _pDest)
|
|
{
|
|
if (!config.generalEmulation.enableFragmentDepthWrite)
|
|
return;
|
|
|
|
u32 size = _pTexture->width * _pTexture->height;
|
|
std::vector<f32> pDestFloat(size);
|
|
for (u32 i = 0; i < size; ++i)
|
|
pDestFloat[i] = _pDest[i] / 65535.0f;
|
|
|
|
Context::InitTextureParams params;
|
|
params.handle = _pTexture->name;
|
|
params.mipMapLevel = 0;
|
|
params.msaaLevel = 0;
|
|
params.width = _pTexture->width;
|
|
params.height = _pTexture->height;
|
|
params.internalFormat = internalcolorFormat::R16F;
|
|
params.format = colorFormat::RED;
|
|
params.dataType = datatype::FLOAT;
|
|
params.data = pDestFloat.data();
|
|
gfxContext.init2DTexture(params);
|
|
}
|
|
|
|
/*
|
|
* Worker function for _load
|
|
*/
|
|
void TextureCache::_getTextureDestData(CachedTexture& tmptex,
|
|
u32* pDest,
|
|
Parameter glInternalFormat,
|
|
GetTexelFunc GetTexel,
|
|
u16* pLine)
|
|
{
|
|
u16 maskSMask, clampSClamp;
|
|
u16 maskTMask, clampTClamp;
|
|
u16 x, y, tx, ty;
|
|
u32 i, j;
|
|
|
|
if (tmptex.maskS > 0) {
|
|
clampSClamp = tmptex.clampS ? tmptex.clampWidth - 1 : (tmptex.mirrorS ? (tmptex.width << 1) - 1 : tmptex.width - 1);
|
|
maskSMask = (1 << tmptex.maskS) - 1;
|
|
} else {
|
|
clampSClamp = tmptex.clampS ? tmptex.clampWidth - 1 : tmptex.width - 1;
|
|
maskSMask = 0xFFFF;
|
|
}
|
|
|
|
if (tmptex.maskT > 0) {
|
|
clampTClamp = tmptex.clampT ? tmptex.clampHeight - 1 : (tmptex.mirrorT ? (tmptex.height << 1) - 1 : tmptex.height - 1);
|
|
maskTMask = (1 << tmptex.maskT) - 1;
|
|
} else {
|
|
clampTClamp = tmptex.clampT ? tmptex.clampHeight - 1 : tmptex.height - 1;
|
|
maskTMask = 0xFFFF;
|
|
}
|
|
|
|
if (tmptex.size == G_IM_SIZ_32b) {
|
|
const u16 * tmem16 = (u16*)TMEM;
|
|
const u32 tbase = tmptex.tMem << 2;
|
|
|
|
int wid_64 = (tmptex.clampWidth) << 2;
|
|
if (wid_64 & 15) {
|
|
wid_64 += 16;
|
|
}
|
|
wid_64 &= 0xFFFFFFF0;
|
|
wid_64 >>= 3;
|
|
int line32 = tmptex.line << 1;
|
|
line32 = (line32 - wid_64) << 3;
|
|
if (wid_64 < 1) {
|
|
wid_64 = 1;
|
|
}
|
|
int width = wid_64 << 1;
|
|
line32 = width + (line32 >> 2);
|
|
|
|
u16 gr, ab;
|
|
|
|
j = 0;
|
|
for (y = 0; y < tmptex.height; ++y) {
|
|
ty = min(y, clampTClamp) & maskTMask;
|
|
|
|
u32 tline = tbase + line32 * ty;
|
|
u32 xorval = (ty & 1) ? 3 : 1;
|
|
|
|
for (x = 0; x < tmptex.width; ++x) {
|
|
tx = min(x, clampSClamp) & maskSMask;
|
|
|
|
u32 taddr = ((tline + tx) ^ xorval) & LOAD_BLOCK32_MASK;
|
|
#ifdef NATIVE
|
|
gr = tmem16[taddr];
|
|
ab = tmem16[taddr | LOAD_BLOCK32_MAX];
|
|
#else
|
|
gr = swapword(tmem16[taddr]);
|
|
ab = swapword(tmem16[taddr | LOAD_BLOCK32_MAX]);
|
|
#endif
|
|
pDest[j++] = (ab << 16) | gr;
|
|
}
|
|
}
|
|
} else if (tmptex.format == G_IM_FMT_YUV) {
|
|
j = 0;
|
|
*pLine <<= 1;
|
|
for (y = 0; y < tmptex.height; ++y) {
|
|
u64* pSrc = &TMEM[tmptex.tMem] + *pLine * y;
|
|
for (x = 0; x < tmptex.width / 2; x++) {
|
|
GetYUV_RGBA8888(pSrc, pDest + j, x);
|
|
j += 2;
|
|
}
|
|
}
|
|
} else {
|
|
j = 0;
|
|
const u32 tMemMask = gDP.otherMode.textureLUT == G_TT_NONE ? 0x1FF : 0xFF;
|
|
for (y = 0; y < tmptex.height; ++y) {
|
|
ty = min(y, clampTClamp) & maskTMask;
|
|
|
|
u16 tmemOffset = (tmptex.tMem + *pLine * ty) & tMemMask;
|
|
|
|
i = (ty & 1) << 1;
|
|
for (x = 0; x < tmptex.width; ++x) {
|
|
tx = min(x, clampSClamp) & maskSMask;
|
|
|
|
if (glInternalFormat == internalcolorFormat::RGBA8)
|
|
pDest[j++] = GetTexel(tmemOffset, tx, i, tmptex.palette);
|
|
else
|
|
((u16*)pDest)[j++] = GetTexel(tmemOffset, tx, i, tmptex.palette);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
template<typename T>
|
|
void doubleTexture(T* pTex, u32 width, u32 height)
|
|
{
|
|
std::vector<T> vData(width * height);
|
|
memcpy(vData.data(), pTex, width * height * sizeof(T));
|
|
u32 srcIdx = 0;
|
|
u32 dstIdx = 0;
|
|
for (u32 y = 0; y < height; ++y) {
|
|
const u32 srcIdxCur = srcIdx;
|
|
for (u32 x = 0; x < width; ++x) {
|
|
pTex[dstIdx++] = vData[srcIdx];
|
|
pTex[dstIdx++] = vData[srcIdx++];
|
|
}
|
|
srcIdx = srcIdxCur;
|
|
for (u32 x = 0; x < width; ++x) {
|
|
pTex[dstIdx++] = vData[srcIdx];
|
|
pTex[dstIdx++] = vData[srcIdx++];
|
|
}
|
|
}
|
|
}
|
|
|
|
void TextureCache::_loadFast(u32 _tile, CachedTexture *_pTexture)
|
|
{
|
|
u64 ricecrc = 0;
|
|
if (_loadHiresTexture(_tile, _pTexture, ricecrc))
|
|
return;
|
|
|
|
s32 mipLevel = 0;
|
|
bool force32bitFormat = false;
|
|
_pTexture->max_level = 0;
|
|
|
|
if (config.generalEmulation.enableLOD != 0 && gSP.texture.level > 1) {
|
|
if (_tile == 0) {
|
|
_pTexture->max_level = 0;
|
|
} else {
|
|
_pTexture->max_level = static_cast<u8>(gSP.texture.level - 1);
|
|
const u16 dim = std::max(_pTexture->width, _pTexture->height);
|
|
while (dim < static_cast<u16>(1 << _pTexture->max_level))
|
|
--_pTexture->max_level;
|
|
|
|
auto texFormat = gDP.tiles[gSP.texture.tile + 1].format;
|
|
auto texSize = gDP.tiles[gSP.texture.tile + 1].size;
|
|
u32 tileMipLevel = gSP.texture.tile + 2;
|
|
while (!force32bitFormat && (tileMipLevel < gSP.texture.tile + gSP.texture.level)) {
|
|
gDPTile const& mipTile = gDP.tiles[tileMipLevel++];
|
|
force32bitFormat = texFormat != mipTile.format || texSize != mipTile.size;
|
|
}
|
|
}
|
|
}
|
|
|
|
u32 sizeShift = 1;
|
|
{
|
|
const TextureLoadParameters & loadParams =
|
|
ImageFormat::get().tlp[gDP.otherMode.textureLUT][_pTexture->size][_pTexture->format];
|
|
if (force32bitFormat || loadParams.autoFormat == internalcolorFormat::RGBA8)
|
|
sizeShift = 2;
|
|
}
|
|
_pTexture->textureBytes = (_pTexture->width * _pTexture->height) << sizeShift;
|
|
|
|
unsigned int totalTexSize = std::max(static_cast<u32>(_pTexture->textureBytes/sizeof(u32) + 8), MIPMAP_TILE_WIDTH)
|
|
* (_pTexture->max_level + 1);
|
|
|
|
if (m_tempTextureHolder.size() < totalTexSize) {
|
|
m_tempTextureHolder.resize(totalTexSize);
|
|
}
|
|
|
|
GetTexelFunc GetTexel;
|
|
InternalColorFormatParam glInternalFormat;
|
|
DatatypeParam glType;
|
|
|
|
auto getLoadParams = [&](u16 _format, u16 _size)
|
|
{
|
|
const TextureLoadParameters & loadParams =
|
|
ImageFormat::get().tlp[gDP.otherMode.textureLUT][_size][_format];
|
|
if (force32bitFormat || loadParams.autoFormat == internalcolorFormat::RGBA8) {
|
|
GetTexel = loadParams.Get32;
|
|
glInternalFormat = loadParams.glInternalFormat32;
|
|
glType = loadParams.glType32;
|
|
}
|
|
else {
|
|
GetTexel = loadParams.Get16;
|
|
glInternalFormat = loadParams.glInternalFormat16;
|
|
glType = loadParams.glType16;
|
|
}
|
|
};
|
|
|
|
CachedTexture tmptex = *_pTexture;
|
|
u16 line = tmptex.line;
|
|
|
|
while (true) {
|
|
getLoadParams(tmptex.format, tmptex.size);
|
|
{
|
|
const u32 tileMipLevel = gSP.texture.tile + mipLevel + 1;
|
|
gDPTile & mipTile = gDP.tiles[tileMipLevel];
|
|
if (tmptex.max_level > 1 &&
|
|
tmptex.width == (mipTile.lrs - mipTile.uls + 1) * 2 &&
|
|
tmptex.height == (mipTile.lrt - mipTile.ult + 1) * 2)
|
|
{
|
|
// Special case for Southern Swamp grass texture, Zelda MM. See #2315
|
|
const u16 texWidth = tmptex.width;
|
|
const u16 texHeight = tmptex.height;
|
|
tmptex.width = mipTile.lrs - mipTile.uls + 1;
|
|
tmptex.height = mipTile.lrt - mipTile.ult + 1;
|
|
_getTextureDestData(tmptex, m_tempTextureHolder.data(), glInternalFormat, GetTexel, &line);
|
|
if (sizeShift == 2)
|
|
doubleTexture<u32>(m_tempTextureHolder.data(), tmptex.width, tmptex.height);
|
|
else
|
|
doubleTexture<u16>((u16*)m_tempTextureHolder.data(), tmptex.width, tmptex.height);
|
|
tmptex.width = texWidth;
|
|
tmptex.height = texHeight;
|
|
} else {
|
|
_getTextureDestData(tmptex, m_tempTextureHolder.data(), glInternalFormat, GetTexel, &line);
|
|
}
|
|
}
|
|
|
|
if ((config.generalEmulation.hacks&hack_LoadDepthTextures) != 0 && gDP.colorImage.address == gDP.depthImageAddress) {
|
|
_loadDepthTexture(_pTexture, (u16*)m_tempTextureHolder.data());
|
|
return;
|
|
}
|
|
|
|
if (m_toggleDumpTex &&
|
|
config.textureFilter.txHiresEnable != 0 &&
|
|
config.hotkeys.enabledKeys[Config::HotKey::hkTexDump] != 0) {
|
|
txfilter_dmptx((u8*)m_tempTextureHolder.data(), tmptex.width, tmptex.height,
|
|
tmptex.width, (u16)u32(glInternalFormat),
|
|
N64FormatSize(_pTexture->format, _pTexture->size),
|
|
ricecrc);
|
|
}
|
|
|
|
bool bLoaded = false;
|
|
bool needEnhance = (config.textureFilter.txEnhancementMode | config.textureFilter.txFilterMode) != 0 &&
|
|
_pTexture->max_level == 0 &&
|
|
TFH.isInited();
|
|
if (needEnhance) {
|
|
if (config.textureFilter.txFilterIgnoreBG != 0) {
|
|
switch (GBI.getMicrocodeType()) {
|
|
case S2DEX_1_07:
|
|
case S2DEX_1_03:
|
|
case S2DEX_1_05:
|
|
needEnhance = RSP.cmd != 0x01 && RSP.cmd != 0x02;
|
|
break;
|
|
case S2DEX2:
|
|
needEnhance = RSP.cmd != 0x09 && RSP.cmd != 0x0A;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (needEnhance) {
|
|
GHQTexInfo ghqTexInfo;
|
|
if (txfilter_filter((u8*)m_tempTextureHolder.data(), tmptex.width, tmptex.height,
|
|
(u16)u32(glInternalFormat), (uint64)_pTexture->crc,
|
|
N64FormatSize(_pTexture->format, _pTexture->size),
|
|
&ghqTexInfo) != 0 && ghqTexInfo.data != nullptr) {
|
|
if (ghqTexInfo.width % 2 != 0 &&
|
|
ghqTexInfo.format != u32(internalcolorFormat::RGBA8) &&
|
|
m_curUnpackAlignment > 1)
|
|
gfxContext.setTextureUnpackAlignment(2);
|
|
ghqTexInfo.format = gfxContext.convertInternalTextureFormat(ghqTexInfo.format);
|
|
Context::InitTextureParams params;
|
|
params.handle = _pTexture->name;
|
|
params.textureUnitIndex = textureIndices::Tex[_tile];
|
|
params.mipMapLevel = 0;
|
|
params.msaaLevel = 0;
|
|
params.width = ghqTexInfo.width;
|
|
params.height = ghqTexInfo.height;
|
|
params.internalFormat = InternalColorFormatParam(ghqTexInfo.format);
|
|
params.format = ColorFormatParam(ghqTexInfo.texture_format);
|
|
params.dataType = DatatypeParam(ghqTexInfo.pixel_type);
|
|
params.data = ghqTexInfo.data;
|
|
gfxContext.init2DTexture(params);
|
|
_updateCachedTexture(ghqTexInfo, _pTexture, tmptex.width, tmptex.height);
|
|
bLoaded = true;
|
|
}
|
|
}
|
|
if (!bLoaded) {
|
|
if (tmptex.width % 2 != 0 &&
|
|
glInternalFormat != internalcolorFormat::RGBA8 &&
|
|
m_curUnpackAlignment > 1)
|
|
gfxContext.setTextureUnpackAlignment(2);
|
|
Context::InitTextureParams params;
|
|
params.handle = _pTexture->name;
|
|
params.textureUnitIndex = textureIndices::Tex[_tile];
|
|
params.mipMapLevel = mipLevel;
|
|
params.mipMapLevels = _pTexture->max_level + 1;
|
|
params.msaaLevel = 0;
|
|
params.width = tmptex.width;
|
|
params.height = tmptex.height;
|
|
params.internalFormat = gfxContext.convertInternalTextureFormat(u32(glInternalFormat));
|
|
params.format = colorFormat::RGBA;
|
|
params.dataType = glType;
|
|
params.data = m_tempTextureHolder.data();
|
|
gfxContext.init2DTexture(params);
|
|
}
|
|
if (mipLevel == _pTexture->max_level)
|
|
break;
|
|
++mipLevel;
|
|
const u32 tileMipLevel = gSP.texture.tile + mipLevel + 1;
|
|
gDPTile & mipTile = gDP.tiles[tileMipLevel];
|
|
line = mipTile.line;
|
|
tmptex.tMem = mipTile.tmem;
|
|
tmptex.palette = mipTile.palette;
|
|
tmptex.maskS = mipTile.masks;
|
|
tmptex.maskT = mipTile.maskt;
|
|
tmptex.format = mipTile.format;
|
|
tmptex.size = mipTile.size;
|
|
TileSizes sizes;
|
|
_calcTileSizes(tileMipLevel, sizes, nullptr);
|
|
tmptex.clampWidth = sizes.clampWidth;
|
|
tmptex.clampHeight = sizes.clampHeight;
|
|
// Insure mip-map levels size consistency.
|
|
if (tmptex.width > 1)
|
|
tmptex.width >>= 1;
|
|
if (tmptex.height > 1)
|
|
tmptex.height >>= 1;
|
|
_pTexture->textureBytes += (tmptex.width * tmptex.height) << sizeShift;
|
|
}
|
|
if (m_curUnpackAlignment > 1)
|
|
gfxContext.setTextureUnpackAlignment(m_curUnpackAlignment);
|
|
}
|
|
|
|
void TextureCache::_loadAccurate(u32 _tile, CachedTexture *_pTexture)
|
|
{
|
|
u64 ricecrc = 0;
|
|
if (_loadHiresTexture(_tile, _pTexture, ricecrc))
|
|
return;
|
|
|
|
bool force32bitFormat = false;
|
|
_pTexture->max_level = 0;
|
|
|
|
if (currentCombiner()->usesLOD() && gSP.texture.level > 1 && _tile > 0) {
|
|
_pTexture->max_level = gDP.otherMode.textureDetail == G_TD_DETAIL ?
|
|
static_cast<u8>(gSP.texture.level) :
|
|
static_cast<u8>(gSP.texture.level - 1);
|
|
force32bitFormat = _pTexture->max_level > 0;
|
|
}
|
|
|
|
u32 sizeShift = 1;
|
|
{
|
|
const TextureLoadParameters & loadParams =
|
|
ImageFormat::get().tlp[gDP.otherMode.textureLUT][_pTexture->size][_pTexture->format];
|
|
if (force32bitFormat || loadParams.autoFormat == internalcolorFormat::RGBA8)
|
|
sizeShift = 2;
|
|
}
|
|
_pTexture->textureBytes = (_pTexture->width * _pTexture->height) << sizeShift;
|
|
|
|
unsigned int totalTexSize = std::max(static_cast<u32>(_pTexture->textureBytes/sizeof(u32) + 8), MIPMAP_TILE_WIDTH)
|
|
* (_pTexture->max_level + 1);
|
|
|
|
if (m_tempTextureHolder.size() < totalTexSize) {
|
|
m_tempTextureHolder.resize(totalTexSize);
|
|
}
|
|
|
|
GetTexelFunc GetTexel;
|
|
InternalColorFormatParam glInternalFormat;
|
|
DatatypeParam glType;
|
|
|
|
auto getLoadParams = [&](u16 _format, u16 _size)
|
|
{
|
|
const TextureLoadParameters & loadParams =
|
|
ImageFormat::get().tlp[gDP.otherMode.textureLUT][_size][_format];
|
|
if (force32bitFormat || loadParams.autoFormat == internalcolorFormat::RGBA8) {
|
|
GetTexel = loadParams.Get32;
|
|
glInternalFormat = loadParams.glInternalFormat32;
|
|
glType = loadParams.glType32;
|
|
}
|
|
else {
|
|
GetTexel = loadParams.Get16;
|
|
glInternalFormat = loadParams.glInternalFormat16;
|
|
glType = loadParams.glType16;
|
|
}
|
|
};
|
|
|
|
CachedTexture tmptex = *_pTexture;
|
|
u16 line = tmptex.line;
|
|
|
|
if (_pTexture->max_level > 0)
|
|
{
|
|
u32 mipLevel = 0;
|
|
u32 texDataOffset = 8; // number of gDP.tiles
|
|
|
|
// Load all tiles into one 1D texture atlas.
|
|
while (true)
|
|
{
|
|
|
|
u32 mipRatioS = gDP.tiles[gSP.texture.tile + mipLevel + 1].shifts + 5u;
|
|
if (mipRatioS >= 16u) mipRatioS -= 16u;
|
|
u32 mipRatioT = gDP.tiles[gSP.texture.tile + mipLevel + 1].shiftt + 5u;
|
|
if (mipRatioT >= 16) mipRatioT -= 16u;
|
|
const u32 tileSizePacked = texDataOffset | (tmptex.width << 16) | (mipRatioT << 24) | (mipRatioS << 28);
|
|
m_tempTextureHolder[mipLevel] = tileSizePacked;
|
|
|
|
getLoadParams(tmptex.format, tmptex.size);
|
|
_getTextureDestData(tmptex, &m_tempTextureHolder[texDataOffset], glInternalFormat, GetTexel, &line);
|
|
|
|
if (m_toggleDumpTex &&
|
|
config.textureFilter.txHiresEnable != 0 &&
|
|
config.hotkeys.enabledKeys[Config::HotKey::hkTexDump] != 0) {
|
|
txfilter_dmptx((u8*)(m_tempTextureHolder.data() + texDataOffset), tmptex.width, tmptex.height,
|
|
tmptex.width, (u16)u32(glInternalFormat),
|
|
N64FormatSize(_pTexture->format, _pTexture->size),
|
|
ricecrc);
|
|
}
|
|
|
|
texDataOffset += tmptex.width * tmptex.height;
|
|
if (mipLevel == _pTexture->max_level)
|
|
break;
|
|
++mipLevel;
|
|
const u32 tileMipLevel = gSP.texture.tile + mipLevel + 1;
|
|
gDPTile & mipTile = gDP.tiles[tileMipLevel];
|
|
gDPTile & prevMipTile = gDP.tiles[tileMipLevel - 1];
|
|
line = mipTile.line;
|
|
tmptex.tMem = mipTile.tmem;
|
|
tmptex.palette = mipTile.palette;
|
|
tmptex.maskS = mipTile.masks;
|
|
tmptex.maskT = mipTile.maskt;
|
|
tmptex.format = mipTile.format;
|
|
tmptex.size = mipTile.size;
|
|
TileSizes sizes;
|
|
_calcTileSizes(tileMipLevel, sizes, nullptr);
|
|
tmptex.width = std::min(tmptex.width, static_cast<u16>(sizes.width));
|
|
tmptex.height = std::min(tmptex.height, static_cast<u16>(sizes.height));
|
|
tmptex.clampWidth = sizes.clampWidth;
|
|
tmptex.clampHeight = sizes.clampHeight;
|
|
_pTexture->textureBytes += (tmptex.width * tmptex.height) << sizeShift;
|
|
}
|
|
|
|
Context::InitTextureParams params;
|
|
params.handle = _pTexture->name;
|
|
params.textureUnitIndex = textureIndices::Tex[_tile];
|
|
params.mipMapLevel = 0;
|
|
params.mipMapLevels =1;
|
|
params.msaaLevel = 0;
|
|
params.width = std::min(texDataOffset, MIPMAP_TILE_WIDTH);
|
|
params.height = (texDataOffset / MIPMAP_TILE_WIDTH) + ((texDataOffset % MIPMAP_TILE_WIDTH) ? 1 : 0);
|
|
params.internalFormat = gfxContext.convertInternalTextureFormat(u32(glInternalFormat));
|
|
params.format = colorFormat::RGBA;
|
|
params.dataType = glType;
|
|
params.data = m_tempTextureHolder.data();
|
|
gfxContext.init2DTexture(params);
|
|
_pTexture->mipmapAtlasWidth = params.width;
|
|
_pTexture->mipmapAtlasHeight = params.height;
|
|
}
|
|
else
|
|
{
|
|
getLoadParams(tmptex.format, tmptex.size);
|
|
_getTextureDestData(tmptex, m_tempTextureHolder.data(), glInternalFormat, GetTexel, &line);
|
|
|
|
if ((config.generalEmulation.hacks&hack_LoadDepthTextures) != 0 && gDP.colorImage.address == gDP.depthImageAddress) {
|
|
_loadDepthTexture(_pTexture, (u16*)m_tempTextureHolder.data());
|
|
return;
|
|
}
|
|
|
|
if (m_toggleDumpTex &&
|
|
config.textureFilter.txHiresEnable != 0 &&
|
|
config.hotkeys.enabledKeys[Config::HotKey::hkTexDump] != 0) {
|
|
txfilter_dmptx((u8*)m_tempTextureHolder.data(), tmptex.width, tmptex.height,
|
|
tmptex.width, (u16)u32(glInternalFormat),
|
|
N64FormatSize(_pTexture->format, _pTexture->size),
|
|
ricecrc);
|
|
}
|
|
|
|
bool bLoaded = false;
|
|
bool needEnhance = (config.textureFilter.txEnhancementMode | config.textureFilter.txFilterMode) != 0 &&
|
|
_pTexture->max_level == 0 &&
|
|
TFH.isInited();
|
|
if (needEnhance) {
|
|
if (config.textureFilter.txFilterIgnoreBG != 0) {
|
|
switch (GBI.getMicrocodeType()) {
|
|
case S2DEX_1_07:
|
|
case S2DEX_1_03:
|
|
case S2DEX_1_05:
|
|
needEnhance = RSP.cmd != 0x01 && RSP.cmd != 0x02;
|
|
break;
|
|
case S2DEX2:
|
|
needEnhance = RSP.cmd != 0x09 && RSP.cmd != 0x0A;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (needEnhance) {
|
|
GHQTexInfo ghqTexInfo;
|
|
if (txfilter_filter((u8*)m_tempTextureHolder.data(), tmptex.width, tmptex.height,
|
|
(u16)u32(glInternalFormat), (uint64)_pTexture->crc,
|
|
N64FormatSize(_pTexture->format, _pTexture->size),
|
|
&ghqTexInfo) != 0 && ghqTexInfo.data != nullptr) {
|
|
if (ghqTexInfo.width % 2 != 0 &&
|
|
ghqTexInfo.format != u32(internalcolorFormat::RGBA8) &&
|
|
m_curUnpackAlignment > 1)
|
|
gfxContext.setTextureUnpackAlignment(2);
|
|
ghqTexInfo.format = gfxContext.convertInternalTextureFormat(ghqTexInfo.format);
|
|
Context::InitTextureParams params;
|
|
params.handle = _pTexture->name;
|
|
params.textureUnitIndex = textureIndices::Tex[_tile];
|
|
params.mipMapLevel = 0;
|
|
params.msaaLevel = 0;
|
|
params.width = ghqTexInfo.width;
|
|
params.height = ghqTexInfo.height;
|
|
params.internalFormat = InternalColorFormatParam(ghqTexInfo.format);
|
|
params.format = ColorFormatParam(ghqTexInfo.texture_format);
|
|
params.dataType = DatatypeParam(ghqTexInfo.pixel_type);
|
|
params.data = ghqTexInfo.data;
|
|
gfxContext.init2DTexture(params);
|
|
_updateCachedTexture(ghqTexInfo, _pTexture, tmptex.width, tmptex.height);
|
|
bLoaded = true;
|
|
}
|
|
}
|
|
if (!bLoaded) {
|
|
if (tmptex.width % 2 != 0 &&
|
|
glInternalFormat != internalcolorFormat::RGBA8 &&
|
|
m_curUnpackAlignment > 1)
|
|
gfxContext.setTextureUnpackAlignment(2);
|
|
Context::InitTextureParams params;
|
|
params.handle = _pTexture->name;
|
|
params.textureUnitIndex = textureIndices::Tex[_tile];
|
|
params.mipMapLevel = 0;
|
|
params.mipMapLevels = 1;
|
|
params.msaaLevel = 0;
|
|
params.width = tmptex.width;
|
|
params.height = tmptex.height;
|
|
params.internalFormat = gfxContext.convertInternalTextureFormat(u32(glInternalFormat));
|
|
params.format = colorFormat::RGBA;
|
|
params.dataType = glType;
|
|
params.data = m_tempTextureHolder.data();
|
|
gfxContext.init2DTexture(params);
|
|
}
|
|
}
|
|
if (m_curUnpackAlignment > 1)
|
|
gfxContext.setTextureUnpackAlignment(m_curUnpackAlignment);
|
|
}
|
|
|
|
struct TextureParams
|
|
{
|
|
u16 width;
|
|
u16 height;
|
|
u32 flags;
|
|
};
|
|
|
|
static
|
|
u64 _calculateCRC(u32 _t, const TextureParams & _params, u32 _bytes)
|
|
{
|
|
const bool rgba32 = gSP.textureTile[_t]->size == G_IM_SIZ_32b;
|
|
if (_bytes == 0) {
|
|
const u32 lineBytes = gSP.textureTile[_t]->line << 3;
|
|
_bytes = _params.height*lineBytes;
|
|
}
|
|
if (rgba32)
|
|
_bytes >>= 1;
|
|
const u32 tMemMask = (gDP.otherMode.textureLUT == G_TT_NONE && !rgba32) ? 0x1FF : 0xFF;
|
|
const u32 tMem = gSP.textureTile[_t]->tmem & tMemMask;
|
|
const u64 *src = (u64*)&TMEM[tMem];
|
|
const u32 maxBytes = (tMemMask + 1) << 3;
|
|
const u32 tileTmemInBytes = tMem << 3;
|
|
if (!rgba32 && (tileTmemInBytes + _bytes > maxBytes))
|
|
_bytes = maxBytes - tileTmemInBytes;
|
|
u64 crc = UINT64_MAX;
|
|
crc = CRC_Calculate(crc, src, _bytes);
|
|
|
|
if (rgba32) {
|
|
src = (u64*)&TMEM[(gSP.textureTile[_t]->tmem + 256) & 0x1FF];
|
|
crc = CRC_Calculate(crc, src, _bytes);
|
|
}
|
|
|
|
if (gDP.otherMode.textureLUT != G_TT_NONE || gSP.textureTile[_t]->format == G_IM_FMT_CI) {
|
|
if (gSP.textureTile[_t]->size == G_IM_SIZ_4b)
|
|
crc = CRC_Calculate( crc, &gDP.paletteCRC16[gSP.textureTile[_t]->palette], sizeof(u64) );
|
|
else if (gSP.textureTile[_t]->size == G_IM_SIZ_8b)
|
|
crc = CRC_Calculate( crc, &gDP.paletteCRC256, sizeof(u64) );
|
|
}
|
|
|
|
if (config.generalEmulation.enableLOD != 0 && gSP.texture.level > 1 && _t > 0)
|
|
crc = CRC_Calculate(crc, &gSP.texture.level, 4);
|
|
|
|
crc = CRC_Calculate(crc, &_params, sizeof(_params));
|
|
|
|
return crc;
|
|
}
|
|
|
|
void TextureCache::activateTexture(u32 _t, CachedTexture *_pTexture)
|
|
{
|
|
|
|
Context::TexParameters params;
|
|
params.handle = _pTexture->name;
|
|
if (config.video.multisampling > 0 && _pTexture->frameBufferTexture == CachedTexture::fbMultiSample) {
|
|
params.target = textureTarget::TEXTURE_2D_MULTISAMPLE;
|
|
params.textureUnitIndex = textureIndices::MSTex[_t];
|
|
} else {
|
|
params.target = textureTarget::TEXTURE_2D;
|
|
params.textureUnitIndex = textureIndices::Tex[_t];
|
|
params.minFilter = textureParameters::FILTER_NEAREST;
|
|
params.magFilter = textureParameters::FILTER_NEAREST;
|
|
params.maxMipmapLevel = Parameter(0);
|
|
|
|
if (config.generalEmulation.enableInaccurateTextureCoordinates != 0) {
|
|
|
|
const bool bUseBilinear = gDP.otherMode.textureFilter != G_TF_POINT && config.texture.bilinearMode != BILINEAR_3POINT;
|
|
const bool bUseLOD = currentCombiner()->usesLOD();
|
|
const s32 texLevel = bUseLOD ? _pTexture->max_level : 0;
|
|
params.maxMipmapLevel = Parameter(texLevel);
|
|
|
|
if (bUseLOD) {
|
|
if (bUseBilinear) {
|
|
// Apply standard bilinear to mipmap textures
|
|
if (texLevel > 0)
|
|
params.minFilter = textureParameters::FILTER_LINEAR_MIPMAP_NEAREST;
|
|
else
|
|
params.minFilter = textureParameters::FILTER_LINEAR;
|
|
params.magFilter = textureParameters::FILTER_LINEAR;
|
|
} else {
|
|
if (texLevel > 0)
|
|
params.minFilter = textureParameters::FILTER_NEAREST_MIPMAP_NEAREST;
|
|
else
|
|
params.minFilter = textureParameters::FILTER_NEAREST;
|
|
params.magFilter = textureParameters::FILTER_NEAREST;
|
|
}
|
|
}
|
|
|
|
// Set clamping modes
|
|
params.wrapS = _pTexture->clampS ? textureParameters::WRAP_CLAMP_TO_EDGE :
|
|
_pTexture->mirrorS ? textureParameters::WRAP_MIRRORED_REPEAT : textureParameters::WRAP_REPEAT;
|
|
params.wrapT = _pTexture->clampT ? textureParameters::WRAP_CLAMP_TO_EDGE :
|
|
_pTexture->mirrorT ? textureParameters::WRAP_MIRRORED_REPEAT : textureParameters::WRAP_REPEAT;
|
|
}
|
|
|
|
if (config.texture.anisotropy != 0) {
|
|
switch (dwnd().getDrawer().getDrawingState()) {
|
|
case DrawingState::Triangle:
|
|
case DrawingState::ScreenSpaceTriangle:
|
|
params.maxAnisotropy = Parameter(static_cast<f32>(config.texture.anisotropy));
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
gfxContext.setTextureParameters(params);
|
|
|
|
current[_t] = _pTexture;
|
|
}
|
|
|
|
void TextureCache::activateDummy(u32 _t)
|
|
{
|
|
Context::TexParameters params;
|
|
params.handle = m_pDummy->name;
|
|
params.target = textureTarget::TEXTURE_2D;
|
|
params.textureUnitIndex = textureIndices::Tex[_t];
|
|
params.minFilter = textureParameters::FILTER_NEAREST;
|
|
params.magFilter = textureParameters::FILTER_NEAREST;
|
|
gfxContext.setTextureParameters(params);
|
|
}
|
|
|
|
void TextureCache::activateMSDummy(u32 _t)
|
|
{
|
|
Context::TexParameters params;
|
|
params.handle = m_pMSDummy->name;
|
|
params.target = textureTarget::TEXTURE_2D_MULTISAMPLE;
|
|
params.textureUnitIndex = textureIndices::MSTex[_t];
|
|
gfxContext.setTextureParameters(params);
|
|
}
|
|
|
|
void TextureCache::_updateBackground()
|
|
{
|
|
u32 numBytes = gSP.bgImage.width * gSP.bgImage.height << gSP.bgImage.size >> 1;
|
|
u64 crc;
|
|
|
|
crc = CRC_Calculate( UINT64_MAX, &RDRAM[gSP.bgImage.address], numBytes );
|
|
|
|
if (gDP.otherMode.textureLUT != G_TT_NONE || gSP.bgImage.format == G_IM_FMT_CI) {
|
|
if (gSP.bgImage.size == G_IM_SIZ_4b)
|
|
crc = CRC_Calculate( crc, &gDP.paletteCRC16[gSP.bgImage.palette], sizeof(u64) );
|
|
else if (gSP.bgImage.size == G_IM_SIZ_8b)
|
|
crc = CRC_Calculate( crc, &gDP.paletteCRC256, sizeof(u64) );
|
|
}
|
|
|
|
u32 params[4] = {gSP.bgImage.width, gSP.bgImage.height, gSP.bgImage.format, gSP.bgImage.size};
|
|
crc = CRC_Calculate(crc, params, sizeof(u32)*4);
|
|
|
|
Texture_Locations::iterator locations_iter = m_lruTextureLocations.find(crc);
|
|
if (locations_iter != m_lruTextureLocations.end()) {
|
|
Textures::iterator iter = locations_iter->second;
|
|
CachedTexture & currentTex = *iter;
|
|
m_textures.splice(m_textures.begin(), m_textures, iter);
|
|
|
|
assert(currentTex.width == gSP.bgImage.width);
|
|
assert(currentTex.height == gSP.bgImage.height);
|
|
assert(currentTex.format == gSP.bgImage.format);
|
|
assert(currentTex.size == gSP.bgImage.size);
|
|
currentTex.clampS = gSP.bgImage.clampS;
|
|
currentTex.clampT = gSP.bgImage.clampT;
|
|
|
|
activateTexture(0, ¤tTex);
|
|
m_hits++;
|
|
return;
|
|
}
|
|
|
|
m_misses++;
|
|
|
|
CachedTexture * pCurrent = _addTexture(crc);
|
|
|
|
pCurrent->address = gSP.bgImage.address;
|
|
|
|
pCurrent->format = gSP.bgImage.format;
|
|
pCurrent->size = gSP.bgImage.size;
|
|
|
|
pCurrent->width = gSP.bgImage.width;
|
|
pCurrent->height = gSP.bgImage.height;
|
|
|
|
pCurrent->clampWidth = gSP.bgImage.width;
|
|
pCurrent->clampHeight = gSP.bgImage.height;
|
|
pCurrent->palette = gSP.bgImage.palette;
|
|
pCurrent->maskS = 0;
|
|
pCurrent->maskT = 0;
|
|
pCurrent->mirrorS = 0;
|
|
pCurrent->mirrorT = 0;
|
|
pCurrent->clampS = gSP.bgImage.clampS;
|
|
pCurrent->clampT = gSP.bgImage.clampT;
|
|
pCurrent->line = 0;
|
|
pCurrent->tMem = 0;
|
|
pCurrent->frameBufferTexture = CachedTexture::fbNone;
|
|
|
|
pCurrent->scaleS = 1.0f / (f32)(pCurrent->width);
|
|
pCurrent->scaleT = 1.0f / (f32)(pCurrent->height);
|
|
|
|
pCurrent->hdRatioS = 1.0f;
|
|
pCurrent->hdRatioT = 1.0f;
|
|
|
|
pCurrent->shiftScaleS = 1.0f;
|
|
pCurrent->shiftScaleT = 1.0f;
|
|
|
|
pCurrent->offsetS = 0.0f;
|
|
pCurrent->offsetT = 0.0f;
|
|
|
|
_loadBackground(pCurrent);
|
|
activateTexture(0, pCurrent);
|
|
|
|
current[0] = pCurrent;
|
|
}
|
|
|
|
void TextureCache::clear()
|
|
{
|
|
current[0] = current[1] = nullptr;
|
|
|
|
for (auto cur = m_textures.cbegin(); cur != m_textures.cend(); ++cur) {
|
|
gfxContext.deleteTexture(cur->name);
|
|
}
|
|
m_textures.clear();
|
|
m_lruTextureLocations.clear();
|
|
m_hdTexCacheSize = 0u;
|
|
}
|
|
|
|
void TextureCache::toggleDumpTex()
|
|
{
|
|
m_toggleDumpTex = !m_toggleDumpTex;
|
|
if (m_toggleDumpTex) {
|
|
displayLoadProgress(L"Texture dump - ON\n");
|
|
clear();
|
|
std::this_thread::sleep_for(std::chrono::seconds(1));
|
|
} else {
|
|
displayLoadProgress(L"Texture dump - OFF\n");
|
|
std::this_thread::sleep_for(std::chrono::seconds(1));
|
|
}
|
|
}
|
|
|
|
void TextureCache::update(u32 _t)
|
|
{
|
|
const gDPTile * pTile = gSP.textureTile[_t];
|
|
switch (pTile->textureMode) {
|
|
case TEXTUREMODE_BGIMAGE:
|
|
_updateBackground();
|
|
return;
|
|
case TEXTUREMODE_FRAMEBUFFER:
|
|
FrameBuffer_ActivateBufferTexture( _t, pTile->frameBufferAddress );
|
|
return;
|
|
case TEXTUREMODE_FRAMEBUFFER_BG:
|
|
FrameBuffer_ActivateBufferTextureBG( _t, pTile->frameBufferAddress );
|
|
return;
|
|
}
|
|
|
|
if (_t == 1 && needReplaceTex1ByTex0()) {
|
|
current[1] = current[0];
|
|
if (current[1] != nullptr) {
|
|
activateTexture(1, current[1]);
|
|
return;
|
|
}
|
|
}
|
|
|
|
if (gSP.texture.tile == 7 &&
|
|
_t == 0 &&
|
|
gSP.textureTile[0] == gDP.loadTile &&
|
|
gDP.loadTile->loadType == LOADTYPE_BLOCK &&
|
|
gSP.textureTile[0]->tmem == gSP.textureTile[1]->tmem) {
|
|
gSP.textureTile[0] = gSP.textureTile[1];
|
|
pTile = gSP.textureTile[_t];
|
|
}
|
|
|
|
TileSizes sizes;
|
|
_calcTileSizes(_t, sizes, gDP.loadTile);
|
|
TextureParams params;
|
|
const u32 texLevel = _t == 0 ? 0U : gSP.texture.level;
|
|
params.flags = pTile->masks |
|
|
(pTile->maskt << 4) |
|
|
(pTile->mirrors << 8) |
|
|
(pTile->mirrort << 9) |
|
|
(pTile->clamps << 10) |
|
|
(pTile->clampt << 11) |
|
|
(pTile->size << 12) |
|
|
(pTile->format << 14) |
|
|
(gDP.otherMode.textureLUT << 17) |
|
|
(texLevel << 19);
|
|
params.width = sizes.width;
|
|
params.height = sizes.height;
|
|
|
|
const u64 crc = _calculateCRC(_t, params, sizes.bytes);
|
|
|
|
if (current[_t] != nullptr && current[_t]->crc == crc) {
|
|
activateTexture(_t, current[_t]);
|
|
return;
|
|
}
|
|
|
|
Texture_Locations::iterator locations_iter = m_lruTextureLocations.find(crc);
|
|
if (locations_iter != m_lruTextureLocations.end()) {
|
|
Textures::iterator iter = locations_iter->second;
|
|
CachedTexture & currentTex = *iter;
|
|
|
|
if (currentTex.width == sizes.width && currentTex.height == sizes.height) {
|
|
m_textures.splice(m_textures.begin(), m_textures, iter);
|
|
|
|
assert(currentTex.format == pTile->format);
|
|
assert(currentTex.size == pTile->size);
|
|
|
|
activateTexture(_t, ¤tTex);
|
|
m_hits++;
|
|
return;
|
|
}
|
|
|
|
if (currentTex.bHDTexture)
|
|
m_hdTexCacheSize -= currentTex.textureBytes;
|
|
gfxContext.deleteTexture(currentTex.name);
|
|
m_lruTextureLocations.erase(locations_iter);
|
|
m_textures.erase(iter);
|
|
}
|
|
|
|
m_misses++;
|
|
|
|
CachedTexture * pCurrent = _addTexture(crc);
|
|
|
|
pCurrent->address = gDP.loadInfo[pTile->tmem].texAddress;
|
|
|
|
pCurrent->format = pTile->format;
|
|
pCurrent->size = pTile->size;
|
|
|
|
pCurrent->width = sizes.width;
|
|
pCurrent->height = sizes.height;
|
|
|
|
pCurrent->clampWidth = sizes.clampWidth;
|
|
pCurrent->clampHeight = sizes.clampHeight;
|
|
|
|
pCurrent->palette = pTile->palette;
|
|
/* pCurrent->fulS = gSP.textureTile[t]->fulS;
|
|
pCurrent->fulT = gSP.textureTile[t]->fulT;
|
|
pCurrent->ulS = gSP.textureTile[t]->ulS;
|
|
pCurrent->ulT = gSP.textureTile[t]->ulT;
|
|
pCurrent->lrS = gSP.textureTile[t]->lrS;
|
|
pCurrent->lrT = gSP.textureTile[t]->lrT;*/
|
|
pCurrent->maskS = pTile->masks;
|
|
pCurrent->maskT = pTile->maskt;
|
|
pCurrent->mirrorS = pTile->mirrors;
|
|
pCurrent->mirrorT = pTile->mirrort;
|
|
pCurrent->clampS = pTile->clamps;
|
|
pCurrent->clampT = pTile->clampt;
|
|
pCurrent->line = pTile->line;
|
|
pCurrent->tMem = pTile->tmem;
|
|
pCurrent->frameBufferTexture = CachedTexture::fbNone;
|
|
|
|
pCurrent->scaleS = 1.0f / (pCurrent->maskS ? f32(pow2(pCurrent->width)) : f32(pCurrent->width));
|
|
pCurrent->scaleT = 1.0f / (pCurrent->maskT ? f32(pow2(pCurrent->height)) : f32(pCurrent->height));
|
|
|
|
pCurrent->hdRatioS = 1.0f;
|
|
pCurrent->hdRatioT = 1.0f;
|
|
|
|
pCurrent->offsetS = 0.0f;
|
|
pCurrent->offsetT = 0.0f;
|
|
|
|
if (config.generalEmulation.enableInaccurateTextureCoordinates) {
|
|
_loadFast(_t, pCurrent);
|
|
} else {
|
|
_loadAccurate(_t, pCurrent);
|
|
}
|
|
activateTexture( _t, pCurrent );
|
|
|
|
current[_t] = pCurrent;
|
|
}
|
|
|
|
void getTextureShiftScale(u32 t, const TextureCache & cache, f32 & shiftScaleS, f32 & shiftScaleT)
|
|
{
|
|
gDPTile & tile = *gSP.textureTile[t];
|
|
if (tile.textureMode != TEXTUREMODE_NORMAL) {
|
|
shiftScaleS = cache.current[t]->shiftScaleS;
|
|
shiftScaleT = cache.current[t]->shiftScaleT;
|
|
return;
|
|
}
|
|
|
|
if (gDP.otherMode.textureLOD == G_TL_LOD && gSP.texture.level == 0 && !currentCombiner()->usesLOD())
|
|
t = 0;
|
|
|
|
shiftScaleS = calcShiftScaleS(tile);
|
|
shiftScaleT = calcShiftScaleT(tile);
|
|
}
|
|
|
|
bool needReplaceTex1ByTex0()
|
|
{
|
|
return config.generalEmulation.enableInaccurateTextureCoordinates &&
|
|
gSP.texture.level == 0 && gDP.otherMode.textureLOD == G_TL_LOD && gDP.otherMode.textureDetail == G_TD_CLAMP;
|
|
}
|
|
|