VideoInterface and Progressive Scan fixes

The "Enable Progressive Scan" option in the Wii menu now controls whether the Wii/GC will detect a progressive scan display.  This affects the timing of some games (both GC and Wii).  Usually, the checkbox should be unticked as progressive scan displays require higher bandwidth.

This fixes the slow speed in NBA JAM.  This also fixes the hang in Megaman Network Transmission.  This should fix Deadly Creatures (turn off progressive scan).

Fixes issue 3314.
Fixes issue 3066.
Fixes issue 2571.

git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@6297 8ced0084-cf51-0410-be5f-012b33b47a6e
This commit is contained in:
skidau 2010-10-21 14:50:42 +00:00
parent 95cfca08e2
commit e9734084ee
9 changed files with 81 additions and 110 deletions

View File

@ -121,6 +121,7 @@ void SConfig::SaveSettings()
ini.Set("Display", "RenderWindowYPos", m_LocalCoreStartupParameter.iRenderWindowYPos);
ini.Set("Display", "RenderWindowWidth", m_LocalCoreStartupParameter.iRenderWindowWidth);
ini.Set("Display", "RenderWindowHeight", m_LocalCoreStartupParameter.iRenderWindowHeight);
ini.Set("Display", "ProgressiveScan", m_LocalCoreStartupParameter.bProgressive);
// Game List Control
ini.Set("GameList", "ListDrives", m_ListDrives);
@ -243,6 +244,7 @@ void SConfig::LoadSettings()
ini.Get("Display", "RenderWindowYPos", &m_LocalCoreStartupParameter.iRenderWindowYPos, 0);
ini.Get("Display", "RenderWindowWidth", &m_LocalCoreStartupParameter.iRenderWindowWidth, 640);
ini.Get("Display", "RenderWindowHeight", &m_LocalCoreStartupParameter.iRenderWindowHeight, 480);
ini.Get("Display", "ProgressiveScan", &m_LocalCoreStartupParameter.bProgressive, false);
// Game List Control
ini.Get("GameList", "ListDrives", &m_ListDrives, false);

View File

