From 2db2f3dce9df8aa28a7f102acb38563078bf5daa Mon Sep 17 00:00:00 2001 From: magumagu Date: Fri, 2 May 2014 22:56:02 -0700 Subject: [PATCH 1/3] VideoInterface: accurate XFB width and height. What we call "fbWidth" here is really the stride, but I'll fix that in a followup. --- Source/Core/Core/HW/VideoInterface.cpp | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/Source/Core/Core/HW/VideoInterface.cpp b/Source/Core/Core/HW/VideoInterface.cpp index 2cff0a4373..547a20ddb5 100644 --- a/Source/Core/Core/HW/VideoInterface.cpp +++ b/Source/Core/Core/HW/VideoInterface.cpp @@ -505,8 +505,18 @@ unsigned int GetTicksPerFrame() static void BeginField(FieldType field) { - u32 fbWidth = m_HorizontalStepping.FieldSteps * 16; - u32 fbHeight = (m_HorizontalStepping.FbSteps / m_HorizontalStepping.FieldSteps) * m_VerticalTimingRegister.ACV; + // TODO: the stride and height shouldn't depend on whether the FieldType is + // "progressive". We're actually telling the video backend to draw unspecified + // junk. Due to the way XFB copies work, the unspecified junk is usually + // the contents of the other field, so it looks okay in most cases, but we + // shouldn't depend on that; a good example of where our output is wrong is + // the title screen teaser videos in Metroid Prime. + // + // What should actually happen is that we should pass on the correct width, + // stride, and height to the video backend, and it should deinterlace the + // output when appropriate. + u32 fbWidth = m_HorizontalStepping.FbSteps * (field == FIELD_PROGRESSIVE ? 16 : 8); + u32 fbHeight = m_VerticalTimingRegister.ACV * (field == FIELD_PROGRESSIVE ? 1 : 2); u32 xfbAddr; // NTSC and PAL have opposite field orders. From 716b3fefd423fc443b3280a65336e9bc0504d96c Mon Sep 17 00:00:00 2001 From: magumagu Date: Fri, 2 May 2014 23:07:55 -0700 Subject: [PATCH 2/3] VideoCommon: recreate XFB texture when the XFB size changes. We need to do this to correctly deal with games which dynamically change the XFB width and height. --- Source/Core/VideoCommon/FramebufferManagerBase.cpp | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/Source/Core/VideoCommon/FramebufferManagerBase.cpp b/Source/Core/VideoCommon/FramebufferManagerBase.cpp index f23af5e36c..6e26dea190 100644 --- a/Source/Core/VideoCommon/FramebufferManagerBase.cpp +++ b/Source/Core/VideoCommon/FramebufferManagerBase.cpp @@ -46,6 +46,13 @@ const XFBSourceBase* const* FramebufferManagerBase::GetRealXFBSource(u32 xfbAddr { xfbCount = 1; + // recreate if needed + if (m_realXFBSource && (m_realXFBSource->texWidth != fbWidth || m_realXFBSource->texHeight != fbHeight)) + { + delete m_realXFBSource; + m_realXFBSource = nullptr; + } + if (!m_realXFBSource) m_realXFBSource = g_framebuffer_manager->CreateXFBSource(fbWidth, fbHeight); @@ -142,8 +149,8 @@ void FramebufferManagerBase::CopyToVirtualXFB(u32 xfbAddr, u32 fbWidth, u32 fbHe // recreate if needed if (vxfb->xfbSource && (vxfb->xfbSource->texWidth != target_width || vxfb->xfbSource->texHeight != target_height)) { - //delete vxfb->xfbSource; - //vxfb->xfbSource = nullptr; + delete vxfb->xfbSource; + vxfb->xfbSource = nullptr; } if (!vxfb->xfbSource) From c01ac18d4d107b8fb85fed730423c3a490869a9e Mon Sep 17 00:00:00 2001 From: magumagu Date: Sat, 3 May 2014 11:40:06 -0700 Subject: [PATCH 3/3] VideoInterface: clean up naming and bitfields. Matching the hardware more closely will hopefully make this code easier to read. --- Source/Core/Core/HW/VideoInterface.cpp | 24 +++++++++++----------- Source/Core/Core/HW/VideoInterface.h | 28 +++++++++++++++++--------- 2 files changed, 31 insertions(+), 21 deletions(-) diff --git a/Source/Core/Core/HW/VideoInterface.cpp b/Source/Core/Core/HW/VideoInterface.cpp index 547a20ddb5..ee83dcbd29 100644 --- a/Source/Core/Core/HW/VideoInterface.cpp +++ b/Source/Core/Core/HW/VideoInterface.cpp @@ -39,13 +39,13 @@ static u16 m_VBeamPos = 0; // 0: Inactive static u16 m_HBeamPos = 0; // 0: Inactive static UVIInterruptRegister m_InterruptRegister[4]; static UVILatchRegister m_LatchRegister[2]; -static UVIHorizontalStepping m_HorizontalStepping; +static PictureConfigurationRegister m_PictureConfiguration; static UVIHorizontalScaling m_HorizontalScaling; static SVIFilterCoefTables m_FilterCoefTables; static u32 m_UnkAARegister = 0;// ??? 0x00FF0000 static u16 m_Clock = 0; // 0: 27MHz, 1: 54MHz static UVIDTVStatus m_DTVStatus; -static u16 m_FBWidth = 0; // Only correct when scaling is enabled? +static UVIHorizontalStepping m_FBWidth; // Only correct when scaling is enabled? static UVIBorderBlankRegister m_BorderHBlank; // 0xcc002076 - 0xcc00207f is full of 0x00FF: unknown // 0xcc002080 - 0xcc002100 even more unknown @@ -76,7 +76,7 @@ void DoState(PointerWrap &p) p.Do(m_HBeamPos); p.DoArray(m_InterruptRegister, 4); p.DoArray(m_LatchRegister, 2); - p.Do(m_HorizontalStepping); + p.Do(m_PictureConfiguration); p.DoPOD(m_HorizontalScaling); p.Do(m_FilterCoefTables); p.Do(m_UnkAARegister); @@ -129,8 +129,8 @@ void Preset(bool _bNTSC) m_InterruptRegister[1].IR_MASK = 1; m_InterruptRegister[1].IR_INT = 0; - m_HorizontalStepping.FbSteps = 40; - m_HorizontalStepping.FieldSteps = 40; + m_PictureConfiguration.STD = 40; + m_PictureConfiguration.WPL = 40; m_HBeamPos = -1; // NTSC-U N64 VC games check for a non-zero HBeamPos m_VBeamPos = 0; // RG4JC0 checks for a zero VBeamPos @@ -160,12 +160,12 @@ void Init() m_3DFBInfoBottom.Hex = 0; m_VBeamPos = 0; m_HBeamPos = 0; - m_HorizontalStepping.Hex = 0; + m_PictureConfiguration.Hex = 0; m_HorizontalScaling.Hex = 0; m_UnkAARegister = 0; m_Clock = 0; m_DTVStatus.Hex = 0; - m_FBWidth = 0; + m_FBWidth.Hex = 0; m_BorderHBlank.Hex = 0; memset(&m_FilterCoefTables, 0, sizeof(m_FilterCoefTables)); @@ -218,7 +218,7 @@ void RegisterMMIO(MMIO::Mapping* mmio, u32 base) { VI_DISPLAY_LATCH_0_LO, &m_LatchRegister[0].Lo }, { VI_DISPLAY_LATCH_1_HI, &m_LatchRegister[1].Hi }, { VI_DISPLAY_LATCH_1_LO, &m_LatchRegister[1].Lo }, - { VI_HSCALEW, &m_HorizontalStepping.Hex }, + { VI_HSCALEW, &m_PictureConfiguration.Hex }, { VI_HSCALER, &m_HorizontalScaling.Hex }, { VI_FILTER_COEF_0_HI, &m_FilterCoefTables.Tables02[0].Hi }, { VI_FILTER_COEF_0_LO, &m_FilterCoefTables.Tables02[0].Lo }, @@ -236,7 +236,7 @@ void RegisterMMIO(MMIO::Mapping* mmio, u32 base) { VI_FILTER_COEF_6_LO, &m_FilterCoefTables.Tables36[3].Lo }, { VI_CLOCK, &m_Clock }, { VI_DTV_STATUS, &m_DTVStatus.Hex }, - { VI_FBWIDTH, &m_FBWidth }, + { VI_FBWIDTH, &m_FBWidth.Hex }, { VI_BORDER_BLANK_END, &m_BorderHBlank.Lo }, { VI_BORDER_BLANK_START, &m_BorderHBlank.Hi }, }; @@ -515,7 +515,7 @@ static void BeginField(FieldType field) // What should actually happen is that we should pass on the correct width, // stride, and height to the video backend, and it should deinterlace the // output when appropriate. - u32 fbWidth = m_HorizontalStepping.FbSteps * (field == FIELD_PROGRESSIVE ? 16 : 8); + u32 fbWidth = m_PictureConfiguration.STD * (field == FIELD_PROGRESSIVE ? 16 : 8); u32 fbHeight = m_VerticalTimingRegister.ACV * (field == FIELD_PROGRESSIVE ? 1 : 2); u32 xfbAddr; @@ -545,8 +545,8 @@ static void BeginField(FieldType field) static const char* const fieldTypeNames[] = { "Progressive", "Upper", "Lower" }; DEBUG_LOG(VIDEOINTERFACE, - "(VI->BeginField): Address: %.08X | FieldSteps %u | FbSteps %u | ACV %u | Field %s", - xfbAddr, m_HorizontalStepping.FieldSteps,m_HorizontalStepping.FbSteps, + "(VI->BeginField): Address: %.08X | WPL %u | STD %u | ACV %u | Field %s", + xfbAddr, m_PictureConfiguration.WPL, m_PictureConfiguration.STD, m_VerticalTimingRegister.ACV, fieldTypeNames[field]); if (xfbAddr) diff --git a/Source/Core/Core/HW/VideoInterface.h b/Source/Core/Core/HW/VideoInterface.h index ff4a5c2b10..0ee68ce9eb 100644 --- a/Source/Core/Core/HW/VideoInterface.h +++ b/Source/Core/Core/HW/VideoInterface.h @@ -135,8 +135,8 @@ union UVIHorizontalTiming0 struct { u16 Lo, Hi; }; struct { - u32 HLW : 9; // Halfline Width (W*16 = Width (720)) - u32 : 7; + u32 HLW : 10; // Halfline Width (W*16 = Width (720)) + u32 : 6; u32 HCE : 7; // Horizontal Sync Start to Color Burst End u32 : 1; u32 HCS : 7; // Horizontal Sync Start to Color Burst Start @@ -151,10 +151,9 @@ union UVIHorizontalTiming1 struct { u32 HSY : 7; // Horizontal Sync Width - u32 HBE640 : 9; // Horizontal Sync Start to horizontal blank end - u32 : 1; - u32 HBS640 : 9; // Half line to horizontal blanking start - u32 : 6; + u32 HBE640 : 10; // Horizontal Sync Start to horizontal blank end + u32 HBS640 : 10; // Half line to horizontal blanking start + u32 : 5; }; }; @@ -232,13 +231,14 @@ union UVILatchRegister }; }; -union UVIHorizontalStepping +union PictureConfigurationRegister { u16 Hex; struct { - u16 FbSteps : 8; - u16 FieldSteps : 8; + u16 STD : 8; + u16 WPL : 7; + u16 : 1; }; }; @@ -316,6 +316,16 @@ union UVIDTVStatus }; }; +union UVIHorizontalStepping +{ + u16 Hex; + struct + { + u16 srcwidth : 10; + u16 : 6; + }; +}; + // urgh, ugly externs. extern u32 TargetRefreshRate;