Large diffs are not rendered by default.

@@ -77,42 +77,6 @@ struct EFBCopyFilterCoefficients
float lower;
};

struct TextureLookupInformation
{
u32 address;

u32 block_width;
u32 block_height;
u32 bytes_per_block;

u32 expanded_width;
u32 expanded_height;
u32 native_width;
u32 native_height;
u32 total_bytes;
u32 native_levels = 1;
u32 computed_levels;

u64 base_hash;
u64 full_hash;

TextureAndTLUTFormat full_format;
u32 tlut_address = 0;

bool is_palette_texture = false;
u32 palette_size = 0;

bool use_mipmaps = false;

bool from_tmem = false;
u32 tmem_address_even = 0;
u32 tmem_address_odd = 0;

int texture_cache_safety_color_sample_size = 0; // Default to safe hashing

u8* src_data;
};

class TextureCacheBase
{
private:
@@ -138,6 +102,7 @@ class TextureCacheBase
// content, aren't just downscaled
bool should_force_safe_hashing = false; // for XFB
bool is_xfb_copy = false;
bool is_xfb_container = false;
u64 id;

bool reference_changed = false; // used by xfb to determine when a reference xfb changed
@@ -243,20 +208,9 @@ class TextureCacheBase
TLUTFormat tlutfmt = TLUTFormat::IA8, bool use_mipmaps = false,
u32 tex_levels = 1, bool from_tmem = false, u32 tmem_address_even = 0,
u32 tmem_address_odd = 0);
TCacheEntry* GetXFBTexture(u32 address, u32 width, u32 height, u32 stride,
MathUtil::Rectangle<int>* display_rect);

TCacheEntry* GetXFBTexture(u32 address, u32 width, u32 height, TextureFormat texformat,
int textureCacheSafetyColorSampleSize);
std::optional<TextureLookupInformation>
ComputeTextureInformation(u32 address, u32 width, u32 height, TextureFormat texformat,
int textureCacheSafetyColorSampleSize, bool from_tmem,
u32 tmem_address_even, u32 tmem_address_odd, u32 tlutaddr,
TLUTFormat tlutfmt, u32 levels);
TCacheEntry* GetXFBFromCache(const TextureLookupInformation& tex_info);
TCacheEntry* GetTextureFromOverlappingTextures(const TextureLookupInformation& tex_info);
TCacheEntry* GetTextureFromMemory(const TextureLookupInformation& tex_info);
TCacheEntry* CreateNormalTexture(const TextureLookupInformation& tex_info, u32 layers);
void LoadTextureLevelZeroFromMemory(TCacheEntry* entry_to_update,
const TextureLookupInformation& tex_info, bool decode_on_gpu);
virtual void BindTextures();
void CopyRenderTargetToTexture(u32 dstAddr, EFBCopyFormat dstFormat, u32 width, u32 height,
u32 dstStride, bool is_depth_copy, const EFBRectangle& srcRect,
@@ -289,13 +243,13 @@ class TextureCacheBase

virtual void CopyEFB(AbstractStagingTexture* dst, const EFBCopyParams& params, u32 native_width,
u32 bytes_per_row, u32 num_blocks_y, u32 memory_stride,
const EFBRectangle& src_rect, bool scale_by_half, float y_scale, float gamma,
bool clamp_top, bool clamp_bottom,
const EFBRectangle& src_rect, bool scale_by_half, bool linear_filter,
float y_scale, float gamma, bool clamp_top, bool clamp_bottom,
const EFBCopyFilterCoefficients& filter_coefficients);
virtual void CopyEFBToCacheEntry(TCacheEntry* entry, bool is_depth_copy,
const EFBRectangle& src_rect, bool scale_by_half,
EFBCopyFormat dst_format, bool is_intensity, float gamma,
bool clamp_top, bool clamp_bottom,
bool linear_filter, EFBCopyFormat dst_format, bool is_intensity,
float gamma, bool clamp_top, bool clamp_bottom,
const EFBCopyFilterCoefficients& filter_coefficients);

alignas(16) u8* temp = nullptr;
@@ -322,10 +276,13 @@ class TextureCacheBase

void SetBackupConfig(const VideoConfig& config);

TCacheEntry* GetXFBFromCache(u32 address, u32 width, u32 height, u32 stride, u64 hash);

TCacheEntry* ApplyPaletteToEntry(TCacheEntry* entry, u8* palette, TLUTFormat tlutfmt);

TCacheEntry* DoPartialTextureUpdates(TCacheEntry* entry_to_update, u8* palette,
TLUTFormat tlutfmt);
void StitchXFBCopy(TCacheEntry* entry_to_update);

void DumpTexture(TCacheEntry* entry, std::string basename, unsigned int level, bool is_arbitrary);
void CheckTempSize(size_t required_size);
@@ -116,6 +116,7 @@ void TexDecoder_DecodeTexel(u8* dst, const u8* src, int s, int t, int imageWidth
TextureFormat texformat, const u8* tlut, TLUTFormat tlutfmt);
void TexDecoder_DecodeTexelRGBA8FromTmem(u8* dst, const u8* src_ar, const u8* src_gb, int s, int t,
int imageWidth);
void TexDecoder_DecodeXFB(u8* dst, const u8* src, u32 width, u32 height, u32 stride);

void TexDecoder_SetTexFmtOverlayOptions(bool enable, bool center);

@@ -751,3 +751,41 @@ void TexDecoder_DecodeRGBA8FromTmem(u8* dst, const u8* src_ar, const u8* src_gb,
}
}
}

