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},
|
{0XE8F7BAB6, SuperManReturns, EU, 0},
|
||||||
{0x06A7506A, SacredBlaze, JP, 0},
|
{0x06A7506A, SacredBlaze, JP, 0},
|
||||||
{0x4CE7FB04, ItadakiStreet, JP, 0},
|
{0x4CE7FB04, ItadakiStreet, JP, 0},
|
||||||
{0x9C712FF0, Jak1, EU, 0}, // Jak and Daxter: The Precursor Legacy
|
{0x9C712FF0, Jak1, EU, TextureInsideRt}, // Jak and Daxter: The Precursor Legacy
|
||||||
{0x472E7699, Jak1, US, 0},
|
{0x472E7699, Jak1, US, TextureInsideRt},
|
||||||
{0x2479F4A9, Jak2, EU, 0},
|
{0x2479F4A9, Jak2, EU, TextureInsideRt},
|
||||||
{0x9184AAF1, Jak2, US, 0},
|
{0x9184AAF1, Jak2, US, TextureInsideRt},
|
||||||
{0xA2034C69, Jak2, US, 0}, // Demo
|
{0xA2034C69, Jak2, US, TextureInsideRt}, // Demo
|
||||||
{0x12804727, Jak3, EU, 0},
|
{0x12804727, Jak3, EU, TextureInsideRt},
|
||||||
{0x644CFD03, Jak3, US, 0},
|
{0x644CFD03, Jak3, US, TextureInsideRt},
|
||||||
{0x23F8D35B, Jak3, NoRegion, 0}, // EU Preview, US Internal test build
|
{0x23F8D35B, Jak3, NoRegion, TextureInsideRt}, // EU Preview, US Internal test build
|
||||||
{0xDF659E77, JakX, EU, 0}, // Jak X: Combat Racing
|
{0xDF659E77, JakX, EU, TextureInsideRt}, // Jak X: Combat Racing
|
||||||
{0xC20596DB, JakX, EU, 0}, // Beta Trial Disc, v0.01
|
{0xC20596DB, JakX, EU, TextureInsideRt}, // Beta Trial Disc, v0.01
|
||||||
{0x3091E6FB, JakX, US, 0},
|
{0x3091E6FB, JakX, US, TextureInsideRt},
|
||||||
{0xDA366A53, JakX, US, 0}, // Public Beta v.1
|
{0xDA366A53, JakX, US, TextureInsideRt}, // Public Beta v.1
|
||||||
{0x4653CA3E, HarleyDavidson, US, 0},
|
{0x4653CA3E, HarleyDavidson, US, 0},
|
||||||
// Games list for Automatic Mipmapping
|
// Games list for Automatic Mipmapping
|
||||||
// Basic mipmapping
|
// Basic mipmapping
|
||||||
|
|
|
@ -185,6 +185,7 @@ public:
|
||||||
enum Flags
|
enum Flags
|
||||||
{
|
{
|
||||||
PointListPalette = 1,
|
PointListPalette = 1,
|
||||||
|
TextureInsideRt = 2,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Game
|
struct Game
|
||||||
|
|
|
@ -58,12 +58,16 @@ GSTextureCache::GSTextureCache(GSRenderer* r)
|
||||||
// isn't enough in custom resolution)
|
// isn't enough in custom resolution)
|
||||||
// Test: onimusha 3 PAL 60Hz
|
// Test: onimusha 3 PAL 60Hz
|
||||||
m_temp = (uint8*)_aligned_malloc(9 * 1024 * 1024, 32);
|
m_temp = (uint8*)_aligned_malloc(9 * 1024 * 1024, 32);
|
||||||
|
|
||||||
|
m_texture_inside_rt_cache.reserve(m_texture_inside_rt_cache_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
GSTextureCache::~GSTextureCache()
|
GSTextureCache::~GSTextureCache()
|
||||||
{
|
{
|
||||||
RemoveAll();
|
RemoveAll();
|
||||||
|
|
||||||
|
m_texture_inside_rt_cache.clear();
|
||||||
|
|
||||||
_aligned_free(m_temp);
|
_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
|
// (Simply not doing this code at all makes a lot of previsouly missing stuff show (but breaks pretty much everything
|
||||||
// else.)
|
// else.)
|
||||||
|
|
||||||
|
bool texture_inside_rt = ShallSearchTextureInsideRt();
|
||||||
|
|
||||||
for(auto t : m_dst[RenderTarget]) {
|
for(auto t : m_dst[RenderTarget]) {
|
||||||
if(t->m_used && t->m_dirty.empty()) {
|
if(t->m_used && t->m_dirty.empty()) {
|
||||||
// Typical bug (MGS3 blue cloud):
|
// Typical bug (MGS3 blue cloud):
|
||||||
|
@ -298,44 +304,93 @@ GSTextureCache::Source* GSTextureCache::LookupSource(const GIFRegTEX0& TEX0, con
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
} else if (m_texture_inside_rt && psm == PSM_PSMCT32 && bw == 1 && bp_end < t->m_end_block && t->m_TEX0.TBP0 < bp) {
|
} else if (texture_inside_rt && psm == PSM_PSMCT32 && t->m_TEX0.PSM == psm && t->m_TEX0.TBP0 < bp && t->m_end_block >= bp) {
|
||||||
// Note bw == 1 until we find a generic formulae below
|
// Only PSMCT32 to limit false hits
|
||||||
dst = t;
|
|
||||||
|
|
||||||
uint32 delta = bp - t->m_TEX0.TBP0;
|
// Check if it is possible to hit with valid <x,y> offset on the given Target
|
||||||
uint32 delta_p = delta / 32;
|
// Fixes Jak eyes rendering
|
||||||
uint32 delta_b = delta % 32;
|
|
||||||
|
|
||||||
// FIXME
|
bool valid_offset_may_exist = true;
|
||||||
x_offset = (delta_p % bw) * psm_s.pgs.x;
|
|
||||||
y_offset = (delta_p / bw) * psm_s.pgs.y;
|
|
||||||
|
|
||||||
static int block32_offset_x[32] = {
|
// CACHE SEARCH: <x,y> offset
|
||||||
0, 1, 0, 1,
|
for (auto& el : m_texture_inside_rt_cache)
|
||||||
2, 3, 2, 3,
|
{
|
||||||
0, 1, 0, 1,
|
if (el.psm == psm && el.bp == bp && el.bp_end == bp_end && el.bw == bw &&
|
||||||
2, 3, 2, 3,
|
el.t_tex0_tbp0 == t->m_TEX0.TBP0 && el.m_end_block == t->m_end_block)
|
||||||
4, 5, 4, 5,
|
{
|
||||||
6, 7, 6, 7,
|
if (el.has_valid_offset)
|
||||||
4, 5, 4, 5,
|
{
|
||||||
6, 7, 6, 7,
|
// 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] = {
|
break;
|
||||||
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,
|
|
||||||
};
|
|
||||||
|
|
||||||
x_offset += block32_offset_x[delta_b] * psm_s.bs.x;
|
if (dst != nullptr)
|
||||||
y_offset += block32_offset_y[delta_b] * psm_s.bs.y;
|
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);
|
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)
|
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];
|
const GSLocalMemory::psm_t& psm_s = GSLocalMemory::m_psm[TEX0.PSM];
|
||||||
|
|
|
@ -185,6 +185,19 @@ public:
|
||||||
void RemoveAt(Source* s);
|
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:
|
protected:
|
||||||
GSRenderer* m_renderer;
|
GSRenderer* m_renderer;
|
||||||
PaletteMap m_palette_map;
|
PaletteMap m_palette_map;
|
||||||
|
@ -199,6 +212,8 @@ protected:
|
||||||
static bool m_disable_partial_invalidation;
|
static bool m_disable_partial_invalidation;
|
||||||
bool m_texture_inside_rt;
|
bool m_texture_inside_rt;
|
||||||
static bool m_wrap_gs_mem;
|
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 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);
|
virtual Target* CreateTarget(const GIFRegTEX0& TEX0, int w, int h, int type);
|
||||||
|
@ -231,6 +246,8 @@ public:
|
||||||
bool UserHacks_HalfPixelOffset;
|
bool UserHacks_HalfPixelOffset;
|
||||||
void ScaleTexture(GSTexture* texture);
|
void ScaleTexture(GSTexture* texture);
|
||||||
|
|
||||||
|
bool ShallSearchTextureInsideRt();
|
||||||
|
|
||||||
const char* to_string(int type) {
|
const char* to_string(int type) {
|
||||||
return (type == DepthStencil) ? "Depth" : "Color";
|
return (type == DepthStencil) ? "Depth" : "Color";
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue