From 583de1bf0b8bef75c48c0a02d8a7f634b2596264 Mon Sep 17 00:00:00 2001 From: Gregory Hainaut Date: Thu, 21 Apr 2016 19:13:47 +0200 Subject: [PATCH] gsdx tc: add a dedicated function to lookup a depth source The hypothesis is that game will use a depth (aka Z32/Z24/Z16/Z16S) format when sampling depth texture as color. Technically one could use a standard color format but block/pixel order won't be the same. (otherwise I'm screwed) => Hypothesis invalid on GoW. They just do a scrambled rendering... Lookup info: * The first searched list is the depth pool as we search a depth texture. * 2nd one is the render target pool (if a depth was converted to a render target already) To avoid any CPU overhead, the source will be a pointer to the real texture * Conversion (if float texture) will be done on the fly by the shader (GPU). * Relative rescaling won't be supported. Texture must be fetched with integral coordinate --- plugins/GSdx/GSTextureCache.cpp | 78 +++++++++++++++++++++++++++++++++ plugins/GSdx/GSTextureCache.h | 2 + 2 files changed, 80 insertions(+) diff --git a/plugins/GSdx/GSTextureCache.cpp b/plugins/GSdx/GSTextureCache.cpp index 377f5e1e5f..a70169effa 100644 --- a/plugins/GSdx/GSTextureCache.cpp +++ b/plugins/GSdx/GSTextureCache.cpp @@ -85,6 +85,75 @@ void GSTextureCache::RemoveAll() } } +GSTextureCache::Source* GSTextureCache::LookupDepthSource(const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA, const GSVector4i& r) +{ + if (!CanConvertDepth()) return NULL; + + if(GSLocalMemory::m_psm[TEX0.PSM].pal > 0) + m_renderer->m_mem.m_clut.Read32(TEX0, TEXA); + + Source* src = NULL; + Target* dst = NULL; + + // Check only current frame, I guess it is only used as a postprocessing effect + uint32 bp = TEX0.TBP0; + uint32 psm = TEX0.PSM; + for(auto t : m_dst[DepthStencil]) { + if(!t->m_age && t->m_used && t->m_dirty.empty() && GSUtil::HasSharedBits(bp, psm, t->m_TEX0.TBP0, t->m_TEX0.PSM)) + { + ASSERT(GSLocalMemory::m_psm[t->m_TEX0.PSM].depth); + dst = t; + break; + } + } + + if (!dst) { + // Retry on the render target (Silent Hill 4) + for(auto t : m_dst[RenderTarget]) { + if(!t->m_age && t->m_used && t->m_dirty.empty() && GSUtil::HasSharedBits(bp, psm, t->m_TEX0.TBP0, t->m_TEX0.PSM)) + { + ASSERT(GSLocalMemory::m_psm[t->m_TEX0.PSM].depth); + dst = t; + break; + } + } + } + + if (dst) { + GL_CACHE("TC depth: dst %s hit: %d (0x%x, F:0x%x)", to_string(dst->m_type), + dst->m_texture ? dst->m_texture->GetID() : 0, + TEX0.TBP0, TEX0.PSM); + + // Create a shared texture source + src = new Source(m_renderer, TEX0, TEXA, m_temp); + src->m_texture = dst->m_texture; + src->m_shared_texture = true; + src->m_target = true; // So renderer can check if a conversion is required + src->m_32_bits_fmt = dst->m_32_bits_fmt; + + // Insert the texture in the hash set to keep track of it. But don't bother with + // texture cache list. It means that a new Source is created everytime we need it. + // If it is too expensive, one could cut memory allocation in Source constructor for this + // use case. + + m_src.m_surfaces.insert(src); + } else { + GL_CACHE("TC depth: ERROR miss (0x%x, F:0x%x)", TEX0.TBP0, TEX0.PSM); + // Possible ? In this case we could call LookupSource + // Or just put a basic texture + // src->m_texture = m_renderer->m_dev->CreateTexture(tw, th); + // In all cases rendering will be broken + // + // Note: might worth to check previous frame + // Note: otherwise return NULL and skip the draw + + //ASSERT(0); + return LookupSource(TEX0, TEXA, r); + } + + return src; +} + GSTextureCache::Source* GSTextureCache::LookupSource(const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA, const GSVector4i& r) { const GSLocalMemory::psm_t& psm = GSLocalMemory::m_psm[TEX0.PSM]; @@ -207,6 +276,14 @@ GSTextureCache::Source* GSTextureCache::LookupSource(const GIFRegTEX0& TEX0, con } } + // Pure depth texture format will be fetched by LookupDepthSource. + // However guess what, some games (GoW) read the depth as a standard + // color format (instead of a depth format). All pixels are scrambled + // (because color and depth don't have same location). They don't care + // pixel will be several draw calls later. + // + // Sigh... They don't help us. + if (dst == NULL && CanConvertDepth()) { // Let's try a trick to avoid to use wrongly a depth buffer // Unfortunately, I don't have any Arc the Lad testcase @@ -217,6 +294,7 @@ GSTextureCache::Source* GSTextureCache::LookupSource(const GIFRegTEX0& TEX0, con if(!t->m_age && t->m_used && t->m_dirty.empty() && GSUtil::HasSharedBits(bp, psm, t->m_TEX0.TBP0, t->m_TEX0.PSM)) { + GL_INS("TC: Warning depth format read as color format. Pixels will be scrambled"); dst = t; break; } diff --git a/plugins/GSdx/GSTextureCache.h b/plugins/GSdx/GSTextureCache.h index babcf8f944..3aed4a3449 100644 --- a/plugins/GSdx/GSTextureCache.h +++ b/plugins/GSdx/GSTextureCache.h @@ -142,6 +142,8 @@ public: void RemovePartial(); Source* LookupSource(const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA, const GSVector4i& r); + Source* LookupDepthSource(const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA, const GSVector4i& r); + Target* LookupTarget(const GIFRegTEX0& TEX0, int w, int h, int type, bool used); Target* LookupTarget(const GIFRegTEX0& TEX0, int w, int h, int real_h);