void TexDecoder_DecodeXFB(u8* dst, const u8* src, u32 width, u32 height, u32 stride)
{
const u8* src_ptr = src;
u8* dst_ptr = dst;

for (u32 y = 0; y < height; y++)
{
const u8* row_ptr = src_ptr;
for (u32 x = 0; x < width; x += 2)
{
// We do this one color sample (aka 2 RGB pixels) at a time
int Y1 = int(*(row_ptr++)) - 16;
int U = int(*(row_ptr++)) - 128;
int Y2 = int(*(row_ptr++)) - 16;
int V = int(*(row_ptr++)) - 128;

// We do the inverse BT.601 conversion for YCbCr to RGB
// http://www.equasys.de/colorconversion.html#YCbCr-RGBColorFormatConversion
u8 R1 = static_cast<u8>(MathUtil::Clamp(int(1.164f * Y1 + 1.596f * V), 0, 255));
u8 G1 = static_cast<u8>(MathUtil::Clamp(int(1.164f * Y1 - 0.392f * U - 0.813f * V), 0, 255));
u8 B1 = static_cast<u8>(MathUtil::Clamp(int(1.164f * Y1 + 2.017f * U), 0, 255));

u8 R2 = static_cast<u8>(MathUtil::Clamp(int(1.164f * Y2 + 1.596f * V), 0, 255));
u8 G2 = static_cast<u8>(MathUtil::Clamp(int(1.164f * Y2 - 0.392f * U - 0.813f * V), 0, 255));
u8 B2 = static_cast<u8>(MathUtil::Clamp(int(1.164f * Y2 + 2.017f * U), 0, 255));

u32 rgba = 0xff000000 | B1 << 16 | G1 << 8 | R1;
std::memcpy(dst_ptr, &rgba, sizeof(rgba));
dst_ptr += sizeof(rgba);
rgba = 0xff000000 | B2 << 16 | G2 << 8 | R2;
std::memcpy(dst_ptr, &rgba, sizeof(rgba));
dst_ptr += sizeof(rgba);
}

src_ptr += stride;
}
}
@@ -346,5 +346,8 @@ void _TexDecoder_DecodeImpl(u32* dst, const u8* src, int width, int height, Text
}
break;
}
case TextureFormat::XFB:
TexDecoder_DecodeXFB(reinterpret_cast<u8*>(dst), src, width, height, width * 2);
break;
}
}
@@ -1488,37 +1488,8 @@ void _TexDecoder_DecodeImpl(u32* dst, const u8* src, int width, int height, Text
break;

case TextureFormat::XFB:
{
for (int y = 0; y < height; y += 1)
{
for (int x = 0; x < width; x += 2)
{
size_t offset = static_cast<size_t>((y * width + x) * 2);

// We do this one color sample (aka 2 RGB pixles) at a time
int Y1 = int(src[offset]) - 16;
int U = int(src[offset + 1]) - 128;
int Y2 = int(src[offset + 2]) - 16;
int V = int(src[offset + 3]) - 128;

// We do the inverse BT.601 conversion for YCbCr to RGB
// http://www.equasys.de/colorconversion.html#YCbCr-RGBColorFormatConversion
u8 R1 = static_cast<u8>(MathUtil::Clamp(int(1.164f * Y1 + 1.596f * V), 0, 255));
u8 G1 =
static_cast<u8>(MathUtil::Clamp(int(1.164f * Y1 - 0.392f * U - 0.813f * V), 0, 255));
u8 B1 = static_cast<u8>(MathUtil::Clamp(int(1.164f * Y1 + 2.017f * U), 0, 255));

u8 R2 = static_cast<u8>(MathUtil::Clamp(int(1.164f * Y2 + 1.596f * V), 0, 255));
u8 G2 =
static_cast<u8>(MathUtil::Clamp(int(1.164f * Y2 - 0.392f * U - 0.813f * V), 0, 255));
u8 B2 = static_cast<u8>(MathUtil::Clamp(int(1.164f * Y2 + 2.017f * U), 0, 255));

dst[y * width + x] = 0xff000000 | B1 << 16 | G1 << 8 | R1;
dst[y * width + x + 1] = 0xff000000 | B2 << 16 | G2 << 8 | R2;
}
}
}
break;
TexDecoder_DecodeXFB(reinterpret_cast<u8*>(dst), src, width, height, width * 2);
break;

default:
PanicAlert("Invalid Texture Format (0x%X)! (_TexDecoder_DecodeImpl)",