mirror of https://github.com/PCSX2/pcsx2.git
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:
parent
7c42928b57
commit
9e687895e1
|
@ -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
|
||||
|
|
|
@ -185,6 +185,7 @@ public:
|
|||
enum Flags
|
||||
{
|
||||
PointListPalette = 1,
|
||||
TextureInsideRt = 2,
|
||||
};
|
||||
|
||||
struct Game
|
||||
|
|
|
@ -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
|
||||
} 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
|
||||
|
||||
// Check if it is possible to hit with valid <x,y> offset on the given Target
|
||||
// Fixes Jak eyes rendering
|
||||
|
||||
bool valid_offset_may_exist = true;
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
uint32 delta = bp - t->m_TEX0.TBP0;
|
||||
uint32 delta_p = delta / 32;
|
||||
uint32 delta_b = delta % 32;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME
|
||||
x_offset = (delta_p % bw) * psm_s.pgs.x;
|
||||
y_offset = (delta_p / bw) * psm_s.pgs.y;
|
||||
if (dst != nullptr)
|
||||
break;
|
||||
|
||||
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,
|
||||
};
|
||||
if (!valid_offset_may_exist)
|
||||
continue;
|
||||
|
||||
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,
|
||||
};
|
||||
// CACHE MISS
|
||||
|
||||
x_offset += block32_offset_x[delta_b] * psm_s.bs.x;
|
||||
y_offset += block32_offset_y[delta_b] * psm_s.bs.y;
|
||||
// SWEEP SEARCH: <x,y> offset
|
||||
|
||||
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);
|
||||
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];
|
||||
|
|
|
@ -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";
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue