GSdx-hw TC: improve search tex in RT

Fixes eyes rendering in Jak games both ingame and in cutscenes.
Previous method yielded no eyes in Jak 2/3/X cutscenes.

- Generalized offset search logic with caching system (works for BW > 1
and any PSM, limited to PSMCT32 for now)
- CRC Flags mechanism for default behavior enabling in Jak games
This commit is contained in:
Alessandro Vetere 2019-08-11 14:43:08 +02:00 committed by lightningterror
parent 7c42928b57
commit 9e687895e1
4 changed files with 122 additions and 44 deletions

View File

@ -440,18 +440,18 @@ CRC::Game CRC::m_games[] =
{0XE8F7BAB6, SuperManReturns, EU, 0},
{0x06A7506A, SacredBlaze, JP, 0},
{0x4CE7FB04, ItadakiStreet, JP, 0},
{0x9C712FF0, Jak1, EU, 0}, // Jak and Daxter: The Precursor Legacy
{0x472E7699, Jak1, US, 0},
{0x2479F4A9, Jak2, EU, 0},
{0x9184AAF1, Jak2, US, 0},
{0xA2034C69, Jak2, US, 0}, // Demo
{0x12804727, Jak3, EU, 0},
{0x644CFD03, Jak3, US, 0},
{0x23F8D35B, Jak3, NoRegion, 0}, // EU Preview, US Internal test build
{0xDF659E77, JakX, EU, 0}, // Jak X: Combat Racing
{0xC20596DB, JakX, EU, 0}, // Beta Trial Disc, v0.01
{0x3091E6FB, JakX, US, 0},
{0xDA366A53, JakX, US, 0}, // Public Beta v.1
{0x9C712FF0, Jak1, EU, TextureInsideRt}, // Jak and Daxter: The Precursor Legacy
{0x472E7699, Jak1, US, TextureInsideRt},
{0x2479F4A9, Jak2, EU, TextureInsideRt},
{0x9184AAF1, Jak2, US, TextureInsideRt},
{0xA2034C69, Jak2, US, TextureInsideRt}, // Demo
{0x12804727, Jak3, EU, TextureInsideRt},
{0x644CFD03, Jak3, US, TextureInsideRt},
{0x23F8D35B, Jak3, NoRegion, TextureInsideRt}, // EU Preview, US Internal test build
{0xDF659E77, JakX, EU, TextureInsideRt}, // Jak X: Combat Racing
{0xC20596DB, JakX, EU, TextureInsideRt}, // Beta Trial Disc, v0.01
{0x3091E6FB, JakX, US, TextureInsideRt},
{0xDA366A53, JakX, US, TextureInsideRt}, // Public Beta v.1
{0x4653CA3E, HarleyDavidson, US, 0},
// Games list for Automatic Mipmapping
// Basic mipmapping

View File

@ -185,6 +185,7 @@ public:
enum Flags
{
PointListPalette = 1,
TextureInsideRt = 2,
};
struct Game

View File

