diff --git a/plugins/GSdx/GSCrc.cpp b/plugins/GSdx/GSCrc.cpp index d191069b2a..c8746d5ede 100644 --- a/plugins/GSdx/GSCrc.cpp +++ b/plugins/GSdx/GSCrc.cpp @@ -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 diff --git a/plugins/GSdx/GSCrc.h b/plugins/GSdx/GSCrc.h index 06f1fbe51d..c36226c7e4 100644 --- a/plugins/GSdx/GSCrc.h +++ b/plugins/GSdx/GSCrc.h @@ -185,6 +185,7 @@ public: enum Flags { PointListPalette = 1, + TextureInsideRt = 2, }; struct Game diff --git a/plugins/GSdx/Renderers/HW/GSTextureCache.cpp b/plugins/GSdx/Renderers/HW/GSTextureCache.cpp index 95dcf2000a..a04e8cfc10 100644 --- a/plugins/GSdx/Renderers/HW/GSTextureCache.cpp +++ b/plugins/GSdx/Renderers/HW/GSTextureCache.cpp @@ -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 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: 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: offset found + dst = t; + x_offset = el.x_offset; + y_offset = el.y_offset; + } + else + { + // CACHE HIT: No valid 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: 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: 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 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]; diff --git a/plugins/GSdx/Renderers/HW/GSTextureCache.h b/plugins/GSdx/Renderers/HW/GSTextureCache.h index 1700e6a99a..20f0639178 100644 --- a/plugins/GSdx/Renderers/HW/GSTextureCache.h +++ b/plugins/GSdx/Renderers/HW/GSTextureCache.h @@ -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 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"; }