IPCHLE: improve HLE timing.

This change attempts to make calls to WII_IPC_HLE_Interface::Update()
more consistent.  We should be calling it whenever there is something we
can pop from a queue, and this patch does that.

DeviceUpdate() now works independently of Update(): it's now just a periodic
timer for devices which need to regularly update state.

With this change, we need a non-zero default delay for IPC replies because
replies are popped off the queue much more aggressively.

This fixes launching channels from the the System Menu.
This commit is contained in:
magumagu 2014-05-27 20:12:12 -07:00
parent d7736ac714
commit 063ab30e3d
5 changed files with 35 additions and 40 deletions

View File

@ -165,7 +165,7 @@ void IPC_HLE_UpdateCallback(u64 userdata, int cyclesLate)
{ {
if (SConfig::GetInstance().m_LocalCoreStartupParameter.bWii) if (SConfig::GetInstance().m_LocalCoreStartupParameter.bWii)
{ {
WII_IPC_HLE_Interface::Update(); WII_IPC_HLE_Interface::UpdateDevices();
CoreTiming::ScheduleEvent(IPC_HLE_PERIOD - cyclesLate, et_IPC_HLE); CoreTiming::ScheduleEvent(IPC_HLE_PERIOD - cyclesLate, et_IPC_HLE);
} }
} }

View File

@ -76,9 +76,9 @@ IWII_IPC_HLE_Device* es_handles[ES_MAX_COUNT];
typedef std::deque<u32> ipc_msg_queue; typedef std::deque<u32> ipc_msg_queue;
static ipc_msg_queue request_queue; // ppc -> arm static ipc_msg_queue request_queue; // ppc -> arm
static ipc_msg_queue reply_queue; // arm -> ppc static ipc_msg_queue reply_queue; // arm -> ppc
static std::mutex s_reply_queue;
static int enque_reply; static int enque_reply;
static int enque_request;
static u64 last_reply_time; static u64 last_reply_time;
@ -87,8 +87,14 @@ static u64 last_reply_time;
// Please search for examples of this being called elsewhere. // Please search for examples of this being called elsewhere.
void EnqueReplyCallback(u64 userdata, int) void EnqueReplyCallback(u64 userdata, int)
{ {
std::lock_guard<std::mutex> lk(s_reply_queue);
reply_queue.push_back((u32)userdata); reply_queue.push_back((u32)userdata);
Update();
}
void EnqueRequestCallback(u64 userdata, int)
{
request_queue.push_back((u32)userdata);
Update();
} }
void Init() void Init()
@ -134,11 +140,13 @@ void Init()
g_DeviceMap[i] = new IWII_IPC_HLE_Device(i, "_Unimplemented_Device_"); i++; g_DeviceMap[i] = new IWII_IPC_HLE_Device(i, "_Unimplemented_Device_"); i++;
enque_reply = CoreTiming::RegisterEvent("IPCReply", EnqueReplyCallback); enque_reply = CoreTiming::RegisterEvent("IPCReply", EnqueReplyCallback);
enque_request = CoreTiming::RegisterEvent("IPCRequest", EnqueRequestCallback);
} }
void Reset(bool _bHard) void Reset(bool _bHard)
{ {
CoreTiming::RemoveAllEvents(enque_reply); CoreTiming::RemoveAllEvents(enque_reply);
CoreTiming::RemoveAllEvents(enque_request);
for (IWII_IPC_HLE_Device*& dev : g_FdMap) for (IWII_IPC_HLE_Device*& dev : g_FdMap)
{ {
@ -175,12 +183,8 @@ void Reset(bool _bHard)
g_DeviceMap.erase(g_DeviceMap.begin(), g_DeviceMap.end()); g_DeviceMap.erase(g_DeviceMap.begin(), g_DeviceMap.end());
} }
request_queue.clear(); request_queue.clear();
reply_queue.clear();
// lock due to using reply_queue
{
std::lock_guard<std::mutex> lk(s_reply_queue);
reply_queue.clear();
}
last_reply_time = 0; last_reply_time = 0;
} }
@ -264,8 +268,6 @@ IWII_IPC_HLE_Device* CreateFileIO(u32 _DeviceID, const std::string& _rDeviceName
void DoState(PointerWrap &p) void DoState(PointerWrap &p)
{ {
std::lock_guard<std::mutex> lk(s_reply_queue);
p.Do(request_queue); p.Do(request_queue);
p.Do(reply_queue); p.Do(reply_queue);
p.Do(last_reply_time); p.Do(last_reply_time);
@ -537,6 +539,11 @@ void ExecuteCommand(u32 _Address)
// Ensure replies happen in order, fairly ugly // Ensure replies happen in order, fairly ugly
// Without this, tons of games fail now that DI commands have different reply delays // Without this, tons of games fail now that DI commands have different reply delays
int reply_delay = pDevice ? pDevice->GetCmdDelay(_Address) : 0; int reply_delay = pDevice ? pDevice->GetCmdDelay(_Address) : 0;
if (!reply_delay)
{
int delay_us = 250;
reply_delay = SystemTimers::GetTicksPerSecond() / 1000000 * delay_us;
}
const s64 ticks_til_last_reply = last_reply_time - CoreTiming::GetTicks(); const s64 ticks_til_last_reply = last_reply_time - CoreTiming::GetTicks();
@ -555,7 +562,7 @@ void ExecuteCommand(u32 _Address)
// Happens AS SOON AS IPC gets a new pointer! // Happens AS SOON AS IPC gets a new pointer!
void EnqRequest(u32 _Address) void EnqRequest(u32 _Address)
{ {
request_queue.push_back(_Address); CoreTiming::ScheduleEvent(1000, enque_request, _Address);
} }
// Called when IOS module has some reply // Called when IOS module has some reply
@ -567,6 +574,11 @@ void EnqReply(u32 _Address, int cycles_in_future)
CoreTiming::ScheduleEvent(cycles_in_future, enque_reply, _Address); CoreTiming::ScheduleEvent(cycles_in_future, enque_reply, _Address);
} }
void EnqReply_Threadsafe(u32 _Address, int cycles_in_future)
{
CoreTiming::ScheduleEvent_Threadsafe(cycles_in_future, enque_reply, _Address);
}
// This is called every IPC_HLE_PERIOD from SystemTimers.cpp // This is called every IPC_HLE_PERIOD from SystemTimers.cpp
// Takes care of routing ipc <-> ipc HLE // Takes care of routing ipc <-> ipc HLE
void Update() void Update()
@ -574,8 +586,6 @@ void Update()
if (!WII_IPCInterface::IsReady()) if (!WII_IPCInterface::IsReady())
return; return;
UpdateDevices();
if (request_queue.size()) if (request_queue.size())
{ {
WII_IPCInterface::GenerateAck(request_queue.front()); WII_IPCInterface::GenerateAck(request_queue.front());
@ -583,21 +593,15 @@ void Update()
u32 command = request_queue.front(); u32 command = request_queue.front();
request_queue.pop_front(); request_queue.pop_front();
ExecuteCommand(command); ExecuteCommand(command);
return;
#if MAX_LOGLEVEL >= DEBUG_LEVEL
Dolphin_Debugger::PrintCallstack(LogTypes::WII_IPC_HLE, LogTypes::LDEBUG);
#endif
} }
// lock due to using reply_queue if (reply_queue.size())
{ {
std::lock_guard<std::mutex> lk(s_reply_queue); WII_IPCInterface::GenerateReply(reply_queue.front());
if (reply_queue.size()) INFO_LOG(WII_IPC_HLE, "<<-- Reply to IPC Request @ 0x%08x", reply_queue.front());
{ reply_queue.pop_front();
WII_IPCInterface::GenerateReply(reply_queue.front()); return;
INFO_LOG(WII_IPC_HLE, "<<-- Reply to IPC Request @ 0x%08x", reply_queue.front());
reply_queue.pop_front();
}
} }
} }
@ -606,9 +610,9 @@ void UpdateDevices()
// Check if a hardware device must be updated // Check if a hardware device must be updated
for (const auto& entry : g_DeviceMap) for (const auto& entry : g_DeviceMap)
{ {
if (entry.second->IsOpened() && entry.second->Update()) if (entry.second->IsOpened())
{ {
break; entry.second->Update();
} }
} }
} }

View File

@ -29,8 +29,6 @@ namespace WII_IPC_HLE_Interface
#define IPC_FIRST_ID 0x00 // First IPC device ID #define IPC_FIRST_ID 0x00 // First IPC device ID
#define IPC_MAX_FILES 0x10 // First IPC file ID #define IPC_MAX_FILES 0x10 // First IPC file ID
void EnqueReplyCallback(u64 userdata, int =0);
// Init // Init
void Init(); void Init();
@ -66,5 +64,6 @@ void ExecuteCommand(u32 _Address);
void EnqRequest(u32 _Address); void EnqRequest(u32 _Address);
void EnqReply(u32 _Address, int cycles_in_future = 0); void EnqReply(u32 _Address, int cycles_in_future = 0);
void EnqReply_Threadsafe(u32 _Address, int cycles_in_future = 0);
} // end of namespace WII_IPC_HLE_Interface } // end of namespace WII_IPC_HLE_Interface

View File

@ -37,7 +37,7 @@ void CWII_IPC_HLE_Device_hid::checkUsbUpdates(CWII_IPC_HLE_Device_hid* hid)
// Return value // Return value
Memory::Write_U32(0, hid->deviceCommandAddress + 4); Memory::Write_U32(0, hid->deviceCommandAddress + 4);
WII_IPC_HLE_Interface::EnqueReplyCallback(hid->deviceCommandAddress); WII_IPC_HLE_Interface::EnqReply_Threadsafe(hid->deviceCommandAddress);
hid->deviceCommandAddress = 0; hid->deviceCommandAddress = 0;
} }
} }
@ -65,7 +65,7 @@ void CWII_IPC_HLE_Device_hid::handleUsbUpdates(struct libusb_transfer *transfer)
// Return value // Return value
Memory::Write_U32(ret, replyAddress + 4); Memory::Write_U32(ret, replyAddress + 4);
WII_IPC_HLE_Interface::EnqueReplyCallback(replyAddress); WII_IPC_HLE_Interface::EnqReply_Threadsafe(replyAddress);
//DEBUG_LOG(WII_IPC_HID, "OMG OMG OMG I GOT A CALLBACK, IMMA BE FAMOUS %d %d %d", transfer->actual_length, transfer->length, transfer->status); //DEBUG_LOG(WII_IPC_HID, "OMG OMG OMG I GOT A CALLBACK, IMMA BE FAMOUS %d %d %d", transfer->actual_length, transfer->length, transfer->status);
} }
@ -124,13 +124,6 @@ bool CWII_IPC_HLE_Device_hid::Close(u32 _CommandAddress, bool _bForce)
return true; return true;
} }
u32 CWII_IPC_HLE_Device_hid::Update()
{
u32 work_done = 0;
return work_done;
}
bool CWII_IPC_HLE_Device_hid::IOCtl(u32 _CommandAddress) bool CWII_IPC_HLE_Device_hid::IOCtl(u32 _CommandAddress)
{ {
u32 Parameter = Memory::Read_U32(_CommandAddress + 0xC); u32 Parameter = Memory::Read_U32(_CommandAddress + 0xC);
@ -256,7 +249,7 @@ bool CWII_IPC_HLE_Device_hid::IOCtl(u32 _CommandAddress)
// Return value // Return value
Memory::Write_U32(-1, deviceCommandAddress + 4); Memory::Write_U32(-1, deviceCommandAddress + 4);
WII_IPC_HLE_Interface::EnqueReplyCallback(deviceCommandAddress); WII_IPC_HLE_Interface::EnqReply(deviceCommandAddress);
deviceCommandAddress = 0; deviceCommandAddress = 0;
} }
DEBUG_LOG(WII_IPC_HID, "HID::IOCtl(Shutdown) (BufferIn: (%08x, %i), BufferOut: (%08x, %i)", DEBUG_LOG(WII_IPC_HID, "HID::IOCtl(Shutdown) (BufferIn: (%08x, %i), BufferOut: (%08x, %i)",

View File

@ -27,7 +27,6 @@ public:
virtual bool Open(u32 _CommandAddress, u32 _Mode) override; virtual bool Open(u32 _CommandAddress, u32 _Mode) override;
virtual bool Close(u32 _CommandAddress, bool _bForce) override; virtual bool Close(u32 _CommandAddress, bool _bForce) override;
virtual u32 Update() override;
virtual bool IOCtlV(u32 _CommandAddress) override; virtual bool IOCtlV(u32 _CommandAddress) override;
virtual bool IOCtl(u32 _CommandAddress) override; virtual bool IOCtl(u32 _CommandAddress) override;