@ -58,12 +58,16 @@ GSTextureCache::GSTextureCache(GSRenderer* r)
// isn't enough in custom resolution)
// Test: onimusha 3 PAL 60Hz
m_temp = (uint8*)_aligned_malloc(9 * 1024 * 1024, 32);
m_texture_inside_rt_cache.reserve(m_texture_inside_rt_cache_size);
}
GSTextureCache::~GSTextureCache()
{
RemoveAll();
m_texture_inside_rt_cache.clear();
_aligned_free(m_temp);
}
@ -262,6 +266,8 @@ GSTextureCache::Source* GSTextureCache::LookupSource(const GIFRegTEX0& TEX0, con
// (Simply not doing this code at all makes a lot of previsouly missing stuff show (but breaks pretty much everything
// else.)
bool texture_inside_rt = ShallSearchTextureInsideRt();
for(auto t : m_dst[RenderTarget]) {
if(t->m_used && t->m_dirty.empty()) {
// Typical bug (MGS3 blue cloud):
@ -298,44 +304,93 @@ GSTextureCache::Source* GSTextureCache::LookupSource(const GIFRegTEX0& TEX0, con
break;
} else if (m_texture_inside_rt && psm == PSM_PSMCT32 && bw == 1 && bp_end < t->m_end_block && t->m_TEX0.TBP0 < bp) {
// Note bw == 1 until we find a generic formulae below
dst = t;
} else if (texture_inside_rt && psm == PSM_PSMCT32 && t->m_TEX0.PSM == psm && t->m_TEX0.TBP0 < bp && t->m_end_block >= bp) {
// Only PSMCT32 to limit false hits
uint32 delta = bp - t->m_TEX0.TBP0;
uint32 delta_p = delta / 32;
uint32 delta_b = delta % 32;
// Check if it is possible to hit with valid <x,y> offset on the given Target
// Fixes Jak eyes rendering
// FIXME
x_offset = (delta_p % bw) * psm_s.pgs.x;
y_offset = (delta_p / bw) * psm_s.pgs.y;
bool valid_offset_may_exist = true;
static int block32_offset_x[32] = {
0, 1, 0, 1,
2, 3, 2, 3,
0, 1, 0, 1,
2, 3, 2, 3,
4, 5, 4, 5,
6, 7, 6, 7,
4, 5, 4, 5,
6, 7, 6, 7,
};
// CACHE SEARCH: <x,y> offset
for (auto& el : m_texture_inside_rt_cache)
{
if (el.psm == psm && el.bp == bp && el.bp_end == bp_end && el.bw == bw &&
el.t_tex0_tbp0 == t->m_TEX0.TBP0 && el.m_end_block == t->m_end_block)
{
if (el.has_valid_offset)
{
// CACHE HIT: <x,y> offset found
dst = t;
x_offset = el.x_offset;
y_offset = el.y_offset;
}
else
{
// CACHE HIT: No valid <x,y> offset exists
valid_offset_may_exist = false;
}
static int block32_offset_y[32] = {
0, 0, 1, 1,
0, 0, 1, 1,
2, 2, 3, 3,
2, 2, 3, 3,
0, 0, 1, 1,
0, 0, 1, 1,
2, 2, 3, 3,
2, 2, 3, 3,
};
break;
}
}
x_offset += block32_offset_x[delta_b] * psm_s.bs.x;
y_offset += block32_offset_y[delta_b] * psm_s.bs.y;
if (dst != nullptr)
break;
GL_INS("WARNING middle of framebuffer 0x%x => 0x%x. Offset %d,%d", t->m_TEX0.TBP0, t->m_end_block, x_offset, y_offset);
if (!valid_offset_may_exist)
continue;
// CACHE MISS
// SWEEP SEARCH: <x,y> offset
TexInsideRtCacheEntry entry = { psm, bp, bp_end, bw, t->m_TEX0.TBP0, t->m_end_block, false, 0, 0 };
for (int candidate_x_offset = 0; candidate_x_offset < t->m_valid.z; ++candidate_x_offset)
{
for (int candidate_y_offset = 0; candidate_y_offset < t->m_valid.w; ++candidate_y_offset)
{
if (candidate_x_offset == 0 && candidate_y_offset == 0)
continue;
uint32 candidate_bp = psm_s.bn(candidate_x_offset, candidate_y_offset, t->m_TEX0.TBP0, bw);
if (bp == candidate_bp && bp_end <= t->m_end_block)
{
// SWEEP HIT: <x,y> offset found
dst = t;
x_offset = candidate_x_offset;
y_offset = candidate_y_offset;
// Add result to cache
while (m_texture_inside_rt_cache.size() > m_texture_inside_rt_cache_size)
{
GL_PERF("TC tex in rt: Size of cache %d too big, clearing it.", m_texture_inside_rt_cache.size());
m_texture_inside_rt_cache.clear();
}
entry.has_valid_offset = true;
entry.x_offset = x_offset;
entry.y_offset = y_offset;
m_texture_inside_rt_cache.emplace_back(entry);
GL_CACHE("TC tex in rt: Cached HIT element (size %d), BW: %d, PSM %s, rt 0x%x <%d,%d> + off <%d,%d> -> 0x%x <%d,%d> (END: 0x%x)",
m_texture_inside_rt_cache.size(), bw, psm_str(psm), t->m_TEX0.TBP0, t->m_valid.z, t->m_valid.w, x_offset, y_offset, bp, tw, th, bp_end);
break;
}
}
if (dst != nullptr)
break;
}
if (dst != nullptr)
break;
// SWEEP MISS: no valid <x,y> offset found
while (m_texture_inside_rt_cache.size() > m_texture_inside_rt_cache_size)
{
GL_PERF("TC tex in rt: Size of cache %d too big, clearing it.", m_texture_inside_rt_cache.size());
m_texture_inside_rt_cache.clear();
}
GL_CACHE("TC tex in rt: Cached MISS element (size %d), BW: %d, PSM %s, rt 0x%x <%d,%d> -/-> 0x%x <%d,%d> (END: 0x%x)",
m_texture_inside_rt_cache.size(), bw, psm_str(psm), t->m_TEX0.TBP0, t->m_valid.z, t->m_valid.w, bp, tw, th, bp_end);
m_texture_inside_rt_cache.emplace_back(entry);
}
}
}
@ -428,6 +483,11 @@ void GSTextureCache::ScaleTexture(GSTexture* texture)
texture->SetScale(scale_factor);
}
bool GSTextureCache::ShallSearchTextureInsideRt()
{
return m_texture_inside_rt || (m_renderer->m_game.flags & CRC::Flags::TextureInsideRt);
}
GSTextureCache::Target* GSTextureCache::LookupTarget(const GIFRegTEX0& TEX0, int w, int h, int type, bool used, uint32 fbmask)
{
const GSLocalMemory::psm_t& psm_s = GSLocalMemory::m_psm[TEX0.PSM];

View File

@ -185,6 +185,19 @@ public:
void RemoveAt(Source* s);
};
struct TexInsideRtCacheEntry
{
uint32 psm;
uint32 bp;
uint32 bp_end;
uint32 bw;
uint32 t_tex0_tbp0;
uint32 m_end_block;
bool has_valid_offset;
int x_offset;
int y_offset;
};
protected:
GSRenderer* m_renderer;
PaletteMap m_palette_map;
@ -199,6 +212,8 @@ protected:
static bool m_disable_partial_invalidation;
bool m_texture_inside_rt;
static bool m_wrap_gs_mem;
uint8 m_texture_inside_rt_cache_size = 255;
std::vector<TexInsideRtCacheEntry> m_texture_inside_rt_cache;
virtual Source* CreateSource(const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA, Target* t = NULL, bool half_right = false, int x_offset = 0, int y_offset = 0);
virtual Target* CreateTarget(const GIFRegTEX0& TEX0, int w, int h, int type);
@ -231,6 +246,8 @@ public:
bool UserHacks_HalfPixelOffset;
void ScaleTexture(GSTexture* texture);
bool ShallSearchTextureInsideRt();
const char* to_string(int type) {
return (type == DepthStencil) ? "Depth" : "Color";
}