diff --git a/plugins/GSdx/GSDeviceOGL.cpp b/plugins/GSdx/GSDeviceOGL.cpp index 91fa170c69..67dda14668 100644 --- a/plugins/GSdx/GSDeviceOGL.cpp +++ b/plugins/GSdx/GSDeviceOGL.cpp @@ -699,7 +699,7 @@ void GSDeviceOGL::CopyRect(GSTexture* sTex, GSTexture* dTex, const GSVector4i& r gl_CopyImageSubData( sid, GL_TEXTURE_2D, 0, r.x, r.y, 0, did, GL_TEXTURE_2D, - 0, r.x, r.y, 0, + 0, 0, 0, 0, r.width(), r.height(), 1); } else { diff --git a/plugins/GSdx/GSRendererHW.cpp b/plugins/GSdx/GSRendererHW.cpp index b60ee36c5b..f14fec57ac 100644 --- a/plugins/GSdx/GSRendererHW.cpp +++ b/plugins/GSdx/GSRendererHW.cpp @@ -34,22 +34,36 @@ GSRendererHW::GSRendererHW(GSTextureCache* tc) m_userhacks_skipdraw = !!theApp.GetConfig("UserHacks", 0) ? theApp.GetConfig("UserHacks_SkipDraw", 0) : 0; m_userhacks_align_sprite_X = !!theApp.GetConfig("UserHacks_align_sprite_X", 0) && !!theApp.GetConfig("UserHacks", 0); m_userhacks_round_sprite_offset = !!theApp.GetConfig("UserHacks", 0) ? theApp.GetConfig("UserHacks_round_sprite_offset", 0) : 0; +} - if(!m_nativeres) +void GSRendererHW::SetScaling(){ + int env = IsEnabled(1) ? 1 : 0; + + m_buffer_size = max(m_context->FRAME.FBW, m_regs->DISP[env].DISPFB.FBW); + + if (m_upscale_multiplier < 6 && (m_width / m_upscale_multiplier) != (m_buffer_size * 64)){ + printf("Frame buffer width on vsync %d m_width %d\n", m_buffer_size, (m_width / m_upscale_multiplier)); + m_tc->RemovePartial(); + } + else { + return; + } + + if (!m_nativeres) { m_width = theApp.GetConfig("resx", m_width); m_height = theApp.GetConfig("resy", m_height); m_upscale_multiplier = theApp.GetConfig("upscale_multiplier", m_upscale_multiplier); - if(m_upscale_multiplier > 6) + if (m_upscale_multiplier > 6) { m_upscale_multiplier = 1; // use the normal upscale math } - else if(m_upscale_multiplier > 1) + else if (m_upscale_multiplier > 1) { - m_width = 640 * m_upscale_multiplier; // 512 is also common, but this is not always detected right. - m_height = 512 * m_upscale_multiplier; // 448 is also common, but this is not always detected right. + m_width = (m_buffer_size * 64) * m_upscale_multiplier; + m_height = m_width; //Keep it square } } else @@ -59,9 +73,15 @@ GSRendererHW::GSRendererHW(GSTextureCache* tc) if (m_upscale_multiplier == 1) { // No upscaling hack at native resolution + if (m_nativeres) { + m_width = (m_buffer_size * 64) * m_upscale_multiplier; + m_height = m_width; //Keep it square + } + m_userhacks_round_sprite_offset = 0; m_userhacks_align_sprite_X = 0; } + printf("Frame buffer width %d m_width set to %d multiplier %d", m_buffer_size, m_width, m_upscale_multiplier); } GSRendererHW::~GSRendererHW() @@ -74,11 +94,6 @@ void GSRendererHW::SetGameCRC(uint32 crc, int options) GSRenderer::SetGameCRC(crc, options); m_hacks.SetGameCRC(m_game); - - if(m_game.title == CRC::JackieChanAdv) - { - m_width = 1280; // TODO: uses a 1280px wide 16 bit render target, but this only fixes half of the problem - } } bool GSRendererHW::CanUpscale() @@ -108,6 +123,9 @@ void GSRendererHW::Reset() void GSRendererHW::VSync(int field) { + //Check if the frame buffer width or display width has changed + SetScaling(); + if(m_reset) { m_tc->RemoveAll(); diff --git a/plugins/GSdx/GSRendererHW.h b/plugins/GSdx/GSRendererHW.h index f1e09e2da3..b5a73e68e1 100644 --- a/plugins/GSdx/GSRendererHW.h +++ b/plugins/GSdx/GSRendererHW.h @@ -25,6 +25,7 @@ #include "GSTextureCache.h" #include "GSCrc.h" #include "GSFunctionMap.h" +#include "GSState.h" class GSRendererHW : public GSRenderer { @@ -34,6 +35,7 @@ private: int m_skip; bool m_reset; int m_upscale_multiplier; + int m_buffer_size; int m_userhacks_skipdraw; bool m_userhacks_align_sprite_X; @@ -151,6 +153,7 @@ public: void SetGameCRC(uint32 crc, int options); bool CanUpscale(); int GetUpscaleMultiplier(); + void SetScaling(); void Reset(); void VSync(int field); diff --git a/plugins/GSdx/GSTextureCache.cpp b/plugins/GSdx/GSTextureCache.cpp index 0aa827af5f..7d762494a5 100644 --- a/plugins/GSdx/GSTextureCache.cpp +++ b/plugins/GSdx/GSTextureCache.cpp @@ -40,6 +40,18 @@ GSTextureCache::~GSTextureCache() _aligned_free(m_temp); } +void GSTextureCache::RemovePartial() +{ + //m_src.RemoveAll(); + + for (int type = 0; type < 2; type++) + { + for_each(m_dst[type].begin(), m_dst[type].end(), delete_object()); + + m_dst[type].clear(); + } +} + void GSTextureCache::RemoveAll() { m_src.RemoveAll(); @@ -92,6 +104,7 @@ GSTextureCache::Source* GSTextureCache::LookupSource(const GIFRegTEX0& TEX0, con } Target* dst = NULL; + bool half_right = false; #ifdef DISABLE_HW_TEXTURE_CACHE if( 0 ) @@ -115,11 +128,23 @@ GSTextureCache::Source* GSTextureCache::LookupSource(const GIFRegTEX0& TEX0, con { Target* t = *i; - if(t->m_used && t->m_dirty.empty() && GSUtil::HasSharedBits(bp, psm, t->m_TEX0.TBP0, t->m_TEX0.PSM)) - { - dst = t; + if(t->m_used && t->m_dirty.empty()) { + if (GSUtil::HasSharedBits(bp, psm, t->m_TEX0.TBP0, t->m_TEX0.PSM)) { + dst = t; - break; + break; + + } else if ((t->m_TEX0.TBW == 20) && (t->m_TEX0.PSM == 2) && GSUtil::HasSharedBits(bp, psm, t->m_TEX0.TBP0 + 0x140, t->m_TEX0.PSM)) { + // try to detect render target bigger than 1024 Texels + // 0x140: In 16 bits format, pages are 64 pixels and 8KB + // Half of 1280 is 640 so 10 pages + // TBP0 unit is block of 256B => (10 pages * 8 KB) / (1 block * 256B) = 320 = 0x140 + + half_right = true; + dst = t; + + break; + } } } } @@ -136,7 +161,7 @@ GSTextureCache::Source* GSTextureCache::LookupSource(const GIFRegTEX0& TEX0, con GL_CACHE("TC: src miss (0x%x)", TEX0.TBP0); } #endif - src = CreateSource(TEX0, TEXA, dst); + src = CreateSource(TEX0, TEXA, dst, half_right); if(src == NULL) { @@ -338,6 +363,28 @@ void GSTextureCache::InvalidateVideoMem(GSOffset* off, const GSVector4i& rect, b m_src.RemoveAt(s); } } + + if ((bw == 20) && (psm == 2)) { + // try to detect render target bigger than 1024 Texels + // 0x140: In 16 bits format, pages are 64 pixels and 8KB + // Half of 1280 is 640 so 10 pages + // TBP0 unit is block of 256B => (10 pages * 8 KB) / (1 block * 256B) = 320 = 0x140 + uint32 bbp = bp + 0x140; + + const list& m = m_src.m_map[bbp >> 5]; + + for(list::const_iterator i = m.begin(); i != m.end(); ) + { + list::const_iterator j = i++; + + Source* s = *j; + + if(GSUtil::HasSharedBits(bbp, psm, s->m_TEX0.TBP0, s->m_TEX0.PSM)) + { + m_src.RemoveAt(s); + } + } + } } GSVector4i r; @@ -612,7 +659,7 @@ void GSTextureCache::IncAge() } //Fixme: Several issues in here. Not handling depth stencil, pitch conversion doesnt work. -GSTextureCache::Source* GSTextureCache::CreateSource(const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA, Target* dst) +GSTextureCache::Source* GSTextureCache::CreateSource(const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA, Target* dst, bool half_right) { const GSLocalMemory::psm_t& psm = GSLocalMemory::m_psm[TEX0.PSM]; Source* src = new Source(m_renderer, TEX0, TEXA, m_temp); @@ -770,13 +817,22 @@ GSTextureCache::Source* GSTextureCache::CreateSource(const GIFRegTEX0& TEX0, con if((sRect == dRect).alltrue()) { - m_renderer->m_dev->CopyRect(sTex, dTex, GSVector4i(0, 0, w, h)); + // Note: use dstsize.x instead of w because w is limited to 1024 whereas dstsize.x could + // be bigger (1280 for snow engine games) + if (half_right) + m_renderer->m_dev->CopyRect(sTex, dTex, GSVector4i(dstsize.x/2, 0, dstsize.x, h)); + else + m_renderer->m_dev->CopyRect(sTex, dTex, GSVector4i(0, 0, w, h)); // <= likely wrong dstsize.x could be bigger than w } else { sRect.z /= sTex->GetWidth(); sRect.w /= sTex->GetHeight(); + if (half_right) { + sRect.x = sRect.z/2.0f; + } + m_renderer->m_dev->StretchRect(sTex, sRect, dTex, dRect, 0, linear); } diff --git a/plugins/GSdx/GSTextureCache.h b/plugins/GSdx/GSTextureCache.h index 4bd5fbe629..2eddfad5ef 100644 --- a/plugins/GSdx/GSTextureCache.h +++ b/plugins/GSdx/GSTextureCache.h @@ -100,6 +100,7 @@ public: void Add(Source* s, const GIFRegTEX0& TEX0, const GSOffset* off); void RemoveAll(); + void RemovePartial(); void RemoveAt(Source* s); }; @@ -111,7 +112,7 @@ protected: int m_spritehack; uint8* m_temp; - virtual Source* CreateSource(const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA, Target* t = NULL); + virtual Source* CreateSource(const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA, Target* t = NULL, bool half_right = false); virtual Target* CreateTarget(const GIFRegTEX0& TEX0, int w, int h, int type); virtual int Get8bitFormat() = 0; @@ -129,6 +130,7 @@ public: virtual void Read(Target* t, const GSVector4i& r) = 0; #endif void RemoveAll(); + void RemovePartial(); Source* LookupSource(const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA, const GSVector4i& r); Target* LookupTarget(const GIFRegTEX0& TEX0, int w, int h, int type, bool used);