SI: Device change logic fix.
This commit is contained in:
parent
a129d60a57
commit
b0cb100958
|
@ -6,6 +6,7 @@
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <array>
|
#include <array>
|
||||||
|
#include <atomic>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
|
@ -102,6 +103,8 @@ struct SSIChannel
|
||||||
USIChannelIn_Hi in_hi;
|
USIChannelIn_Hi in_hi;
|
||||||
USIChannelIn_Lo in_lo;
|
USIChannelIn_Lo in_lo;
|
||||||
std::unique_ptr<ISIDevice> device;
|
std::unique_ptr<ISIDevice> device;
|
||||||
|
|
||||||
|
bool has_recent_device_change;
|
||||||
};
|
};
|
||||||
|
|
||||||
// SI Poll: Controls how often a device is polled
|
// SI Poll: Controls how often a device is polled
|
||||||
|
@ -205,6 +208,9 @@ union USIEXIClockCount
|
||||||
static CoreTiming::EventType* s_change_device_event;
|
static CoreTiming::EventType* s_change_device_event;
|
||||||
static CoreTiming::EventType* s_tranfer_pending_event;
|
static CoreTiming::EventType* s_tranfer_pending_event;
|
||||||
|
|
||||||
|
// User-configured device type. possibly overridden by TAS/Netplay
|
||||||
|
static std::array<std::atomic<SIDevices>, MAX_SI_CHANNELS> s_desired_device_types;
|
||||||
|
|
||||||
// STATE_TO_SAVE
|
// STATE_TO_SAVE
|
||||||
static std::array<SSIChannel, MAX_SI_CHANNELS> s_channel;
|
static std::array<SSIChannel, MAX_SI_CHANNELS> s_channel;
|
||||||
static USIPoll s_poll;
|
static USIPoll s_poll;
|
||||||
|
@ -236,20 +242,8 @@ static void SetNoResponse(u32 channel)
|
||||||
|
|
||||||
static void ChangeDeviceCallback(u64 user_data, s64 cycles_late)
|
static void ChangeDeviceCallback(u64 user_data, s64 cycles_late)
|
||||||
{
|
{
|
||||||
u8 channel = (u8)(user_data >> 32);
|
// The purpose of this callback is to simply re-enable device changes.
|
||||||
SIDevices device = (SIDevices)(u32)user_data;
|
s_channel[user_data].has_recent_device_change = false;
|
||||||
|
|
||||||
// Skip redundant (spammed) device changes
|
|
||||||
if (GetDeviceType(channel) != device)
|
|
||||||
{
|
|
||||||
s_channel[channel].out.hex = 0;
|
|
||||||
s_channel[channel].in_hi.hex = 0;
|
|
||||||
s_channel[channel].in_lo.hex = 0;
|
|
||||||
|
|
||||||
SetNoResponse(channel);
|
|
||||||
|
|
||||||
AddDevice(device, channel);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void UpdateInterrupts()
|
static void UpdateInterrupts()
|
||||||
|
@ -329,26 +323,18 @@ void DoState(PointerWrap& p)
|
||||||
p.Do(s_channel[i].in_hi.hex);
|
p.Do(s_channel[i].in_hi.hex);
|
||||||
p.Do(s_channel[i].in_lo.hex);
|
p.Do(s_channel[i].in_lo.hex);
|
||||||
p.Do(s_channel[i].out.hex);
|
p.Do(s_channel[i].out.hex);
|
||||||
|
p.Do(s_channel[i].has_recent_device_change);
|
||||||
|
|
||||||
std::unique_ptr<ISIDevice>& device = s_channel[i].device;
|
std::unique_ptr<ISIDevice>& device = s_channel[i].device;
|
||||||
SIDevices type = device->GetDeviceType();
|
SIDevices type = device->GetDeviceType();
|
||||||
p.Do(type);
|
p.Do(type);
|
||||||
|
|
||||||
if (type == device->GetDeviceType())
|
if (type != device->GetDeviceType())
|
||||||
{
|
{
|
||||||
device->DoState(p);
|
AddDevice(SIDevice_Create(type, i));
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// If no movie is active, we'll assume the user wants to keep their current devices
|
|
||||||
// instead of the ones they had when the savestate was created.
|
|
||||||
// But we need to restore the current devices first just in case.
|
|
||||||
SIDevices original_device = device->GetDeviceType();
|
|
||||||
std::unique_ptr<ISIDevice> save_device = SIDevice_Create(type, i);
|
|
||||||
save_device->DoState(p);
|
|
||||||
AddDevice(std::move(save_device));
|
|
||||||
ChangeDeviceDeterministic(original_device, i);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
device->DoState(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
p.Do(s_poll);
|
p.Do(s_poll);
|
||||||
|
@ -365,27 +351,30 @@ void Init()
|
||||||
s_channel[i].out.hex = 0;
|
s_channel[i].out.hex = 0;
|
||||||
s_channel[i].in_hi.hex = 0;
|
s_channel[i].in_hi.hex = 0;
|
||||||
s_channel[i].in_lo.hex = 0;
|
s_channel[i].in_lo.hex = 0;
|
||||||
|
s_channel[i].has_recent_device_change = false;
|
||||||
|
|
||||||
if (Movie::IsMovieActive())
|
if (Movie::IsMovieActive())
|
||||||
{
|
{
|
||||||
|
s_desired_device_types[i] = SIDEVICE_NONE;
|
||||||
|
|
||||||
if (Movie::IsUsingPad(i))
|
if (Movie::IsUsingPad(i))
|
||||||
{
|
{
|
||||||
SIDevices current = SConfig::GetInstance().m_SIDevice[i];
|
SIDevices current = SConfig::GetInstance().m_SIDevice[i];
|
||||||
// GC pad-compatible devices can be used for both playing and recording
|
// GC pad-compatible devices can be used for both playing and recording
|
||||||
if (SIDevice_IsGCController(current))
|
if (Movie::IsUsingBongo(i))
|
||||||
AddDevice(Movie::IsUsingBongo(i) ? SIDEVICE_GC_TARUKONGA : current, i);
|
s_desired_device_types[i] = SIDEVICE_GC_TARUKONGA;
|
||||||
|
else if (SIDevice_IsGCController(current))
|
||||||
|
s_desired_device_types[i] = current;
|
||||||
else
|
else
|
||||||
AddDevice(Movie::IsUsingBongo(i) ? SIDEVICE_GC_TARUKONGA : SIDEVICE_GC_CONTROLLER, i);
|
s_desired_device_types[i] = SIDEVICE_GC_CONTROLLER;
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
AddDevice(SIDEVICE_NONE, i);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (!NetPlay::IsNetPlayRunning())
|
else if (!NetPlay::IsNetPlayRunning())
|
||||||
{
|
{
|
||||||
AddDevice(SConfig::GetInstance().m_SIDevice[i], i);
|
s_desired_device_types[i] = SConfig::GetInstance().m_SIDevice[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
AddDevice(s_desired_device_types[i], i);
|
||||||
}
|
}
|
||||||
|
|
||||||
s_poll.hex = 0;
|
s_poll.hex = 0;
|
||||||
|
@ -594,31 +583,48 @@ void AddDevice(const SIDevices device, int device_number)
|
||||||
|
|
||||||
void ChangeDevice(SIDevices device, int channel)
|
void ChangeDevice(SIDevices device, int channel)
|
||||||
{
|
{
|
||||||
// Called from GUI, so we need to use FromThread::NON_CPU.
|
// Actual device change will happen in UpdateDevices.
|
||||||
// Let the hardware see no device for 1 second
|
s_desired_device_types[channel] = device;
|
||||||
// TODO: Calling GetDeviceType here isn't threadsafe.
|
|
||||||
if (GetDeviceType(channel) != device)
|
|
||||||
{
|
|
||||||
CoreTiming::ScheduleEvent(0, s_change_device_event, ((u64)channel << 32) | SIDEVICE_NONE,
|
|
||||||
CoreTiming::FromThread::NON_CPU);
|
|
||||||
CoreTiming::ScheduleEvent(SystemTimers::GetTicksPerSecond(), s_change_device_event,
|
|
||||||
((u64)channel << 32) | device, CoreTiming::FromThread::NON_CPU);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ChangeDeviceDeterministic(SIDevices device, int channel)
|
static void ChangeDeviceDeterministic(SIDevices device, int channel)
|
||||||
{
|
{
|
||||||
// Called from savestates, so we don't use FromThread::NON_CPU.
|
if (s_channel[channel].has_recent_device_change)
|
||||||
if (GetDeviceType(channel) != device)
|
return;
|
||||||
|
|
||||||
|
if (GetDeviceType(channel) != SIDEVICE_NONE)
|
||||||
{
|
{
|
||||||
CoreTiming::ScheduleEvent(0, s_change_device_event, ((u64)channel << 32) | SIDEVICE_NONE);
|
// Detach the current device before switching to the new one.
|
||||||
CoreTiming::ScheduleEvent(SystemTimers::GetTicksPerSecond(), s_change_device_event,
|
device = SIDEVICE_NONE;
|
||||||
((u64)channel << 32) | device);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
s_channel[channel].out.hex = 0;
|
||||||
|
s_channel[channel].in_hi.hex = 0;
|
||||||
|
s_channel[channel].in_lo.hex = 0;
|
||||||
|
|
||||||
|
SetNoResponse(channel);
|
||||||
|
|
||||||
|
AddDevice(device, channel);
|
||||||
|
|
||||||
|
// Prevent additional device changes on this channel for one second.
|
||||||
|
s_channel[channel].has_recent_device_change = true;
|
||||||
|
CoreTiming::ScheduleEvent(SystemTimers::GetTicksPerSecond(), s_change_device_event, channel);
|
||||||
}
|
}
|
||||||
|
|
||||||
void UpdateDevices()
|
void UpdateDevices()
|
||||||
{
|
{
|
||||||
|
// Check for device change requests:
|
||||||
|
for (int i = 0; i != MAX_SI_CHANNELS; ++i)
|
||||||
|
{
|
||||||
|
const SIDevices current_type = GetDeviceType(i);
|
||||||
|
const SIDevices desired_type = s_desired_device_types[i];
|
||||||
|
|
||||||
|
if (current_type != desired_type)
|
||||||
|
{
|
||||||
|
ChangeDeviceDeterministic(desired_type, i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Hinting NetPlay that all controllers will be polled in
|
// Hinting NetPlay that all controllers will be polled in
|
||||||
// succession, in order to optimize networking
|
// succession, in order to optimize networking
|
||||||
NetPlay::SetSIPollBatching(true);
|
NetPlay::SetSIPollBatching(true);
|
||||||
|
|
|
@ -38,7 +38,6 @@ void AddDevice(SIDevices device, int device_number);
|
||||||
void AddDevice(std::unique_ptr<ISIDevice> device);
|
void AddDevice(std::unique_ptr<ISIDevice> device);
|
||||||
|
|
||||||
void ChangeDevice(SIDevices device, int channel);
|
void ChangeDevice(SIDevices device, int channel);
|
||||||
void ChangeDeviceDeterministic(SIDevices device, int channel);
|
|
||||||
|
|
||||||
SIDevices GetDeviceType(int channel);
|
SIDevices GetDeviceType(int channel);
|
||||||
|
|
||||||
|
|
|
@ -409,7 +409,7 @@ bool IsNetPlayRecording()
|
||||||
}
|
}
|
||||||
|
|
||||||
// NOTE: Host Thread
|
// NOTE: Host Thread
|
||||||
void ChangePads(bool instantly)
|
void ChangePads()
|
||||||
{
|
{
|
||||||
if (!Core::IsRunning())
|
if (!Core::IsRunning())
|
||||||
return;
|
return;
|
||||||
|
@ -422,7 +422,7 @@ void ChangePads(bool instantly)
|
||||||
controllers |= (1 << i);
|
controllers |= (1 << i);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (instantly && (s_controllers & 0x0F) == controllers)
|
if ((s_controllers & 0x0F) == controllers)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
for (int i = 0; i < SerialInterface::MAX_SI_CHANNELS; ++i)
|
for (int i = 0; i < SerialInterface::MAX_SI_CHANNELS; ++i)
|
||||||
|
@ -441,10 +441,7 @@ void ChangePads(bool instantly)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (instantly) // Changes from savestates need to be instantaneous
|
SerialInterface::ChangeDevice(device, i);
|
||||||
SerialInterface::AddDevice(device, i);
|
|
||||||
else
|
|
||||||
SerialInterface::ChangeDevice(device, i);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -961,7 +958,7 @@ void LoadInput(const std::string& movie_path)
|
||||||
t_record.WriteArray(&tmpHeader, 1);
|
t_record.WriteArray(&tmpHeader, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
ChangePads(true);
|
ChangePads();
|
||||||
if (SConfig::GetInstance().bWii)
|
if (SConfig::GetInstance().bWii)
|
||||||
ChangeWiiPads(true);
|
ChangeWiiPads(true);
|
||||||
|
|
||||||
|
|
|
@ -152,7 +152,7 @@ bool IsNetPlayRecording();
|
||||||
bool IsUsingPad(int controller);
|
bool IsUsingPad(int controller);
|
||||||
bool IsUsingWiimote(int wiimote);
|
bool IsUsingWiimote(int wiimote);
|
||||||
bool IsUsingBongo(int controller);
|
bool IsUsingBongo(int controller);
|
||||||
void ChangePads(bool instantly = false);
|
void ChangePads();
|
||||||
void ChangeWiiPads(bool instantly = false);
|
void ChangeWiiPads(bool instantly = false);
|
||||||
|
|
||||||
void SetReadOnly(bool bEnabled);
|
void SetReadOnly(bool bEnabled);
|
||||||
|
|
|
@ -1566,21 +1566,21 @@ void NetPlayClient::UpdateDevices()
|
||||||
{
|
{
|
||||||
if (SerialInterface::SIDevice_IsGCController(SConfig::GetInstance().m_SIDevice[local_pad]))
|
if (SerialInterface::SIDevice_IsGCController(SConfig::GetInstance().m_SIDevice[local_pad]))
|
||||||
{
|
{
|
||||||
SerialInterface::AddDevice(SConfig::GetInstance().m_SIDevice[local_pad], pad);
|
SerialInterface::ChangeDevice(SConfig::GetInstance().m_SIDevice[local_pad], pad);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
SerialInterface::AddDevice(SerialInterface::SIDEVICE_GC_CONTROLLER, pad);
|
SerialInterface::ChangeDevice(SerialInterface::SIDEVICE_GC_CONTROLLER, pad);
|
||||||
}
|
}
|
||||||
local_pad++;
|
local_pad++;
|
||||||
}
|
}
|
||||||
else if (player_id > 0)
|
else if (player_id > 0)
|
||||||
{
|
{
|
||||||
SerialInterface::AddDevice(SerialInterface::SIDEVICE_GC_CONTROLLER, pad);
|
SerialInterface::ChangeDevice(SerialInterface::SIDEVICE_GC_CONTROLLER, pad);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
SerialInterface::AddDevice(SerialInterface::SIDEVICE_NONE, pad);
|
SerialInterface::ChangeDevice(SerialInterface::SIDEVICE_NONE, pad);
|
||||||
}
|
}
|
||||||
pad++;
|
pad++;
|
||||||
}
|
}
|
||||||
|
|
|
@ -74,7 +74,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 = 101; // Last changed in PR 7761
|
static const u32 STATE_VERSION = 102; // Last changed in PR 7742
|
||||||
|
|
||||||
// Maps savestate versions to Dolphin versions.
|
// Maps savestate versions to Dolphin versions.
|
||||||
// Versions after 42 don't need to be added to this list,
|
// Versions after 42 don't need to be added to this list,
|
||||||
|
|
Loading…
Reference in New Issue