GS-HW: Scale display texture width in TC.

This commit is contained in:
refractionpcsx2 2022-08-22 22:03:33 +01:00
parent b74f91b868
commit 4ef879d1f2
5 changed files with 39 additions and 20 deletions

View File

@ -575,6 +575,20 @@ int GSState::GetFramebufferHeight()
return frame_memory_height; return frame_memory_height;
} }
int GSState::GetFramebufferWidth()
{
// Framebuffer height is 11 bits max
constexpr int width_limit = (1 << 11);
const GSVector4i disp1_rect = GetFrameRect(0, true);
const GSVector4i disp2_rect = GetFrameRect(1, true);
const GSVector4i combined = disp1_rect.runion(disp2_rect);
const int max_width = std::max(disp1_rect.width(), disp2_rect.width());
return max_width;
}
bool GSState::IsEnabled(int i) bool GSState::IsEnabled(int i)
{ {
ASSERT(i >= 0 && i < 2); ASSERT(i >= 0 && i < 2);

View File

@ -322,6 +322,7 @@ public:
void ResetHandlers(); void ResetHandlers();
int GetFramebufferHeight(); int GetFramebufferHeight();
int GetFramebufferWidth();
int GetDisplayHMagnification(); int GetDisplayHMagnification();
GSVector4i GetDisplayRect(int i = -1); GSVector4i GetDisplayRect(int i = -1);
GSVector4i GetFrameMagnifiedRect(int i = -1); GSVector4i GetFrameMagnifiedRect(int i = -1);

View File

@ -239,10 +239,11 @@ GSTexture* GSRendererHW::GetOutput(int i, int& y_offset)
const int videomode = static_cast<int>(GetVideoMode()) - 1; const int videomode = static_cast<int>(GetVideoMode()) - 1;
const GSVector4i offsets = !GSConfig.PCRTCOverscan ? VideoModeOffsets[videomode] : VideoModeOffsetsOverscan[videomode]; const GSVector4i offsets = !GSConfig.PCRTCOverscan ? VideoModeOffsets[videomode] : VideoModeOffsetsOverscan[videomode];
const int fb_width = std::min<int>(std::min<int>(GetFramebufferWidth(), DISPFB.FBW * 64) + (int)DISPFB.DBX, 2048);
const int display_height = offsets.y * ((isinterlaced() && !m_regs->SMODE2.FFMD) ? 2 : 1); const int display_height = offsets.y * ((isinterlaced() && !m_regs->SMODE2.FFMD) ? 2 : 1);
const int display_offset = GetResolutionOffset(i).y; const int display_offset = GetResolutionOffset(i).y;
int fb_height = std::min<int>(std::min<int>(GetFramebufferHeight(), display_height) + (int)DISPFB.DBY, 2048); int fb_height = std::min<int>(std::min<int>(GetFramebufferHeight(), display_height) + (int)DISPFB.DBY, 2048);
// If there is a negative vertical offset on the picture, we need to read more. // If there is a negative vertical offset on the picture, we need to read more.
if (display_offset < 0) if (display_offset < 0)
{ {
@ -253,11 +254,7 @@ GSTexture* GSRendererHW::GetOutput(int i, int& y_offset)
GSTexture* t = nullptr; GSTexture* t = nullptr;
GSVector2i size = GetOutputSize(fb_height); GSVector2i size = GetOutputSize(fb_height);
// Expand read horizontally if offset in to the texture. (Causes visible stretching on FMVs otherwise) if (GSTextureCache::Target* rt = m_tc->LookupDisplayTarget(TEX0, GetOutputSize(fb_height), fb_height, fb_width))
if (DISPFB.DBX)
size.x += DISPFB.DBX;
if (GSTextureCache::Target* rt = m_tc->LookupDisplayTarget(TEX0, size, fb_height))
{ {
t = rt->m_texture; t = rt->m_texture;
@ -293,7 +290,12 @@ GSTexture* GSRendererHW::GetFeedbackOutput()
TEX0.PSM = m_regs->DISP[m_regs->EXTBUF.FBIN & 1].DISPFB.PSM; TEX0.PSM = m_regs->DISP[m_regs->EXTBUF.FBIN & 1].DISPFB.PSM;
const int fb_height = /*GetFrameRect(i).bottom*/ m_regs->DISP[m_regs->EXTBUF.FBIN & 1].DISPLAY.DH; const int fb_height = /*GetFrameRect(i).bottom*/ m_regs->DISP[m_regs->EXTBUF.FBIN & 1].DISPLAY.DH;
GSTextureCache::Target* rt = m_tc->LookupDisplayTarget(TEX0, GetOutputSize(fb_height), fb_height); GSVector2i size = GetOutputSize(fb_height);
if (m_regs->DISP[m_regs->EXTBUF.FBIN & 1].DISPFB.DBX)
size.x += m_regs->DISP[m_regs->EXTBUF.FBIN & 1].DISPFB.DBX * static_cast<int>(GSConfig.UpscaleMultiplier);
GSTextureCache::Target* rt = m_tc->LookupDisplayTarget(TEX0, GetOutputSize(fb_height), fb_height, size.x);
GSTexture* t = rt->m_texture; GSTexture* t = rt->m_texture;

View File

@ -414,7 +414,7 @@ GSTextureCache::Source* GSTextureCache::LookupSource(const GIFRegTEX0& TEX0, con
return src; return src;
} }
GSTextureCache::Target* GSTextureCache::LookupTarget(const GIFRegTEX0& TEX0, const GSVector2i& size, int type, bool used, u32 fbmask, const bool is_frame, const int real_h) GSTextureCache::Target* GSTextureCache::LookupTarget(const GIFRegTEX0& TEX0, const GSVector2i& size, int type, bool used, u32 fbmask, const bool is_frame, const int real_h, const int real_w)
{ {
const GSLocalMemory::psm_t& psm_s = GSLocalMemory::m_psm[TEX0.PSM]; const GSLocalMemory::psm_t& psm_s = GSLocalMemory::m_psm[TEX0.PSM];
const GSVector2& new_s = static_cast<GSRendererHW*>(g_gs_renderer.get())->GetTextureScaleFactor(); const GSVector2& new_s = static_cast<GSRendererHW*>(g_gs_renderer.get())->GetTextureScaleFactor();
@ -469,8 +469,8 @@ GSTextureCache::Target* GSTextureCache::LookupTarget(const GIFRegTEX0& TEX0, con
{ {
dst = t; dst = t;
GL_CACHE("TC: Lookup Frame %dx%d, perfect hit: %d (0x%x -> 0x%x %s)", size.x, size.y, dst->m_texture->GetID(), bp, t->m_end_block, psm_str(TEX0.PSM)); GL_CACHE("TC: Lookup Frame %dx%d, perfect hit: %d (0x%x -> 0x%x %s)", size.x, size.y, dst->m_texture->GetID(), bp, t->m_end_block, psm_str(TEX0.PSM));
if (real_h > 0) if (real_h > 0 || real_w > 0)
ScaleTargetForDisplay(dst, TEX0, real_h); ScaleTargetForDisplay(dst, TEX0, real_h, real_w);
break; break;
} }
@ -485,8 +485,8 @@ GSTextureCache::Target* GSTextureCache::LookupTarget(const GIFRegTEX0& TEX0, con
{ {
dst = t; dst = t;
GL_CACHE("TC: Lookup Frame %dx%d, inclusive hit: %d (0x%x, took 0x%x -> 0x%x %s)", size.x, size.y, t->m_texture->GetID(), bp, t->m_TEX0.TBP0, t->m_end_block, psm_str(TEX0.PSM)); GL_CACHE("TC: Lookup Frame %dx%d, inclusive hit: %d (0x%x, took 0x%x -> 0x%x %s)", size.x, size.y, t->m_texture->GetID(), bp, t->m_TEX0.TBP0, t->m_end_block, psm_str(TEX0.PSM));
if (real_h > 0) if (real_h > 0 || real_w > 0)
ScaleTargetForDisplay(dst, TEX0, real_h); ScaleTargetForDisplay(dst, TEX0, real_h, real_w);
break; break;
} }
@ -623,12 +623,12 @@ GSTextureCache::Target* GSTextureCache::LookupTarget(const GIFRegTEX0& TEX0, con
return dst; return dst;
} }
GSTextureCache::Target* GSTextureCache::LookupDisplayTarget(const GIFRegTEX0& TEX0, const GSVector2i& size, const int real_h) GSTextureCache::Target* GSTextureCache::LookupDisplayTarget(const GIFRegTEX0& TEX0, const GSVector2i& size, const int real_h, const int real_w)
{ {
return LookupTarget(TEX0, size, RenderTarget, true, 0, true, real_h); return LookupTarget(TEX0, size, RenderTarget, true, 0, true, real_h, real_w);
} }
void GSTextureCache::ScaleTargetForDisplay(Target* t, const GIFRegTEX0& dispfb, int real_h) void GSTextureCache::ScaleTargetForDisplay(Target* t, const GIFRegTEX0& dispfb, int real_h, int real_w)
{ {
// This handles a case where you have two images stacked on top of one another (usually FMVs), and // This handles a case where you have two images stacked on top of one another (usually FMVs), and
// the size of the top framebuffer is larger than the height of the image. Usually happens when // the size of the top framebuffer is larger than the height of the image. Usually happens when
@ -656,11 +656,13 @@ void GSTextureCache::ScaleTargetForDisplay(Target* t, const GIFRegTEX0& dispfb,
GSTexture* old_texture = t->m_texture; GSTexture* old_texture = t->m_texture;
const int needed_height = std::min(real_h + y_offset, GSRendererHW::MAX_FRAMEBUFFER_HEIGHT); const int needed_height = std::min(real_h + y_offset, GSRendererHW::MAX_FRAMEBUFFER_HEIGHT);
const int scaled_needed_height = static_cast<int>(static_cast<float>(needed_height) * old_texture->GetScale().y); const int scaled_needed_height = static_cast<int>(static_cast<float>(needed_height) * old_texture->GetScale().y);
if (scaled_needed_height <= old_texture->GetHeight()) const int needed_width = std::min(real_w, static_cast<int>(dispfb.TBW * 64));
const int scaled_needed_width = static_cast<int>(static_cast<float>(needed_width) * old_texture->GetScale().x);
if (scaled_needed_height <= old_texture->GetHeight() && scaled_needed_width <= old_texture->GetWidth())
return; return;
// We're expanding, so create a new texture. // We're expanding, so create a new texture.
GSTexture* new_texture = g_gs_device->CreateRenderTarget(old_texture->GetWidth(), scaled_needed_height, GSTexture::Format::Color, false); GSTexture* new_texture = g_gs_device->CreateRenderTarget(scaled_needed_width, scaled_needed_height, GSTexture::Format::Color, false);
if (!new_texture) if (!new_texture)
{ {
// Memory allocation failure, do our best to hobble along. // Memory allocation failure, do our best to hobble along.

View File

@ -311,7 +311,7 @@ protected:
/// Expands a target when the block pointer for a display framebuffer is within another target, but the read offset /// Expands a target when the block pointer for a display framebuffer is within another target, but the read offset
/// plus the height is larger than the current size of the target. /// plus the height is larger than the current size of the target.
void ScaleTargetForDisplay(Target* t, const GIFRegTEX0& dispfb, int real_h); void ScaleTargetForDisplay(Target* t, const GIFRegTEX0& dispfb, int real_h, int real_w);
HashCacheEntry* LookupHashCache(const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA, bool& paltex, const u32* clut, const GSVector2i* lod); HashCacheEntry* LookupHashCache(const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA, bool& paltex, const u32* clut, const GSVector2i* lod);
@ -335,8 +335,8 @@ public:
Source* LookupSource(const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA, const GSVector4i& r, const GSVector2i* lod); Source* LookupSource(const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA, const GSVector4i& r, const GSVector2i* lod);
Source* LookupDepthSource(const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA, const GSVector4i& r, bool palette = false); Source* LookupDepthSource(const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA, const GSVector4i& r, bool palette = false);
Target* LookupTarget(const GIFRegTEX0& TEX0, const GSVector2i& size, int type, bool used, u32 fbmask = 0, const bool is_frame = false, const int real_h = 0); Target* LookupTarget(const GIFRegTEX0& TEX0, const GSVector2i& size, int type, bool used, u32 fbmask = 0, const bool is_frame = false, const int real_h = 0, const int real_w = 0);
Target* LookupDisplayTarget(const GIFRegTEX0& TEX0, const GSVector2i& size, const int real_h); Target* LookupDisplayTarget(const GIFRegTEX0& TEX0, const GSVector2i& size, const int real_h, const int real_w);
/// Looks up a target in the cache, and only returns it if the BP/BW/PSM match exactly. /// Looks up a target in the cache, and only returns it if the BP/BW/PSM match exactly.
Target* GetExactTarget(u32 BP, u32 BW, u32 PSM) const; Target* GetExactTarget(u32 BP, u32 BW, u32 PSM) const;