@ -56,6 +56,7 @@ SCoreStartupParameter::SCoreStartupParameter()
iRenderWindowXPos(0), iRenderWindowYPos(0),
iRenderWindowWidth(640), iRenderWindowHeight(480),
bFullscreen(false), bRenderToMain(false),
bProgressive(false),
iTheme(0),
iPosX(100), iPosY(100), iWidth(800), iHeight(600)
{

View File

@ -101,6 +101,7 @@ struct SCoreStartupParameter
int iRenderWindowXPos, iRenderWindowYPos;
int iRenderWindowWidth, iRenderWindowHeight;
bool bFullscreen, bRenderToMain;
bool bProgressive;
int iTheme;
int iPosX, iPosY, iWidth, iHeight;

View File

@ -182,7 +182,7 @@ void IPC_HLE_UpdateCallback(u64 userdata, int cyclesLate)
void VICallback(u64 userdata, int cyclesLate)
{
VideoInterface::Update();
CoreTiming::ScheduleEvent(VideoInterface::GetTicksPerFrame() - cyclesLate, et_VI);
CoreTiming::ScheduleEvent(VideoInterface::GetTicksPerLine() - cyclesLate, et_VI);
}
void SICallback(u64 userdata, int cyclesLate)
@ -278,7 +278,7 @@ void Init()
// This is the biggest question mark.
AI_PERIOD = GetTicksPerSecond() / 80;
// System internal sample rate is fixed at 32KHz
// System internal sample rate is fixed at 32KHz * 4 (16bit Stereo) / 32 bytes DMA
AUDIO_DMA_PERIOD = CPU_CORE_CLOCK / (32000 * 4 / 32);
Common::Timer::IncreaseResolution();
@ -301,7 +301,7 @@ void Init()
et_PatchEngine = CoreTiming::RegisterEvent("PatchEngine", PatchEngineCallback);
CoreTiming::ScheduleEvent(AI_PERIOD, et_AI);
CoreTiming::ScheduleEvent(VideoInterface::GetTicksPerFrame(), et_VI);
CoreTiming::ScheduleEvent(VideoInterface::GetTicksPerLine(), et_VI);
CoreTiming::ScheduleEvent(DSP_PERIOD, et_DSP);
CoreTiming::ScheduleEvent(VideoInterface::GetTicksPerFrame(), et_SI);
CoreTiming::ScheduleEvent(AUDIO_DMA_PERIOD, et_AudioDMA);

View File

@ -145,17 +145,18 @@ void Preset(bool _bNTSC)
m_VBeamPos = 1;
// 54MHz, capable of progressive scan
m_Clock = 1;
m_Clock = Core::g_CoreStartupParameter.bProgressive?1:0;
// Say component cable is plugged
m_DTVStatus = 1;
m_DTVStatus = Core::g_CoreStartupParameter.bProgressive?1:0;
UpdateParameters();
}
void SetRegionReg(char _region)
{
m_DTVStatus = _region | (m_DTVStatus & 1);
if (Core::g_CoreStartupParameter.bProgressive)
m_DTVStatus = _region | (m_DTVStatus & 1);
}
void Init()
@ -280,6 +281,8 @@ void Read16(u16& _uReturnValue, const u32 _iAddress)
// RETRACE STUFF ...
case VI_PRERETRACE_HI:
_uReturnValue = m_InterruptRegister[0].Hi;
m_InterruptRegister[0].IR_INT = 0;
UpdateInterrupts();
return;
case VI_PRERETRACE_LO:
_uReturnValue = m_InterruptRegister[0].Lo;
@ -287,6 +290,8 @@ void Read16(u16& _uReturnValue, const u32 _iAddress)
case VI_POSTRETRACE_HI:
_uReturnValue = m_InterruptRegister[1].Hi;
m_InterruptRegister[1].IR_INT = 0;
UpdateInterrupts();
return;
case VI_POSTRETRACE_LO:
_uReturnValue = m_InterruptRegister[1].Lo;
@ -294,6 +299,8 @@ void Read16(u16& _uReturnValue, const u32 _iAddress)
case VI_DISPLAY_INTERRUPT_2_HI:
_uReturnValue = m_InterruptRegister[2].Hi;
m_InterruptRegister[2].IR_INT = 0;
UpdateInterrupts();
return;
case VI_DISPLAY_INTERRUPT_2_LO:
_uReturnValue = m_InterruptRegister[2].Lo;
@ -301,6 +308,8 @@ void Read16(u16& _uReturnValue, const u32 _iAddress)
case VI_DISPLAY_INTERRUPT_3_HI:
_uReturnValue = m_InterruptRegister[3].Hi;
m_InterruptRegister[3].IR_INT = 0;
UpdateInterrupts();
return;
case VI_DISPLAY_INTERRUPT_3_LO:
_uReturnValue = m_InterruptRegister[3].Lo;
@ -528,7 +537,6 @@ void Write16(const u16 _iValue, const u32 _iAddress)
// RETRACE STUFF ...
case VI_PRERETRACE_HI:
m_InterruptRegister[0].Hi = _iValue;
UpdateInterrupts();
break;
case VI_PRERETRACE_LO:
m_InterruptRegister[0].Lo = _iValue;
@ -536,7 +544,6 @@ void Write16(const u16 _iValue, const u32 _iAddress)
case VI_POSTRETRACE_HI:
m_InterruptRegister[1].Hi = _iValue;
UpdateInterrupts();
break;
case VI_POSTRETRACE_LO:
m_InterruptRegister[1].Lo = _iValue;
@ -544,7 +551,6 @@ void Write16(const u16 _iValue, const u32 _iAddress)
case VI_DISPLAY_INTERRUPT_2_HI:
m_InterruptRegister[2].Hi = _iValue;
UpdateInterrupts();
break;
case VI_DISPLAY_INTERRUPT_2_LO:
m_InterruptRegister[2].Lo = _iValue;
@ -552,7 +558,6 @@ void Write16(const u16 _iValue, const u32 _iAddress)
case VI_DISPLAY_INTERRUPT_3_HI:
m_InterruptRegister[3].Hi = _iValue;
UpdateInterrupts();
break;
case VI_DISPLAY_INTERRUPT_3_LO:
m_InterruptRegister[3].Lo = _iValue;
@ -717,23 +722,19 @@ void UpdateParameters()
case 0: // NTSC
case 2: // PAL-M
TargetRefreshRate = NTSC_FIELD_RATE;
// AyuanX: Some games are pretty sensitive to this value
// So we have to make it run a little faster to prevent potential time out
TicksPerFrame = SystemTimers::GetTicksPerSecond() / (NTSC_FIELD_RATE + 1);
s_lineCount = m_DisplayControlRegister.NIN ? NTSC_LINE_COUNT : (NTSC_LINE_COUNT+1)/2;
//s_upperFieldBegin = NTSC_UPPER_BEGIN;
//s_lowerFieldBegin = NTSC_LOWER_BEGIN;
break;
TicksPerFrame = SystemTimers::GetTicksPerSecond() / (NTSC_FIELD_RATE / 2);
s_lineCount = NTSC_LINE_COUNT;
s_upperFieldBegin = NTSC_UPPER_BEGIN;
s_lowerFieldBegin = NTSC_LOWER_BEGIN;
break;
case 1: // PAL
TargetRefreshRate = PAL_FIELD_RATE;
// AyuanX: Some games are pretty sensitive to this value
// So we have to make it run a little faster to prevent potential time out
TicksPerFrame = SystemTimers::GetTicksPerSecond() / (PAL_FIELD_RATE + 1);
s_lineCount = m_DisplayControlRegister.NIN ? PAL_LINE_COUNT : (PAL_LINE_COUNT+1)/2;
//s_upperFieldBegin = PAL_UPPER_BEGIN;
//s_lowerFieldBegin = PAL_LOWER_BEGIN;
break;
TicksPerFrame = SystemTimers::GetTicksPerSecond() / (PAL_FIELD_RATE / 2);
s_lineCount = PAL_LINE_COUNT;
s_upperFieldBegin = PAL_UPPER_BEGIN;
s_lowerFieldBegin = PAL_LOWER_BEGIN;
break;
case 3: // Debug
PanicAlert("Debug video mode not implemented");
@ -748,9 +749,13 @@ void UpdateParameters()
int GetTicksPerLine()
{
if (s_lineCount == 0)
return 100000;
{
return 1;
}
else
return TicksPerFrame / s_lineCount;
{
return TicksPerFrame / (s_lineCount * 2);
}
}
int GetTicksPerFrame()
@ -781,35 +786,56 @@ static void BeginField(FieldType field)
video->Video_BeginField(xfbAddr, field, fbWidth, fbHeight);
}
/*
static void EndField()
{
Common::PluginVideo* video = CPluginManager::GetInstance().GetVideo();
if (video->IsValid())
{
video->Video_EndField();
Core::VideoThrottle();
}
}
*/
// AyuanX: No need to update per scan line, update per frame is good enough, and faster
// Purpose: Send VI interrupt when triggered
// Run when: When a frame is scaned (progressive/interlace)
// Run when: When a frame is scanned (progressive/interlace)
void Update()
{
u16 NewVBeamPos;
u16 NewVBeamPos = 0;
if (m_DisplayControlRegister.NIN)
{
// Progressive
NewVBeamPos = s_lineCount + 1;
BeginField(FIELD_PROGRESSIVE);
}
else if (m_VBeamPos == s_lineCount)
else if (m_VBeamPos == s_upperFieldBegin)
{
// Interlace Upper
NewVBeamPos = s_lineCount * 2;
BeginField(FIELD_UPPER);
}
else
else if (m_VBeamPos == s_lowerFieldBegin)
{
// Interlace Lower
NewVBeamPos = s_lineCount;
BeginField(FIELD_LOWER);
}
if (m_DisplayControlRegister.NIN)
{
// Progressive
if (m_VBeamPos == s_lineCount)
EndField();
}
else if (m_VBeamPos == s_upperFieldBegin + m_VerticalTimingRegister.ACV)
{
// Interlace Upper. Do not EndField (swapBuffer) at the end of the upper field.
//EndField();
}
else if (m_VBeamPos == s_lowerFieldBegin + m_VerticalTimingRegister.ACV)
{
// Interlace Lower
EndField();
}
for (int i = 0; i < 4; i++)
@ -819,62 +845,10 @@ void Update()
}
UpdateInterrupts();
if (m_DisplayControlRegister.NIN)
if (++m_VBeamPos > s_lineCount)
{
// Progressive
BeginField(FIELD_PROGRESSIVE);
m_VBeamPos = (NewVBeamPos > s_lineCount) ? 1 : NewVBeamPos;
}
else if (m_VBeamPos == s_lineCount)
{
// Interlace Upper
BeginField(FIELD_UPPER);
}
else
{
// Interlace Lower
BeginField(FIELD_LOWER);
}
m_VBeamPos = (NewVBeamPos > s_lineCount) ? 1 : NewVBeamPos;
Core::VideoThrottle();
}
/*
// Purpose: Send VI interrupt when triggered
// Run when: When a line is scaned
void Update()
{
// TODO: What's the correct behavior for progressive mode?
if (m_VBeamPos == s_upperFieldBegin + m_VerticalTimingRegister.ACV)
EndField();
else if (m_VBeamPos == s_lowerFieldBegin + m_VerticalTimingRegister.ACV)
EndField();
if (++m_VBeamPos > s_lineCount)
{
m_VBeamPos = 1;
// Apply video throttle whenever a full screen scan finishes
Core::VideoThrottle();
}
for (int i = 0; i < 4; ++i)
{
if (m_InterruptRegister[i].VCT == m_VBeamPos)
m_InterruptRegister[i].IR_INT = 1;
}
UpdateInterrupts();
if (m_VBeamPos == s_upperFieldBegin)
BeginField(m_DisplayControlRegister.NIN ? FIELD_PROGRESSIVE : FIELD_UPPER);
else if (m_VBeamPos == s_lowerFieldBegin)
BeginField(m_DisplayControlRegister.NIN ? FIELD_PROGRESSIVE : FIELD_LOWER);
}
*/
} // namespace

View File

@ -1039,6 +1039,7 @@ void CConfigMain::WiiSettingsChanged(wxCommandEvent& event)
break;
case ID_WII_IPL_PGS:
SConfig::GetInstance().m_SYSCONF->SetData("IPL.PGS", WiiProgressiveScan->IsChecked());
SConfig::GetInstance().m_LocalCoreStartupParameter.bProgressive = WiiProgressiveScan->IsChecked();
break;
case ID_WII_IPL_E60:
SConfig::GetInstance().m_SYSCONF->SetData("IPL.E60", WiiEuRGB60->IsChecked());

View File

@ -863,7 +863,7 @@ void CISOProperties::LoadGameConfig()
else
BlockMerging->Set3StateValue(wxCHK_UNDETERMINED);
if (GameIni.Get("Wii", "ProgressiveScan", &bTemp))
if (GameIni.Get("Display", "ProgressiveScan", &bTemp))
EnableProgressiveScan->Set3StateValue((wxCheckBoxState)bTemp);
else
EnableProgressiveScan->Set3StateValue(wxCHK_UNDETERMINED);
@ -980,9 +980,9 @@ bool CISOProperties::SaveGameConfig()
GameIni.Set("Core", "BlockMerging", BlockMerging->Get3StateValue());
if (EnableProgressiveScan->Get3StateValue() == wxCHK_UNDETERMINED)
GameIni.DeleteKey("Wii", "ProgressiveScan");
GameIni.DeleteKey("Display", "ProgressiveScan");
else
GameIni.Set("Wii", "ProgressiveScan", EnableProgressiveScan->Get3StateValue());
GameIni.Set("Display", "ProgressiveScan", EnableProgressiveScan->Get3StateValue());
if (EnableWideScreen->Get3StateValue() == wxCHK_UNDETERMINED)
GameIni.DeleteKey("Wii", "Widescreen");

View File

@ -357,26 +357,22 @@ void Video_BeginField(u32 xfbAddr, FieldType field, u32 fbWidth, u32 fbHeight)
{
if (s_PluginInitialized && g_ActiveConfig.bUseXFB)
{
if (g_VideoInitialize.bOnThread)
{
while (Common::AtomicLoadAcquire(s_swapRequested) && !s_FifoShuttingDown)
//Common::SleepCurrentThread(1);
Common::YieldCPU();
}
else
if (!g_VideoInitialize.bOnThread)
VideoFifo_CheckSwapRequest();
s_beginFieldArgs.xfbAddr = xfbAddr;
s_beginFieldArgs.field = field;
s_beginFieldArgs.fbWidth = fbWidth;
s_beginFieldArgs.fbHeight = fbHeight;
Common::AtomicStoreRelease(s_swapRequested, TRUE);
}
}
// Run from the CPU thread (from VideoInterface.cpp)
void Video_EndField()
{
if (s_PluginInitialized)
{
Common::AtomicStoreRelease(s_swapRequested, TRUE);
}
}
void Video_AddMessage(const char* pstr, u32 milliseconds)

View File

@ -387,26 +387,22 @@ void Video_BeginField(u32 xfbAddr, FieldType field, u32 fbWidth, u32 fbHeight)
{
if (s_PluginInitialized && g_ActiveConfig.bUseXFB)
{
if (g_VideoInitialize.bOnThread)
{
while (Common::AtomicLoadAcquire(s_swapRequested) && !s_FifoShuttingDown)
//Common::SleepCurrentThread(1);
Common::YieldCPU();
}
else
if (!g_VideoInitialize.bOnThread)
VideoFifo_CheckSwapRequest();
s_beginFieldArgs.xfbAddr = xfbAddr;
s_beginFieldArgs.field = field;
s_beginFieldArgs.fbWidth = fbWidth;
s_beginFieldArgs.fbHeight = fbHeight;
Common::AtomicStoreRelease(s_swapRequested, TRUE);
}
}
// Run from the CPU thread (from VideoInterface.cpp)
void Video_EndField()
{
if (s_PluginInitialized)
{
Common::AtomicStoreRelease(s_swapRequested, TRUE);
}
}
void Video_AddMessage(const char* pstr, u32 milliseconds)