Use different reply delays for various DI commands.

Fixes issue 5983.
This commit is contained in:
Jordan Woyak 2013-02-08 16:20:15 -06:00
parent 95d08db46f
commit a11827cdf0
3 changed files with 55 additions and 6 deletions

View File

@ -84,6 +84,8 @@ static ipc_msg_queue reply_queue; // arm -> ppc
static int enque_reply; static int enque_reply;
static u64 last_reply_time;
void EnqueReplyCallback(u64 userdata, int) void EnqueReplyCallback(u64 userdata, int)
{ {
reply_queue.push_back(userdata); reply_queue.push_back(userdata);
@ -163,6 +165,7 @@ void Reset(bool _bHard)
} }
request_queue.clear(); request_queue.clear();
reply_queue.clear(); reply_queue.clear();
last_reply_time = 0;
} }
void Shutdown() void Shutdown()
@ -246,6 +249,7 @@ void DoState(PointerWrap &p)
{ {
p.Do(request_queue); p.Do(request_queue);
p.Do(reply_queue); p.Do(reply_queue);
p.Do(last_reply_time);
TDeviceMap::const_iterator itr; TDeviceMap::const_iterator itr;
@ -518,8 +522,18 @@ void ExecuteCommand(u32 _Address)
if (CmdSuccess) if (CmdSuccess)
{ {
// Ensure replies happen in order, fairly ugly
// Without this, tons of games fail now that DI commads have different reply delays
int reply_delay = pDevice ? pDevice->GetCmdDelay(_Address) : 0;
const s64 ticks_til_last_reply = last_reply_time - CoreTiming::GetTicks();
if (ticks_til_last_reply > 0)
reply_delay = ticks_til_last_reply;
last_reply_time = CoreTiming::GetTicks() + reply_delay;
// Generate a reply to the IPC command // Generate a reply to the IPC command
int const reply_delay = pDevice ? pDevice->GetCmdDelay(_Address) : 0;
EnqReply(_Address, reply_delay); EnqReply(_Address, reply_delay);
} }
else else

View File

@ -462,8 +462,43 @@ u32 CWII_IPC_HLE_Device_di::ExecuteCommand(u32 _BufferIn, u32 _BufferInSize, u32
return 1; return 1;
} }
int CWII_IPC_HLE_Device_di::GetCmdDelay(u32) int CWII_IPC_HLE_Device_di::GetCmdDelay(u32 _CommandAddress)
{ {
// Less than ~1/150th of a second hangs Oregon Trail at "loading wheel". u32 BufferIn = Memory::Read_U32(_CommandAddress + 0x10);
return SystemTimers::GetTicksPerSecond() / 100; u32 Command = Memory::Read_U32(BufferIn) >> 24;
}
// Hacks below
switch (Command)
{
case DVDLowRead:
case DVDLowUnencryptedRead:
{
u32 const Size = Memory::Read_U32(BufferIn + 0x04);
// Delay depends on size of read, that makes sense, right?
// More than ~1150K "bytes / sec" hangs NSMBWii on boot.
// Less than ~800K "bytes / sec" hangs DKCR randomly.
return SystemTimers::GetTicksPerSecond() / 975000 * Size;
break;
}
case DVDLowClearCoverInterrupt:
// Less than ~1/155th of a second hangs Oregon Trail at "loading wheel".
// More than ~1/140th of a second hangs Resident Evil Archives: Resident Evil Zero.
return SystemTimers::GetTicksPerSecond() / 146;
break;
// case DVDLowAudioBufferConfig:
// case DVDLowInquiry:
// case DVDLowReadDiskID:
// case DVDLowWaitForCoverClose:
// case DVDLowGetCoverReg:
// case DVDLowGetCoverStatus:
// case DVDLowReset:
// case DVDLowClosePartition:
default:
// ranom numbers here!
return SystemTimers::GetTicksPerSecond() / 1500;
break;
}
}

View File

@ -71,7 +71,7 @@ static Common::Event g_compressAndDumpStateSyncEvent;
static std::thread g_save_thread; static std::thread g_save_thread;
// Don't forget to increase this after doing changes on the savestate system // Don't forget to increase this after doing changes on the savestate system
static const u32 STATE_VERSION = 11; static const u32 STATE_VERSION = 12;
struct StateHeader struct StateHeader
{ {