From 03124ec3f0d23a28429a91d5096ab5292bff51e6 Mon Sep 17 00:00:00 2001 From: Scott Mansell Date: Tue, 23 Jun 2015 22:05:32 +1200 Subject: [PATCH 001/583] IPC_HLE: Simplify lifecycle of devices with shared pointers. This also fixes a memory/filehandle leak when loading savestates. --- Source/Core/Core/IPC_HLE/WII_IPC_HLE.cpp | 99 +++++++++--------------- Source/Core/Core/IPC_HLE/WII_IPC_HLE.h | 7 +- 2 files changed, 42 insertions(+), 64 deletions(-) diff --git a/Source/Core/Core/IPC_HLE/WII_IPC_HLE.cpp b/Source/Core/Core/IPC_HLE/WII_IPC_HLE.cpp index d428573442..56bb610431 100644 --- a/Source/Core/Core/IPC_HLE/WII_IPC_HLE.cpp +++ b/Source/Core/Core/IPC_HLE/WII_IPC_HLE.cpp @@ -61,7 +61,7 @@ They will also generate a true or false return for UpdateInterrupts() in WII_IPC namespace WII_IPC_HLE_Interface { -typedef std::map TDeviceMap; +typedef std::map> TDeviceMap; static TDeviceMap g_DeviceMap; // STATE_TO_SAVE @@ -69,9 +69,9 @@ typedef std::map TFileNameMap; #define IPC_MAX_FDS 0x18 #define ES_MAX_COUNT 2 -static IWII_IPC_HLE_Device* g_FdMap[IPC_MAX_FDS]; +static std::shared_ptr g_FdMap[IPC_MAX_FDS]; static bool es_inuse[ES_MAX_COUNT]; -static IWII_IPC_HLE_Device* es_handles[ES_MAX_COUNT]; +static std::shared_ptr es_handles[ES_MAX_COUNT]; typedef std::deque ipc_msg_queue; @@ -107,42 +107,37 @@ void Init() _dbg_assert_msg_(WII_IPC_HLE, g_DeviceMap.empty(), "DeviceMap isn't empty on init"); CWII_IPC_HLE_Device_es::m_ContentFile = ""; - for (IWII_IPC_HLE_Device*& dev : g_FdMap) - { - dev = nullptr; - } - u32 i = 0; // Build hardware devices - g_DeviceMap[i] = new CWII_IPC_HLE_Device_usb_oh1_57e_305(i, "/dev/usb/oh1/57e/305"); i++; - g_DeviceMap[i] = new CWII_IPC_HLE_Device_stm_immediate(i, "/dev/stm/immediate"); i++; - g_DeviceMap[i] = new CWII_IPC_HLE_Device_stm_eventhook(i, "/dev/stm/eventhook"); i++; - g_DeviceMap[i] = new CWII_IPC_HLE_Device_fs(i, "/dev/fs"); i++; + g_DeviceMap[i] = std::make_shared(i, "/dev/usb/oh1/57e/305"); i++; + g_DeviceMap[i] = std::make_shared(i, "/dev/stm/immediate"); i++; + g_DeviceMap[i] = std::make_shared(i, "/dev/stm/eventhook"); i++; + g_DeviceMap[i] = std::make_shared(i, "/dev/fs"); i++; // IOS allows two ES devices at a time for (u32 j=0; j(i, "/dev/es"); i++; es_inuse[j] = false; } - g_DeviceMap[i] = new CWII_IPC_HLE_Device_di(i, std::string("/dev/di")); i++; - g_DeviceMap[i] = new CWII_IPC_HLE_Device_net_kd_request(i, "/dev/net/kd/request"); i++; - g_DeviceMap[i] = new CWII_IPC_HLE_Device_net_kd_time(i, "/dev/net/kd/time"); i++; - g_DeviceMap[i] = new CWII_IPC_HLE_Device_net_ncd_manage(i, "/dev/net/ncd/manage"); i++; - g_DeviceMap[i] = new CWII_IPC_HLE_Device_net_wd_command(i, "/dev/net/wd/command"); i++; - g_DeviceMap[i] = new CWII_IPC_HLE_Device_net_ip_top(i, "/dev/net/ip/top"); i++; - g_DeviceMap[i] = new CWII_IPC_HLE_Device_net_ssl(i, "/dev/net/ssl"); i++; - g_DeviceMap[i] = new CWII_IPC_HLE_Device_usb_kbd(i, "/dev/usb/kbd"); i++; - g_DeviceMap[i] = new CWII_IPC_HLE_Device_sdio_slot0(i, "/dev/sdio/slot0"); i++; - g_DeviceMap[i] = new CWII_IPC_HLE_Device_stub(i, "/dev/sdio/slot1"); i++; + g_DeviceMap[i] = std::make_shared(i, std::string("/dev/di")); i++; + g_DeviceMap[i] = std::make_shared(i, "/dev/net/kd/request"); i++; + g_DeviceMap[i] = std::make_shared(i, "/dev/net/kd/time"); i++; + g_DeviceMap[i] = std::make_shared(i, "/dev/net/ncd/manage"); i++; + g_DeviceMap[i] = std::make_shared(i, "/dev/net/wd/command"); i++; + g_DeviceMap[i] = std::make_shared(i, "/dev/net/ip/top"); i++; + g_DeviceMap[i] = std::make_shared(i, "/dev/net/ssl"); i++; + g_DeviceMap[i] = std::make_shared(i, "/dev/usb/kbd"); i++; + g_DeviceMap[i] = std::make_shared(i, "/dev/sdio/slot0"); i++; + g_DeviceMap[i] = std::make_shared(i, "/dev/sdio/slot1"); i++; #if defined(__LIBUSB__) || defined(_WIN32) - g_DeviceMap[i] = new CWII_IPC_HLE_Device_hid(i, "/dev/usb/hid"); i++; + g_DeviceMap[i] = std::make_shared(i, "/dev/usb/hid"); i++; #else - g_DeviceMap[i] = new CWII_IPC_HLE_Device_stub(i, "/dev/usb/hid"); i++; + g_DeviceMap[i] = std::make_shared(i, "/dev/usb/hid"); i++; #endif - g_DeviceMap[i] = new CWII_IPC_HLE_Device_stub(i, "/dev/usb/oh1"); i++; - g_DeviceMap[i] = new IWII_IPC_HLE_Device(i, "_Unimplemented_Device_"); i++; + g_DeviceMap[i] = std::make_shared(i, "/dev/usb/oh1"); i++; + g_DeviceMap[i] = std::make_shared(i, "_Unimplemented_Device_"); i++; event_enqueue = CoreTiming::RegisterEvent("IPCEvent", EnqueueEvent); } @@ -151,16 +146,15 @@ void Reset(bool _bHard) { CoreTiming::RemoveAllEvents(event_enqueue); - for (IWII_IPC_HLE_Device*& dev : g_FdMap) + for (auto& dev : g_FdMap) { - if (dev != nullptr && !dev->IsHardware()) + if (dev && !dev->IsHardware()) { // close all files and delete their resources dev->Close(0, true); - delete dev; } - dev = nullptr; + dev.reset(); } for (bool& in_use : es_inuse) @@ -174,16 +168,12 @@ void Reset(bool _bHard) { // Force close entry.second->Close(0, true); - - // Hardware should not be deleted unless it is a hard reset - if (_bHard) - delete entry.second; } } if (_bHard) { - g_DeviceMap.erase(g_DeviceMap.begin(), g_DeviceMap.end()); + g_DeviceMap.clear(); } request_queue.clear(); reply_queue.clear(); @@ -202,7 +192,7 @@ void SetDefaultContentFile(const std::string& _rFilename) { if (entry.second && entry.second->GetDeviceName().find("/dev/es") == 0) { - ((CWII_IPC_HLE_Device_es*)entry.second)->LoadWAD(_rFilename); + static_cast(entry.second.get())->LoadWAD(_rFilename); } } } @@ -214,8 +204,7 @@ void ES_DIVerify(u8 *_pTMD, u32 _sz) void SDIO_EventNotify() { - CWII_IPC_HLE_Device_sdio_slot0 *pDevice = - (CWII_IPC_HLE_Device_sdio_slot0*)GetDeviceByName("/dev/sdio/slot0"); + auto pDevice = static_cast(GetDeviceByName("/dev/sdio/slot0").get()); if (pDevice) pDevice->EventNotify(); } @@ -233,7 +222,7 @@ int getFreeDeviceId() return -1; } -IWII_IPC_HLE_Device* GetDeviceByName(const std::string& _rDeviceName) +std::shared_ptr GetDeviceByName(const std::string& _rDeviceName) { for (const auto& entry : g_DeviceMap) { @@ -246,7 +235,7 @@ IWII_IPC_HLE_Device* GetDeviceByName(const std::string& _rDeviceName) return nullptr; } -IWII_IPC_HLE_Device* AccessDeviceByID(u32 _ID) +std::shared_ptr AccessDeviceByID(u32 _ID) { if (g_DeviceMap.find(_ID) != g_DeviceMap.end()) { @@ -257,11 +246,11 @@ IWII_IPC_HLE_Device* AccessDeviceByID(u32 _ID) } // This is called from ExecuteCommand() COMMAND_OPEN_DEVICE -IWII_IPC_HLE_Device* CreateFileIO(u32 _DeviceID, const std::string& _rDeviceName) +std::shared_ptr CreateFileIO(u32 _DeviceID, const std::string& _rDeviceName) { // scan device name and create the right one INFO_LOG(WII_IPC_FILEIO, "IOP: Create FileIO %s", _rDeviceName.c_str()); - return new CWII_IPC_HLE_Device_FileIO(_DeviceID, _rDeviceName); + return std::make_shared(_DeviceID, _rDeviceName); } @@ -297,13 +286,13 @@ void DoState(PointerWrap &p) } else { - g_FdMap[i] = new CWII_IPC_HLE_Device_FileIO(i, ""); + g_FdMap[i] = std::make_shared(i, ""); g_FdMap[i]->DoState(p); } } else { - g_FdMap[i] = nullptr; + g_FdMap[i].reset(); } } @@ -318,7 +307,7 @@ void DoState(PointerWrap &p) } else { - for (IWII_IPC_HLE_Device*& dev : g_FdMap) + for (auto& dev : g_FdMap) { u32 exists = dev ? 1 : 0; p.Do(exists); @@ -354,9 +343,9 @@ void ExecuteCommand(u32 _Address) IPCCommandType Command = static_cast(Memory::Read_U32(_Address)); s32 DeviceID = Memory::Read_U32(_Address + 8); - IWII_IPC_HLE_Device* pDevice = (DeviceID >= 0 && DeviceID < IPC_MAX_FDS) ? g_FdMap[DeviceID] : nullptr; + std::shared_ptr pDevice = (DeviceID >= 0 && DeviceID < IPC_MAX_FDS) ? g_FdMap[DeviceID] : nullptr; - INFO_LOG(WII_IPC_HLE, "-->> Execute Command Address: 0x%08x (code: %x, device: %x) %p", _Address, Command, DeviceID, pDevice); + INFO_LOG(WII_IPC_HLE, "-->> Execute Command Address: 0x%08x (code: %x, device: %x) %p", _Address, Command, DeviceID, pDevice.get()); switch (Command) { @@ -420,11 +409,6 @@ void ExecuteCommand(u32 _Address) { g_FdMap[DeviceID] = pDevice; } - else - { - delete pDevice; - pDevice = nullptr; - } } } else @@ -448,14 +432,7 @@ void ExecuteCommand(u32 _Address) } } - g_FdMap[DeviceID] = nullptr; - - // Don't delete hardware - if (!pDevice->IsHardware()) - { - delete pDevice; - pDevice = nullptr; - } + g_FdMap[DeviceID].reset(); } else { diff --git a/Source/Core/Core/IPC_HLE/WII_IPC_HLE.h b/Source/Core/Core/IPC_HLE/WII_IPC_HLE.h index 31142804b3..7863d678ba 100644 --- a/Source/Core/Core/IPC_HLE/WII_IPC_HLE.h +++ b/Source/Core/Core/IPC_HLE/WII_IPC_HLE.h @@ -4,6 +4,7 @@ #pragma once +#include #include #include "Common/CommonTypes.h" @@ -63,10 +64,10 @@ void ES_DIVerify(u8 *_pTMD, u32 _sz); void SDIO_EventNotify(); -IWII_IPC_HLE_Device* CreateFileIO(u32 _DeviceID, const std::string& _rDeviceName); +std::shared_ptr CreateFileIO(u32 _DeviceID, const std::string& _rDeviceName); -IWII_IPC_HLE_Device* GetDeviceByName(const std::string& _rDeviceName); -IWII_IPC_HLE_Device* AccessDeviceByID(u32 _ID); +std::shared_ptr GetDeviceByName(const std::string& _rDeviceName); +std::shared_ptr AccessDeviceByID(u32 _ID); int getFreeDeviceId(); // Update From 8b4734133e9b5b74d8a987c680fb80b53b8ece27 Mon Sep 17 00:00:00 2001 From: Scott Mansell Date: Tue, 23 Jun 2015 23:08:21 +1200 Subject: [PATCH 002/583] IPC_HLE: Don't open/close file for every single file operation. On the first boot of Pokemon Snap it copies a 144KB file to the Wii's NAND, but it only copies 32 bytes per IPC write call. This was causing dolphin to open and close the same file over 4000 times. This wouldn't usually be a huge issue, except some operating systems (namely Windows) allow 3rd party programs (namely antivirus software) to hook all accesses to the filesystem. This causes the antivirus software to scan the same file for viruses 4000+ times, which is kind of slow. This fix reduces the initial boot time of pokemon snap from 3+ min to just a few seconds. Could also improve other games which write things to NAND. Will break a few things, see the next commit for an improved fix. --- .../IPC_HLE/WII_IPC_HLE_Device_FileIO.cpp | 36 ++++++++++++------- .../Core/IPC_HLE/WII_IPC_HLE_Device_FileIO.h | 3 +- 2 files changed, 25 insertions(+), 14 deletions(-) diff --git a/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_FileIO.cpp b/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_FileIO.cpp index 573f698021..b820ecccc2 100644 --- a/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_FileIO.cpp +++ b/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_FileIO.cpp @@ -73,6 +73,7 @@ CWII_IPC_HLE_Device_FileIO::CWII_IPC_HLE_Device_FileIO(u32 _DeviceID, const std: : IWII_IPC_HLE_Device(_DeviceID, _rDeviceName, false) // not a real hardware , m_Mode(0) , m_SeekPos(0) + , m_file() { Common::ReadReplacements(replacements); } @@ -86,6 +87,8 @@ IPCCommandResult CWII_IPC_HLE_Device_FileIO::Close(u32 _CommandAddress, bool _bF INFO_LOG(WII_IPC_FILEIO, "FileIO: Close %s (DeviceID=%08x)", m_Name.c_str(), m_DeviceID); m_Mode = 0; + m_file.Close(); + // Close always return 0 for success if (_CommandAddress && !_bForce) Memory::Write_U32(0, _CommandAddress + 4); @@ -121,13 +124,15 @@ IPCCommandResult CWII_IPC_HLE_Device_FileIO::Open(u32 _CommandAddress, u32 _Mode ReturnValue = FS_FILE_NOT_EXIST; } + OpenFile(); + if (_CommandAddress) Memory::Write_U32(ReturnValue, _CommandAddress+4); m_Active = true; return IPC_DEFAULT_REPLY; } -File::IOFile CWII_IPC_HLE_Device_FileIO::OpenFile() +void CWII_IPC_HLE_Device_FileIO::OpenFile() { const char* open_mode = ""; @@ -147,7 +152,7 @@ File::IOFile CWII_IPC_HLE_Device_FileIO::OpenFile() break; } - return File::IOFile(m_filepath, open_mode); + m_file = File::IOFile(m_filepath, open_mode); } IPCCommandResult CWII_IPC_HLE_Device_FileIO::Seek(u32 _CommandAddress) @@ -156,11 +161,11 @@ IPCCommandResult CWII_IPC_HLE_Device_FileIO::Seek(u32 _CommandAddress) const s32 SeekPosition = Memory::Read_U32(_CommandAddress + 0xC); const s32 Mode = Memory::Read_U32(_CommandAddress + 0x10); - if (auto file = OpenFile()) + if (m_file) { ReturnValue = FS_RESULT_FATAL; - const s32 fileSize = (s32) file.GetSize(); + const s32 fileSize = (s32) m_file.GetSize(); INFO_LOG(WII_IPC_FILEIO, "FileIO: Seek Pos: 0x%08x, Mode: %i (%s, Length=0x%08x)", SeekPosition, Mode, m_Name.c_str(), fileSize); switch (Mode) @@ -204,6 +209,7 @@ IPCCommandResult CWII_IPC_HLE_Device_FileIO::Seek(u32 _CommandAddress) break; } } + m_file.Seek(m_SeekPos, SEEK_SET); } else { @@ -221,7 +227,7 @@ IPCCommandResult CWII_IPC_HLE_Device_FileIO::Read(u32 _CommandAddress) const u32 Size = Memory::Read_U32(_CommandAddress + 0x10); - if (auto file = OpenFile()) + if (m_file) { if (m_Mode == ISFS_OPEN_WRITE) { @@ -230,9 +236,8 @@ IPCCommandResult CWII_IPC_HLE_Device_FileIO::Read(u32 _CommandAddress) else { INFO_LOG(WII_IPC_FILEIO, "FileIO: Read 0x%x bytes to 0x%08x from %s", Size, Address, m_Name.c_str()); - file.Seek(m_SeekPos, SEEK_SET); - ReturnValue = (u32)fread(Memory::GetPointer(Address), 1, Size, file.GetHandle()); - if (ReturnValue != Size && ferror(file.GetHandle())) + ReturnValue = (u32)fread(Memory::GetPointer(Address), 1, Size, m_file.GetHandle()); + if (ReturnValue != Size && ferror(m_file.GetHandle())) { ReturnValue = FS_EACCESS; } @@ -259,7 +264,7 @@ IPCCommandResult CWII_IPC_HLE_Device_FileIO::Write(u32 _CommandAddress) const u32 Address = Memory::Read_U32(_CommandAddress + 0xC); // Write data from this memory address const u32 Size = Memory::Read_U32(_CommandAddress + 0x10); - if (auto file = OpenFile()) + if (m_file) { if (m_Mode == ISFS_OPEN_READ) { @@ -268,8 +273,7 @@ IPCCommandResult CWII_IPC_HLE_Device_FileIO::Write(u32 _CommandAddress) else { INFO_LOG(WII_IPC_FILEIO, "FileIO: Write 0x%04x bytes from 0x%08x to %s", Size, Address, m_Name.c_str()); - file.Seek(m_SeekPos, SEEK_SET); - if (file.WriteBytes(Memory::GetPointer(Address), Size)) + if (m_file.WriteBytes(Memory::GetPointer(Address), Size)) { ReturnValue = Size; m_SeekPos += Size; @@ -299,9 +303,9 @@ IPCCommandResult CWII_IPC_HLE_Device_FileIO::IOCtl(u32 _CommandAddress) { case ISFS_IOCTL_GETFILESTATS: { - if (auto file = OpenFile()) + if (m_file) { - u32 m_FileLength = (u32)file.GetSize(); + u32 m_FileLength = (u32)m_file.GetSize(); const u32 BufferOut = Memory::Read_U32(_CommandAddress + 0x18); INFO_LOG(WII_IPC_FILEIO, " File: %s, Length: %i, Pos: %i", m_Name.c_str(), m_FileLength, m_SeekPos); @@ -337,4 +341,10 @@ void CWII_IPC_HLE_Device_FileIO::DoState(PointerWrap &p) p.Do(m_SeekPos); m_filepath = HLE_IPC_BuildFilename(m_Name); + + if (p.GetMode() == PointerWrap::MODE_READ) + { + OpenFile(); + m_file.Seek(m_SeekPos, SEEK_SET); + } } diff --git a/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_FileIO.h b/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_FileIO.h index 45f7b9ed1b..fb03764ae6 100644 --- a/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_FileIO.h +++ b/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_FileIO.h @@ -28,7 +28,7 @@ public: IPCCommandResult IOCtl(u32 _CommandAddress) override; void DoState(PointerWrap &p) override; - File::IOFile OpenFile(); + void OpenFile(); private: enum @@ -75,4 +75,5 @@ private: u32 m_SeekPos; std::string m_filepath; + File::IOFile m_file; }; From 84e42904a2ec24ad5cd707bbf27cd0efa63d2b01 Mon Sep 17 00:00:00 2001 From: "Admiral H. Curtiss" Date: Wed, 24 Jun 2015 12:41:10 +0200 Subject: [PATCH 003/583] Netplay: Sync Video Mode settings. (Progressive Scan and PAL60) Must match so that Wii games don't desync, especially PAL games. --- Source/Core/Core/BootManager.cpp | 2 ++ Source/Core/Core/NetPlayClient.cpp | 2 ++ Source/Core/Core/NetPlayProto.h | 4 +++- Source/Core/Core/NetPlayServer.cpp | 2 ++ Source/Core/DolphinWX/NetPlay/NetWindow.cpp | 2 ++ 5 files changed, 11 insertions(+), 1 deletion(-) diff --git a/Source/Core/Core/BootManager.cpp b/Source/Core/Core/BootManager.cpp index 8b0bde8cee..4b8351a005 100644 --- a/Source/Core/Core/BootManager.cpp +++ b/Source/Core/Core/BootManager.cpp @@ -246,6 +246,8 @@ bool BootCore(const std::string& _rFilename) StartUp.iCPUCore = g_NetPlaySettings.m_CPUcore; StartUp.SelectedLanguage = g_NetPlaySettings.m_SelectedLanguage; StartUp.bOverrideGCLanguage = g_NetPlaySettings.m_OverrideGCLanguage; + StartUp.bProgressive = g_NetPlaySettings.m_ProgressiveScan; + StartUp.bPAL60 = g_NetPlaySettings.m_PAL60; SConfig::GetInstance().m_DSPEnableJIT = g_NetPlaySettings.m_DSPEnableJIT; SConfig::GetInstance().m_OCEnable = g_NetPlaySettings.m_OCEnable; SConfig::GetInstance().m_OCFactor = g_NetPlaySettings.m_OCFactor; diff --git a/Source/Core/Core/NetPlayClient.cpp b/Source/Core/Core/NetPlayClient.cpp index e7ccc696da..d499e6b90e 100644 --- a/Source/Core/Core/NetPlayClient.cpp +++ b/Source/Core/Core/NetPlayClient.cpp @@ -381,6 +381,8 @@ unsigned int NetPlayClient::OnData(sf::Packet& packet) packet >> g_NetPlaySettings.m_CPUcore; packet >> g_NetPlaySettings.m_SelectedLanguage; packet >> g_NetPlaySettings.m_OverrideGCLanguage; + packet >> g_NetPlaySettings.m_ProgressiveScan; + packet >> g_NetPlaySettings.m_PAL60; packet >> g_NetPlaySettings.m_DSPEnableJIT; packet >> g_NetPlaySettings.m_DSPHLE; packet >> g_NetPlaySettings.m_WriteToMemcard; diff --git a/Source/Core/Core/NetPlayProto.h b/Source/Core/Core/NetPlayProto.h index 506286de09..e3572dd212 100644 --- a/Source/Core/Core/NetPlayProto.h +++ b/Source/Core/Core/NetPlayProto.h @@ -14,6 +14,8 @@ struct NetSettings int m_CPUcore; int m_SelectedLanguage; bool m_OverrideGCLanguage; + bool m_ProgressiveScan; + bool m_PAL60; bool m_DSPHLE; bool m_DSPEnableJIT; bool m_WriteToMemcard; @@ -31,7 +33,7 @@ struct Rpt : public std::vector typedef std::vector NetWiimote; -#define NETPLAY_VERSION "Dolphin NetPlay 2015-06-14" +#define NETPLAY_VERSION "Dolphin NetPlay 2015-06-24" extern u64 g_netplay_initial_gctime; diff --git a/Source/Core/Core/NetPlayServer.cpp b/Source/Core/Core/NetPlayServer.cpp index b26a5d0391..2ac2170827 100644 --- a/Source/Core/Core/NetPlayServer.cpp +++ b/Source/Core/Core/NetPlayServer.cpp @@ -717,6 +717,8 @@ bool NetPlayServer::StartGame() *spac << m_settings.m_CPUcore; *spac << m_settings.m_SelectedLanguage; *spac << m_settings.m_OverrideGCLanguage; + *spac << m_settings.m_ProgressiveScan; + *spac << m_settings.m_PAL60; *spac << m_settings.m_DSPEnableJIT; *spac << m_settings.m_DSPHLE; *spac << m_settings.m_WriteToMemcard; diff --git a/Source/Core/DolphinWX/NetPlay/NetWindow.cpp b/Source/Core/DolphinWX/NetPlay/NetWindow.cpp index a181765176..5db7c7e56f 100644 --- a/Source/Core/DolphinWX/NetPlay/NetWindow.cpp +++ b/Source/Core/DolphinWX/NetPlay/NetWindow.cpp @@ -254,6 +254,8 @@ void NetPlayDialog::GetNetSettings(NetSettings &settings) settings.m_CPUcore = instance.iCPUCore; settings.m_SelectedLanguage = instance.SelectedLanguage; settings.m_OverrideGCLanguage = instance.bOverrideGCLanguage; + settings.m_ProgressiveScan = instance.bProgressive; + settings.m_PAL60 = instance.bPAL60; settings.m_DSPHLE = instance.bDSPHLE; settings.m_DSPEnableJIT = instance.m_DSPEnableJIT; settings.m_WriteToMemcard = m_memcard_write->GetValue(); From 384a1b4e3b63aec988260fdb23e1c48429ee97e5 Mon Sep 17 00:00:00 2001 From: comex Date: Sun, 21 Jun 2015 16:03:32 -0400 Subject: [PATCH 004/583] Fix DoFileSearch returning the passed-in directories themselves. Fixes https://code.google.com/p/dolphin-emu/issues/detail?id=8697&can=3 --- Source/Core/Common/FileSearch.cpp | 4 +++- Source/Core/DolphinQt/GameList/GameTracker.cpp | 7 ++----- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/Source/Core/Common/FileSearch.cpp b/Source/Core/Common/FileSearch.cpp index 13e99fe88a..b5395cf21c 100644 --- a/Source/Core/Common/FileSearch.cpp +++ b/Source/Core/Common/FileSearch.cpp @@ -28,7 +28,8 @@ static std::vector FileSearchWithTest(const std::vector DoFileSearch(const std::vector& globs, con }); } +// Result includes the passed directories themselves as well as their subdirectories. std::vector FindSubdirectories(const std::vector& directories, bool recursive) { return FileSearchWithTest(directories, true, [&](const File::FSTEntry& entry) { diff --git a/Source/Core/DolphinQt/GameList/GameTracker.cpp b/Source/Core/DolphinQt/GameList/GameTracker.cpp index 8bb41c39aa..7213024fe1 100644 --- a/Source/Core/DolphinQt/GameList/GameTracker.cpp +++ b/Source/Core/DolphinQt/GameList/GameTracker.cpp @@ -80,16 +80,13 @@ void DGameTracker::ScanForGames() delete m_watcher; m_watcher = new QFileSystemWatcher(this); + for (std::string dir : SConfig::GetInstance().m_ISOFolder) + m_watcher->addPath(QString::fromStdString(dir)); if (SConfig::GetInstance().m_RecursiveISOFolder) { for (std::string dir : FindSubdirectories(SConfig::GetInstance().m_ISOFolder, /*recursive*/ true)) m_watcher->addPath(QString::fromStdString(dir)); } - else - { - for (std::string dir : SConfig::GetInstance().m_ISOFolder) - m_watcher->addPath(QString::fromStdString(dir)); - } std::vector exts; if (SConfig::GetInstance().m_ListGC) From 0679e43efec8e9ca8dc690ea2a59bf7c1d045f7c Mon Sep 17 00:00:00 2001 From: sigmabeta Date: Thu, 25 Jun 2015 21:43:00 -0400 Subject: [PATCH 005/583] Android: Show screenshot on EmulationActivity before game starts. --- .../activities/EmulationActivity.java | 30 +++++++++++++++++++ .../dolphinemu/adapters/GameAdapter.java | 1 + .../main/res/layout/activity_emulation.xml | 13 +++++++- 3 files changed, 43 insertions(+), 1 deletion(-) diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/activities/EmulationActivity.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/activities/EmulationActivity.java index d1e6f47273..ce3f9624c7 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/activities/EmulationActivity.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/activities/EmulationActivity.java @@ -12,6 +12,10 @@ import android.view.Menu; import android.view.MenuItem; import android.view.MotionEvent; import android.view.View; +import android.widget.FrameLayout; +import android.widget.ImageView; + +import com.squareup.picasso.Picasso; import org.dolphinemu.dolphinemu.NativeLibrary; import org.dolphinemu.dolphinemu.R; @@ -22,6 +26,8 @@ import java.util.List; public final class EmulationActivity extends AppCompatActivity { private View mDecorView; + private ImageView mImageView; + private FrameLayout mFrameLayout; private boolean mDeviceHasTouchScreen; private boolean mSystemUiVisible; @@ -79,9 +85,33 @@ public final class EmulationActivity extends AppCompatActivity setContentView(R.layout.activity_emulation); + mImageView = (ImageView) findViewById(R.id.image_screenshot); + mFrameLayout = (FrameLayout) findViewById(R.id.frame_content); + Intent gameToEmulate = getIntent(); String path = gameToEmulate.getStringExtra("SelectedGame"); String title = gameToEmulate.getStringExtra("SelectedTitle"); + String screenPath = gameToEmulate.getStringExtra("ScreenPath"); + + Picasso.with(this) + .load(screenPath) + .fit() + .noFade() + .into(mImageView); + + mImageView.animate() + .setStartDelay(2000) + .setDuration(500) + .alpha(0.0f) + .withEndAction(new Runnable() + { + @Override + public void run() + { + mImageView.setVisibility(View.GONE); + mFrameLayout.setVisibility(View.VISIBLE); + } + }); setTitle(title); diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/adapters/GameAdapter.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/adapters/GameAdapter.java index a9a7be930e..8b279c52c2 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/adapters/GameAdapter.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/adapters/GameAdapter.java @@ -220,6 +220,7 @@ public final class GameAdapter extends RecyclerView.Adapter impl intent.putExtra("SelectedGame", holder.path); intent.putExtra("SelectedTitle", holder.title); + intent.putExtra("ScreenPath", holder.screenshotPath); view.getContext().startActivity(intent); } diff --git a/Source/Android/app/src/main/res/layout/activity_emulation.xml b/Source/Android/app/src/main/res/layout/activity_emulation.xml index 63ea99ba83..5a644b260a 100644 --- a/Source/Android/app/src/main/res/layout/activity_emulation.xml +++ b/Source/Android/app/src/main/res/layout/activity_emulation.xml @@ -1,5 +1,16 @@ + > + + + + \ No newline at end of file From ca36ff0551456fffd98c769b0dc55e56b4fb25b6 Mon Sep 17 00:00:00 2001 From: Tillmann Karras Date: Thu, 25 Jun 2015 05:24:07 +0200 Subject: [PATCH 006/583] Interpreter: consolidate fdiv/fdivs/ps_div --- .../PowerPC/Interpreter/Interpreter_FPUtils.h | 22 +++++ .../Interpreter/Interpreter_FloatingPoint.cpp | 69 +------------- .../Interpreter/Interpreter_Paired.cpp | 93 +------------------ 3 files changed, 26 insertions(+), 158 deletions(-) diff --git a/Source/Core/Core/PowerPC/Interpreter/Interpreter_FPUtils.h b/Source/Core/Core/PowerPC/Interpreter/Interpreter_FPUtils.h index 5392cc7ee0..8fbd379c5b 100644 --- a/Source/Core/Core/PowerPC/Interpreter/Interpreter_FPUtils.h +++ b/Source/Core/Core/PowerPC/Interpreter/Interpreter_FPUtils.h @@ -95,6 +95,28 @@ inline double NI_mul(double a, double b) return t; } +inline double NI_div(double a, double b) +{ + double t = a / b; + if (std::isnan(t)) + { + if (std::isnan(a)) return a; + if (std::isnan(b)) return b; + if (b == 0.0) + { + SetFPException(FPSCR_ZX); + if (a == 0.0) + SetFPException(FPSCR_VXZDZ); + } + else if (std::isinf(a) && std::isinf(b)) + { + SetFPException(FPSCR_VXIDI); + } + return PPC_NAN; + } + return t; +} + inline double NI_add(double a, double b) { double t = a + b; diff --git a/Source/Core/Core/PowerPC/Interpreter/Interpreter_FloatingPoint.cpp b/Source/Core/Core/PowerPC/Interpreter/Interpreter_FloatingPoint.cpp index c5eee4d0ea..fa4132c4ee 100644 --- a/Source/Core/Core/PowerPC/Interpreter/Interpreter_FloatingPoint.cpp +++ b/Source/Core/Core/PowerPC/Interpreter/Interpreter_FloatingPoint.cpp @@ -351,38 +351,7 @@ void Interpreter::faddsx(UGeckoInstruction _inst) void Interpreter::fdivx(UGeckoInstruction _inst) { - double a = rPS0(_inst.FA); - double b = rPS0(_inst.FB); - - if (a != a) - { - rPS0(_inst.FD) = a; - } - else if (b != b) - { - rPS0(_inst.FD) = b; - } - else - { - rPS0(_inst.FD) = ForceDouble(a / b); - if (b == 0.0) - { - if (a == 0.0) - { - SetFPException(FPSCR_VXZDZ); - rPS0(_inst.FD) = PPC_NAN; - } - SetFPException(FPSCR_ZX); - } - else - { - if (IsINF(a) && IsINF(b)) - { - SetFPException(FPSCR_VXIDI); - rPS0(_inst.FD) = PPC_NAN; - } - } - } + rPS0(_inst.FD) = ForceDouble(NI_div(rPS0(_inst.FA), rPS0(_inst.FB))); UpdateFPRF(rPS0(_inst.FD)); // FR,FI,OX,UX??? @@ -391,41 +360,7 @@ void Interpreter::fdivx(UGeckoInstruction _inst) } void Interpreter::fdivsx(UGeckoInstruction _inst) { - double a = rPS0(_inst.FA); - double b = rPS0(_inst.FB); - double res; - - if (a != a) - { - res = a; - } - else if (b != b) - { - res = b; - } - else - { - res = ForceSingle(a / b); - if (b == 0.0) - { - if (a == 0.0) - { - SetFPException(FPSCR_VXZDZ); - res = PPC_NAN; - } - SetFPException(FPSCR_ZX); - } - else - { - if (IsINF(a) && IsINF(b)) - { - SetFPException(FPSCR_VXIDI); - res = PPC_NAN; - } - } - } - - rPS0(_inst.FD) = rPS1(_inst.FD) = res; + rPS0(_inst.FD) = rPS1(_inst.FD) = ForceSingle(NI_div(rPS0(_inst.FA), rPS0(_inst.FB))); UpdateFPRF(rPS0(_inst.FD)); if (_inst.Rc) diff --git a/Source/Core/Core/PowerPC/Interpreter/Interpreter_Paired.cpp b/Source/Core/Core/PowerPC/Interpreter/Interpreter_Paired.cpp index 2c9656bd8f..fc56a4a33d 100644 --- a/Source/Core/Core/PowerPC/Interpreter/Interpreter_Paired.cpp +++ b/Source/Core/Core/PowerPC/Interpreter/Interpreter_Paired.cpp @@ -104,97 +104,8 @@ void Interpreter::ps_merge11(UGeckoInstruction _inst) // From here on, the real deal. void Interpreter::ps_div(UGeckoInstruction _inst) { - u32 ex_mask = 0; - - // PS0 - { - double a = rPS0(_inst.FA); - double b = rPS0(_inst.FB); - double &res = rPS0(_inst.FD); - - if (a != a) - { - res = a; - } - else if (b != b) - { - res = b; - } - else - { - if (b == 0.0) - { - ex_mask |= FPSCR_ZX; - if (rPS0(_inst.FA) == 0.0) - { - ex_mask |= FPSCR_VXZDZ; - res = PPC_NAN; - } - else - { - res = ForceSingle(a / b); - } - } - else - { - if (IsINF(a) && IsINF(b)) - { - ex_mask |= FPSCR_VXIDI; - res = PPC_NAN; - } - else - { - res = ForceSingle(a / b); - } - } - } - } - - // PS1 - { - double a = rPS1(_inst.FA); - double b = rPS1(_inst.FB); - double &res = rPS1(_inst.FD); - - if (a != a) - { - res = a; - } - else if (b != b) - { - res = b; - } - else - { - if (b == 0.0) - { - ex_mask |= FPSCR_ZX; - if (rPS0(_inst.FA) == 0.0) - { - ex_mask |= FPSCR_VXZDZ; - res = PPC_NAN; - } - else - { - res = ForceSingle(a / b); - } - } - else - { - if (IsINF(a) && IsINF(b)) - { - ex_mask |= FPSCR_VXIDI; - res = PPC_NAN; - } - else - { - res = ForceSingle(a / b); - } - } - } - } - - SetFPException(ex_mask); + rPS0(_inst.FD) = ForceSingle(NI_div(rPS0(_inst.FA), rPS0(_inst.FB))); + rPS1(_inst.FD) = ForceSingle(NI_div(rPS1(_inst.FA), rPS1(_inst.FB))); UpdateFPRF(rPS0(_inst.FD)); if (_inst.Rc) From b2c21e800abe0beb121f85a9adb235a8eb3b95c0 Mon Sep 17 00:00:00 2001 From: Tillmann Karras Date: Thu, 25 Jun 2015 06:05:40 +0200 Subject: [PATCH 007/583] Interpreter: drop unused macros --- Source/Core/Core/PowerPC/Interpreter/Interpreter_FPUtils.h | 3 --- 1 file changed, 3 deletions(-) diff --git a/Source/Core/Core/PowerPC/Interpreter/Interpreter_FPUtils.h b/Source/Core/Core/PowerPC/Interpreter/Interpreter_FPUtils.h index 8fbd379c5b..dac55e608d 100644 --- a/Source/Core/Core/PowerPC/Interpreter/Interpreter_FPUtils.h +++ b/Source/Core/Core/PowerPC/Interpreter/Interpreter_FPUtils.h @@ -12,9 +12,6 @@ #include "Core/PowerPC/Gekko.h" #include "Core/PowerPC/Interpreter/Interpreter.h" -#define MIN_SINGLE 0xc7efffffe0000000ull -#define MAX_SINGLE 0x47efffffe0000000ull - const u64 PPC_NAN_U64 = 0x7ff8000000000000ull; const double PPC_NAN = *(double* const)&PPC_NAN_U64; From 174ada3a62d7835f877d534062883e75305fdf18 Mon Sep 17 00:00:00 2001 From: Tillmann Karras Date: Thu, 25 Jun 2015 06:26:24 +0200 Subject: [PATCH 008/583] Interpreter: assign directly instead via variables --- .../Interpreter/Interpreter_Paired.cpp | 60 +++++++------------ 1 file changed, 20 insertions(+), 40 deletions(-) diff --git a/Source/Core/Core/PowerPC/Interpreter/Interpreter_Paired.cpp b/Source/Core/Core/PowerPC/Interpreter/Interpreter_Paired.cpp index fc56a4a33d..e8a0132413 100644 --- a/Source/Core/Core/PowerPC/Interpreter/Interpreter_Paired.cpp +++ b/Source/Core/Core/PowerPC/Interpreter/Interpreter_Paired.cpp @@ -59,10 +59,8 @@ void Interpreter::ps_abs(UGeckoInstruction _inst) // These are just moves, double is OK. void Interpreter::ps_merge00(UGeckoInstruction _inst) { - double p0 = rPS0(_inst.FA); - double p1 = rPS0(_inst.FB); - rPS0(_inst.FD) = p0; - rPS1(_inst.FD) = p1; + rPS0(_inst.FD) = rPS0(_inst.FA); + rPS1(_inst.FD) = rPS0(_inst.FB); if (_inst.Rc) Helper_UpdateCR1(); @@ -70,10 +68,8 @@ void Interpreter::ps_merge00(UGeckoInstruction _inst) void Interpreter::ps_merge01(UGeckoInstruction _inst) { - double p0 = rPS0(_inst.FA); - double p1 = rPS1(_inst.FB); - rPS0(_inst.FD) = p0; - rPS1(_inst.FD) = p1; + rPS0(_inst.FD) = rPS0(_inst.FA); + rPS1(_inst.FD) = rPS1(_inst.FB); if (_inst.Rc) Helper_UpdateCR1(); @@ -81,10 +77,8 @@ void Interpreter::ps_merge01(UGeckoInstruction _inst) void Interpreter::ps_merge10(UGeckoInstruction _inst) { - double p0 = rPS1(_inst.FA); - double p1 = rPS0(_inst.FB); - rPS0(_inst.FD) = p0; - rPS1(_inst.FD) = p1; + rPS0(_inst.FD) = rPS1(_inst.FA); + rPS1(_inst.FD) = rPS0(_inst.FB); if (_inst.Rc) Helper_UpdateCR1(); @@ -92,10 +86,8 @@ void Interpreter::ps_merge10(UGeckoInstruction _inst) void Interpreter::ps_merge11(UGeckoInstruction _inst) { - double p0 = rPS1(_inst.FA); - double p1 = rPS1(_inst.FB); - rPS0(_inst.FD) = p0; - rPS1(_inst.FD) = p1; + rPS0(_inst.FD) = rPS1(_inst.FA); + rPS1(_inst.FD) = rPS1(_inst.FB); if (_inst.Rc) Helper_UpdateCR1(); @@ -236,10 +228,8 @@ void Interpreter::ps_nmadd(UGeckoInstruction _inst) void Interpreter::ps_sum0(UGeckoInstruction _inst) { - double p0 = ForceSingle(NI_add(rPS0(_inst.FA), rPS1(_inst.FB))); - double p1 = ForceSingle(rPS1(_inst.FC)); - rPS0(_inst.FD) = p0; - rPS1(_inst.FD) = p1; + rPS0(_inst.FD) = ForceSingle(NI_add(rPS0(_inst.FA), rPS1(_inst.FB))); + rPS1(_inst.FD) = ForceSingle(rPS1(_inst.FC)); UpdateFPRF(rPS0(_inst.FD)); if (_inst.Rc) @@ -248,10 +238,8 @@ void Interpreter::ps_sum0(UGeckoInstruction _inst) void Interpreter::ps_sum1(UGeckoInstruction _inst) { - double p0 = ForceSingle(rPS0(_inst.FC)); - double p1 = ForceSingle(NI_add(rPS0(_inst.FA), rPS1(_inst.FB))); - rPS0(_inst.FD) = p0; - rPS1(_inst.FD) = p1; + rPS0(_inst.FD) = ForceSingle(rPS0(_inst.FC)); + rPS1(_inst.FD) = ForceSingle(NI_add(rPS0(_inst.FA), rPS1(_inst.FB))); UpdateFPRF(rPS1(_inst.FD)); if (_inst.Rc) @@ -261,10 +249,8 @@ void Interpreter::ps_sum1(UGeckoInstruction _inst) void Interpreter::ps_muls0(UGeckoInstruction _inst) { double c0 = Force25Bit(rPS0(_inst.FC)); - double p0 = ForceSingle(NI_mul(rPS0(_inst.FA), c0)); - double p1 = ForceSingle(NI_mul(rPS1(_inst.FA), c0)); - rPS0(_inst.FD) = p0; - rPS1(_inst.FD) = p1; + rPS0(_inst.FD) = ForceSingle(NI_mul(rPS0(_inst.FA), c0)); + rPS1(_inst.FD) = ForceSingle(NI_mul(rPS1(_inst.FA), c0)); UpdateFPRF(rPS0(_inst.FD)); if (_inst.Rc) @@ -274,10 +260,8 @@ void Interpreter::ps_muls0(UGeckoInstruction _inst) void Interpreter::ps_muls1(UGeckoInstruction _inst) { double c1 = Force25Bit(rPS1(_inst.FC)); - double p0 = ForceSingle(NI_mul(rPS0(_inst.FA), c1)); - double p1 = ForceSingle(NI_mul(rPS1(_inst.FA), c1)); - rPS0(_inst.FD) = p0; - rPS1(_inst.FD) = p1; + rPS0(_inst.FD) = ForceSingle(NI_mul(rPS0(_inst.FA), c1)); + rPS1(_inst.FD) = ForceSingle(NI_mul(rPS1(_inst.FA), c1)); UpdateFPRF(rPS0(_inst.FD)); if (_inst.Rc) @@ -287,10 +271,8 @@ void Interpreter::ps_muls1(UGeckoInstruction _inst) void Interpreter::ps_madds0(UGeckoInstruction _inst) { double c0 = Force25Bit(rPS0(_inst.FC)); - double p0 = ForceSingle(NI_madd(rPS0(_inst.FA), c0, rPS0(_inst.FB))); - double p1 = ForceSingle(NI_madd(rPS1(_inst.FA), c0, rPS1(_inst.FB))); - rPS0(_inst.FD) = p0; - rPS1(_inst.FD) = p1; + rPS0(_inst.FD) = ForceSingle(NI_madd(rPS0(_inst.FA), c0, rPS0(_inst.FB))); + rPS1(_inst.FD) = ForceSingle(NI_madd(rPS1(_inst.FA), c0, rPS1(_inst.FB))); UpdateFPRF(rPS0(_inst.FD)); if (_inst.Rc) @@ -300,10 +282,8 @@ void Interpreter::ps_madds0(UGeckoInstruction _inst) void Interpreter::ps_madds1(UGeckoInstruction _inst) { double c1 = Force25Bit(rPS1(_inst.FC)); - double p0 = ForceSingle(NI_madd(rPS0(_inst.FA), c1, rPS0(_inst.FB))); - double p1 = ForceSingle(NI_madd(rPS1(_inst.FA), c1, rPS1(_inst.FB))); - rPS0(_inst.FD) = p0; - rPS1(_inst.FD) = p1; + rPS0(_inst.FD) = ForceSingle(NI_madd(rPS0(_inst.FA), c1, rPS0(_inst.FB))); + rPS1(_inst.FD) = ForceSingle(NI_madd(rPS1(_inst.FA), c1, rPS1(_inst.FB))); UpdateFPRF(rPS0(_inst.FD)); if (_inst.Rc) From b78310bbe562ee1c133d06739cf5a16167f10145 Mon Sep 17 00:00:00 2001 From: Tillmann Karras Date: Thu, 25 Jun 2015 22:29:31 +0200 Subject: [PATCH 009/583] Interpreter: simplify fres --- Source/Core/Common/MathUtil.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Source/Core/Common/MathUtil.cpp b/Source/Core/Common/MathUtil.cpp index 07fa5bf293..a9252ddf55 100644 --- a/Source/Core/Common/MathUtil.cpp +++ b/Source/Core/Common/MathUtil.cpp @@ -209,23 +209,23 @@ double ApproximateReciprocal(double val) // Special case 0 if (mantissa == 0 && exponent == 0) - return sign ? -std::numeric_limits::infinity() : std::numeric_limits::infinity(); + return std::copysign(std::numeric_limits::infinity(), valf); // Special case NaN-ish numbers if (exponent == (0x7FFLL << 52)) { if (mantissa == 0) - return sign ? -0.0 : 0.0; + return std::copysign(0.0, valf); return 0.0 + valf; } // Special case small inputs if (exponent < (895LL << 52)) - return sign ? -std::numeric_limits::max() : std::numeric_limits::max(); + return std::copysign(std::numeric_limits::max(), valf); // Special case large inputs if (exponent >= (1149LL << 52)) - return sign ? -0.0f : 0.0f; + return std::copysign(0.0, valf); exponent = (0x7FDLL << 52) - exponent; From 2711d5201b88d47ac5b980f0d73eb0b688368f91 Mon Sep 17 00:00:00 2001 From: Tillmann Karras Date: Thu, 25 Jun 2015 05:25:17 +0200 Subject: [PATCH 010/583] Interpreter: turn SNaNs into QNaNs --- .../PowerPC/Interpreter/Interpreter_FPUtils.h | 39 +++++++++++-------- 1 file changed, 23 insertions(+), 16 deletions(-) diff --git a/Source/Core/Core/PowerPC/Interpreter/Interpreter_FPUtils.h b/Source/Core/Core/PowerPC/Interpreter/Interpreter_FPUtils.h index dac55e608d..0c210fcc7d 100644 --- a/Source/Core/Core/PowerPC/Interpreter/Interpreter_FPUtils.h +++ b/Source/Core/Core/PowerPC/Interpreter/Interpreter_FPUtils.h @@ -76,6 +76,13 @@ inline double Force25Bit(double d) return x.d; } +inline double MakeQuiet(double d) +{ + MathUtil::IntDouble x(d); + x.i |= MathUtil::DOUBLE_QBIT; + return x.d; +} + // these functions allow globally modify operations behaviour // also, these may be used to set flags like FR, FI, OX, UX @@ -84,8 +91,8 @@ inline double NI_mul(double a, double b) double t = a * b; if (std::isnan(t)) { - if (std::isnan(a)) return a; - if (std::isnan(b)) return b; + if (std::isnan(a)) return MakeQuiet(a); + if (std::isnan(b)) return MakeQuiet(b); SetFPException(FPSCR_VXIMZ); return PPC_NAN; } @@ -97,8 +104,8 @@ inline double NI_div(double a, double b) double t = a / b; if (std::isnan(t)) { - if (std::isnan(a)) return a; - if (std::isnan(b)) return b; + if (std::isnan(a)) return MakeQuiet(a); + if (std::isnan(b)) return MakeQuiet(b); if (b == 0.0) { SetFPException(FPSCR_ZX); @@ -119,8 +126,8 @@ inline double NI_add(double a, double b) double t = a + b; if (std::isnan(t)) { - if (std::isnan(a)) return a; - if (std::isnan(b)) return b; + if (std::isnan(a)) return MakeQuiet(a); + if (std::isnan(b)) return MakeQuiet(b); SetFPException(FPSCR_VXISI); return PPC_NAN; } @@ -132,8 +139,8 @@ inline double NI_sub(double a, double b) double t = a - b; if (std::isnan(t)) { - if (std::isnan(a)) return a; - if (std::isnan(b)) return b; + if (std::isnan(a)) return MakeQuiet(a); + if (std::isnan(b)) return MakeQuiet(b); SetFPException(FPSCR_VXISI); return PPC_NAN; } @@ -148,16 +155,16 @@ inline double NI_madd(double a, double c, double b, bool negate = false) double t = a * c; if (std::isnan(t)) { - if (std::isnan(a)) return a; - if (std::isnan(b)) return b; // ! - if (std::isnan(c)) return c; + if (std::isnan(a)) return MakeQuiet(a); + if (std::isnan(b)) return MakeQuiet(b); // ! + if (std::isnan(c)) return MakeQuiet(c); SetFPException(FPSCR_VXIMZ); return PPC_NAN; } t += b; if (std::isnan(t)) { - if (std::isnan(b)) return b; + if (std::isnan(b)) return MakeQuiet(b); SetFPException(FPSCR_VXISI); return PPC_NAN; } @@ -169,9 +176,9 @@ inline double NI_msub(double a, double c, double b, bool negate = false) double t = a * c; if (std::isnan(t)) { - if (std::isnan(a)) return a; - if (std::isnan(b)) return b; // ! - if (std::isnan(c)) return c; + if (std::isnan(a)) return MakeQuiet(a); + if (std::isnan(b)) return MakeQuiet(b); // ! + if (std::isnan(c)) return MakeQuiet(c); SetFPException(FPSCR_VXIMZ); return PPC_NAN; } @@ -179,7 +186,7 @@ inline double NI_msub(double a, double c, double b, bool negate = false) t -= b; if (std::isnan(t)) { - if (std::isnan(b)) return b; + if (std::isnan(b)) return MakeQuiet(b); SetFPException(FPSCR_VXISI); return PPC_NAN; } From 0fcf0e1d213892dd316bb57e5932c2e77fba691b Mon Sep 17 00:00:00 2001 From: sigmabeta Date: Fri, 26 Jun 2015 08:32:51 -0400 Subject: [PATCH 011/583] Android: Show transition animation while game loads. --- .../activities/EmulationActivity.java | 49 +++++++++++++++++-- .../dolphinemu/adapters/GameAdapter.java | 8 ++- .../main/res/layout/activity_emulation.xml | 14 +++--- .../app/src/main/res/layout/card_game.xml | 2 +- .../res/transition/change_image_transform.xml | 4 ++ .../app/src/main/res/values/styles.xml | 26 +++++++++- 6 files changed, 91 insertions(+), 12 deletions(-) create mode 100644 Source/Android/app/src/main/res/transition/change_image_transform.xml diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/activities/EmulationActivity.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/activities/EmulationActivity.java index ce3f9624c7..44bfbb8272 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/activities/EmulationActivity.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/activities/EmulationActivity.java @@ -12,9 +12,11 @@ import android.view.Menu; import android.view.MenuItem; import android.view.MotionEvent; import android.view.View; +import android.view.ViewTreeObserver; import android.widget.FrameLayout; import android.widget.ImageView; +import com.squareup.picasso.Callback; import com.squareup.picasso.Picasso; import org.dolphinemu.dolphinemu.NativeLibrary; @@ -51,6 +53,10 @@ public final class EmulationActivity extends AppCompatActivity { super.onCreate(savedInstanceState); + // Picasso will take a while to load these big-ass screenshots. So don't run + // the animation until we say so. + postponeEnterTransition(); + mDeviceHasTouchScreen = getPackageManager().hasSystemFeature("android.hardware.touchscreen"); // Get a handle to the Window containing the UI. @@ -95,21 +101,42 @@ public final class EmulationActivity extends AppCompatActivity Picasso.with(this) .load(screenPath) - .fit() .noFade() - .into(mImageView); + .noPlaceholder() + .into(mImageView, new Callback() + { + @Override + public void onSuccess() + { + scheduleStartPostponedTransition(mImageView); + } + + @Override + public void onError() + { + // Still have to do this, or else the app will crash. + scheduleStartPostponedTransition(mImageView); + } + }); mImageView.animate() .setStartDelay(2000) .setDuration(500) .alpha(0.0f) + .withStartAction(new Runnable() + { + @Override + public void run() + { + mFrameLayout.setVisibility(View.VISIBLE); + } + }) .withEndAction(new Runnable() { @Override public void run() { mImageView.setVisibility(View.GONE); - mFrameLayout.setVisibility(View.VISIBLE); } }); @@ -354,4 +381,20 @@ public final class EmulationActivity extends AppCompatActivity hideSystemUiAfterDelay(); } + + + private void scheduleStartPostponedTransition(final View sharedElement) + { + sharedElement.getViewTreeObserver().addOnPreDrawListener( + new ViewTreeObserver.OnPreDrawListener() + { + @Override + public boolean onPreDraw() + { + sharedElement.getViewTreeObserver().removeOnPreDrawListener(this); + startPostponedEnterTransition(); + return true; + } + }); + } } diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/adapters/GameAdapter.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/adapters/GameAdapter.java index 8b279c52c2..3cb832f91b 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/adapters/GameAdapter.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/adapters/GameAdapter.java @@ -1,6 +1,7 @@ package org.dolphinemu.dolphinemu.adapters; import android.app.Activity; +import android.app.ActivityOptions; import android.content.Intent; import android.database.Cursor; import android.database.DataSetObserver; @@ -222,7 +223,12 @@ public final class GameAdapter extends RecyclerView.Adapter impl intent.putExtra("SelectedTitle", holder.title); intent.putExtra("ScreenPath", holder.screenshotPath); - view.getContext().startActivity(intent); + ActivityOptions options = ActivityOptions.makeSceneTransitionAnimation( + (Activity) view.getContext(), + holder.imageScreenshot, + "image_game_screenshot"); + + view.getContext().startActivity(intent, options.toBundle()); } /** diff --git a/Source/Android/app/src/main/res/layout/activity_emulation.xml b/Source/Android/app/src/main/res/layout/activity_emulation.xml index 5a644b260a..c686c6191e 100644 --- a/Source/Android/app/src/main/res/layout/activity_emulation.xml +++ b/Source/Android/app/src/main/res/layout/activity_emulation.xml @@ -3,14 +3,16 @@ android:layout_height="match_parent" > - - + android:visibility="invisible"/> + + + \ No newline at end of file diff --git a/Source/Android/app/src/main/res/layout/card_game.xml b/Source/Android/app/src/main/res/layout/card_game.xml index b18bc9e7ee..9b172b6871 100644 --- a/Source/Android/app/src/main/res/layout/card_game.xml +++ b/Source/Android/app/src/main/res/layout/card_game.xml @@ -20,7 +20,7 @@ android:id="@+id/image_game_screen" android:layout_width="match_parent" android:layout_height="0dp" - android:transitionName="image_game_screen" + android:transitionName="image_game_screenshot" android:layout_weight="1" tools:src="@drawable/placeholder_screenshot" tools:scaleType="centerCrop"/> diff --git a/Source/Android/app/src/main/res/transition/change_image_transform.xml b/Source/Android/app/src/main/res/transition/change_image_transform.xml new file mode 100644 index 0000000000..3ee92bd7c4 --- /dev/null +++ b/Source/Android/app/src/main/res/transition/change_image_transform.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/Source/Android/app/src/main/res/values/styles.xml b/Source/Android/app/src/main/res/values/styles.xml index 98cf984807..dc81c173a7 100644 --- a/Source/Android/app/src/main/res/values/styles.xml +++ b/Source/Android/app/src/main/res/values/styles.xml @@ -7,6 +7,18 @@ @color/dolphin_blue @color/dolphin_blue_dark + + @@ -66,6 +78,19 @@ @color/dolphin_blue @color/dolphin_blue_dark true + + + true + + + @android:transition/explode + @android:transition/explode + + + @transition/change_image_transform + + @transition/change_image_transform + @@ -81,7 +106,6 @@ @color/dolphin_accent_wiiware - @@ -74,23 +67,17 @@ @color/dolphin_accent_wiiware - From df70f50fdfcc69726f7d8fd186054dbe3e68c57e Mon Sep 17 00:00:00 2001 From: "Admiral H. Curtiss" Date: Fri, 26 Jun 2015 23:43:45 +0200 Subject: [PATCH 014/583] GetExeDirectory() shouldn't return paths with /../ in the middle. --- Source/Core/Common/FileUtil.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Source/Core/Common/FileUtil.cpp b/Source/Core/Common/FileUtil.cpp index 4709c011b2..0b4a99bbd7 100644 --- a/Source/Core/Common/FileUtil.cpp +++ b/Source/Core/Common/FileUtil.cpp @@ -731,8 +731,12 @@ std::string& GetExeDirectory() if (DolphinPath.empty()) { TCHAR Dolphin_exe_Path[2048]; + TCHAR Dolphin_exe_Clean_Path[MAX_PATH]; GetModuleFileName(nullptr, Dolphin_exe_Path, 2048); - DolphinPath = TStrToUTF8(Dolphin_exe_Path); + if (_tfullpath(Dolphin_exe_Clean_Path, Dolphin_exe_Path, MAX_PATH) != nullptr) + DolphinPath = TStrToUTF8(Dolphin_exe_Clean_Path); + else + DolphinPath = TStrToUTF8(Dolphin_exe_Path); DolphinPath = DolphinPath.substr(0, DolphinPath.find_last_of('\\')); } return DolphinPath; From 583e3fd9e01fba73db77adf32a3818c57075b81a Mon Sep 17 00:00:00 2001 From: "Admiral H. Curtiss" Date: Fri, 26 Jun 2015 23:42:23 +0200 Subject: [PATCH 015/583] GameCubeConfig: If the user selects a memcard file path within Dolphin's directory, store the path relative to it. This makes Dolphin more portable in portable mode, since the memory card file is still found if the directory is moved somewhere else. This also means that we have to explicitly compare absolute paths if we want to check for both slots containing the same file. --- .../DolphinWX/Config/GameCubeConfigPane.cpp | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/Source/Core/DolphinWX/Config/GameCubeConfigPane.cpp b/Source/Core/DolphinWX/Config/GameCubeConfigPane.cpp index 369d383dc7..807015427c 100644 --- a/Source/Core/DolphinWX/Config/GameCubeConfigPane.cpp +++ b/Source/Core/DolphinWX/Config/GameCubeConfigPane.cpp @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -332,22 +333,21 @@ void GameCubeConfigPane::ChooseSlotPath(bool is_slot_a, TEXIDevices device_type) } } #ifdef _WIN32 - if (!strncmp(File::GetExeDirectory().c_str(), filename.c_str(), File::GetExeDirectory().size())) - { - // If the Exe Directory Matches the prefix of the filename, we still need to verify - // that the next character is a directory separator character, otherwise we may create an invalid path - char next_char = filename.at(File::GetExeDirectory().size()) + 1; - if (next_char == '/' || next_char == '\\') - { - filename.erase(0, File::GetExeDirectory().size() + 1); - filename = "./" + filename; - } - } + // If the Memory Card file is within the Exe dir, we can assume that the user wants it to be stored relative + // to the executable, so it stays set correctly when the probably portable Exe dir is moved. + std::string exeDir = File::GetExeDirectory() + '\\'; + if (!strncmp(exeDir.c_str(), filename.c_str(), exeDir.size())) + filename.erase(0, exeDir.size()); + std::replace(filename.begin(), filename.end(), '\\', '/'); #endif // also check that the path isn't used for the other memcard... - if (filename.compare(is_slot_a ? pathB : pathA) != 0) + wxFileName newFilename(filename); + wxFileName otherFilename(is_slot_a ? pathB : pathA); + newFilename.MakeAbsolute(); + otherFilename.MakeAbsolute(); + if (newFilename.GetFullPath().compare(otherFilename.GetFullPath()) != 0) { if (memcard) { From c5b81b1aff9d9f34bac41da71ae02905fe4ee913 Mon Sep 17 00:00:00 2001 From: "Admiral H. Curtiss" Date: Sat, 27 Jun 2015 18:34:54 +0200 Subject: [PATCH 016/583] GameCubeConfig: Case insensitive compare & absolute path compare for the part-of-exe-dir check. --- Source/Core/DolphinWX/Config/GameCubeConfigPane.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/Source/Core/DolphinWX/Config/GameCubeConfigPane.cpp b/Source/Core/DolphinWX/Config/GameCubeConfigPane.cpp index 807015427c..f4426ef3a9 100644 --- a/Source/Core/DolphinWX/Config/GameCubeConfigPane.cpp +++ b/Source/Core/DolphinWX/Config/GameCubeConfigPane.cpp @@ -332,20 +332,24 @@ void GameCubeConfigPane::ChooseSlotPath(bool is_slot_a, TEXIDevices device_type) } } } + + wxFileName newFilename(filename); + newFilename.MakeAbsolute(); + filename = newFilename.GetFullPath(); + #ifdef _WIN32 // If the Memory Card file is within the Exe dir, we can assume that the user wants it to be stored relative // to the executable, so it stays set correctly when the probably portable Exe dir is moved. + // TODO: Replace this with a cleaner, non-wx solution once std::filesystem is standard std::string exeDir = File::GetExeDirectory() + '\\'; - if (!strncmp(exeDir.c_str(), filename.c_str(), exeDir.size())) + if (wxString(filename).Lower().StartsWith(wxString(exeDir).Lower())) filename.erase(0, exeDir.size()); std::replace(filename.begin(), filename.end(), '\\', '/'); #endif // also check that the path isn't used for the other memcard... - wxFileName newFilename(filename); wxFileName otherFilename(is_slot_a ? pathB : pathA); - newFilename.MakeAbsolute(); otherFilename.MakeAbsolute(); if (newFilename.GetFullPath().compare(otherFilename.GetFullPath()) != 0) { From 66136fc710a2d583d2fef905d667e176c43e6080 Mon Sep 17 00:00:00 2001 From: JosJuice Date: Sun, 28 Jun 2015 10:39:24 +0200 Subject: [PATCH 017/583] Fix more game list name encoding errors caused by 4.0-6419 (d7900b4) 4.0-6442 (a26cf63) didn't fix names read from INIs or titles.txt. --- Source/Core/DolphinWX/GameListCtrl.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Source/Core/DolphinWX/GameListCtrl.cpp b/Source/Core/DolphinWX/GameListCtrl.cpp index 34f50ef4d5..0c847387ba 100644 --- a/Source/Core/DolphinWX/GameListCtrl.cpp +++ b/Source/Core/DolphinWX/GameListCtrl.cpp @@ -403,7 +403,7 @@ void CGameListCtrl::InsertItemInReportView(long _Index) if (line.substr(0,rISOFile.GetUniqueID().size()) == rISOFile.GetUniqueID()) { - name = line.substr(rISOFile.GetUniqueID().size() + 3); + name = StrToWxStr(line.substr(rISOFile.GetUniqueID().size() + 3)); break; } } @@ -413,7 +413,7 @@ void CGameListCtrl::InsertItemInReportView(long _Index) std::string title; IniFile gameini = SCoreStartupParameter::LoadGameIni(rISOFile.GetUniqueID(), rISOFile.GetRevision()); if (gameini.GetIfExists("EmuState", "Title", &title)) - name = title; + name = StrToWxStr(title); int disc_number = rISOFile.GetDiscNumber() + 1; if (disc_number > 1 && name.Lower().find(wxString::Format("disc %i", disc_number)) == std::string::npos From 3f39e38372cbc4169c9d03dd15d3608b6dcd83b7 Mon Sep 17 00:00:00 2001 From: Jules Blok Date: Sun, 28 Jun 2015 17:50:29 +0200 Subject: [PATCH 018/583] CheatSearchTab: Check Core state instead of checking a memory pointer. --- Source/Core/DolphinWX/Cheats/CheatSearchTab.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Source/Core/DolphinWX/Cheats/CheatSearchTab.cpp b/Source/Core/DolphinWX/Cheats/CheatSearchTab.cpp index d559e9dacd..d73c11a7c3 100644 --- a/Source/Core/DolphinWX/Cheats/CheatSearchTab.cpp +++ b/Source/Core/DolphinWX/Cheats/CheatSearchTab.cpp @@ -17,6 +17,7 @@ #include "Common/CommonTypes.h" #include "Common/StringUtil.h" #include "Core/ActionReplay.h" +#include "Core/Core.h" #include "Core/HW/Memmap.h" #include "DolphinWX/WxUtils.h" #include "DolphinWX/Cheats/CheatSearchTab.h" @@ -125,7 +126,7 @@ CheatSearchTab::CheatSearchTab(wxWindow* const parent) void CheatSearchTab::StartNewSearch(wxCommandEvent& WXUNUSED(event)) { const u8* const memptr = Memory::m_pRAM; - if (memptr == nullptr) + if (!Core::IsRunningAndStarted()) { WxUtils::ShowErrorDialog(_("A game is not currently running.")); return; @@ -157,7 +158,7 @@ void CheatSearchTab::StartNewSearch(wxCommandEvent& WXUNUSED(event)) void CheatSearchTab::FilterCheatSearchResults(wxCommandEvent&) { const u8* const memptr = Memory::m_pRAM; - if (memptr == nullptr) + if (!Core::IsRunningAndStarted()) { WxUtils::ShowErrorDialog(_("A game is not currently running.")); return; From daa205990fa043092394931b85be6efdc37408df Mon Sep 17 00:00:00 2001 From: Lioncash Date: Sun, 28 Jun 2015 19:08:28 -0400 Subject: [PATCH 019/583] Use emplace() instead of insert() where applicable for maps. --- Source/Core/Common/SymbolDB.cpp | 2 +- Source/Core/Core/NetPlayServer.cpp | 2 +- .../Core/Core/PowerPC/JitCommon/JitCache.cpp | 2 +- Source/Core/Core/State.cpp | 7 +++-- Source/Core/DiscIO/VolumeDirectory.cpp | 2 +- .../Core/DolphinWX/ControllerConfigDiag.cpp | 10 +++---- Source/Core/DolphinWX/VideoConfigDiag.cpp | 4 +-- Source/Core/VideoBackends/D3D/D3DState.cpp | 26 ++++++++++++------- .../VideoBackends/D3D/PSTextureEncoder.cpp | 2 +- Source/Core/VideoCommon/DriverDetails.cpp | 2 +- Source/Core/VideoCommon/OnScreenDisplay.cpp | 2 +- Source/Core/VideoCommon/TextureCacheBase.cpp | 10 +++---- 12 files changed, 41 insertions(+), 30 deletions(-) diff --git a/Source/Core/Common/SymbolDB.cpp b/Source/Core/Common/SymbolDB.cpp index 9e7b553b13..f8b9cec346 100644 --- a/Source/Core/Common/SymbolDB.cpp +++ b/Source/Core/Common/SymbolDB.cpp @@ -53,5 +53,5 @@ Symbol* SymbolDB::GetSymbolFromName(const std::string& name) void SymbolDB::AddCompleteSymbol(const Symbol &symbol) { - functions.insert(std::pair(symbol.address, symbol)); + functions.emplace(symbol.address, symbol); } diff --git a/Source/Core/Core/NetPlayServer.cpp b/Source/Core/Core/NetPlayServer.cpp index b26a5d0391..d61632584c 100644 --- a/Source/Core/Core/NetPlayServer.cpp +++ b/Source/Core/Core/NetPlayServer.cpp @@ -333,7 +333,7 @@ unsigned int NetPlayServer::OnConnect(ENetPeer* socket) // add client to the player list { std::lock_guard lkp(m_crit.players); - m_players.insert(std::pair(*(PlayerId *)player.socket->data, player)); + m_players.emplace(*(PlayerId *)player.socket->data, player); UpdatePadMapping(); // sync pad mappings with everyone UpdateWiimoteMapping(); } diff --git a/Source/Core/Core/PowerPC/JitCommon/JitCache.cpp b/Source/Core/Core/PowerPC/JitCommon/JitCache.cpp index 44f55681f0..c3e3e2fdfc 100644 --- a/Source/Core/Core/PowerPC/JitCommon/JitCache.cpp +++ b/Source/Core/Core/PowerPC/JitCommon/JitCache.cpp @@ -136,7 +136,7 @@ using namespace Gen; { for (const auto& e : b.linkData) { - links_to.insert(std::pair(e.exitAddress, block_num)); + links_to.emplace(e.exitAddress, block_num); } LinkBlock(block_num); diff --git a/Source/Core/Core/State.cpp b/Source/Core/Core/State.cpp index 62d6111580..1ace08f922 100644 --- a/Source/Core/Core/State.cpp +++ b/Source/Core/Core/State.cpp @@ -257,9 +257,12 @@ static std::map GetSavedStates() if (ReadHeader(filename, header)) { double d = Common::Timer::GetDoubleTime() - header.time; + // increase time until unique value is obtained - while (m.find(d) != m.end()) d += .001; - m.insert(std::pair(d, i)); + while (m.find(d) != m.end()) + d += .001; + + m.emplace(d, i); } } } diff --git a/Source/Core/DiscIO/VolumeDirectory.cpp b/Source/Core/DiscIO/VolumeDirectory.cpp index ee22db75ab..905403e14b 100644 --- a/Source/Core/DiscIO/VolumeDirectory.cpp +++ b/Source/Core/DiscIO/VolumeDirectory.cpp @@ -467,7 +467,7 @@ void CVolumeDirectory::WriteEntry(const File::FSTEntry& entry, u32& fstOffset, u // write entry to virtual disk _dbg_assert_(DVDINTERFACE, m_virtualDisk.find(dataOffset) == m_virtualDisk.end()); - m_virtualDisk.insert(make_pair(dataOffset, entry.physicalName)); + m_virtualDisk.emplace(dataOffset, entry.physicalName); // 4 byte aligned dataOffset = ROUND_UP(dataOffset + entry.size, 0x8000ull); diff --git a/Source/Core/DolphinWX/ControllerConfigDiag.cpp b/Source/Core/DolphinWX/ControllerConfigDiag.cpp index ab5e220764..ff5bafc44e 100644 --- a/Source/Core/DolphinWX/ControllerConfigDiag.cpp +++ b/Source/Core/DolphinWX/ControllerConfigDiag.cpp @@ -87,13 +87,13 @@ wxStaticBoxSizer* ControllerConfigDiag::CreateGamecubeSizer() // Create an ID for the config button. const wxWindowID button_id = wxWindow::NewControlId(); - m_gc_port_config_ids.insert(std::make_pair(button_id, i)); + m_gc_port_config_ids.emplace(button_id, i); gamecube_configure_bt[i] = new wxButton(this, button_id, _("Configure"), wxDefaultPosition, wxSize(100, 25)); gamecube_configure_bt[i]->Bind(wxEVT_BUTTON, &ControllerConfigDiag::OnGameCubeConfigButton, this); // Create a control ID for the choice boxes on the fly. const wxWindowID choice_id = wxWindow::NewControlId(); - m_gc_port_choice_ids.insert(std::make_pair(choice_id, i)); + m_gc_port_choice_ids.emplace(choice_id, i); // Only add AM-Baseboard to the first pad. if (i == 0) @@ -223,10 +223,10 @@ wxStaticBoxSizer* ControllerConfigDiag::CreateWiimoteConfigSizer() // reserve four ids, so that we can calculate the index from the ids later on // Stupid wx 2.8 doesn't support reserving sequential IDs, so we need to do that more complicated.. int source_ctrl_id = wxWindow::NewControlId(); - m_wiimote_index_from_ctrl_id.insert(std::pair(source_ctrl_id, i)); + m_wiimote_index_from_ctrl_id.emplace(source_ctrl_id, i); int config_bt_id = wxWindow::NewControlId(); - m_wiimote_index_from_conf_bt_id.insert(std::pair(config_bt_id, i)); + m_wiimote_index_from_conf_bt_id.emplace(config_bt_id, i); wiimote_label[i] = new wxStaticText(this, wxID_ANY, wiimote_str); wiimote_source_ch[i] = new wxChoice(this, source_ctrl_id, wxDefaultPosition, wxDefaultSize, src_choices.size(), src_choices.data()); @@ -284,7 +284,7 @@ wxStaticBoxSizer* ControllerConfigDiag::CreateBalanceBoardSizer() wxFlexGridSizer* const bb_sizer = new wxFlexGridSizer(1, 5, 5); int source_ctrl_id = wxWindow::NewControlId(); - m_wiimote_index_from_ctrl_id.insert(std::pair(source_ctrl_id, WIIMOTE_BALANCE_BOARD)); + m_wiimote_index_from_ctrl_id.emplace(source_ctrl_id, WIIMOTE_BALANCE_BOARD); static const std::array src_choices = {{ _("None"), _("Real Balance Board") diff --git a/Source/Core/DolphinWX/VideoConfigDiag.cpp b/Source/Core/DolphinWX/VideoConfigDiag.cpp index 9d3d66959c..0e8044b25c 100644 --- a/Source/Core/DolphinWX/VideoConfigDiag.cpp +++ b/Source/Core/DolphinWX/VideoConfigDiag.cpp @@ -655,7 +655,7 @@ SettingRadioButton* VideoConfigDiag::CreateRadioButton(wxWindow* parent, const w /* Use this to register descriptions for controls which have NOT been created using the Create* functions from above */ wxControl* VideoConfigDiag::RegisterControl(wxControl* const control, const wxString& description) { - ctrl_descs.insert(std::pair(control, description)); + ctrl_descs.emplace(control, description); control->Bind(wxEVT_ENTER_WINDOW, &VideoConfigDiag::Evt_EnterControl, this); control->Bind(wxEVT_LEAVE_WINDOW, &VideoConfigDiag::Evt_LeaveControl, this); return control; @@ -710,7 +710,7 @@ void VideoConfigDiag::CreateDescriptionArea(wxPanel* const page, wxBoxSizer* con desc_sizer->Add(desc_text, 1, wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM, 5); // Store description text object for later lookup - desc_texts.insert(std::pair(page, desc_text)); + desc_texts.emplace(page, desc_text); } void VideoConfigDiag::PopulatePostProcessingShaders() diff --git a/Source/Core/VideoBackends/D3D/D3DState.cpp b/Source/Core/VideoBackends/D3D/D3DState.cpp index 5bd95bc8f3..9627ae2019 100644 --- a/Source/Core/VideoBackends/D3D/D3DState.cpp +++ b/Source/Core/VideoBackends/D3D/D3DState.cpp @@ -315,9 +315,11 @@ ID3D11SamplerState* StateCache::Get(SamplerState state) ID3D11SamplerState* res = nullptr; HRESULT hr = D3D::device->CreateSamplerState(&sampdc, &res); - if (FAILED(hr)) PanicAlert("Fail %s %d\n", __FILE__, __LINE__); + if (FAILED(hr)) + PanicAlert("Fail %s %d\n", __FILE__, __LINE__); + D3D::SetDebugObjectName((ID3D11DeviceChild*)res, "sampler state used to emulate the GX pipeline"); - m_sampler.insert(std::make_pair(state.packed, res)); + m_sampler.emplace(state.packed, res); return res; } @@ -394,9 +396,11 @@ ID3D11BlendState* StateCache::Get(BlendState state) ID3D11BlendState* res = nullptr; HRESULT hr = D3D::device->CreateBlendState(&blenddc, &res); - if (FAILED(hr)) PanicAlert("Failed to create blend state at %s %d\n", __FILE__, __LINE__); + if (FAILED(hr)) + PanicAlert("Failed to create blend state at %s %d\n", __FILE__, __LINE__); + D3D::SetDebugObjectName((ID3D11DeviceChild*)res, "blend state used to emulate the GX pipeline"); - m_blend.insert(std::make_pair(state.packed, res)); + m_blend.emplace(state.packed, res); return res; } @@ -415,9 +419,11 @@ ID3D11RasterizerState* StateCache::Get(RasterizerState state) ID3D11RasterizerState* res = nullptr; HRESULT hr = D3D::device->CreateRasterizerState(&rastdc, &res); - if (FAILED(hr)) PanicAlert("Failed to create rasterizer state at %s %d\n", __FILE__, __LINE__); + if (FAILED(hr)) + PanicAlert("Failed to create rasterizer state at %s %d\n", __FILE__, __LINE__); + D3D::SetDebugObjectName((ID3D11DeviceChild*)res, "rasterizer state used to emulate the GX pipeline"); - m_raster.insert(std::make_pair(state.packed, res)); + m_raster.emplace(state.packed, res); return res; } @@ -466,10 +472,12 @@ ID3D11DepthStencilState* StateCache::Get(ZMode state) ID3D11DepthStencilState* res = nullptr; HRESULT hr = D3D::device->CreateDepthStencilState(&depthdc, &res); - if (SUCCEEDED(hr)) D3D::SetDebugObjectName((ID3D11DeviceChild*)res, "depth-stencil state used to emulate the GX pipeline"); - else PanicAlert("Failed to create depth state at %s %d\n", __FILE__, __LINE__); + if (SUCCEEDED(hr)) + D3D::SetDebugObjectName((ID3D11DeviceChild*)res, "depth-stencil state used to emulate the GX pipeline"); + else + PanicAlert("Failed to create depth state at %s %d\n", __FILE__, __LINE__); - m_depth.insert(std::make_pair(state.hex, res)); + m_depth.emplace(state.hex, res); return res; } diff --git a/Source/Core/VideoBackends/D3D/PSTextureEncoder.cpp b/Source/Core/VideoBackends/D3D/PSTextureEncoder.cpp index 485cf54ee3..cdb7f75102 100644 --- a/Source/Core/VideoBackends/D3D/PSTextureEncoder.cpp +++ b/Source/Core/VideoBackends/D3D/PSTextureEncoder.cpp @@ -258,7 +258,7 @@ ID3D11PixelShader* PSTextureEncoder::SetStaticShader(unsigned int dstFormat, PEC dstFormat, srcFormat, isIntensity, scaleByHalf); D3D::SetDebugObjectName(newShader, debugName); - it = m_staticShaders.insert(std::make_pair(key, newShader)).first; + it = m_staticShaders.emplace(key, newShader).first; bytecode->Release(); } diff --git a/Source/Core/VideoCommon/DriverDetails.cpp b/Source/Core/VideoCommon/DriverDetails.cpp index d3b1883cb3..04808c3e62 100644 --- a/Source/Core/VideoCommon/DriverDetails.cpp +++ b/Source/Core/VideoCommon/DriverDetails.cpp @@ -105,7 +105,7 @@ namespace DriverDetails ( bug.m_versionstart <= m_version || bug.m_versionstart == -1 ) && ( bug.m_versionend > m_version || bug.m_versionend == -1 ) ) - m_bugs.insert(std::make_pair(bug.m_bug, bug)); + m_bugs.emplace(bug.m_bug, bug); } } diff --git a/Source/Core/VideoCommon/OnScreenDisplay.cpp b/Source/Core/VideoCommon/OnScreenDisplay.cpp index ddd80065e1..dfd597f0ed 100644 --- a/Source/Core/VideoCommon/OnScreenDisplay.cpp +++ b/Source/Core/VideoCommon/OnScreenDisplay.cpp @@ -71,7 +71,7 @@ void ClearMessages() // On-Screen Display Callbacks void AddCallback(CallbackType type, Callback cb) { - s_callbacks.insert(std::pair(type, cb)); + s_callbacks.emplace(type, cb); } void DoCallbacks(CallbackType type) diff --git a/Source/Core/VideoCommon/TextureCacheBase.cpp b/Source/Core/VideoCommon/TextureCacheBase.cpp index 0b0588cf6e..6baca12326 100644 --- a/Source/Core/VideoCommon/TextureCacheBase.cpp +++ b/Source/Core/VideoCommon/TextureCacheBase.cpp @@ -474,7 +474,7 @@ TextureCache::TCacheEntryBase* TextureCache::Load(const u32 stage) decoded_entry->is_efb_copy = false; g_texture_cache->ConvertTexture(decoded_entry, entry, &texMem[tlutaddr], (TlutFormat)tlutfmt); - textures_by_address.insert(TexCache::value_type((u64)address, decoded_entry)); + textures_by_address.emplace((u64)address, decoded_entry); return ReturnEntry(stage, decoded_entry); } @@ -560,11 +560,11 @@ TextureCache::TCacheEntryBase* TextureCache::Load(const u32 stage) TCacheEntryBase* entry = AllocateTexture(config); GFX_DEBUGGER_PAUSE_AT(NEXT_NEW_TEXTURE, true); - textures_by_address.insert(TexCache::value_type((u64)address, entry)); + textures_by_address.emplace((u64)address, entry); if (g_ActiveConfig.iSafeTextureCache_ColorSamples == 0 || std::max(texture_size, palette_size) <= (u32)g_ActiveConfig.iSafeTextureCache_ColorSamples * 8) { - entry->textures_by_hash_iter = textures_by_hash.insert(TexCache::value_type(full_hash, entry)); + entry->textures_by_hash_iter = textures_by_hash.emplace(full_hash, entry); } entry->SetGeneralParameters(address, texture_size, full_format); @@ -963,7 +963,7 @@ void TextureCache::CopyRenderTargetToTexture(u32 dstAddr, unsigned int dstFormat count++), 0); } - textures_by_address.insert(TexCache::value_type((u64)dstAddr, entry)); + textures_by_address.emplace((u64)dstAddr, entry); } TextureCache::TCacheEntryBase* TextureCache::AllocateTexture(const TCacheEntryConfig& config) @@ -996,7 +996,7 @@ TextureCache::TexCache::iterator TextureCache::FreeTexture(TexCache::iterator it } entry->frameCount = FRAMECOUNT_INVALID; - texture_pool.insert(TexPool::value_type(entry->config, entry)); + texture_pool.emplace(entry->config, entry); return textures_by_address.erase(iter); } From 7248f9b5248389ac4f2978f2b1276484b0e4396d Mon Sep 17 00:00:00 2001 From: Stevoisiak Date: Thu, 2 Apr 2015 15:50:14 -0400 Subject: [PATCH 020/583] Minor spelling corrections --- Source/Core/AudioCommon/aldlist.cpp | 2 +- Source/Core/Core/Boot/Boot_BS2Emu.cpp | 6 +++--- Source/Core/Core/HW/GCMemcard.h | 4 ++-- Source/Core/DiscIO/VolumeCreator.cpp | 12 ++++++------ 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/Source/Core/AudioCommon/aldlist.cpp b/Source/Core/AudioCommon/aldlist.cpp index e5fe5f2cb4..c775554401 100644 --- a/Source/Core/AudioCommon/aldlist.cpp +++ b/Source/Core/AudioCommon/aldlist.cpp @@ -335,7 +335,7 @@ s32 ALDeviceList::GetNextFilteredDevice() } /* - * Internal function to detemine max number of Sources that can be generated + * Internal function to determine max number of Sources that can be generated */ u32 ALDeviceList::GetMaxNumSources() { diff --git a/Source/Core/Core/Boot/Boot_BS2Emu.cpp b/Source/Core/Core/Boot/Boot_BS2Emu.cpp index 854d71049c..af720a955a 100644 --- a/Source/Core/Core/Boot/Boot_BS2Emu.cpp +++ b/Source/Core/Core/Boot/Boot_BS2Emu.cpp @@ -229,7 +229,7 @@ bool CBoot::SetupWiiMemory(DiscIO::IVolume::ECountry country) if (!settingsFileHandle.WriteBytes(gen.GetData(), SettingsHandler::SETTINGS_SIZE)) { - PanicAlertT("SetupWiiMemory: Cant create setting.txt file"); + PanicAlertT("SetupWiiMemory: Can't create setting.txt file"); return false; } // Write the 256 byte setting.txt to memory. @@ -240,7 +240,7 @@ bool CBoot::SetupWiiMemory(DiscIO::IVolume::ECountry country) /* Set hardcoded global variables to Wii memory. These are partly collected from - Wiibrew. These values are needed for the games to function correctly. A few + WiiBrew. These values are needed for the games to function correctly. A few values in this region will also be placed here by the game as it boots. They are: 0x80000038 Start of FST @@ -315,7 +315,7 @@ bool CBoot::EmulatedBS2_Wii() { INFO_LOG(BOOT, "Faking Wii BS2..."); - // setup Wii memory + // Setup Wii memory DiscIO::IVolume::ECountry country_code = DiscIO::IVolume::COUNTRY_UNKNOWN; if (DVDInterface::VolumeIsValid()) country_code = DVDInterface::GetVolume().GetCountry(); diff --git a/Source/Core/Core/HW/GCMemcard.h b/Source/Core/Core/HW/GCMemcard.h index 0b3fa41391..cdd760f2cf 100644 --- a/Source/Core/Core/HW/GCMemcard.h +++ b/Source/Core/Core/HW/GCMemcard.h @@ -116,7 +116,7 @@ struct Header //Offset Size Description // end Serial in libogc u8 deviceID[2]; //0x0020 2 0 if formated in slot A 1 if formated in slot B u8 SizeMb[2]; //0x0022 2 Size of memcard in Mbits - u16 Encoding; //0x0024 2 Encoding (ASCII or japanese) + u16 Encoding; //0x0024 2 Encoding (ASCII or Japanese) u8 Unused1[468]; //0x0026 468 Unused (0xff) u16 UpdateCounter; //0x01fa 2 Update Counter (?, probably unused) u16 Checksum; //0x01fc 2 Additive Checksum @@ -139,7 +139,7 @@ struct Header //Offset Size Description // Nintendo format algorithm. // Constants are fixed by the GC SDK - // Changing the constants will break memorycard support + // Changing the constants will break memory card support Header(int slot = 0, u16 sizeMb = MemCard2043Mb, bool ascii = true) { memset(this, 0xFF, BLOCK_SIZE); diff --git a/Source/Core/DiscIO/VolumeCreator.cpp b/Source/Core/DiscIO/VolumeCreator.cpp index 14ba411d90..fdcf4f955e 100644 --- a/Source/Core/DiscIO/VolumeCreator.cpp +++ b/Source/Core/DiscIO/VolumeCreator.cpp @@ -178,7 +178,7 @@ static IVolume* CreateVolumeFromCryptedWiiImage(IBlobReader& _rReader, u32 _Part }; SPartitionGroup PartitionGroup[4]; - // read all partitions + // Read all partitions for (SPartitionGroup& group : PartitionGroup) { for (u32 i = 0; i < numPartitions; i++) @@ -190,9 +190,9 @@ static IVolume* CreateVolumeFromCryptedWiiImage(IBlobReader& _rReader, u32 _Part } } - // return the partition type specified or number + // Return the partition type specified or number // types: 0 = game, 1 = firmware update, 2 = channel installer - // some partitions on ssbb use the ascii title id of the demo VC game they hold... + // some partitions on SSBB use the ASCII title id of the demo VC game they hold... for (size_t i = 0; i < PartitionGroup[_PartitionGroup].PartitionsVec.size(); i++) { const SPartition& rPartition = PartitionGroup[_PartitionGroup].PartitionsVec.at(i); @@ -216,18 +216,18 @@ EDiscType GetDiscType(IBlobReader& _rReader) u32 WADMagic = Reader.Read32(0x02); u32 GCMagic = Reader.Read32(0x1C); - // check for Wii + // Check for Wii if (WiiMagic == 0x5D1C9EA3 && WiiContainerMagic != 0) return DISC_TYPE_WII; if (WiiMagic == 0x5D1C9EA3 && WiiContainerMagic == 0) return DISC_TYPE_WII_CONTAINER; - // check for WAD + // Check for WAD // 0x206962 for boot2 wads if (WADMagic == 0x00204973 || WADMagic == 0x00206962) return DISC_TYPE_WAD; - // check for GC + // Check for GC if (GCMagic == 0xC2339F3D) return DISC_TYPE_GC; From afc3d30f5ce270d64cdc4c7a9151b9fb1590b818 Mon Sep 17 00:00:00 2001 From: Ryan Houdek Date: Mon, 29 Jun 2015 19:00:22 -0500 Subject: [PATCH 021/583] [AArch64] Implement BFI & UBFIZ in the emitter. Also fixes a bug in the UBFX instruction emitter. Naughty Naughty PPSSPP, not testing emitter functions you add. --- Source/Core/Common/Arm64Emitter.cpp | 15 +++++++++++++++ Source/Core/Common/Arm64Emitter.h | 4 +++- 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/Source/Core/Common/Arm64Emitter.cpp b/Source/Core/Common/Arm64Emitter.cpp index 600b424d51..c31583e5fc 100644 --- a/Source/Core/Common/Arm64Emitter.cpp +++ b/Source/Core/Common/Arm64Emitter.cpp @@ -1523,6 +1523,21 @@ void ARM64XEmitter::UBFM(ARM64Reg Rd, ARM64Reg Rn, u32 immr, u32 imms) { EncodeBitfieldMOVInst(2, Rd, Rn, immr, imms); } + +void ARM64XEmitter::BFI(ARM64Reg Rd, ARM64Reg Rn, u32 lsb, u32 width) +{ + u32 size = Is64Bit(Rn) ? 64 : 32; + _assert_msg_(DYNA_REC, (lsb + width) <= size, "%s passed lsb %d and width %d which is greater than the register size!", + __FUNCTION__, lsb, width); + EncodeBitfieldMOVInst(1, Rd, Rn, (size - lsb) % size, width - 1); +} +void ARM64XEmitter::UBFIZ(ARM64Reg Rd, ARM64Reg Rn, u32 lsb, u32 width) +{ + u32 size = Is64Bit(Rn) ? 64 : 32; + _assert_msg_(DYNA_REC, (lsb + width) <= size, "%s passed lsb %d and width %d which is greater than the register size!", + __FUNCTION__, lsb, width); + EncodeBitfieldMOVInst(2, Rd, Rn, (size - lsb) % size, width - 1); +} void ARM64XEmitter::EXTR(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm, u32 shift) { bool sf = Is64Bit(Rd); diff --git a/Source/Core/Common/Arm64Emitter.h b/Source/Core/Common/Arm64Emitter.h index d4d95ba78d..6db19dc890 100644 --- a/Source/Core/Common/Arm64Emitter.h +++ b/Source/Core/Common/Arm64Emitter.h @@ -578,6 +578,8 @@ public: void BFM(ARM64Reg Rd, ARM64Reg Rn, u32 immr, u32 imms); void SBFM(ARM64Reg Rd, ARM64Reg Rn, u32 immr, u32 imms); void UBFM(ARM64Reg Rd, ARM64Reg Rn, u32 immr, u32 imms); + void BFI(ARM64Reg Rd, ARM64Reg Rn, u32 lsb, u32 width); + void UBFIZ(ARM64Reg Rd, ARM64Reg Rn, u32 lsb, u32 width); // Extract register (ROR with two inputs, if same then faster on A67) void EXTR(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm, u32 shift); @@ -591,7 +593,7 @@ public: void UBFX(ARM64Reg Rd, ARM64Reg Rn, int lsb, int width) { - UBFM(Rd, Rn, lsb, lsb + width <= (Is64Bit(Rn) ? 64 : 32)); + UBFM(Rd, Rn, lsb, lsb + width - 1); } // Load Register (Literal) From 388ab13db1c2a10534a9b81acba8fef98d96409c Mon Sep 17 00:00:00 2001 From: Shane Nelson Date: Sat, 27 Jun 2015 17:45:31 -0400 Subject: [PATCH 022/583] Audio: new dsp_coef.bin with windowed sinc filter coefficients --- Data/Sys/GC/dsp_coef.bin | Bin 4096 -> 4096 bytes Source/Core/Core/DSP/DSPCore.cpp | 7 +++++-- docs/DSP/free_dsp_rom/dsp_rom_readme.txt | 13 ++++++++++++ docs/DSP/free_dsp_rom/generate_coefs.py | 25 +++++++++++++++++++++++ 4 files changed, 43 insertions(+), 2 deletions(-) create mode 100644 docs/DSP/free_dsp_rom/generate_coefs.py diff --git a/Data/Sys/GC/dsp_coef.bin b/Data/Sys/GC/dsp_coef.bin index a276f2cede1a8e6936b4526f9621a391ca6b9515..1137fd741ec917caab4716a3ef5d8374ef246e5a 100644 GIT binary patch literal 4096 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 literal 4096 zcmeIz)mD&E6h+}l34*jBNOwwicXufuDXny;kFGEuL;rJezWX)y8Vlg}pV#kALiB}D zeI`tw2-im<^nrJJPo&-vrMJA-8>01^7`@_yUJ|Pp#OXQldPahtlBg#n=`qRri;wz~ z6g?tU5Ba1Ar0G8Cy2oeTB|~?})E{K&HrcvGj&72x8|3La`MO4dey31ZDbf{+b(s?V zMyYjVutPNR;|q@y(J2rW8Hs}9ko zgS6`a9okQ)_R*!ibZZYi+D)%^(WjmCYX<|`&Y-q2q^%5V3nSXhs5UXCjf`sp6I#!t z)-k2EOlu7@TFtChF{fXc*Gd+&f<-N7Nz3@ErF_#8mbI7_En-y*`K|@5X+G}fjtn#O^C;!smL(iDE`M}BEC$C|{6CUU9?oM}Ag8pnmk za;YD<(ipBanj3x3twwRDk=*M$9yEeS4d+S2c-Bx}G~~7MZ!hS7t~mt#5BmRh2toft d?L)Bt!T!G;La_h;_WoP;;0qE668P^D_zP_)!utRK diff --git a/Source/Core/Core/DSP/DSPCore.cpp b/Source/Core/Core/DSP/DSPCore.cpp index 54262ede66..bfe7c64b6c 100644 --- a/Source/Core/Core/DSP/DSPCore.cpp +++ b/Source/Core/Core/DSP/DSPCore.cpp @@ -42,7 +42,10 @@ static bool VerifyRoms() // delroth's improvement on LM1234 replacement ROM (Zelda and AX only, // IPL/Card/GBA still broken) - { 0xd9907f71, 0xb019c2fb } + { 0xd9907f71, 0xb019c2fb }, + + // above with improved resampling coefficients + { 0xd9907f71, 0xdb6880c1 } }; u32 hash_irom = HashAdler32((u8*)g_dsp.irom, DSP_IROM_BYTE_SIZE); @@ -69,7 +72,7 @@ static bool VerifyRoms() DSPHost::OSD_AddMessage("You are using an old free DSP ROM made by the Dolphin Team.", 6000); DSPHost::OSD_AddMessage("Only games using the Zelda UCode will work correctly.", 6000); } - else if (rom_idx == 2) + else if (rom_idx == 2 || rom_idx == 3) { DSPHost::OSD_AddMessage("You are using a free DSP ROM made by the Dolphin Team.", 8000); DSPHost::OSD_AddMessage("All Wii games will work correctly, and most GC games should ", 8000); diff --git a/docs/DSP/free_dsp_rom/dsp_rom_readme.txt b/docs/DSP/free_dsp_rom/dsp_rom_readme.txt index bcaa2eee43..7dc073a80b 100644 --- a/docs/DSP/free_dsp_rom/dsp_rom_readme.txt +++ b/docs/DSP/free_dsp_rom/dsp_rom_readme.txt @@ -1,3 +1,16 @@ +Legal GC/WII DSP IROM replacement (v0.2.1) +------------------------------------------------------- + +- coef: 4-tap polyphase FIR filters +- irom: unchanged + +Coefficients are roughly equivalent to those in the official DROM. +Improves resampling quality greatly over linear interpolation. +See generate_coefs.py for details. + +stgn +29/june/2015 + Legal GC/WII DSP IROM replacement (v0.2) ------------------------------------------------------- diff --git a/docs/DSP/free_dsp_rom/generate_coefs.py b/docs/DSP/free_dsp_rom/generate_coefs.py new file mode 100644 index 0000000000..5b1771429d --- /dev/null +++ b/docs/DSP/free_dsp_rom/generate_coefs.py @@ -0,0 +1,25 @@ +from numpy import * +from struct import pack + +def pack_coefs(c): + cw = list(zip(c[ :128][::-1], + c[128:256][::-1], + c[256:384][::-1], + c[384: ][::-1])) + m = max(sum(x) for x in cw) + return b''.join(pack('>4h', *(int(round(n / m * 32767)) for n in x)) for x in cw) + +x = linspace(-2, 2, 512, endpoint=False) + +w1 = hamming(512) +w2 = kaiser(512, pi * 9/4) + +coef_1 = [sinc(n * 0.5) for n in x] * w1 +coef_2 = [sinc(n * 0.75) for n in x] * w2 +coef_3 = [sinc(n) for n in x] * w1 + +with open('dsp_coef.bin', 'wb') as f: + f.write(pack_coefs(coef_1)) + f.write(pack_coefs(coef_2)) + f.write(pack_coefs(coef_3)) + f.write(b'\0' * 1024) From 6f8a38cefbe5c33fe59888d30fda36d6a5cba880 Mon Sep 17 00:00:00 2001 From: Jeffrey Pfau Date: Wed, 24 Jun 2015 03:32:17 -0700 Subject: [PATCH 023/583] WiimoteReal: Add IOHIDDevice support for OS X --- Source/Core/Core/HW/WiimoteReal/IOdarwin.mm | 261 +++++++++++++++--- .../Core/HW/WiimoteReal/WiimoteRealBase.h | 1 + 2 files changed, 222 insertions(+), 40 deletions(-) diff --git a/Source/Core/Core/HW/WiimoteReal/IOdarwin.mm b/Source/Core/Core/HW/WiimoteReal/IOdarwin.mm index 253c93b5a2..febb029073 100644 --- a/Source/Core/Core/HW/WiimoteReal/IOdarwin.mm +++ b/Source/Core/Core/HW/WiimoteReal/IOdarwin.mm @@ -45,6 +45,31 @@ private: IOPMAssertionID m_pm_assertion; }; +class WiimoteDarwinHid final : public Wiimote +{ +public: + WiimoteDarwinHid(IOHIDDeviceRef device); + ~WiimoteDarwinHid() override; + +protected: + bool ConnectInternal() override; + void DisconnectInternal() override; + bool IsConnected() const override; + void IOWakeup() override; + int IORead(u8* buf) override; + int IOWrite(u8 const* buf, size_t len) override; + +private: + static void ReportCallback(void* context, IOReturn result, void* sender, IOHIDReportType type, u32 reportID, u8* report, CFIndex reportLength); + static void RemoveCallback(void* context, IOReturn result, void* sender); + void QueueBufferReport(int length); + IOHIDDeviceRef m_device; + bool m_connected; + std::atomic m_interrupted; + Report m_report_buffer; + Common::FifoQueue m_buffered_reports; +}; + WiimoteScanner::WiimoteScanner() : m_run_thread() , m_want_wiimotes() @@ -61,65 +86,109 @@ void WiimoteScanner::FindWiimotes(std::vector & found_wiimotes, Wiimot // TODO: find the device in the constructor and save it for later IOBluetoothHostController *bth; IOBluetoothDeviceInquiry *bti; + IOHIDManagerRef hid; SearchBT *sbt; NSEnumerator *en; found_board = nullptr; + bool btFailed = false; + bool hidFailed = false; + bth = [[IOBluetoothHostController alloc] init]; - if ([bth addressAsString] == nil) - { + btFailed = [bth addressAsString] == nil; + if (btFailed) WARN_LOG(WIIMOTE, "No Bluetooth host controller"); + + hid = IOHIDManagerCreate(NULL, kIOHIDOptionsTypeNone); + hidFailed = CFGetTypeID(hid) != IOHIDManagerGetTypeID(); + if (hidFailed) + WARN_LOG(WIIMOTE, "No HID manager"); + + if (hidFailed && btFailed) + { + CFRelease(hid); [bth release]; return; } - sbt = [[SearchBT alloc] init]; - sbt->maxDevices = 32; - bti = [[IOBluetoothDeviceInquiry alloc] init]; - [bti setDelegate: sbt]; - [bti setInquiryLength: 2]; - - if ([bti start] != kIOReturnSuccess) + if (!btFailed) { - ERROR_LOG(WIIMOTE, "Unable to do Bluetooth discovery"); + sbt = [[SearchBT alloc] init]; + sbt->maxDevices = 32; + bti = [[IOBluetoothDeviceInquiry alloc] init]; + [bti setDelegate: sbt]; + [bti setInquiryLength: 2]; + + if ([bti start] != kIOReturnSuccess) + { + ERROR_LOG(WIIMOTE, "Unable to do Bluetooth discovery"); + [bth release]; + [sbt release]; + btFailed = true; + } + + do + { + CFRunLoopRun(); + } + while (!sbt->done); + + int found_devices = [[bti foundDevices] count]; + + if (found_devices) + NOTICE_LOG(WIIMOTE, "Found %i Bluetooth devices", found_devices); + + en = [[bti foundDevices] objectEnumerator]; + for (int i = 0; i < found_devices; i++) + { + IOBluetoothDevice *dev = [en nextObject]; + if (!IsValidBluetoothName([[dev name] UTF8String])) + continue; + + Wiimote* wm = new WiimoteDarwin([dev retain]); + + if (IsBalanceBoardName([[dev name] UTF8String])) + { + found_board = wm; + } + else + { + found_wiimotes.push_back(wm); + } + } + [bth release]; + [bti release]; [sbt release]; - return; } - do + if (!hidFailed) { + NSArray *criteria = @[ + @{ @kIOHIDVendorIDKey: @0x057e, @kIOHIDProductIDKey: @0x0306 }, + @{ @kIOHIDVendorIDKey: @0x057e, @kIOHIDProductIDKey: @0x0330 }, + ]; + IOHIDManagerSetDeviceMatchingMultiple(hid, (CFArrayRef)criteria); CFRunLoopRun(); - } - while (!sbt->done); - - int found_devices = [[bti foundDevices] count]; - - if (found_devices) - NOTICE_LOG(WIIMOTE, "Found %i Bluetooth devices", found_devices); - - en = [[bti foundDevices] objectEnumerator]; - for (int i = 0; i < found_devices; i++) - { - IOBluetoothDevice *dev = [en nextObject]; - if (!IsValidBluetoothName([[dev name] UTF8String])) - continue; - - Wiimote* wm = new WiimoteDarwin([dev retain]); - - if (IsBalanceBoardName([[dev name] UTF8String])) + CFSetRef devices = IOHIDManagerCopyDevices(hid); + if (devices) { - found_board = wm; - } - else - { - found_wiimotes.push_back(wm); - } - } + int found_devices = CFSetGetCount(devices); + if (found_devices) + { + NOTICE_LOG(WIIMOTE, "Found %i HID devices", found_devices); - [bth release]; - [bti release]; - [sbt release]; + IOHIDDeviceRef values[found_devices]; + CFSetGetValues(devices, reinterpret_cast(&values)); + for (int i = 0; i < found_devices; i++) + { + Wiimote* wm = new WiimoteDarwinHid(values[i]); + found_wiimotes.push_back(wm); + } + } + } + CFRelease(hid); + } } bool WiimoteScanner::IsReady() const @@ -287,6 +356,118 @@ void WiimoteDarwin::DisablePowerAssertionInternal() } } +WiimoteDarwinHid::WiimoteDarwinHid(IOHIDDeviceRef device) : m_device(device) +{ + CFRetain(m_device); + m_connected = false; + m_report_buffer = Report(MAX_PAYLOAD); +} + +WiimoteDarwinHid::~WiimoteDarwinHid() +{ + Shutdown(); + CFRelease(m_device); +} + +bool WiimoteDarwinHid::ConnectInternal() +{ + IOReturn ret = IOHIDDeviceOpen(m_device, kIOHIDOptionsTypeNone); + m_connected = ret == kIOReturnSuccess; + if (m_connected) + { + IOHIDDeviceScheduleWithRunLoop(m_device, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode); + IOHIDDeviceRegisterInputReportCallback(m_device, + m_report_buffer.data() + 1, + MAX_PAYLOAD - 1, + &WiimoteDarwinHid::ReportCallback, + this); + IOHIDDeviceRegisterRemovalCallback(m_device, &WiimoteDarwinHid::RemoveCallback, this); + NOTICE_LOG(WIIMOTE, "Connected to Wiimote %i", m_index + 1); + } + else + { + ERROR_LOG(WIIMOTE, "Could not open IOHID Wiimote: %08x", ret); + } + + return m_connected; +} + +void WiimoteDarwinHid::DisconnectInternal() +{ + IOHIDDeviceUnscheduleFromRunLoop(m_device, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode); + IOWakeup(); + IOReturn ret = IOHIDDeviceClose(m_device, kIOHIDOptionsTypeNone); + if (ret != kIOReturnSuccess) + ERROR_LOG(WIIMOTE, "Error closing IOHID Wiimote: %08x", ret); + + if (!IsConnected()) + return; + + NOTICE_LOG(WIIMOTE, "Disconnecting Wiimote %i", m_index + 1); + + m_buffered_reports.Clear(); + + m_connected = false; +} + +bool WiimoteDarwinHid::IsConnected() const +{ + return m_connected; +} + +void WiimoteDarwinHid::IOWakeup() +{ + m_interrupted.store(true); + CFRunLoopStop(CFRunLoopGetCurrent()); +} + +int WiimoteDarwinHid::IORead(u8* buf) +{ + Report rpt; + m_interrupted.store(false); + while (m_buffered_reports.Empty() && !m_interrupted.load()) + CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0, true); + + if (m_buffered_reports.Pop(rpt)) + { + memcpy(buf, rpt.data(), rpt.size()); + return rpt.size(); + } + return -1; +} + +int WiimoteDarwinHid::IOWrite(u8 const* buf, size_t len) +{ + IOReturn ret = IOHIDDeviceSetReport(m_device, kIOHIDReportTypeOutput, buf[1], buf + 1, len - 1); + if (ret != kIOReturnSuccess) + { + ERROR_LOG(WIIMOTE, "Error writing to Wiimote: %08x", ret); + return 0; + } + return len; +} + +void WiimoteDarwinHid::QueueBufferReport(int length) +{ + Report rpt(m_report_buffer); + rpt[0] = 0xa1; + rpt.resize(length + 1); + m_buffered_reports.Push(std::move(rpt)); +} + +void WiimoteDarwinHid::ReportCallback(void* context, IOReturn result, void*, IOHIDReportType type, u32 report_id, u8* report, CFIndex report_length) +{ + WiimoteDarwinHid* wm = static_cast(context); + report[0] = report_id; + wm->QueueBufferReport(report_length); +} + +void WiimoteDarwinHid::RemoveCallback(void* context, IOReturn result, void*) +{ + WiimoteDarwinHid* wm = static_cast(context); + wm->DisconnectInternal(); +} + } // namespace @implementation SearchBT diff --git a/Source/Core/Core/HW/WiimoteReal/WiimoteRealBase.h b/Source/Core/Core/HW/WiimoteReal/WiimoteRealBase.h index 232d1f23d5..e313177e43 100644 --- a/Source/Core/Core/HW/WiimoteReal/WiimoteRealBase.h +++ b/Source/Core/Core/HW/WiimoteReal/WiimoteRealBase.h @@ -16,6 +16,7 @@ // end hack #import #include + #include #elif defined(__linux__) && HAVE_BLUEZ #include #endif From 717d4bfbccba7b3f9b6a3787809a17130dd49afc Mon Sep 17 00:00:00 2001 From: degasus Date: Sun, 28 Jun 2015 11:05:14 +0200 Subject: [PATCH 024/583] Interpreter: Idle skipping support --- .../Interpreter/Interpreter_Branch.cpp | 22 +++++++++++++++++++ .../Core/Core/PowerPC/Jit64/Jit_LoadStore.cpp | 2 +- Source/Core/Core/PowerPC/Jit64IL/IR_X86.cpp | 2 +- .../PowerPC/JitArm64/JitArm64_LoadStore.cpp | 2 +- Source/Core/Core/PowerPC/PowerPC.cpp | 5 ----- Source/Core/Core/PowerPC/PowerPC.h | 2 -- 6 files changed, 25 insertions(+), 10 deletions(-) diff --git a/Source/Core/Core/PowerPC/Interpreter/Interpreter_Branch.cpp b/Source/Core/Core/PowerPC/Interpreter/Interpreter_Branch.cpp index 67f2707e9a..d642ad897c 100644 --- a/Source/Core/Core/PowerPC/Interpreter/Interpreter_Branch.cpp +++ b/Source/Core/Core/PowerPC/Interpreter/Interpreter_Branch.cpp @@ -23,6 +23,11 @@ void Interpreter::bx(UGeckoInstruction _inst) #endif*/ m_EndBlock = true; + + if (NPC == PC && SConfig::GetInstance().bSkipIdle) + { + CoreTiming::Idle(); + } } // bcx - ugly, straight from PPC manual equations :) @@ -50,6 +55,23 @@ void Interpreter::bcx(UGeckoInstruction _inst) } m_EndBlock = true; + + // this code trys to detect the most common idle loop: + // lwz r0, XXXX(r13) + // cmpXwi r0,0 + // beq -8 + if (NPC == PC - 8 && _inst.hex == 0x4182fff8 /* beq */ && SConfig::GetInstance().bSkipIdle) + { + if (PowerPC::HostRead_U32(PC - 8) >> 16 == 0x800D /* lwz */ ) + { + u32 last_inst = PowerPC::HostRead_U32(PC - 4); + + if (last_inst == 0x28000000 /* cmplwi */ || (last_inst == 0x2C000000 /* cmpwi */ && SConfig::GetInstance().bWii)) + { + CoreTiming::Idle(); + } + } + } } void Interpreter::bcctrx(UGeckoInstruction _inst) diff --git a/Source/Core/Core/PowerPC/Jit64/Jit_LoadStore.cpp b/Source/Core/Core/PowerPC/Jit64/Jit_LoadStore.cpp index 74bbe9d407..03c426e24c 100644 --- a/Source/Core/Core/PowerPC/Jit64/Jit_LoadStore.cpp +++ b/Source/Core/Core/PowerPC/Jit64/Jit_LoadStore.cpp @@ -137,7 +137,7 @@ void Jit64::lXXx(UGeckoInstruction inst) BitSet32 registersInUse = CallerSavedRegistersInUse(); ABI_PushRegistersAndAdjustStack(registersInUse, 0); - ABI_CallFunction((void *)&PowerPC::OnIdle); + ABI_CallFunction((void *)&CoreTiming::Idle); ABI_PopRegistersAndAdjustStack(registersInUse, 0); diff --git a/Source/Core/Core/PowerPC/Jit64IL/IR_X86.cpp b/Source/Core/Core/PowerPC/Jit64IL/IR_X86.cpp index 17007be31f..399f1cbd6c 100644 --- a/Source/Core/Core/PowerPC/Jit64IL/IR_X86.cpp +++ b/Source/Core/Core/PowerPC/Jit64IL/IR_X86.cpp @@ -2111,7 +2111,7 @@ static void DoWriteCode(IRBuilder* ibuild, JitIL* Jit, u32 exitAddress) FixupBranch noidle = Jit->J_CC(CC_NZ); RI.Jit->Cleanup(); // is it needed? - Jit->ABI_CallFunction((void *)&PowerPC::OnIdle); + Jit->ABI_CallFunction((void *)&CoreTiming::Idle); Jit->MOV(32, PPCSTATE(pc), Imm32(ibuild->GetImmValue( getOp2(I) ))); Jit->WriteExceptionExit(); diff --git a/Source/Core/Core/PowerPC/JitArm64/JitArm64_LoadStore.cpp b/Source/Core/Core/PowerPC/JitArm64/JitArm64_LoadStore.cpp index 9739fb35c1..6d86fa004f 100644 --- a/Source/Core/Core/PowerPC/JitArm64/JitArm64_LoadStore.cpp +++ b/Source/Core/Core/PowerPC/JitArm64/JitArm64_LoadStore.cpp @@ -426,7 +426,7 @@ void JitArm64::lXX(UGeckoInstruction inst) ARM64Reg WA = gpr.GetReg(); ARM64Reg XA = EncodeRegTo64(WA); - MOVI2R(XA, (u64)&PowerPC::OnIdle); + MOVI2R(XA, (u64)&CoreTiming::Idle); BLR(XA); gpr.Unlock(WA); diff --git a/Source/Core/Core/PowerPC/PowerPC.cpp b/Source/Core/Core/PowerPC/PowerPC.cpp index 27274d51e7..057d41730f 100644 --- a/Source/Core/Core/PowerPC/PowerPC.cpp +++ b/Source/Core/Core/PowerPC/PowerPC.cpp @@ -529,11 +529,6 @@ void CheckBreakPoints() } } -void OnIdle() -{ - CoreTiming::Idle(); -} - } // namespace diff --git a/Source/Core/Core/PowerPC/PowerPC.h b/Source/Core/Core/PowerPC/PowerPC.h index 67a0f9d85f..1ad1bc8f62 100644 --- a/Source/Core/Core/PowerPC/PowerPC.h +++ b/Source/Core/Core/PowerPC/PowerPC.h @@ -163,8 +163,6 @@ volatile CPUState *GetStatePtr(); // this oddity is here instead of an extern d u32 CompactCR(); void ExpandCR(u32 cr); -void OnIdle(); - void UpdatePerformanceMonitor(u32 cycles, u32 num_load_stores, u32 num_fp_inst); // Easy register access macros. From 2721fdf8a94e2e49f907eda24a1406d2225acaf6 Mon Sep 17 00:00:00 2001 From: Scott Mansell Date: Mon, 29 Jun 2015 12:17:35 +1200 Subject: [PATCH 025/583] Linux: Add an evdev based controller backend, to replace SDL. --- CMakeLists.txt | 13 + CMakeTests/FindLibevdev.cmake | 33 +++ CMakeTests/FindLibudev.cmake | 28 ++ Source/Core/InputCommon/CMakeLists.txt | 5 + .../ControllerInterface.cpp | 6 + .../ControllerInterface/ControllerInterface.h | 3 + .../ControllerInterface/evdev/evdev.cpp | 264 ++++++++++++++++++ .../ControllerInterface/evdev/evdev.h | 86 ++++++ 8 files changed, 438 insertions(+) create mode 100644 CMakeTests/FindLibevdev.cmake create mode 100644 CMakeTests/FindLibudev.cmake create mode 100644 Source/Core/InputCommon/ControllerInterface/evdev/evdev.cpp create mode 100644 Source/Core/InputCommon/ControllerInterface/evdev/evdev.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 91071aefdb..e64061a6b7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -513,6 +513,19 @@ if(USE_EGL) add_definitions(-DUSE_EGL=1) endif() +if(${CMAKE_SYSTEM_NAME} STREQUAL "Linux") + include(FindLibudev OPTIONAL) + include(FindLibevdev OPTIONAL) + if(LIBUDEV_FOUND AND LIBEVDEV_FOUND) + message("libevdev/libudev found, enabling evdev controller backend") + add_definitions(-DHAVE_LIBUDEV=1) + add_definitions(-DHAVE_LIBEVDEV=1) + include_directories(${LIBUDEV_INCLUDE_DIR} ${LIBEVDEV_INCLUDE_DIR}) + else() + message("Could find libevdev/libudev, disabling evdev controller backend") + endif() +endif() + ######################################## # Setup include directories (and make sure they are preferred over the Externals) # diff --git a/CMakeTests/FindLibevdev.cmake b/CMakeTests/FindLibevdev.cmake new file mode 100644 index 0000000000..e89a5f229d --- /dev/null +++ b/CMakeTests/FindLibevdev.cmake @@ -0,0 +1,33 @@ +# - Try to find libevdev +# Once done this will define +# LIBEVDEV_FOUND - System has libevdev +# LIBEVDEV_INCLUDE_DIRS - The libevdev include directories +# LIBEVDEV_LIBRARIES - The libraries needed to use libevdev + +find_package(PkgConfig) +pkg_check_modules(PC_LIBEVDEV QUIET libevdev) + +FIND_PATH( + LIBEVDEV_INCLUDE_DIR libevdev/libevdev.h + HINTS ${PC_LIBEVDEV_INCLUDEDIR} ${PC_LIBEVDEV_INCLUDE_DIRS} + /usr/include + /usr/local/include + ${LIBEVDEV_PATH_INCLUDES} +) + +FIND_LIBRARY( + LIBEVDEV_LIBRARY + NAMES evdev libevdev + HINTS ${PC_LIBEVDEV_LIBDIR} ${PC_LIBEVDEV_LIBRARY_DIRS} + PATHS ${ADDITIONAL_LIBRARY_PATHS} + ${LIBEVDEV_PATH_LIB} +) + +set(LIBEVDEV_LIBRARIES ${LIBEVDEV_LIBRARY} ) +set(LIBEVDEV_INCLUDE_DIRS ${LIBEVDEV_INCLUDE_DIR} ) + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(libevdev DEFAULT_MSG + LIBEVDEV_LIBRARY LIBEVDEV_INCLUDE_DIR) + +mark_as_advanced(LIBEVDEV_INCLUDE_DIR LIBEVDEV_LIBRARY ) diff --git a/CMakeTests/FindLibudev.cmake b/CMakeTests/FindLibudev.cmake new file mode 100644 index 0000000000..2b71e4e605 --- /dev/null +++ b/CMakeTests/FindLibudev.cmake @@ -0,0 +1,28 @@ +# - Try to find LIBUDEV +# Once done this will define +# LIBUDEV_FOUND - System has LIBUDEV +# LIBUDEV_INCLUDE_DIRS - The LIBUDEV include directories +# LIBUDEV_LIBRARIES - The libraries needed to use LIBUDEV + +FIND_PATH( + LIBUDEV_INCLUDE_DIR libudev.h + /usr/include + /usr/local/include + ${LIBUDEV_PATH_INCLUDES} +) + +FIND_LIBRARY( + LIBUDEV_LIBRARY + NAMES udev libudev + PATHS ${ADDITIONAL_LIBRARY_PATHS} + ${LIBUDEV_PATH_LIB} +) + +set(LIBUDEV_LIBRARIES ${LIBUDEV_LIBRARY} ) +set(LIBUDEV_INCLUDE_DIRS ${LIBUDEV_INCLUDE_DIR} ) + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(LIBUDEV DEFAULT_MSG + LIBUDEV_LIBRARY LIBUDEV_INCLUDE_DIR) + +mark_as_advanced(LIBUDEV_INCLUDE_DIR LIBUDEV_LIBRARY ) diff --git a/Source/Core/InputCommon/CMakeLists.txt b/Source/Core/InputCommon/CMakeLists.txt index 75679b6a9f..549865b8e9 100644 --- a/Source/Core/InputCommon/CMakeLists.txt +++ b/Source/Core/InputCommon/CMakeLists.txt @@ -37,6 +37,11 @@ elseif(ANDROID) ControllerInterface/Android/Android.cpp) endif() +if(LIBEVDEV_FOUND AND LIBUDEV_FOUND) + set(SRCS ${SRCS} ControllerInterface/evdev/evdev.cpp) + set(LIBS ${LIBS} ${LIBEVDEV_LIBRARY} ${LIBUDEV_LIBRARY}) +endif() + if(SDL_FOUND OR SDL2_FOUND) set(SRCS ${SRCS} ControllerInterface/SDL/SDL.cpp) if (SDL2_FOUND) diff --git a/Source/Core/InputCommon/ControllerInterface/ControllerInterface.cpp b/Source/Core/InputCommon/ControllerInterface/ControllerInterface.cpp index 6b8b11fd3a..0631069e16 100644 --- a/Source/Core/InputCommon/ControllerInterface/ControllerInterface.cpp +++ b/Source/Core/InputCommon/ControllerInterface/ControllerInterface.cpp @@ -26,6 +26,9 @@ #ifdef CIFACE_USE_ANDROID #include "InputCommon/ControllerInterface/Android/Android.h" #endif +#ifdef CIFACE_USE_EVDEV + #include "InputCommon/ControllerInterface/evdev/evdev.h" +#endif using namespace ciface::ExpressionParser; @@ -69,6 +72,9 @@ void ControllerInterface::Initialize(void* const hwnd) #ifdef CIFACE_USE_ANDROID ciface::Android::Init(m_devices); #endif +#ifdef CIFACE_USE_EVDEV + ciface::evdev::Init(m_devices); +#endif m_is_init = true; } diff --git a/Source/Core/InputCommon/ControllerInterface/ControllerInterface.h b/Source/Core/InputCommon/ControllerInterface/ControllerInterface.h index 408a36fefa..3aca18e95c 100644 --- a/Source/Core/InputCommon/ControllerInterface/ControllerInterface.h +++ b/Source/Core/InputCommon/ControllerInterface/ControllerInterface.h @@ -35,6 +35,9 @@ #if defined(HAVE_SDL) && HAVE_SDL #define CIFACE_USE_SDL #endif +#if defined(HAVE_LIBEVDEV) && defined(HAVE_LIBUDEV) + #define CIFACE_USE_EVDEV +#endif // // ControllerInterface diff --git a/Source/Core/InputCommon/ControllerInterface/evdev/evdev.cpp b/Source/Core/InputCommon/ControllerInterface/evdev/evdev.cpp new file mode 100644 index 0000000000..2f4d53e234 --- /dev/null +++ b/Source/Core/InputCommon/ControllerInterface/evdev/evdev.cpp @@ -0,0 +1,264 @@ +// Copyright 2015 Dolphin Emulator Project +// Licensed under GPLv2+ +// Refer to the license.txt file included. + +#include +#include + +#include "Common/Logging/Log.h" +#include "InputCommon/ControllerInterface/evdev/evdev.h" + + +namespace ciface +{ +namespace evdev +{ + +void Init(std::vector &controllerDevices) +{ + int num_controllers = 0; + + // We use Udev to find any devices. In the future this will allow for hotplugging. + // But for now it is essentially iterating over /dev/input/event0 to event31. However if the + // naming scheme is ever updated in the future, this *should* be forwards compatable. + + struct udev* udev = udev_new(); + _assert_msg_(PAD, udev != 0, "Couldn't initilize libudev."); + + // List all input devices + udev_enumerate* enumerate = udev_enumerate_new(udev); + udev_enumerate_add_match_subsystem(enumerate, "input"); + udev_enumerate_scan_devices(enumerate); + udev_list_entry* devices = udev_enumerate_get_list_entry(enumerate); + + // Iterate over all input devices + udev_list_entry* dev_list_entry; + udev_list_entry_foreach(dev_list_entry, devices) + { + const char* path = udev_list_entry_get_name(dev_list_entry); + + udev_device* dev = udev_device_new_from_syspath(udev, path); + + const char* devnode = udev_device_get_devnode(dev); + // We only care about devices which we have read/write access to. + if (access(devnode, W_OK) == 0) + { + // Unfortunately udev gives us no way to filter out the non event device interfaces. + // So we open it and see if it works with evdev ioctls or not. + evdevDevice* input = new evdevDevice(devnode, num_controllers); + + if (input->IsInteresting()) + { + controllerDevices.push_back(input); + num_controllers++; + } + else + { + // Either it wasn't a evdev device, or it didn't have at least 8 buttons or two axis. + delete input; + } + } + udev_device_unref(dev); + } + udev_enumerate_unref(enumerate); + udev_unref(udev); +} + +evdevDevice::evdevDevice(const std::string &devnode, int id) : m_devfile(devnode), m_id(id) +{ + // The device file will be read on one of the main threads, so we open in non-blocking mode. + m_fd = open(devnode.c_str(), O_RDWR|O_NONBLOCK); + int ret = libevdev_new_from_fd(m_fd, &m_dev); + + if (ret != 0) + { + // This useally fails because the device node isn't an evdev device, such as /dev/input/js0 + m_initialized = false; + close(m_fd); + return; + } + + m_name = libevdev_get_name(m_dev); + + // Controller buttons (and keyboard keys) + int num_buttons = 0; + for (int key = 0; key < KEY_MAX; key++) + if (libevdev_has_event_code(m_dev, EV_KEY, key)) + AddInput(new Button(num_buttons++, key, m_dev)); + + // Absolute axis (thumbsticks) + int num_axis = 0; + for (int axis = 0; axis < 0x100; axis++) + if (libevdev_has_event_code(m_dev, EV_ABS, axis)) + { + AddAnalogInputs(new Axis(num_axis, axis, false, m_dev), + new Axis(num_axis, axis, true, m_dev)); + num_axis++; + } + + // Force feedback + if (libevdev_has_event_code(m_dev, EV_FF, FF_PERIODIC)) + { + for (auto type : {FF_SINE, FF_SQUARE, FF_TRIANGLE, FF_SAW_UP, FF_SAW_DOWN}) + if (libevdev_has_event_code(m_dev, EV_FF, type)) + AddOutput(new ForceFeedback(type, m_dev)); + } + if (libevdev_has_event_code(m_dev, EV_FF, FF_RUMBLE)) + { + AddOutput(new ForceFeedback(FF_RUMBLE, m_dev)); + } + + // TODO: Add leds as output devices + + m_initialized = true; + m_interesting = num_axis >= 2 || num_buttons >= 8; +} + +evdevDevice::~evdevDevice() +{ + if (m_initialized) + { + libevdev_free(m_dev); + close(m_fd); + } +} + +void evdevDevice::UpdateInput() +{ + // Run through all evdev events + // libevdev will keep track of the actual controller state internally which can be queried + // later with libevdev_fetch_event_value() + input_event ev; + int rc = LIBEVDEV_READ_STATUS_SUCCESS; + do + { + if (rc == LIBEVDEV_READ_STATUS_SYNC) + rc = libevdev_next_event(m_dev, LIBEVDEV_READ_FLAG_SYNC, &ev); + else + rc = libevdev_next_event(m_dev, LIBEVDEV_READ_FLAG_NORMAL, &ev); + } while (rc >= 0); +} + + +std::string evdevDevice::Button::GetName() const +{ + // Buttons below 0x100 are mostly keyboard keys, and the names make sense + if (m_code < 0x100) + { + const char* name = libevdev_event_code_get_name(EV_KEY, m_code); + if (name) + return std::string(name); + } + // But controllers use codes above 0x100, and the standard label often doesn't match. + // We are better off with Button 0 and so on. + return "Button " + std::to_string(m_index); +} + +ControlState evdevDevice::Button::GetState() const +{ + int value = 0; + libevdev_fetch_event_value(m_dev, EV_KEY, m_code, &value); + return value; +} + +evdevDevice::Axis::Axis(u8 index, u16 code, bool upper, libevdev* dev) : + m_code(code), m_index(index), m_upper(upper), m_dev(dev) +{ + m_range = libevdev_get_abs_maximum(m_dev, m_code); +} + +std::string evdevDevice::Axis::GetName() const +{ + return "Axis " + std::to_string(m_index) + (m_upper ? "+" : "-"); +} + +ControlState evdevDevice::Axis::GetState() const +{ + int value = 0; + libevdev_fetch_event_value(m_dev, EV_ABS, m_code, &value); + if (m_upper) + return std::max(0.0, double(value) / double(m_range) - 0.5) * 2.0; + else + return (0.5 - std::min(0.5, double(value) / double(m_range))) * 2.0; +} + +std::string evdevDevice::ForceFeedback::GetName() const +{ + // We have some default names. + switch (m_type) + { + case FF_SINE: + return "Sine"; + case FF_TRIANGLE: + return "Triangle"; + case FF_SQUARE: + return "Square"; + case FF_RUMBLE: + return "LeftRight"; + default: + { + const char* name = libevdev_event_code_get_name(EV_FF, m_type); + if (name) + return std::string(name); + return "Unknown"; + } + } +} + +void evdevDevice::ForceFeedback::SetState(ControlState state) +{ + // libevdev doesn't have nice helpers for forcefeedback + // we will use the file descriptors directly. + + if (state > 0) // Upload and start an effect. + { + ff_effect effect; + + effect.id = -1; + effect.direction = 0; // down + effect.replay.length = 500; // 500ms + effect.replay.delay = 0; + effect.trigger.button = 0; // don't trigger on button press + effect.trigger.interval = 0; + + // This is the the interface that XInput uses, with 2 motors of differing sizes/frequencies that + // are controlled seperatally + if (m_type == FF_RUMBLE) + { + effect.type = FF_RUMBLE; + // max ranges tuned to 'feel' similar in magnitude to triangle/sine on xbox360 controller + effect.u.rumble.strong_magnitude = u16(state * 0x4000); + effect.u.rumble.weak_magnitude = u16(state * 0xFFFF); + } + else // FF_PERIODIC, a more generic interface. + { + effect.type = FF_PERIODIC; + effect.u.periodic.waveform = m_type; + effect.u.periodic.phase = 0x7fff; // 180 degrees + effect.u.periodic.offset = 0; + effect.u.periodic.period = 10; + effect.u.periodic.magnitude = s16(state * 0x7FFF); + effect.u.periodic.envelope.attack_length = 0; // no attack + effect.u.periodic.envelope.attack_level = 0; + effect.u.periodic.envelope.fade_length = 0; + effect.u.periodic.envelope.fade_level = 0; + } + + ioctl(m_fd, EVIOCSFF, &effect); + m_id = effect.id; + + input_event play; + play.type = EV_FF; + play.code = m_id; + play.value = 1; + + write(m_fd, (const void*) &play, sizeof(play)); + } + else if (m_id != -1) // delete the effect (which also stops it) + { + ioctl(m_id, EVIOCRMFF, m_id); + } +} + +} +} diff --git a/Source/Core/InputCommon/ControllerInterface/evdev/evdev.h b/Source/Core/InputCommon/ControllerInterface/evdev/evdev.h new file mode 100644 index 0000000000..7290fbc379 --- /dev/null +++ b/Source/Core/InputCommon/ControllerInterface/evdev/evdev.h @@ -0,0 +1,86 @@ +// Copyright 2015 Dolphin Emulator Project +// Licensed under GPLv2+ +// Refer to the license.txt file included. + +#pragma once + +#include +#include +#include + +#include "InputCommon/ControllerInterface/Device.h" + +namespace ciface +{ +namespace evdev +{ + +void Init(std::vector& devices); + +class evdevDevice : public Core::Device +{ +private: + class Button : public Core::Device::Input + { + public: + std::string GetName() const override; + Button(u8 index, u16 code, libevdev* dev) : m_index(index), m_code(code), m_dev(dev) {} + ControlState GetState() const override; + private: + const u8 m_index; + const u16 m_code; + libevdev* m_dev; + }; + + class Axis : public Core::Device::Input + { + public: + std::string GetName() const override; + Axis(u8 index, u16 code, bool upper, libevdev* dev); + ControlState GetState() const override; + private: + const u16 m_code; + const u8 m_index; + const bool m_upper; + int m_range; + libevdev* m_dev; + }; + + class ForceFeedback : public Core::Device::Output + { + public: + std::string GetName() const override; + ForceFeedback(u16 type, libevdev* dev) : m_type(type), m_dev(dev), m_id(-1) { m_fd = libevdev_get_fd(dev); } + void SetState(ControlState state) override; + private: + const u16 m_type; + libevdev* m_dev; + int m_fd; + int m_id; + }; + +public: + void UpdateInput() override; + + evdevDevice(const std::string &devnode, int id); + ~evdevDevice(); + + std::string GetName() const override { return m_name; } + int GetId() const override { return m_id; } + std::string GetSource() const override { return "evdev"; } + + bool IsInteresting() const { return m_initialized && m_interesting; } + +private: + const std::string m_devfile; + int m_fd; + libevdev* m_dev; + std::string m_name; + const int m_id; + bool m_initialized; + bool m_interesting; +}; + +} + +} From 9065ddf5fadf337b6b8cd5ed7a36bf796199cda2 Mon Sep 17 00:00:00 2001 From: Scott Mansell Date: Mon, 29 Jun 2015 13:09:24 +1200 Subject: [PATCH 026/583] Linux: Disable SDL controller backend by default. Not deleted, because it's the only option for some other operating systems such as FreeBSD or any other slightly exotic operating system someone might try and run dolphin on. --- CMakeLists.txt | 19 +++++++++++-------- CMakeTests/FindSDL2.cmake | 15 ++++++++++++++- 2 files changed, 25 insertions(+), 9 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index e64061a6b7..5162b86dd4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -14,6 +14,14 @@ option(ENABLE_PCH "Use PCH to speed up compilation" ON) option(ENABLE_PIE "Build a Position-Independent Executable (PIE)" ON) option(ENABLE_LTO "Enables Link Time Optimization" OFF) option(ENABLE_GENERIC "Enables generic build that should run on any little-endian host" OFF) + +# Enable SDL for default on operating systems that aren't OSX, Android, Linux or Windows. +if(NOT APPLE AND NOT ANDROID AND NOT ${CMAKE_SYSTEM_NAME} STREQUAL "Linux" AND NOT MSVC) + option(ENABLE_SDL "Enables SDL as a generic controller backend" ON) +else() + option(ENABLE_SDL "Enables SDL as a generic controller backend" OFF) +endif() + if(APPLE) option(OSX_USE_DEFAULT_SEARCH_PATH "Don't prioritize system library paths" OFF) endif() @@ -632,26 +640,21 @@ if(OPENAL_FOUND) endif() endif() -if(NOT ANDROID) - if(NOT APPLE) - include(FindSDL2 OPTIONAL) - endif() +if(ENABLE_SDL) + include(FindSDL2 OPTIONAL) if(SDL2_FOUND) message("Using shared SDL2") add_definitions(-DHAVE_SDL=1) include_directories(${SDL2_INCLUDE_DIR}) else(SDL2_FOUND) # SDL2 not found, try SDL - if(NOT APPLE) - include(FindSDL OPTIONAL) - endif() + include(FindSDL OPTIONAL) if(SDL_FOUND) message("Using shared SDL") add_definitions(-DHAVE_SDL=1) include_directories(${SDL_INCLUDE_DIR}) else(SDL_FOUND) message("SDL NOT found, disabling SDL input") - add_definitions(-DHAVE_SDL=0) endif(SDL_FOUND) endif(SDL2_FOUND) endif() diff --git a/CMakeTests/FindSDL2.cmake b/CMakeTests/FindSDL2.cmake index 614426cccf..aef817ec6a 100644 --- a/CMakeTests/FindSDL2.cmake +++ b/CMakeTests/FindSDL2.cmake @@ -172,9 +172,22 @@ IF(SDL2_LIBRARY_TEMP) SET(SDL2_LIBRARY_TEMP "${SDL2_LIBRARY_TEMP}" CACHE INTERNAL "") SET(SDL2_FOUND "YES") + + # extract the major and minor version numbers from SDL2/SDL_version.h + # we have to handle framework a little bit differently : + if("${SDL2_INCLUDE_DIR}" MATCHES ".framework") + set(SDL2_VERSION_H_INPUT "${SDL2_INCLUDE_DIR}/Headers/SDL_version.h") + else() + set(SDL2_VERSION_H_INPUT "${SDL2_INCLUDE_DIR}/SDL_version.h") + endif() + FILE(READ "${SDL2_VERSION_H_INPUT}" SDL2_VERSION_H_CONTENTS) + STRING(REGEX REPLACE ".*#define[ \t]+SDL_MAJOR_VERSION[ \t]+([0-9]+).*#define[ \t]+SDL_MINOR_VERSION[ \t]+([0-9]+).*#define[ \t]+SDL_PATCHLEVEL[ \t]+([0-9]+).*" + "\\1.\\2.\\3" SDL2_VERSION "${SDL2_VERSION_H_CONTENTS}") +#MESSAGE("SDL2 Version is ${SDL2_VERSION}") + ENDIF(SDL2_LIBRARY_TEMP) INCLUDE(FindPackageHandleStandardArgs) FIND_PACKAGE_HANDLE_STANDARD_ARGS(SDL2 - REQUIRED_VARS SDL2_LIBRARY SDL2_INCLUDE_DIR) + REQUIRED_VARS SDL2_LIBRARY SDL2_INCLUDE_DIR VERSION_VAR SDL2_VERSION) From ad714993aaae2826a41fc55691d869e46bb3b479 Mon Sep 17 00:00:00 2001 From: Scott Mansell Date: Mon, 29 Jun 2015 13:57:30 +1200 Subject: [PATCH 027/583] CMake: Explicitly pull in threads. Dolphin uses threads, but never actually pulled them it. Normally some library we depend on would pull threads in, but there are potential builds that forget to pull in threads. --- CMakeLists.txt | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 5162b86dd4..347b87c2b7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -313,6 +313,14 @@ if(WIN32) add_definitions(-D_CRT_SECURE_NO_DEPRECATE) endif(WIN32) +# Dolphin requires threads. +# The Apple build may not need an explicit flag because one of the +# frameworks may already provide it. +# But for non-OSX systems, we will use the CMake Threads package. +IF(NOT APPLE) + FIND_PACKAGE(Threads) +ENDIF(NOT APPLE) + if(NOT CMAKE_BUILD_TYPE) set(CMAKE_BUILD_TYPE "Release" CACHE STRING "Build type (Release/Debug/RelWithDebInfo/MinSizeRe)" FORCE) From 0dc8763247051797bb4952206bfe6fc99164229b Mon Sep 17 00:00:00 2001 From: Scott Mansell Date: Tue, 30 Jun 2015 23:57:54 +1200 Subject: [PATCH 028/583] Linux: Don't allow dolphin to be build without evdev support. Unless explicitly requested. --- CMakeLists.txt | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 347b87c2b7..d6c1c4b05f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -22,6 +22,10 @@ else() option(ENABLE_SDL "Enables SDL as a generic controller backend" OFF) endif() +if(${CMAKE_SYSTEM_NAME} STREQUAL "Linux" AND NOT ANDROID) + option(ENABLE_EVDEV "Enables the evdev controller backend" ON) +endif() + if(APPLE) option(OSX_USE_DEFAULT_SEARCH_PATH "Don't prioritize system library paths" OFF) endif() @@ -529,16 +533,16 @@ if(USE_EGL) add_definitions(-DUSE_EGL=1) endif() -if(${CMAKE_SYSTEM_NAME} STREQUAL "Linux") - include(FindLibudev OPTIONAL) - include(FindLibevdev OPTIONAL) +if(ENABLE_EVDEV) + include(FindLibudev REQUIRED) + include(FindLibevdev REQUIRED) if(LIBUDEV_FOUND AND LIBEVDEV_FOUND) message("libevdev/libudev found, enabling evdev controller backend") add_definitions(-DHAVE_LIBUDEV=1) add_definitions(-DHAVE_LIBEVDEV=1) include_directories(${LIBUDEV_INCLUDE_DIR} ${LIBEVDEV_INCLUDE_DIR}) else() - message("Could find libevdev/libudev, disabling evdev controller backend") + message(FATAL_ERROR "Couldn't find libevdev and/or libudev. Can't build evdev controller backend.\nDisable ENABLE_EVDEV if you wish to build without controller support") endif() endif() From 77183899e0526a343b8429cf04a1c07b31aafc34 Mon Sep 17 00:00:00 2001 From: Scott Mansell Date: Wed, 1 Jul 2015 00:37:26 +1200 Subject: [PATCH 029/583] evdev: Support axis with ranges which extend below zero. --- .../InputCommon/ControllerInterface/evdev/evdev.cpp | 12 +++++++++--- .../InputCommon/ControllerInterface/evdev/evdev.h | 1 + 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/Source/Core/InputCommon/ControllerInterface/evdev/evdev.cpp b/Source/Core/InputCommon/ControllerInterface/evdev/evdev.cpp index 2f4d53e234..9b31da73c4 100644 --- a/Source/Core/InputCommon/ControllerInterface/evdev/evdev.cpp +++ b/Source/Core/InputCommon/ControllerInterface/evdev/evdev.cpp @@ -164,7 +164,8 @@ ControlState evdevDevice::Button::GetState() const evdevDevice::Axis::Axis(u8 index, u16 code, bool upper, libevdev* dev) : m_code(code), m_index(index), m_upper(upper), m_dev(dev) { - m_range = libevdev_get_abs_maximum(m_dev, m_code); + m_min = libevdev_get_abs_minimum(m_dev, m_code); + m_range = libevdev_get_abs_maximum(m_dev, m_code) + abs(m_min); } std::string evdevDevice::Axis::GetName() const @@ -176,10 +177,15 @@ ControlState evdevDevice::Axis::GetState() const { int value = 0; libevdev_fetch_event_value(m_dev, EV_ABS, m_code, &value); + + // Value from 0.0 to 1.0 + ControlState fvalue = double(value - m_min) / double(m_range); + + // Split into two axis, each covering half the range from 0.0 to 1.0 if (m_upper) - return std::max(0.0, double(value) / double(m_range) - 0.5) * 2.0; + return std::max(0.0, fvalue - 0.5) * 2.0; else - return (0.5 - std::min(0.5, double(value) / double(m_range))) * 2.0; + return (0.5 - std::min(0.5, fvalue)) * 2.0; } std::string evdevDevice::ForceFeedback::GetName() const diff --git a/Source/Core/InputCommon/ControllerInterface/evdev/evdev.h b/Source/Core/InputCommon/ControllerInterface/evdev/evdev.h index 7290fbc379..d1555c8cce 100644 --- a/Source/Core/InputCommon/ControllerInterface/evdev/evdev.h +++ b/Source/Core/InputCommon/ControllerInterface/evdev/evdev.h @@ -43,6 +43,7 @@ private: const u8 m_index; const bool m_upper; int m_range; + int m_min; libevdev* m_dev; }; From 08b952ef31bf9034229a57cd798ed91131cea440 Mon Sep 17 00:00:00 2001 From: "Admiral H. Curtiss" Date: Wed, 1 Jul 2015 01:28:41 +0200 Subject: [PATCH 030/583] GC Adapter: Do not attempt to claim_interface when libusb_open() returns an error. Fixes a crash / nullptr dereference when the adapter is plugged in but no drivers are installed for it, on Windows. --- Source/Core/Core/HW/SI_GCAdapter.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/Source/Core/Core/HW/SI_GCAdapter.cpp b/Source/Core/Core/HW/SI_GCAdapter.cpp index 7115dc3e40..b54c07ef74 100644 --- a/Source/Core/Core/HW/SI_GCAdapter.cpp +++ b/Source/Core/Core/HW/SI_GCAdapter.cpp @@ -235,6 +235,7 @@ static bool CheckDeviceAccess(libusb_device* device) if (ret == LIBUSB_ERROR_NOT_SUPPORTED) s_libusb_driver_not_supported = true; } + return false; } else if ((ret = libusb_kernel_driver_active(s_handle, 0)) == 1) { From 2cddaa09f06329971fc3ec3e4a7f76d2a88058fe Mon Sep 17 00:00:00 2001 From: Ryan Houdek Date: Mon, 29 Jun 2015 19:02:30 -0500 Subject: [PATCH 031/583] [AArch64] Implement rlwimix. --- Source/Core/Core/PowerPC/JitArm64/Jit.h | 1 + .../PowerPC/JitArm64/JitArm64_Integer.cpp | 76 +++++++++++++++++++ .../Core/PowerPC/JitArm64/JitArm64_Tables.cpp | 2 +- 3 files changed, 78 insertions(+), 1 deletion(-) diff --git a/Source/Core/Core/PowerPC/JitArm64/Jit.h b/Source/Core/Core/PowerPC/JitArm64/Jit.h index 639892e441..aa9f43add3 100644 --- a/Source/Core/Core/PowerPC/JitArm64/Jit.h +++ b/Source/Core/Core/PowerPC/JitArm64/Jit.h @@ -98,6 +98,7 @@ public: void subfx(UGeckoInstruction inst); void addcx(UGeckoInstruction inst); void slwx(UGeckoInstruction inst); + void rlwimix(UGeckoInstruction inst); // System Registers void mtmsr(UGeckoInstruction inst); diff --git a/Source/Core/Core/PowerPC/JitArm64/JitArm64_Integer.cpp b/Source/Core/Core/PowerPC/JitArm64/JitArm64_Integer.cpp index 86d85cedb8..542b636b30 100644 --- a/Source/Core/Core/PowerPC/JitArm64/JitArm64_Integer.cpp +++ b/Source/Core/Core/PowerPC/JitArm64/JitArm64_Integer.cpp @@ -766,3 +766,79 @@ void JitArm64::slwx(UGeckoInstruction inst) ComputeRC(gpr.R(a), 0); } } + +void JitArm64::rlwimix(UGeckoInstruction inst) +{ + INSTRUCTION_START + JITDISABLE(bJITIntegerOff); + + int a = inst.RA, s = inst.RS; + u32 mask = Helper_Mask(inst.MB, inst.ME); + + if (gpr.IsImm(a) && gpr.IsImm(s)) + { + u32 res = (gpr.GetImm(a) & ~mask) | (_rotl(gpr.GetImm(s), inst.SH) & mask); + gpr.SetImmediate(a, res); + if (inst.Rc) + ComputeRC(res, 0); + } + else + { + if (mask == 0 || (a == s && inst.SH == 0)) + { + // Do Nothing + } + else if (mask == 0xFFFFFFFF) + { + if (inst.SH || a != s) + gpr.BindToRegister(a, a == s); + + if (inst.SH) + ROR(gpr.R(a), gpr.R(s), 32 - inst.SH); + else if (a != s) + MOV(gpr.R(a), gpr.R(s)); + } + else if (inst.SH == 0 && inst.MB <= inst.ME) + { + // No rotation + // No mask inversion + u32 lsb = 31 - inst.ME; + u32 width = inst.ME - inst.MB + 1; + + gpr.BindToRegister(a, true); + ARM64Reg WA = gpr.GetReg(); + UBFX(WA, gpr.R(s), lsb, width); + BFI(gpr.R(a), WA, lsb, width); + gpr.Unlock(WA); + } + else if (inst.SH && inst.MB <= inst.ME) + { + // No mask inversion + u32 lsb = 31 - inst.ME; + u32 width = inst.ME - inst.MB + 1; + + gpr.BindToRegister(a, true); + ARM64Reg WA = gpr.GetReg(); + ROR(WA, gpr.R(s), 32 - inst.SH); + UBFX(WA, WA, lsb, width); + BFI(gpr.R(a), WA, lsb, width); + gpr.Unlock(WA); + } + else + { + gpr.BindToRegister(a, true); + ARM64Reg WA = gpr.GetReg(); + ARM64Reg WB = gpr.GetReg(); + + MOVI2R(WA, mask); + BIC(WB, gpr.R(a), WA); + AND(WA, WA, gpr.R(s), ArithOption(gpr.R(s), ST_ROR, 32 - inst.SH)); + ORR(gpr.R(a), WB, WA); + + gpr.Unlock(WA, WB); + } + + if (inst.Rc) + ComputeRC(gpr.R(a), 0); + } +} diff --git a/Source/Core/Core/PowerPC/JitArm64/JitArm64_Tables.cpp b/Source/Core/Core/PowerPC/JitArm64/JitArm64_Tables.cpp index b25eb6ec50..fe3bb519a4 100644 --- a/Source/Core/Core/PowerPC/JitArm64/JitArm64_Tables.cpp +++ b/Source/Core/Core/PowerPC/JitArm64/JitArm64_Tables.cpp @@ -52,7 +52,7 @@ static GekkoOPTemplate primarytable[] = {14, &JitArm64::arith_imm}, // addi {15, &JitArm64::arith_imm}, // addis - {20, &JitArm64::FallBackToInterpreter}, // rlwimix + {20, &JitArm64::rlwimix}, // rlwimix {21, &JitArm64::rlwinmx}, // rlwinmx {23, &JitArm64::FallBackToInterpreter}, // rlwnmx From 8d69c2b4b722e2c4f9f0496b9ff1912c1a10d9e1 Mon Sep 17 00:00:00 2001 From: Anthony Serna Date: Wed, 1 Jul 2015 15:46:16 +0200 Subject: [PATCH 032/583] Small changes to description to "Store EFB Copies to Texture Only" --- Source/Core/DolphinWX/VideoConfigDiag.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/Core/DolphinWX/VideoConfigDiag.cpp b/Source/Core/DolphinWX/VideoConfigDiag.cpp index 0e8044b25c..853edb4c44 100644 --- a/Source/Core/DolphinWX/VideoConfigDiag.cpp +++ b/Source/Core/DolphinWX/VideoConfigDiag.cpp @@ -115,7 +115,7 @@ static wxString borderless_fullscreen_desc = wxTRANSLATE("Implement fullscreen m static wxString internal_res_desc = wxTRANSLATE("Specifies the resolution used to render at. A high resolution greatly improves visual quality, but also greatly increases GPU load and can cause issues in certain games.\n\"Multiple of 640x528\" will result in a size slightly larger than \"Window Size\" but yield fewer issues. Generally speaking, the lower the internal resolution is, the better your performance will be.\n\nIf unsure, select 640x528."); static wxString efb_access_desc = wxTRANSLATE("Ignore any requests from the CPU to read from or write to the EFB.\nImproves performance in some games, but might disable some gameplay-related features or graphical effects.\n\nIf unsure, leave this unchecked."); static wxString efb_emulate_format_changes_desc = wxTRANSLATE("Ignore any changes to the EFB format.\nImproves performance in many games without any negative effect. Causes graphical defects in a small number of other games.\n\nIf unsure, leave this checked."); -static wxString skip_efb_copy_to_ram_desc = wxTRANSLATE("Skip GPU synchronizing on EFB copies. Causes graphical defects in a small number of games.\n\nIf unsure, leave this checked."); +static wxString skip_efb_copy_to_ram_desc = wxTRANSLATE("Stores EFB Copies exclusively on the GPU, bypassing system memory. Causes graphical defects in a small number of games.\n\nEnabled = EFB Copies to Texture\nDisabled = EFB Copies to RAM (and Texture)\n\nIf unsure, leave this checked."); static wxString stc_desc = wxTRANSLATE("The \"Safe\" setting eliminates the likelihood of the GPU missing texture updates from RAM.\nLower accuracies cause in-game text to appear garbled in certain games.\n\nIf unsure, use the rightmost value."); static wxString wireframe_desc = wxTRANSLATE("Render the scene as a wireframe.\n\nIf unsure, leave this unchecked."); static wxString disable_fog_desc = wxTRANSLATE("Makes distant objects more visible by removing fog, thus increasing the overall detail.\nDisabling fog will break some games which rely on proper fog emulation.\n\nIf unsure, leave this unchecked."); From 9b95faaed7ca9c50685fe869d59355e771439455 Mon Sep 17 00:00:00 2001 From: Anthony Serna Date: Wed, 1 Jul 2015 15:46:16 +0200 Subject: [PATCH 033/583] Small changes to description to "Store EFB Copies to Texture Only" --- Source/Core/DolphinWX/VideoConfigDiag.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/Core/DolphinWX/VideoConfigDiag.cpp b/Source/Core/DolphinWX/VideoConfigDiag.cpp index 2e132576b3..a5639fdff5 100644 --- a/Source/Core/DolphinWX/VideoConfigDiag.cpp +++ b/Source/Core/DolphinWX/VideoConfigDiag.cpp @@ -116,7 +116,7 @@ static wxString borderless_fullscreen_desc = wxTRANSLATE("Implement fullscreen m static wxString internal_res_desc = wxTRANSLATE("Specifies the resolution used to render at. A high resolution greatly improves visual quality, but also greatly increases GPU load and can cause issues in certain games.\n\"Multiple of 640x528\" will result in a size slightly larger than \"Window Size\" but yield fewer issues. Generally speaking, the lower the internal resolution is, the better your performance will be.\n\nIf unsure, select 640x528."); static wxString efb_access_desc = wxTRANSLATE("Ignore any requests from the CPU to read from or write to the EFB.\nImproves performance in some games, but might disable some gameplay-related features or graphical effects.\n\nIf unsure, leave this unchecked."); static wxString efb_emulate_format_changes_desc = wxTRANSLATE("Ignore any changes to the EFB format.\nImproves performance in many games without any negative effect. Causes graphical defects in a small number of other games.\n\nIf unsure, leave this checked."); -static wxString skip_efb_copy_to_ram_desc = wxTRANSLATE("Skip GPU synchronizing on EFB copies. Causes graphical defects in a small number of games.\n\nIf unsure, leave this checked."); +static wxString skip_efb_copy_to_ram_desc = wxTRANSLATE("Stores EFB Copies exclusively on the GPU, bypassing system memory. Causes graphical defects in a small number of games.\n\nEnabled = EFB Copies to Texture\nDisabled = EFB Copies to RAM (and Texture)\n\nIf unsure, leave this checked."); static wxString stc_desc = wxTRANSLATE("The \"Safe\" setting eliminates the likelihood of the GPU missing texture updates from RAM.\nLower accuracies cause in-game text to appear garbled in certain games.\n\nIf unsure, use the rightmost value."); static wxString wireframe_desc = wxTRANSLATE("Render the scene as a wireframe.\n\nIf unsure, leave this unchecked."); static wxString disable_fog_desc = wxTRANSLATE("Makes distant objects more visible by removing fog, thus increasing the overall detail.\nDisabling fog will break some games which rely on proper fog emulation.\n\nIf unsure, leave this unchecked."); From dc83c8912f5ff2e474c59bdef6c67b3c7c9c70d4 Mon Sep 17 00:00:00 2001 From: degasus Date: Sun, 28 Jun 2015 11:06:16 +0200 Subject: [PATCH 034/583] JitArm64: Support branching fallbacks --- Source/Core/Core/ConfigManager.cpp | 1 + Source/Core/Core/PowerPC/JitArm64/Jit.cpp | 35 +++++++++++++++++++ .../Core/PowerPC/JitArm64/JitArm64_Branch.cpp | 6 ++++ .../JitArm64/JitArm64_SystemRegisters.cpp | 4 +-- 4 files changed, 44 insertions(+), 2 deletions(-) diff --git a/Source/Core/Core/ConfigManager.cpp b/Source/Core/Core/ConfigManager.cpp index 75f047129d..bace9b7971 100644 --- a/Source/Core/Core/ConfigManager.cpp +++ b/Source/Core/Core/ConfigManager.cpp @@ -621,6 +621,7 @@ void SConfig::LoadDefaults() bJITIntegerOff = false; bJITPairedOff = false; bJITSystemRegistersOff = false; + bJITBranchOff = false; m_strName = "NONE"; m_strUniqueID = "00000000"; diff --git a/Source/Core/Core/PowerPC/JitArm64/Jit.cpp b/Source/Core/Core/PowerPC/JitArm64/Jit.cpp index b968aeacf9..a658252043 100644 --- a/Source/Core/Core/PowerPC/JitArm64/Jit.cpp +++ b/Source/Core/Core/PowerPC/JitArm64/Jit.cpp @@ -51,10 +51,45 @@ void JitArm64::FallBackToInterpreter(UGeckoInstruction inst) { gpr.Flush(FlushMode::FLUSH_INTERPRETER, js.op); fpr.Flush(FlushMode::FLUSH_INTERPRETER, js.op); + + if (js.op->opinfo->flags & FL_ENDBLOCK) + { + // also flush the program counter + ARM64Reg WA = gpr.GetReg(); + MOVI2R(WA, js.compilerPC); + STR(INDEX_UNSIGNED, WA, X29, PPCSTATE_OFF(pc)); + ADD(WA, WA, 4); + STR(INDEX_UNSIGNED, WA, X29, PPCSTATE_OFF(npc)); + gpr.Unlock(WA); + } + Interpreter::_interpreterInstruction instr = GetInterpreterOp(inst); MOVI2R(W0, inst.hex); MOVI2R(X30, (u64)instr); BLR(X30); + + if (js.op->opinfo->flags & FL_ENDBLOCK) + { + if (js.isLastInstruction) + { + ARM64Reg WA = gpr.GetReg(); + LDR(INDEX_UNSIGNED, WA, X29, PPCSTATE_OFF(npc)); + WriteExceptionExit(WA); + } + else + { + // only exit if ppcstate.npc was changed + ARM64Reg WA = gpr.GetReg(); + LDR(INDEX_UNSIGNED, WA, X29, PPCSTATE_OFF(npc)); + ARM64Reg WB = gpr.GetReg(); + MOVI2R(WB, js.compilerPC + 4); + CMP(WB, WA); + gpr.Unlock(WB); + FixupBranch c = B(CC_EQ); + WriteExceptionExit(WA); + SetJumpTarget(c); + } + } } void JitArm64::HLEFunction(UGeckoInstruction inst) diff --git a/Source/Core/Core/PowerPC/JitArm64/JitArm64_Branch.cpp b/Source/Core/Core/PowerPC/JitArm64/JitArm64_Branch.cpp index 8efd81e0f1..2abe7d1016 100644 --- a/Source/Core/Core/PowerPC/JitArm64/JitArm64_Branch.cpp +++ b/Source/Core/Core/PowerPC/JitArm64/JitArm64_Branch.cpp @@ -18,6 +18,7 @@ using namespace Arm64Gen; void JitArm64::sc(UGeckoInstruction inst) { INSTRUCTION_START + JITDISABLE(bJITBranchOff); gpr.Flush(FlushMode::FLUSH_ALL); fpr.Flush(FlushMode::FLUSH_ALL); @@ -38,6 +39,7 @@ void JitArm64::sc(UGeckoInstruction inst) void JitArm64::rfi(UGeckoInstruction inst) { INSTRUCTION_START + JITDISABLE(bJITBranchOff); gpr.Flush(FlushMode::FLUSH_ALL); fpr.Flush(FlushMode::FLUSH_ALL); @@ -78,6 +80,7 @@ void JitArm64::rfi(UGeckoInstruction inst) void JitArm64::bx(UGeckoInstruction inst) { INSTRUCTION_START + JITDISABLE(bJITBranchOff); gpr.Flush(FlushMode::FLUSH_ALL); fpr.Flush(FlushMode::FLUSH_ALL); @@ -115,6 +118,7 @@ void JitArm64::bx(UGeckoInstruction inst) void JitArm64::bcx(UGeckoInstruction inst) { INSTRUCTION_START + JITDISABLE(bJITBranchOff); ARM64Reg WA = gpr.GetReg(); FixupBranch pCTRDontBranch; @@ -173,6 +177,7 @@ void JitArm64::bcx(UGeckoInstruction inst) void JitArm64::bcctrx(UGeckoInstruction inst) { INSTRUCTION_START + JITDISABLE(bJITBranchOff); // bcctrx doesn't decrement and/or test CTR _assert_msg_(DYNA_REC, inst.BO_2 & BO_DONT_DECREMENT_FLAG, "bcctrx with decrement and test CTR option is invalid!"); @@ -212,6 +217,7 @@ void JitArm64::bcctrx(UGeckoInstruction inst) void JitArm64::bclrx(UGeckoInstruction inst) { INSTRUCTION_START + JITDISABLE(bJITBranchOff); ARM64Reg WA = gpr.GetReg(); FixupBranch pCTRDontBranch; diff --git a/Source/Core/Core/PowerPC/JitArm64/JitArm64_SystemRegisters.cpp b/Source/Core/Core/PowerPC/JitArm64/JitArm64_SystemRegisters.cpp index 72e42c1769..212c12fa8c 100644 --- a/Source/Core/Core/PowerPC/JitArm64/JitArm64_SystemRegisters.cpp +++ b/Source/Core/Core/PowerPC/JitArm64/JitArm64_SystemRegisters.cpp @@ -48,8 +48,7 @@ FixupBranch JitArm64::JumpIfCRFieldBit(int field, int bit, bool jump_if_set) void JitArm64::mtmsr(UGeckoInstruction inst) { INSTRUCTION_START - // Don't interpret this, if we do we get thrown out - //JITDISABLE(bJITSystemRegistersOff) + JITDISABLE(bJITSystemRegistersOff); gpr.BindToRegister(inst.RS, true); STR(INDEX_UNSIGNED, gpr.R(inst.RS), X29, PPCSTATE_OFF(msr)); @@ -143,6 +142,7 @@ void JitArm64::mtsrin(UGeckoInstruction inst) void JitArm64::twx(UGeckoInstruction inst) { INSTRUCTION_START + JITDISABLE(bJITSystemRegistersOff); s32 a = inst.RA; From 0054c4e0d9799765cdeb99f117fb664aa9d19c84 Mon Sep 17 00:00:00 2001 From: degasus Date: Sun, 28 Jun 2015 18:40:24 +0200 Subject: [PATCH 035/583] JitArm64: Drop icbi instruction It was already just a fallback + exit. Now we emit the exit for all affected fallbacks. --- Source/Core/Core/PowerPC/JitArm64/Jit.h | 1 - Source/Core/Core/PowerPC/JitArm64/JitArm64_LoadStore.cpp | 9 --------- Source/Core/Core/PowerPC/JitArm64/JitArm64_Tables.cpp | 2 +- 3 files changed, 1 insertion(+), 11 deletions(-) diff --git a/Source/Core/Core/PowerPC/JitArm64/Jit.h b/Source/Core/Core/PowerPC/JitArm64/Jit.h index aa9f43add3..6b2d0c3fe8 100644 --- a/Source/Core/Core/PowerPC/JitArm64/Jit.h +++ b/Source/Core/Core/PowerPC/JitArm64/Jit.h @@ -114,7 +114,6 @@ public: void mtspr(UGeckoInstruction inst); // LoadStore - void icbi(UGeckoInstruction inst); void lXX(UGeckoInstruction inst); void stX(UGeckoInstruction inst); void lmw(UGeckoInstruction inst); diff --git a/Source/Core/Core/PowerPC/JitArm64/JitArm64_LoadStore.cpp b/Source/Core/Core/PowerPC/JitArm64/JitArm64_LoadStore.cpp index 9739fb35c1..19433dcda0 100644 --- a/Source/Core/Core/PowerPC/JitArm64/JitArm64_LoadStore.cpp +++ b/Source/Core/Core/PowerPC/JitArm64/JitArm64_LoadStore.cpp @@ -18,15 +18,6 @@ using namespace Arm64Gen; -void JitArm64::icbi(UGeckoInstruction inst) -{ - gpr.Flush(FlushMode::FLUSH_ALL); - fpr.Flush(FlushMode::FLUSH_ALL); - - FallBackToInterpreter(inst); - WriteExit(js.compilerPC + 4); -} - void JitArm64::SafeLoadToReg(u32 dest, s32 addr, s32 offsetReg, u32 flags, s32 offset, bool update) { // We want to make sure to not get LR as a temp register diff --git a/Source/Core/Core/PowerPC/JitArm64/JitArm64_Tables.cpp b/Source/Core/Core/PowerPC/JitArm64/JitArm64_Tables.cpp index fe3bb519a4..7bf211bdc5 100644 --- a/Source/Core/Core/PowerPC/JitArm64/JitArm64_Tables.cpp +++ b/Source/Core/Core/PowerPC/JitArm64/JitArm64_Tables.cpp @@ -302,7 +302,7 @@ static GekkoOPTemplate table31[] = {4, &JitArm64::twx}, // tw {598, &JitArm64::DoNothing}, // sync - {982, &JitArm64::icbi}, // icbi + {982, &JitArm64::FallBackToInterpreter}, // icbi // Unused instructions on GC {310, &JitArm64::FallBackToInterpreter}, // eciwx From 245a639e2c729af3f9ef22a7d1d36e2b85d79aa9 Mon Sep 17 00:00:00 2001 From: degasus Date: Sun, 28 Jun 2015 20:27:50 +0200 Subject: [PATCH 036/583] JitArm64: Partially fallback on bcctrx No need to assert, fallbacks on branching instructions now works fine. --- .../Core/PowerPC/JitArm64/JitArm64_Branch.cpp | 51 +++++++++---------- 1 file changed, 23 insertions(+), 28 deletions(-) diff --git a/Source/Core/Core/PowerPC/JitArm64/JitArm64_Branch.cpp b/Source/Core/Core/PowerPC/JitArm64/JitArm64_Branch.cpp index 2abe7d1016..4dfd88b92e 100644 --- a/Source/Core/Core/PowerPC/JitArm64/JitArm64_Branch.cpp +++ b/Source/Core/Core/PowerPC/JitArm64/JitArm64_Branch.cpp @@ -179,39 +179,34 @@ void JitArm64::bcctrx(UGeckoInstruction inst) INSTRUCTION_START JITDISABLE(bJITBranchOff); + // Rare condition seen in (just some versions of?) Nintendo's NES Emulator + // BO_2 == 001zy -> b if false + // BO_2 == 011zy -> b if true + FALLBACK_IF(!(inst.BO_2 & BO_DONT_CHECK_CONDITION)); + // bcctrx doesn't decrement and/or test CTR _assert_msg_(DYNA_REC, inst.BO_2 & BO_DONT_DECREMENT_FLAG, "bcctrx with decrement and test CTR option is invalid!"); - if (inst.BO_2 & BO_DONT_CHECK_CONDITION) + // BO_2 == 1z1zz -> b always + + //NPC = CTR & 0xfffffffc; + gpr.Flush(FlushMode::FLUSH_ALL); + fpr.Flush(FlushMode::FLUSH_ALL); + + if (inst.LK_3) { - // BO_2 == 1z1zz -> b always - - //NPC = CTR & 0xfffffffc; - gpr.Flush(FlushMode::FLUSH_ALL); - fpr.Flush(FlushMode::FLUSH_ALL); - - if (inst.LK_3) - { - ARM64Reg WB = gpr.GetReg(); - u32 Jumpto = js.compilerPC + 4; - MOVI2R(WB, Jumpto); - STR(INDEX_UNSIGNED, WB, X29, PPCSTATE_OFF(spr[SPR_LR])); - gpr.Unlock(WB); - } - - ARM64Reg WA = gpr.GetReg(); - - LDR(INDEX_UNSIGNED, WA, X29, PPCSTATE_OFF(spr[SPR_CTR])); - AND(WA, WA, 30, 29); // Wipe the bottom 2 bits. - WriteExitDestInR(WA); - } - else - { - // Rare condition seen in (just some versions of?) Nintendo's NES Emulator - // BO_2 == 001zy -> b if false - // BO_2 == 011zy -> b if true - _assert_msg_(DYNA_REC, false, "Haven't implemented rare form of bcctrx yet"); + ARM64Reg WB = gpr.GetReg(); + u32 Jumpto = js.compilerPC + 4; + MOVI2R(WB, Jumpto); + STR(INDEX_UNSIGNED, WB, X29, PPCSTATE_OFF(spr[SPR_LR])); + gpr.Unlock(WB); } + + ARM64Reg WA = gpr.GetReg(); + + LDR(INDEX_UNSIGNED, WA, X29, PPCSTATE_OFF(spr[SPR_CTR])); + AND(WA, WA, 30, 29); // Wipe the bottom 2 bits. + WriteExitDestInR(WA); } void JitArm64::bclrx(UGeckoInstruction inst) From 6a33f174de618dc698ceba02e792cc6b2dba9732 Mon Sep 17 00:00:00 2001 From: "Admiral H. Curtiss" Date: Wed, 1 Jul 2015 01:28:41 +0200 Subject: [PATCH 037/583] GC Adapter: Do not attempt to claim_interface when libusb_open() returns an error. Fixes a crash / nullptr dereference when the adapter is plugged in but no drivers are installed for it, on Windows. --- Source/Core/Core/HW/SI_GCAdapter.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/Source/Core/Core/HW/SI_GCAdapter.cpp b/Source/Core/Core/HW/SI_GCAdapter.cpp index 7115dc3e40..b54c07ef74 100644 --- a/Source/Core/Core/HW/SI_GCAdapter.cpp +++ b/Source/Core/Core/HW/SI_GCAdapter.cpp @@ -235,6 +235,7 @@ static bool CheckDeviceAccess(libusb_device* device) if (ret == LIBUSB_ERROR_NOT_SUPPORTED) s_libusb_driver_not_supported = true; } + return false; } else if ((ret = libusb_kernel_driver_active(s_handle, 0)) == 1) { From d8cd2c3252ab6f2ce6c1656b5eb194863e834f52 Mon Sep 17 00:00:00 2001 From: Rodolfo Bogado Date: Mon, 29 Jun 2015 22:19:19 -0300 Subject: [PATCH 038/583] Implement scaled partial texture updates --- Data/Sys/GameSettings/SMN.ini | 4 +- .../Core/VideoBackends/D3D/TextureCache.cpp | 62 ++++++++++- Source/Core/VideoBackends/D3D/TextureCache.h | 5 +- .../Core/VideoBackends/OGL/TextureCache.cpp | 69 ++++++++++-- Source/Core/VideoBackends/OGL/TextureCache.h | 5 +- Source/Core/VideoCommon/TextureCacheBase.cpp | 100 +++++++++++++----- Source/Core/VideoCommon/TextureCacheBase.h | 9 +- 7 files changed, 211 insertions(+), 43 deletions(-) diff --git a/Data/Sys/GameSettings/SMN.ini b/Data/Sys/GameSettings/SMN.ini index 70e3592672..204d8a32df 100644 --- a/Data/Sys/GameSettings/SMN.ini +++ b/Data/Sys/GameSettings/SMN.ini @@ -5,7 +5,6 @@ [EmuState] # The Emulation State. 1 is worst, 5 is best, 0 is not set. -EmulationIssues = If "Store EFB Copies to Texture Only" is enabled, "Scaled EFB Copy" needs to be disabled for the coins to spin. EmulationStateId = 4 [OnLoad] @@ -20,5 +19,4 @@ EmulationStateId = 4 [Video_Settings] SafeTextureCacheColorSamples = 512 -[Video_Hacks] -EFBScaledCopy = False +[Video_Hacks] \ No newline at end of file diff --git a/Source/Core/VideoBackends/D3D/TextureCache.cpp b/Source/Core/VideoBackends/D3D/TextureCache.cpp index 2c820849d5..de204fa2af 100644 --- a/Source/Core/VideoBackends/D3D/TextureCache.cpp +++ b/Source/Core/VideoBackends/D3D/TextureCache.cpp @@ -77,11 +77,67 @@ bool TextureCache::TCacheEntry::Save(const std::string& filename, unsigned int l return saved_png; } -void TextureCache::TCacheEntry::DoPartialTextureUpdate(TCacheEntryBase* entry_, u32 x, u32 y) +void TextureCache::TCacheEntry::CopyRectangleFromTexture( + const TCacheEntryBase* source, + const MathUtil::Rectangle &srcrect, + const MathUtil::Rectangle &dstrect) { - TCacheEntry* entry = (TCacheEntry*)entry_; + TCacheEntry* srcentry = (TCacheEntry*)source; + if (srcrect.GetWidth() == dstrect.GetWidth() + && srcrect.GetHeight() == dstrect.GetHeight()) + { + const D3D11_BOX *psrcbox = nullptr; + D3D11_BOX srcbox; + if (srcrect.left != 0 || srcrect.top != 0) + { + srcbox.left = srcrect.left; + srcbox.top = srcrect.top; + srcbox.right = srcrect.right; + srcbox.bottom = srcrect.bottom; + psrcbox = &srcbox; + } + D3D::context->CopySubresourceRegion( + texture->GetTex(), + 0, + dstrect.left, + dstrect.top, + 0, + srcentry->texture->GetTex(), + 0, + psrcbox); + return; + } + else if (!config.rendertarget) + { + return; + } + g_renderer->ResetAPIState(); // reset any game specific settings - D3D::context->CopySubresourceRegion(texture->GetTex(), 0, x , y , 0, entry->texture->GetTex(), 0, NULL); + const D3D11_VIEWPORT vp = CD3D11_VIEWPORT( + float(dstrect.left), + float(dstrect.top), + float(dstrect.GetWidth()), + float(dstrect.GetHeight())); + + D3D::context->OMSetRenderTargets(1, &texture->GetRTV(), nullptr); + D3D::context->RSSetViewports(1, &vp); + D3D::SetLinearCopySampler(); + D3D11_RECT srcRC; + srcRC.left = srcrect.left; + srcRC.right = srcrect.right; + srcRC.top = srcrect.top; + srcRC.bottom = srcrect.bottom; + D3D::drawShadedTexQuad(srcentry->texture->GetSRV(), &srcRC, + srcentry->config.width, srcentry->config.height, + PixelShaderCache::GetColorCopyProgram(false), + VertexShaderCache::GetSimpleVertexShader(), + VertexShaderCache::GetSimpleInputLayout(), nullptr, 1.0, 0); + + D3D::context->OMSetRenderTargets(1, + &FramebufferManager::GetEFBColorTexture()->GetRTV(), + FramebufferManager::GetEFBDepthTexture()->GetDSV()); + + g_renderer->RestoreAPIState(); } void TextureCache::TCacheEntry::Load(unsigned int width, unsigned int height, diff --git a/Source/Core/VideoBackends/D3D/TextureCache.h b/Source/Core/VideoBackends/D3D/TextureCache.h index d6cb7eeef0..608fa47044 100644 --- a/Source/Core/VideoBackends/D3D/TextureCache.h +++ b/Source/Core/VideoBackends/D3D/TextureCache.h @@ -26,7 +26,10 @@ private: TCacheEntry(const TCacheEntryConfig& config, D3DTexture2D *_tex) : TCacheEntryBase(config), texture(_tex) {} ~TCacheEntry(); - void DoPartialTextureUpdate(TCacheEntryBase* entry, u32 x, u32 y) override; + void CopyRectangleFromTexture( + const TCacheEntryBase* source, + const MathUtil::Rectangle &srcrect, + const MathUtil::Rectangle &dstrect) override; void Load(unsigned int width, unsigned int height, unsigned int expanded_width, unsigned int levels) override; diff --git a/Source/Core/VideoBackends/OGL/TextureCache.cpp b/Source/Core/VideoBackends/OGL/TextureCache.cpp index cefc8017d6..ebc3a672f1 100644 --- a/Source/Core/VideoBackends/OGL/TextureCache.cpp +++ b/Source/Core/VideoBackends/OGL/TextureCache.cpp @@ -33,11 +33,13 @@ namespace OGL { +static SHADER s_ColorCopyProgram; static SHADER s_ColorMatrixProgram; static SHADER s_DepthMatrixProgram; static GLuint s_ColorMatrixUniform; static GLuint s_DepthMatrixUniform; static GLuint s_ColorCopyPositionUniform; +static GLuint s_ColorMatrixPositionUniform; static GLuint s_DepthCopyPositionUniform; static u32 s_ColorCbufid; static u32 s_DepthCbufid; @@ -137,12 +139,53 @@ TextureCache::TCacheEntryBase* TextureCache::CreateTexture(const TCacheEntryConf return entry; } -void TextureCache::TCacheEntry::DoPartialTextureUpdate(TCacheEntryBase* entry_, u32 x, u32 y) +void TextureCache::TCacheEntry::CopyRectangleFromTexture( + const TCacheEntryBase* source, + const MathUtil::Rectangle &srcrect, + const MathUtil::Rectangle &dstrect) { - - TCacheEntry* entry = (TCacheEntry*)entry_; - - glCopyImageSubData(entry->texture, GL_TEXTURE_2D_ARRAY, 0, 0, 0, 0, texture, GL_TEXTURE_2D_ARRAY, 0, x, y, 0, entry->native_width, entry->native_height, 1); + TCacheEntry* srcentry = (TCacheEntry*)source; + if (srcrect.GetWidth() == dstrect.GetWidth() + && srcrect.GetHeight() == dstrect.GetHeight() + && g_ActiveConfig.backend_info.bSupportsCopySubImage) + { + glCopyImageSubData( + srcentry->texture, + GL_TEXTURE_2D_ARRAY, + 0, + srcrect.left, + srcrect.top, + 0, + texture, + GL_TEXTURE_2D_ARRAY, + 0, + dstrect.left, + dstrect.top, + 0, + dstrect.GetWidth(), + dstrect.GetHeight(), + 1); + return; + } + else if (!config.rendertarget) + { + return; + } + g_renderer->ResetAPIState(); + FramebufferManager::SetFramebuffer(framebuffer); + glActiveTexture(GL_TEXTURE9); + glBindTexture(GL_TEXTURE_2D_ARRAY, srcentry->texture); + g_sampler_cache->BindLinearSampler(9); + glViewport(dstrect.left, dstrect.top, dstrect.GetWidth(), dstrect.GetHeight()); + s_ColorCopyProgram.Bind(); + glUniform4f(s_ColorCopyPositionUniform, + float(srcrect.left), + float(srcrect.top), + float(srcrect.GetWidth()), + float(srcrect.GetHeight())); + glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); + FramebufferManager::SetFramebuffer(0); + g_renderer->RestoreAPIState(); } void TextureCache::TCacheEntry::Load(unsigned int width, unsigned int height, @@ -208,7 +251,7 @@ void TextureCache::TCacheEntry::FromRenderTarget(u32 dstAddr, unsigned int dstFo if (s_ColorCbufid != cbufid) glUniform4fv(s_ColorMatrixUniform, 7, colmat); s_ColorCbufid = cbufid; - uniform_location = s_ColorCopyPositionUniform; + uniform_location = s_ColorMatrixPositionUniform; } TargetRectangle R = g_renderer->ConvertEFBRectangle(srcRect); @@ -286,6 +329,16 @@ void TextureCache::SetStage() void TextureCache::CompileShaders() { + const char *pColorCopyProg = + "SAMPLER_BINDING(9) uniform sampler2DArray samp9;\n" + "in vec3 f_uv0;\n" + "out vec4 ocol0;\n" + "\n" + "void main(){\n" + " vec4 texcol = texture(samp9, f_uv0);\n" + " ocol0 = texcol;\n" + "}\n"; + const char *pColorMatrixProg = "SAMPLER_BINDING(9) uniform sampler2DArray samp9;\n" "uniform vec4 colmat[7];\n" @@ -357,6 +410,7 @@ void TextureCache::CompileShaders() const char* prefix = (GProgram == nullptr) ? "f" : "v"; const char* depth_layer = (g_ActiveConfig.bStereoEFBMonoDepth) ? "0.0" : "f_uv0.z"; + ProgramShaderCache::CompileShader(s_ColorCopyProgram, StringFromFormat(VProgram, prefix, prefix).c_str(), pColorCopyProg, GProgram); ProgramShaderCache::CompileShader(s_ColorMatrixProgram, StringFromFormat(VProgram, prefix, prefix).c_str(), pColorMatrixProg, GProgram); ProgramShaderCache::CompileShader(s_DepthMatrixProgram, StringFromFormat(VProgram, prefix, prefix).c_str(), StringFromFormat(pDepthMatrixProg, depth_layer).c_str(), GProgram); @@ -365,7 +419,8 @@ void TextureCache::CompileShaders() s_ColorCbufid = -1; s_DepthCbufid = -1; - s_ColorCopyPositionUniform = glGetUniformLocation(s_ColorMatrixProgram.glprogid, "copy_position"); + s_ColorCopyPositionUniform = glGetUniformLocation(s_ColorCopyProgram.glprogid, "copy_position"); + s_ColorMatrixPositionUniform = glGetUniformLocation(s_ColorMatrixProgram.glprogid, "copy_position"); s_DepthCopyPositionUniform = glGetUniformLocation(s_DepthMatrixProgram.glprogid, "copy_position"); std::string palette_shader = diff --git a/Source/Core/VideoBackends/OGL/TextureCache.h b/Source/Core/VideoBackends/OGL/TextureCache.h index 42c83d8dda..1ed85b0539 100644 --- a/Source/Core/VideoBackends/OGL/TextureCache.h +++ b/Source/Core/VideoBackends/OGL/TextureCache.h @@ -33,7 +33,10 @@ private: TCacheEntry(const TCacheEntryConfig& config); ~TCacheEntry(); - void DoPartialTextureUpdate(TCacheEntryBase* entry, u32 x, u32 y) override; + void CopyRectangleFromTexture( + const TCacheEntryBase* source, + const MathUtil::Rectangle &srcrect, + const MathUtil::Rectangle &dstrect) override; void Load(unsigned int width, unsigned int height, unsigned int expanded_width, unsigned int level) override; diff --git a/Source/Core/VideoCommon/TextureCacheBase.cpp b/Source/Core/VideoCommon/TextureCacheBase.cpp index 6baca12326..7d49e698da 100644 --- a/Source/Core/VideoCommon/TextureCacheBase.cpp +++ b/Source/Core/VideoCommon/TextureCacheBase.cpp @@ -211,46 +211,98 @@ bool TextureCache::TCacheEntryBase::OverlapsMemoryRange(u32 range_address, u32 r return true; } -void TextureCache::TCacheEntryBase::DoPartialTextureUpdates() +TextureCache::TCacheEntryBase* TextureCache::DoPartialTextureUpdates(TexCache::iterator iter_t) { - const bool isPaletteTexture = (format== GX_TF_C4 || format == GX_TF_C8 || format == GX_TF_C14X2 || format >= 0x10000); + TCacheEntryBase* entry_to_update = iter_t->second; + const bool isPaletteTexture = (entry_to_update->format == GX_TF_C4 + || entry_to_update->format == GX_TF_C8 + || entry_to_update->format == GX_TF_C14X2 + || entry_to_update->format >= 0x10000); // Efb copies and paletted textures are excluded from these updates, until there's an example where a game would // benefit from this. Both would require more work to be done. // TODO: Implement upscaling support for normal textures, and then remove the efb to ram and the scaled efb restrictions - if (!g_ActiveConfig.backend_info.bSupportsCopySubImage || !g_ActiveConfig.bSkipEFBCopyToRam || IsEfbCopy() - || isPaletteTexture || (g_ActiveConfig.bCopyEFBScaled && g_ActiveConfig.iEFBScale != SCALE_1X)) - return; + if (entry_to_update->IsEfbCopy() + || isPaletteTexture) + return entry_to_update; - u32 block_width = TexDecoder_GetBlockWidthInTexels(format); - u32 block_height = TexDecoder_GetBlockHeightInTexels(format); - u32 block_size = block_width * block_height * TexDecoder_GetTexelSizeInNibbles(format) / 2; + u32 block_width = TexDecoder_GetBlockWidthInTexels(entry_to_update->format); + u32 block_height = TexDecoder_GetBlockHeightInTexels(entry_to_update->format); + u32 block_size = block_width * block_height * TexDecoder_GetTexelSizeInNibbles(entry_to_update->format) / 2; - u32 numBlocksX = (native_width + block_width - 1) / block_width; - - TexCache::iterator iter = textures_by_address.lower_bound(addr); - TexCache::iterator iterend = textures_by_address.upper_bound(addr + size_in_bytes); + u32 numBlocksX = (entry_to_update->native_width + block_width - 1) / block_width; + TexCache::iterator iter = textures_by_address.lower_bound(entry_to_update->addr); + TexCache::iterator iterend = textures_by_address.upper_bound(entry_to_update->addr + entry_to_update->size_in_bytes); + bool entry_need_scaling = true; while (iter != iterend) { TCacheEntryBase* entry = iter->second; - if (entry->IsEfbCopy() && addr <= entry->addr && entry->addr + entry->size_in_bytes <= addr + size_in_bytes - && entry->frameCount == FRAMECOUNT_INVALID && entry->copyMipMapStrideChannels * 32 == numBlocksX * block_size) + if (entry != entry_to_update + && entry->IsEfbCopy() + && entry_to_update->addr <= entry->addr + && entry->addr + entry->size_in_bytes <= entry_to_update->addr + entry_to_update->size_in_bytes + && entry->frameCount == FRAMECOUNT_INVALID + && entry->copyMipMapStrideChannels * 32 == numBlocksX * block_size) { - u32 block_offset = (entry->addr - addr) / block_size; + u32 block_offset = (entry->addr - entry_to_update->addr) / block_size; u32 block_x = block_offset % numBlocksX; u32 block_y = block_offset / numBlocksX; u32 x = block_x * block_width; u32 y = block_y * block_height; - - DoPartialTextureUpdate(entry, x, y); - + MathUtil::Rectangle srcrect, dstrect; + srcrect.left = 0; + srcrect.top = 0; + dstrect.left = 0; + dstrect.top = 0; + if (entry_need_scaling) + { + entry_need_scaling = false; + u32 w = entry_to_update->native_width * entry->config.width / entry->native_width; + u32 h = entry_to_update->native_height * entry->config.height / entry->native_height; + u32 max = g_renderer->GetMaxTextureSize(); + if (max < w || max < h) + { + iter++; + continue; + } + if (entry_to_update->config.width != w || entry_to_update->config.height != h) + { + TextureCache::TCacheEntryConfig newconfig; + newconfig.width = w; + newconfig.height = h; + newconfig.rendertarget = true; + TCacheEntryBase* newentry = AllocateTexture(newconfig); + newentry->SetGeneralParameters(entry_to_update->addr, entry_to_update->size_in_bytes, entry_to_update->format); + newentry->SetDimensions(entry_to_update->native_width, entry_to_update->native_height, 1); + newentry->SetHashes(entry_to_update->hash); + newentry->frameCount = frameCount; + newentry->is_efb_copy = false; + srcrect.right = entry_to_update->config.width; + srcrect.bottom = entry_to_update->config.height; + dstrect.right = w; + dstrect.bottom = h; + newentry->CopyRectangleFromTexture(entry_to_update, srcrect, dstrect); + entry_to_update = newentry; + u64 key = iter_t->first; + iter_t = FreeTexture(iter_t); + textures_by_address.emplace(key, entry_to_update); + } + } + srcrect.right = entry->config.width; + srcrect.bottom = entry->config.height; + dstrect.left = x * entry_to_update->config.width / entry_to_update->native_width; + dstrect.top = y * entry_to_update->config.height / entry_to_update->native_height; + dstrect.right = (x + entry->native_width) * entry_to_update->config.width / entry_to_update->native_width; + dstrect.bottom = (y + entry->native_height) * entry_to_update->config.height / entry_to_update->native_height; + entry_to_update->CopyRectangleFromTexture(entry, srcrect, dstrect); // Mark the texture update as used, so it isn't applied more than once entry->frameCount = frameCount; } ++iter; } + return entry_to_update; } void TextureCache::DumpTexture(TCacheEntryBase* entry, std::string basename, unsigned int level) @@ -323,7 +375,7 @@ TextureCache::TCacheEntryBase* TextureCache::Load(const u32 stage) const unsigned int bsw = TexDecoder_GetBlockWidthInTexels(texformat) - 1; const unsigned int bsh = TexDecoder_GetBlockHeightInTexels(texformat) - 1; - unsigned int expandedWidth = (width + bsw) & (~bsw); + unsigned int expandedWidth = (width + bsw) & (~bsw); unsigned int expandedHeight = (height + bsh) & (~bsh); const unsigned int nativeW = width; const unsigned int nativeH = height; @@ -440,7 +492,7 @@ TextureCache::TCacheEntryBase* TextureCache::Load(const u32 stage) if (entry->hash == full_hash && entry->format == full_format && entry->native_levels >= tex_levels && entry->native_width == nativeW && entry->native_height == nativeH) { - entry->DoPartialTextureUpdates(); + entry = DoPartialTextureUpdates(iter); return ReturnEntry(stage, entry); } @@ -494,7 +546,7 @@ TextureCache::TCacheEntryBase* TextureCache::Load(const u32 stage) if (entry->format == full_format && entry->native_levels >= tex_levels && entry->native_width == nativeW && entry->native_height == nativeH) { - entry->DoPartialTextureUpdates(); + entry = DoPartialTextureUpdates(iter); return ReturnEntry(stage, entry); } @@ -539,7 +591,7 @@ TextureCache::TCacheEntryBase* TextureCache::Load(const u32 stage) if (!(texformat == GX_TF_RGBA8 && from_tmem)) { const u8* tlut = &texMem[tlutaddr]; - TexDecoder_Decode(temp, src_data, expandedWidth, expandedHeight, texformat, tlut, (TlutFormat) tlutfmt); + TexDecoder_Decode(temp, src_data, expandedWidth, expandedHeight, texformat, tlut, (TlutFormat)tlutfmt); } else { @@ -560,7 +612,7 @@ TextureCache::TCacheEntryBase* TextureCache::Load(const u32 stage) TCacheEntryBase* entry = AllocateTexture(config); GFX_DEBUGGER_PAUSE_AT(NEXT_NEW_TEXTURE, true); - textures_by_address.emplace((u64)address, entry); + iter = textures_by_address.emplace((u64)address, entry); if (g_ActiveConfig.iSafeTextureCache_ColorSamples == 0 || std::max(texture_size, palette_size) <= (u32)g_ActiveConfig.iSafeTextureCache_ColorSamples * 8) { @@ -636,7 +688,7 @@ TextureCache::TCacheEntryBase* TextureCache::Load(const u32 stage) INCSTAT(stats.numTexturesUploaded); SETSTAT(stats.numTexturesAlive, textures_by_address.size()); - entry->DoPartialTextureUpdates(); + entry = DoPartialTextureUpdates(iter); return ReturnEntry(stage, entry); } diff --git a/Source/Core/VideoCommon/TextureCacheBase.h b/Source/Core/VideoCommon/TextureCacheBase.h index 5d4f9204fc..0a51ef64b9 100644 --- a/Source/Core/VideoCommon/TextureCacheBase.h +++ b/Source/Core/VideoCommon/TextureCacheBase.h @@ -89,7 +89,10 @@ public: virtual void Bind(unsigned int stage) = 0; virtual bool Save(const std::string& filename, unsigned int level) = 0; - virtual void DoPartialTextureUpdate(TCacheEntryBase* entry, u32 x, u32 y) = 0; + virtual void CopyRectangleFromTexture( + const TCacheEntryBase* source, + const MathUtil::Rectangle &srcrect, + const MathUtil::Rectangle &dstrect) = 0; virtual void Load(unsigned int width, unsigned int height, unsigned int expanded_width, unsigned int level) = 0; @@ -100,8 +103,6 @@ public: bool OverlapsMemoryRange(u32 range_address, u32 range_size) const; - void DoPartialTextureUpdates(); - bool IsEfbCopy() const { return is_efb_copy; } }; @@ -140,7 +141,7 @@ protected: private: typedef std::multimap TexCache; typedef std::unordered_multimap TexPool; - + static TCacheEntryBase* DoPartialTextureUpdates(TexCache::iterator iter); static void DumpTexture(TCacheEntryBase* entry, std::string basename, unsigned int level); static void CheckTempSize(size_t required_size); From d09d59007a483198e26c925cecf9b1f8afec5388 Mon Sep 17 00:00:00 2001 From: Lioncash Date: Thu, 2 Jul 2015 11:09:01 -0400 Subject: [PATCH 039/583] Arm64Emitter: Add a missing const specifier for an array table --- Source/Core/Common/Arm64Emitter.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/Core/Common/Arm64Emitter.cpp b/Source/Core/Common/Arm64Emitter.cpp index c31583e5fc..6eaa4fdfca 100644 --- a/Source/Core/Common/Arm64Emitter.cpp +++ b/Source/Core/Common/Arm64Emitter.cpp @@ -406,7 +406,7 @@ static const u32 LogicalEnc[][2] = { }; // Load/Store Exclusive -static u32 LoadStoreExcEnc[][5] = { +static const u32 LoadStoreExcEnc[][5] = { {0, 0, 0, 0, 0}, // STXRB {0, 0, 0, 0, 1}, // STLXRB {0, 0, 1, 0, 0}, // LDXRB From 64bd20aba72f2dfa4d61041f825c389401b8ae0c Mon Sep 17 00:00:00 2001 From: Trace Bullet Date: Thu, 2 Jul 2015 02:43:18 -0400 Subject: [PATCH 040/583] DiscIO: Check if m_Disc is null in ParsePartitionData() --- Source/Core/DiscIO/DiscScrubber.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/Source/Core/DiscIO/DiscScrubber.cpp b/Source/Core/DiscIO/DiscScrubber.cpp index e44195492b..10d0c0e417 100644 --- a/Source/Core/DiscIO/DiscScrubber.cpp +++ b/Source/Core/DiscIO/DiscScrubber.cpp @@ -265,8 +265,14 @@ bool ParsePartitionData(SPartition& _rPartition) // Ready some stuff m_Disc = CreateVolumeFromFilename(m_Filename, _rPartition.GroupNumber, _rPartition.Number); - std::unique_ptr filesystem(CreateFileSystem(m_Disc)); + if (m_Disc == nullptr) + { + ERROR_LOG(DISCIO, "Failed to create volume from file %s", m_Filename.c_str()); + m_Disc = OldVolume; + return false; + } + std::unique_ptr filesystem(CreateFileSystem(m_Disc)); if (!filesystem) { ERROR_LOG(DISCIO, "Failed to create filesystem for group %d partition %u", _rPartition.GroupNumber, _rPartition.Number); From 3ad151062b707b628a55df4bf710904fb1855b8e Mon Sep 17 00:00:00 2001 From: sigmabeta Date: Fri, 3 Jul 2015 13:46:54 -0400 Subject: [PATCH 041/583] Android TV: Game selection screen highlights games with accent color. --- Source/Android/app/src/main/res/values/styles.xml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Source/Android/app/src/main/res/values/styles.xml b/Source/Android/app/src/main/res/values/styles.xml index dcfe4a77b7..ba80861700 100644 --- a/Source/Android/app/src/main/res/values/styles.xml +++ b/Source/Android/app/src/main/res/values/styles.xml @@ -12,6 +12,8 @@ true true true + + ?attr/colorAccent From afea72edfed99a954edf987406af7fabdb7e895f Mon Sep 17 00:00:00 2001 From: Tillmann Karras Date: Fri, 3 Jul 2015 21:10:18 +0200 Subject: [PATCH 042/583] Revert "Interpreter: assign directly instead via variables" This reverts commit 174ada3a62d7835f877d534062883e75305fdf18. --- .../Interpreter/Interpreter_Paired.cpp | 60 ++++++++++++------- 1 file changed, 40 insertions(+), 20 deletions(-) diff --git a/Source/Core/Core/PowerPC/Interpreter/Interpreter_Paired.cpp b/Source/Core/Core/PowerPC/Interpreter/Interpreter_Paired.cpp index e8a0132413..fc56a4a33d 100644 --- a/Source/Core/Core/PowerPC/Interpreter/Interpreter_Paired.cpp +++ b/Source/Core/Core/PowerPC/Interpreter/Interpreter_Paired.cpp @@ -59,8 +59,10 @@ void Interpreter::ps_abs(UGeckoInstruction _inst) // These are just moves, double is OK. void Interpreter::ps_merge00(UGeckoInstruction _inst) { - rPS0(_inst.FD) = rPS0(_inst.FA); - rPS1(_inst.FD) = rPS0(_inst.FB); + double p0 = rPS0(_inst.FA); + double p1 = rPS0(_inst.FB); + rPS0(_inst.FD) = p0; + rPS1(_inst.FD) = p1; if (_inst.Rc) Helper_UpdateCR1(); @@ -68,8 +70,10 @@ void Interpreter::ps_merge00(UGeckoInstruction _inst) void Interpreter::ps_merge01(UGeckoInstruction _inst) { - rPS0(_inst.FD) = rPS0(_inst.FA); - rPS1(_inst.FD) = rPS1(_inst.FB); + double p0 = rPS0(_inst.FA); + double p1 = rPS1(_inst.FB); + rPS0(_inst.FD) = p0; + rPS1(_inst.FD) = p1; if (_inst.Rc) Helper_UpdateCR1(); @@ -77,8 +81,10 @@ void Interpreter::ps_merge01(UGeckoInstruction _inst) void Interpreter::ps_merge10(UGeckoInstruction _inst) { - rPS0(_inst.FD) = rPS1(_inst.FA); - rPS1(_inst.FD) = rPS0(_inst.FB); + double p0 = rPS1(_inst.FA); + double p1 = rPS0(_inst.FB); + rPS0(_inst.FD) = p0; + rPS1(_inst.FD) = p1; if (_inst.Rc) Helper_UpdateCR1(); @@ -86,8 +92,10 @@ void Interpreter::ps_merge10(UGeckoInstruction _inst) void Interpreter::ps_merge11(UGeckoInstruction _inst) { - rPS0(_inst.FD) = rPS1(_inst.FA); - rPS1(_inst.FD) = rPS1(_inst.FB); + double p0 = rPS1(_inst.FA); + double p1 = rPS1(_inst.FB); + rPS0(_inst.FD) = p0; + rPS1(_inst.FD) = p1; if (_inst.Rc) Helper_UpdateCR1(); @@ -228,8 +236,10 @@ void Interpreter::ps_nmadd(UGeckoInstruction _inst) void Interpreter::ps_sum0(UGeckoInstruction _inst) { - rPS0(_inst.FD) = ForceSingle(NI_add(rPS0(_inst.FA), rPS1(_inst.FB))); - rPS1(_inst.FD) = ForceSingle(rPS1(_inst.FC)); + double p0 = ForceSingle(NI_add(rPS0(_inst.FA), rPS1(_inst.FB))); + double p1 = ForceSingle(rPS1(_inst.FC)); + rPS0(_inst.FD) = p0; + rPS1(_inst.FD) = p1; UpdateFPRF(rPS0(_inst.FD)); if (_inst.Rc) @@ -238,8 +248,10 @@ void Interpreter::ps_sum0(UGeckoInstruction _inst) void Interpreter::ps_sum1(UGeckoInstruction _inst) { - rPS0(_inst.FD) = ForceSingle(rPS0(_inst.FC)); - rPS1(_inst.FD) = ForceSingle(NI_add(rPS0(_inst.FA), rPS1(_inst.FB))); + double p0 = ForceSingle(rPS0(_inst.FC)); + double p1 = ForceSingle(NI_add(rPS0(_inst.FA), rPS1(_inst.FB))); + rPS0(_inst.FD) = p0; + rPS1(_inst.FD) = p1; UpdateFPRF(rPS1(_inst.FD)); if (_inst.Rc) @@ -249,8 +261,10 @@ void Interpreter::ps_sum1(UGeckoInstruction _inst) void Interpreter::ps_muls0(UGeckoInstruction _inst) { double c0 = Force25Bit(rPS0(_inst.FC)); - rPS0(_inst.FD) = ForceSingle(NI_mul(rPS0(_inst.FA), c0)); - rPS1(_inst.FD) = ForceSingle(NI_mul(rPS1(_inst.FA), c0)); + double p0 = ForceSingle(NI_mul(rPS0(_inst.FA), c0)); + double p1 = ForceSingle(NI_mul(rPS1(_inst.FA), c0)); + rPS0(_inst.FD) = p0; + rPS1(_inst.FD) = p1; UpdateFPRF(rPS0(_inst.FD)); if (_inst.Rc) @@ -260,8 +274,10 @@ void Interpreter::ps_muls0(UGeckoInstruction _inst) void Interpreter::ps_muls1(UGeckoInstruction _inst) { double c1 = Force25Bit(rPS1(_inst.FC)); - rPS0(_inst.FD) = ForceSingle(NI_mul(rPS0(_inst.FA), c1)); - rPS1(_inst.FD) = ForceSingle(NI_mul(rPS1(_inst.FA), c1)); + double p0 = ForceSingle(NI_mul(rPS0(_inst.FA), c1)); + double p1 = ForceSingle(NI_mul(rPS1(_inst.FA), c1)); + rPS0(_inst.FD) = p0; + rPS1(_inst.FD) = p1; UpdateFPRF(rPS0(_inst.FD)); if (_inst.Rc) @@ -271,8 +287,10 @@ void Interpreter::ps_muls1(UGeckoInstruction _inst) void Interpreter::ps_madds0(UGeckoInstruction _inst) { double c0 = Force25Bit(rPS0(_inst.FC)); - rPS0(_inst.FD) = ForceSingle(NI_madd(rPS0(_inst.FA), c0, rPS0(_inst.FB))); - rPS1(_inst.FD) = ForceSingle(NI_madd(rPS1(_inst.FA), c0, rPS1(_inst.FB))); + double p0 = ForceSingle(NI_madd(rPS0(_inst.FA), c0, rPS0(_inst.FB))); + double p1 = ForceSingle(NI_madd(rPS1(_inst.FA), c0, rPS1(_inst.FB))); + rPS0(_inst.FD) = p0; + rPS1(_inst.FD) = p1; UpdateFPRF(rPS0(_inst.FD)); if (_inst.Rc) @@ -282,8 +300,10 @@ void Interpreter::ps_madds0(UGeckoInstruction _inst) void Interpreter::ps_madds1(UGeckoInstruction _inst) { double c1 = Force25Bit(rPS1(_inst.FC)); - rPS0(_inst.FD) = ForceSingle(NI_madd(rPS0(_inst.FA), c1, rPS0(_inst.FB))); - rPS1(_inst.FD) = ForceSingle(NI_madd(rPS1(_inst.FA), c1, rPS1(_inst.FB))); + double p0 = ForceSingle(NI_madd(rPS0(_inst.FA), c1, rPS0(_inst.FB))); + double p1 = ForceSingle(NI_madd(rPS1(_inst.FA), c1, rPS1(_inst.FB))); + rPS0(_inst.FD) = p0; + rPS1(_inst.FD) = p1; UpdateFPRF(rPS0(_inst.FD)); if (_inst.Rc) From 12aed77e8a58f2b6e6a6d2e3bdf1c59bec9a6109 Mon Sep 17 00:00:00 2001 From: Tillmann Karras Date: Fri, 3 Jul 2015 23:33:47 +0200 Subject: [PATCH 043/583] CMake: fix PolarSSL test --- CMakeTests/FindPolarSSL.cmake | 1 + 1 file changed, 1 insertion(+) diff --git a/CMakeTests/FindPolarSSL.cmake b/CMakeTests/FindPolarSSL.cmake index 32302a9780..a209f2f2a1 100644 --- a/CMakeTests/FindPolarSSL.cmake +++ b/CMakeTests/FindPolarSSL.cmake @@ -34,6 +34,7 @@ if (POLARSSL_FOUND) set(CMAKE_REQUIRED_LIBRARIES ${POLARSSL_LIBRARY}) unset(POLARSSL_WORKS CACHE) check_cxx_source_compiles(" + #include #include #include #include From 3639755120815bdae5a343df0638920570cb1750 Mon Sep 17 00:00:00 2001 From: RGamma <> Date: Fri, 3 Jul 2015 11:11:21 -0400 Subject: [PATCH 044/583] Fix TASInput Crash When Stick Bitmap Is Null Patch provided by RGamma --- Source/Core/DolphinWX/TASInputDlg.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Source/Core/DolphinWX/TASInputDlg.cpp b/Source/Core/DolphinWX/TASInputDlg.cpp index 40ced03275..c921be7497 100644 --- a/Source/Core/DolphinWX/TASInputDlg.cpp +++ b/Source/Core/DolphinWX/TASInputDlg.cpp @@ -868,7 +868,9 @@ void TASInputDlg::UpdateStickBitmap(Stick stick) x = 256 - (u8)x; if (stick.y_cont.reverse) y = 256 - (u8)y; - stick.bitmap->SetBitmap(CreateStickBitmap(x, y)); + // If TASInputDlg::UpdateFromText(wxCommandEvent&) interrupts stick initialization, this bitmap is a nullptr + if (stick.bitmap != nullptr) + stick.bitmap->SetBitmap(CreateStickBitmap(x, y)); } void TASInputDlg::OnCloseWindow(wxCloseEvent& event) From 10f50f33fbf1c8a45374bf4a6bc1ebb50bd67b9d Mon Sep 17 00:00:00 2001 From: Fog Date: Fri, 3 Jul 2015 21:54:18 -0400 Subject: [PATCH 045/583] Fix random hangs when loading savestates with TAS Input --- Source/Core/DolphinWX/TASInputDlg.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Source/Core/DolphinWX/TASInputDlg.cpp b/Source/Core/DolphinWX/TASInputDlg.cpp index 40ced03275..0275980fa0 100644 --- a/Source/Core/DolphinWX/TASInputDlg.cpp +++ b/Source/Core/DolphinWX/TASInputDlg.cpp @@ -776,8 +776,8 @@ void TASInputDlg::GetValues(GCPadStatus* PadStatus) PadStatus->stickY = m_main_stick.y_cont.value; PadStatus->substickX = m_c_stick.x_cont.value; PadStatus->substickY = m_c_stick.y_cont.value; - PadStatus->triggerLeft = m_l.checkbox->GetValue() ? 255 : m_l_cont.slider->GetValue(); - PadStatus->triggerRight = m_r.checkbox->GetValue() ? 255 : m_r_cont.slider->GetValue(); + PadStatus->triggerLeft = m_l.checkbox->GetValue() ? 255 : m_l_cont.value; + PadStatus->triggerRight = m_r.checkbox->GetValue() ? 255 : m_r_cont.value; for (unsigned int i = 0; i < ArraySize(m_buttons); ++i) { From 30869135d50d2f3889de122e4cda8b4f9ba19f6a Mon Sep 17 00:00:00 2001 From: degasus Date: Fri, 3 Jul 2015 22:00:46 +0200 Subject: [PATCH 046/583] Jit64: Fallback support of branching instructions --- Source/Core/Core/PowerPC/Jit64/Jit.cpp | 21 ++++++++++++++++++- Source/Core/Core/PowerPC/Jit64/Jit.h | 2 -- .../Core/Core/PowerPC/Jit64/Jit64_Tables.cpp | 2 +- .../Core/Core/PowerPC/Jit64/Jit_LoadStore.cpp | 6 ------ .../PowerPC/Jit64/Jit_SystemRegisters.cpp | 3 +-- 5 files changed, 22 insertions(+), 12 deletions(-) diff --git a/Source/Core/Core/PowerPC/Jit64/Jit.cpp b/Source/Core/Core/PowerPC/Jit64/Jit.cpp index 65227a07f4..ec98a0385b 100644 --- a/Source/Core/Core/PowerPC/Jit64/Jit.cpp +++ b/Source/Core/Core/PowerPC/Jit64/Jit.cpp @@ -236,7 +236,7 @@ void Jit64::WriteCallInterpreter(UGeckoInstruction inst) { gpr.Flush(); fpr.Flush(); - if (js.isLastInstruction) + if (js.op->opinfo->flags & FL_ENDBLOCK) { MOV(32, PPCSTATE(pc), Imm32(js.compilerPC)); MOV(32, PPCSTATE(npc), Imm32(js.compilerPC + 4)); @@ -245,6 +245,25 @@ void Jit64::WriteCallInterpreter(UGeckoInstruction inst) ABI_PushRegistersAndAdjustStack({}, 0); ABI_CallFunctionC((void*)instr, inst.hex); ABI_PopRegistersAndAdjustStack({}, 0); + if (js.op->opinfo->flags & FL_ENDBLOCK) + { + if (js.isLastInstruction) + { + MOV(32, R(RSCRATCH), PPCSTATE(npc)); + MOV(32, PPCSTATE(pc), R(RSCRATCH)); + WriteExceptionExit(); + } + else + { + MOV(32, R(RSCRATCH), PPCSTATE(npc)); + SUB(32, R(RSCRATCH), Imm32(js.compilerPC + 4)); + FixupBranch c = J_CC(CC_Z); + MOV(32, R(RSCRATCH), PPCSTATE(npc)); + MOV(32, PPCSTATE(pc), R(RSCRATCH)); + WriteExceptionExit(); + SetJumpTarget(c); + } + } } void Jit64::FallBackToInterpreter(UGeckoInstruction _inst) diff --git a/Source/Core/Core/PowerPC/Jit64/Jit.h b/Source/Core/Core/PowerPC/Jit64/Jit.h index fe0376e921..c7305e000e 100644 --- a/Source/Core/Core/PowerPC/Jit64/Jit.h +++ b/Source/Core/Core/PowerPC/Jit64/Jit.h @@ -248,6 +248,4 @@ public: void lmw(UGeckoInstruction inst); void stmw(UGeckoInstruction inst); - - void icbi(UGeckoInstruction inst); }; diff --git a/Source/Core/Core/PowerPC/Jit64/Jit64_Tables.cpp b/Source/Core/Core/PowerPC/Jit64/Jit64_Tables.cpp index 051a85f335..7f6f97a619 100644 --- a/Source/Core/Core/PowerPC/Jit64/Jit64_Tables.cpp +++ b/Source/Core/Core/PowerPC/Jit64/Jit64_Tables.cpp @@ -300,7 +300,7 @@ static GekkoOPTemplate table31[] = {4, &Jit64::twX}, // tw {598, &Jit64::DoNothing}, // sync - {982, &Jit64::icbi}, // icbi + {982, &Jit64::FallBackToInterpreter}, // icbi // Unused instructions on GC {310, &Jit64::FallBackToInterpreter}, // eciwx diff --git a/Source/Core/Core/PowerPC/Jit64/Jit_LoadStore.cpp b/Source/Core/Core/PowerPC/Jit64/Jit_LoadStore.cpp index 03c426e24c..5b80bbee77 100644 --- a/Source/Core/Core/PowerPC/Jit64/Jit_LoadStore.cpp +++ b/Source/Core/Core/PowerPC/Jit64/Jit_LoadStore.cpp @@ -561,9 +561,3 @@ void Jit64::stmw(UGeckoInstruction inst) } gpr.UnlockAllX(); } - -void Jit64::icbi(UGeckoInstruction inst) -{ - FallBackToInterpreter(inst); - WriteExit(js.compilerPC + 4); -} diff --git a/Source/Core/Core/PowerPC/Jit64/Jit_SystemRegisters.cpp b/Source/Core/Core/PowerPC/Jit64/Jit_SystemRegisters.cpp index d7c56fbe10..9597143311 100644 --- a/Source/Core/Core/PowerPC/Jit64/Jit_SystemRegisters.cpp +++ b/Source/Core/Core/PowerPC/Jit64/Jit_SystemRegisters.cpp @@ -348,8 +348,7 @@ void Jit64::mfspr(UGeckoInstruction inst) void Jit64::mtmsr(UGeckoInstruction inst) { INSTRUCTION_START - // Don't interpret this, if we do we get thrown out - //JITDISABLE(bJITSystemRegistersOff); + JITDISABLE(bJITSystemRegistersOff); if (!gpr.R(inst.RS).IsImm()) { gpr.Lock(inst.RS); From c9a25f9484d9a1e1dd6037ebd7a7c130ac40cfde Mon Sep 17 00:00:00 2001 From: Jeffrey Pfau Date: Fri, 3 Jul 2015 22:27:36 -0700 Subject: [PATCH 047/583] Common: CallLambdaTrampoline can return a value As it is currently written, CallLambdaTrampoline does not return a value. However, some of the functions that are being wrapped may return a value that the JIT is expected to understand. A compiler *cough cough clang* may opt to alter %rax after the wrapped lambda returns, e.g. popping a previous value, which can clobber the return value. If we actually have a return value, then the compiler must not clobber it. --- Source/Core/Common/Arm64Emitter.h | 5 ++--- Source/Core/Common/x64Emitter.h | 5 ++--- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/Source/Core/Common/Arm64Emitter.h b/Source/Core/Common/Arm64Emitter.h index 6db19dc890..6939984308 100644 --- a/Source/Core/Common/Arm64Emitter.h +++ b/Source/Core/Common/Arm64Emitter.h @@ -711,10 +711,9 @@ public: // (this method might be a thunk in the case of multi-inheritance) so we // have to go through a trampoline function. template - static void CallLambdaTrampoline(const std::function* f, - Args... args) + static T CallLambdaTrampoline(const std::function* f, Args... args) { - (*f)(args...); + return (*f)(args...); } // This function expects you to have set up the state. diff --git a/Source/Core/Common/x64Emitter.h b/Source/Core/Common/x64Emitter.h index 7e3b64f49e..f6faea44bd 100644 --- a/Source/Core/Common/x64Emitter.h +++ b/Source/Core/Common/x64Emitter.h @@ -971,10 +971,9 @@ public: // (this method might be a thunk in the case of multi-inheritance) so we // have to go through a trampoline function. template - static void CallLambdaTrampoline(const std::function* f, - Args... args) + static T CallLambdaTrampoline(const std::function* f, Args... args) { - (*f)(args...); + return (*f)(args...); } template From 64b51df55d378c457b3e324b64a16c113d54ff5f Mon Sep 17 00:00:00 2001 From: Tillmann Karras Date: Sat, 4 Jul 2015 14:14:15 +0200 Subject: [PATCH 048/583] evdev: fix -Wunused-private-field warning --- Source/Core/InputCommon/ControllerInterface/evdev/evdev.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Source/Core/InputCommon/ControllerInterface/evdev/evdev.h b/Source/Core/InputCommon/ControllerInterface/evdev/evdev.h index d1555c8cce..c6c65e312d 100644 --- a/Source/Core/InputCommon/ControllerInterface/evdev/evdev.h +++ b/Source/Core/InputCommon/ControllerInterface/evdev/evdev.h @@ -51,11 +51,10 @@ private: { public: std::string GetName() const override; - ForceFeedback(u16 type, libevdev* dev) : m_type(type), m_dev(dev), m_id(-1) { m_fd = libevdev_get_fd(dev); } + ForceFeedback(u16 type, libevdev* dev) : m_type(type), m_id(-1) { m_fd = libevdev_get_fd(dev); } void SetState(ControlState state) override; private: const u16 m_type; - libevdev* m_dev; int m_fd; int m_id; }; From bd196e8c71853ef83a47156117efc2ad581f4b38 Mon Sep 17 00:00:00 2001 From: Jeffrey Pfau Date: Fri, 3 Jul 2015 22:27:36 -0700 Subject: [PATCH 049/583] Common: CallLambdaTrampoline can return a value As it is currently written, CallLambdaTrampoline does not return a value. However, some of the functions that are being wrapped may return a value that the JIT is expected to understand. A compiler *cough cough clang* may opt to alter %rax after the wrapped lambda returns, e.g. popping a previous value, which can clobber the return value. If we actually have a return value, then the compiler must not clobber it. --- Source/Core/Common/Arm64Emitter.h | 5 ++--- Source/Core/Common/x64Emitter.h | 5 ++--- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/Source/Core/Common/Arm64Emitter.h b/Source/Core/Common/Arm64Emitter.h index a5eb986e2f..899c2dbde6 100644 --- a/Source/Core/Common/Arm64Emitter.h +++ b/Source/Core/Common/Arm64Emitter.h @@ -709,10 +709,9 @@ public: // (this method might be a thunk in the case of multi-inheritance) so we // have to go through a trampoline function. template - static void CallLambdaTrampoline(const std::function* f, - Args... args) + static T CallLambdaTrampoline(const std::function* f, Args... args) { - (*f)(args...); + return (*f)(args...); } // This function expects you to have set up the state. diff --git a/Source/Core/Common/x64Emitter.h b/Source/Core/Common/x64Emitter.h index c62254aec4..627c940cdb 100644 --- a/Source/Core/Common/x64Emitter.h +++ b/Source/Core/Common/x64Emitter.h @@ -964,10 +964,9 @@ public: // (this method might be a thunk in the case of multi-inheritance) so we // have to go through a trampoline function. template - static void CallLambdaTrampoline(const std::function* f, - Args... args) + static T CallLambdaTrampoline(const std::function* f, Args... args) { - (*f)(args...); + return (*f)(args...); } template From 1d5cda98208e8dcb1a14161299f2490b6cf04b90 Mon Sep 17 00:00:00 2001 From: Scott Mansell Date: Wed, 24 Jun 2015 03:18:23 +1200 Subject: [PATCH 050/583] IPC_HLE: Reimplement fix for issues 2917/5232 with more sanity. Instead of opening... and... closing... files... after... every... file... operation... (which can be slow, especially if a virus scanner is running), we catch attempts to open the same file twice and only open one copy of the file. --- .../IPC_HLE/WII_IPC_HLE_Device_FileIO.cpp | 80 ++++++++++++------- .../Core/IPC_HLE/WII_IPC_HLE_Device_FileIO.h | 2 +- 2 files changed, 52 insertions(+), 30 deletions(-) diff --git a/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_FileIO.cpp b/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_FileIO.cpp index b820ecccc2..23067f0dbb 100644 --- a/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_FileIO.cpp +++ b/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_FileIO.cpp @@ -19,6 +19,8 @@ static Common::replace_v replacements; +static std::map > openFiles; + // This is used by several of the FileIO and /dev/fs functions std::string HLE_IPC_BuildFilename(std::string path_wii) { @@ -87,7 +89,8 @@ IPCCommandResult CWII_IPC_HLE_Device_FileIO::Close(u32 _CommandAddress, bool _bF INFO_LOG(WII_IPC_FILEIO, "FileIO: Close %s (DeviceID=%08x)", m_Name.c_str(), m_DeviceID); m_Mode = 0; - m_file.Close(); + // Let go of our pointer to the file, it will automatically close if we are the last handle accessing it. + m_file.reset(); // Close always return 0 for success if (_CommandAddress && !_bForce) @@ -116,6 +119,7 @@ IPCCommandResult CWII_IPC_HLE_Device_FileIO::Open(u32 _CommandAddress, u32 _Mode if (File::Exists(m_filepath) && !File::IsDirectory(m_filepath)) { INFO_LOG(WII_IPC_FILEIO, "FileIO: Open %s (%s == %08X)", m_Name.c_str(), Modes[_Mode], _Mode); + OpenFile(); ReturnValue = m_DeviceID; } else @@ -124,35 +128,53 @@ IPCCommandResult CWII_IPC_HLE_Device_FileIO::Open(u32 _CommandAddress, u32 _Mode ReturnValue = FS_FILE_NOT_EXIST; } - OpenFile(); - if (_CommandAddress) Memory::Write_U32(ReturnValue, _CommandAddress+4); m_Active = true; return IPC_DEFAULT_REPLY; } +// This isn't theadsafe, but it's only called from the CPU thread. void CWII_IPC_HLE_Device_FileIO::OpenFile() { - const char* open_mode = ""; + // On the wii, all file operations are strongly ordered. + // If a game opens the same file twice (or 8 times, looking at you PokePark Wii) + // and writes to one file handle, it will be able to immediately read the written + // data from the other handle. + // On 'real' operating systems, there are various buffers and caches meaning + // applications doing such naughty things will not get expected results. - switch (m_Mode) + // So we fix this by catching any attempts to open the same file twice and + // only opening one file. Accesses to a single file handle are ordered. + // + // Hall of Shame: + // - PokePark Wii (gets stuck on the loading screen of Pikachu falling) + // - PokePark 2 (Also gets stuck while loading) + // - Wii System Menu (Can't access the system settings, gets stuck on blank screen) + // - The Beatles: Rock Band (saving doesn't work) + + // Check if the file has already been opened. + auto search = openFiles.find(m_Name); + if (search != openFiles.end()) { - case ISFS_OPEN_READ: - open_mode = "rb"; - break; - - case ISFS_OPEN_WRITE: - case ISFS_OPEN_RW: - open_mode = "r+b"; - break; - - default: - PanicAlert("FileIO: Unknown open mode : 0x%02x", m_Mode); - break; + m_file = search->second.lock(); // Lock a shared pointer to use. } + else + { + std::string path = m_Name; + // This code will be called when all references to the shared pointer below have been removed. + auto deleter = [path](File::IOFile* ptr) + { + delete ptr; // IOFile's deconstructor closes the file. + openFiles.erase(path); // erase the weak pointer from the list of open files. + }; - m_file = File::IOFile(m_filepath, open_mode); + // All files are opened read/write. Actual access rights will be controlled per handle by the read/write functions below + m_file = std::shared_ptr(new File::IOFile(m_filepath, "r+b"), deleter); // Use the custom deleter from above. + + // Store a weak pointer to our newly opened file in the cache. + openFiles[path] = std::weak_ptr(m_file); + } } IPCCommandResult CWII_IPC_HLE_Device_FileIO::Seek(u32 _CommandAddress) @@ -161,11 +183,11 @@ IPCCommandResult CWII_IPC_HLE_Device_FileIO::Seek(u32 _CommandAddress) const s32 SeekPosition = Memory::Read_U32(_CommandAddress + 0xC); const s32 Mode = Memory::Read_U32(_CommandAddress + 0x10); - if (m_file) + if (m_file->IsOpen()) { ReturnValue = FS_RESULT_FATAL; - const s32 fileSize = (s32) m_file.GetSize(); + const s32 fileSize = (s32) m_file->GetSize(); INFO_LOG(WII_IPC_FILEIO, "FileIO: Seek Pos: 0x%08x, Mode: %i (%s, Length=0x%08x)", SeekPosition, Mode, m_Name.c_str(), fileSize); switch (Mode) @@ -209,7 +231,6 @@ IPCCommandResult CWII_IPC_HLE_Device_FileIO::Seek(u32 _CommandAddress) break; } } - m_file.Seek(m_SeekPos, SEEK_SET); } else { @@ -227,7 +248,7 @@ IPCCommandResult CWII_IPC_HLE_Device_FileIO::Read(u32 _CommandAddress) const u32 Size = Memory::Read_U32(_CommandAddress + 0x10); - if (m_file) + if (m_file->IsOpen()) { if (m_Mode == ISFS_OPEN_WRITE) { @@ -236,8 +257,9 @@ IPCCommandResult CWII_IPC_HLE_Device_FileIO::Read(u32 _CommandAddress) else { INFO_LOG(WII_IPC_FILEIO, "FileIO: Read 0x%x bytes to 0x%08x from %s", Size, Address, m_Name.c_str()); - ReturnValue = (u32)fread(Memory::GetPointer(Address), 1, Size, m_file.GetHandle()); - if (ReturnValue != Size && ferror(m_file.GetHandle())) + m_file->Seek(m_SeekPos, SEEK_SET); // File might be opened twice, need to seek before we read + ReturnValue = (u32)fread(Memory::GetPointer(Address), 1, Size, m_file->GetHandle()); + if (ReturnValue != Size && ferror(m_file->GetHandle())) { ReturnValue = FS_EACCESS; } @@ -264,7 +286,7 @@ IPCCommandResult CWII_IPC_HLE_Device_FileIO::Write(u32 _CommandAddress) const u32 Address = Memory::Read_U32(_CommandAddress + 0xC); // Write data from this memory address const u32 Size = Memory::Read_U32(_CommandAddress + 0x10); - if (m_file) + if (m_file->IsOpen()) { if (m_Mode == ISFS_OPEN_READ) { @@ -273,7 +295,8 @@ IPCCommandResult CWII_IPC_HLE_Device_FileIO::Write(u32 _CommandAddress) else { INFO_LOG(WII_IPC_FILEIO, "FileIO: Write 0x%04x bytes from 0x%08x to %s", Size, Address, m_Name.c_str()); - if (m_file.WriteBytes(Memory::GetPointer(Address), Size)) + m_file->Seek(m_SeekPos, SEEK_SET); // File might be opened twice, need to seek before we write + if (m_file->WriteBytes(Memory::GetPointer(Address), Size)) { ReturnValue = Size; m_SeekPos += Size; @@ -303,9 +326,9 @@ IPCCommandResult CWII_IPC_HLE_Device_FileIO::IOCtl(u32 _CommandAddress) { case ISFS_IOCTL_GETFILESTATS: { - if (m_file) + if (m_file->IsOpen()) { - u32 m_FileLength = (u32)m_file.GetSize(); + u32 m_FileLength = (u32)m_file->GetSize(); const u32 BufferOut = Memory::Read_U32(_CommandAddress + 0x18); INFO_LOG(WII_IPC_FILEIO, " File: %s, Length: %i, Pos: %i", m_Name.c_str(), m_FileLength, m_SeekPos); @@ -345,6 +368,5 @@ void CWII_IPC_HLE_Device_FileIO::DoState(PointerWrap &p) if (p.GetMode() == PointerWrap::MODE_READ) { OpenFile(); - m_file.Seek(m_SeekPos, SEEK_SET); } } diff --git a/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_FileIO.h b/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_FileIO.h index fb03764ae6..c8715a4a86 100644 --- a/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_FileIO.h +++ b/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_FileIO.h @@ -75,5 +75,5 @@ private: u32 m_SeekPos; std::string m_filepath; - File::IOFile m_file; + std::shared_ptr m_file; }; From 08fcc7bf843f17a2e02bbd3fd0201d5cd89da756 Mon Sep 17 00:00:00 2001 From: Scott Mansell Date: Wed, 24 Jun 2015 04:50:02 +1200 Subject: [PATCH 051/583] IPC_HLE: Cleanup device definitions with templates. Less copy/pasted code will make future modifications easier. --- Source/Core/Core/IPC_HLE/WII_IPC_HLE.cpp | 52 +++++++++++++++--------- 1 file changed, 32 insertions(+), 20 deletions(-) diff --git a/Source/Core/Core/IPC_HLE/WII_IPC_HLE.cpp b/Source/Core/Core/IPC_HLE/WII_IPC_HLE.cpp index 56bb610431..2738ad2f7a 100644 --- a/Source/Core/Core/IPC_HLE/WII_IPC_HLE.cpp +++ b/Source/Core/Core/IPC_HLE/WII_IPC_HLE.cpp @@ -102,42 +102,54 @@ static void EnqueueEvent(u64 userdata, int cycles_late = 0) Update(); } +static u32 num_devices; + +template +std::shared_ptr AddDevice(const char* deviceName) +{ + auto device = std::make_shared(num_devices, deviceName); + g_DeviceMap[num_devices] = device; + num_devices++; + return device; +} + void Init() { _dbg_assert_msg_(WII_IPC_HLE, g_DeviceMap.empty(), "DeviceMap isn't empty on init"); CWII_IPC_HLE_Device_es::m_ContentFile = ""; - u32 i = 0; + num_devices = 0; + // Build hardware devices - g_DeviceMap[i] = std::make_shared(i, "/dev/usb/oh1/57e/305"); i++; - g_DeviceMap[i] = std::make_shared(i, "/dev/stm/immediate"); i++; - g_DeviceMap[i] = std::make_shared(i, "/dev/stm/eventhook"); i++; - g_DeviceMap[i] = std::make_shared(i, "/dev/fs"); i++; + AddDevice("/dev/usb/oh1/57e/305"); + AddDevice("/dev/stm/immediate"); + AddDevice("/dev/stm/eventhook"); + AddDevice("/dev/fs"); // IOS allows two ES devices at a time for (u32 j=0; j(i, "/dev/es"); i++; + es_handles[j] = AddDevice("/dev/es"); es_inuse[j] = false; } - g_DeviceMap[i] = std::make_shared(i, std::string("/dev/di")); i++; - g_DeviceMap[i] = std::make_shared(i, "/dev/net/kd/request"); i++; - g_DeviceMap[i] = std::make_shared(i, "/dev/net/kd/time"); i++; - g_DeviceMap[i] = std::make_shared(i, "/dev/net/ncd/manage"); i++; - g_DeviceMap[i] = std::make_shared(i, "/dev/net/wd/command"); i++; - g_DeviceMap[i] = std::make_shared(i, "/dev/net/ip/top"); i++; - g_DeviceMap[i] = std::make_shared(i, "/dev/net/ssl"); i++; - g_DeviceMap[i] = std::make_shared(i, "/dev/usb/kbd"); i++; - g_DeviceMap[i] = std::make_shared(i, "/dev/sdio/slot0"); i++; - g_DeviceMap[i] = std::make_shared(i, "/dev/sdio/slot1"); i++; + AddDevice("/dev/di"); + AddDevice("/dev/net/kd/request"); + AddDevice("/dev/net/kd/time"); + AddDevice("/dev/net/ncd/manage"); + AddDevice("/dev/net/wd/command"); + AddDevice("/dev/net/ip/top"); + AddDevice("/dev/net/ssl"); + AddDevice("/dev/usb/kbd"); + AddDevice("/dev/sdio/slot0"); + AddDevice("/dev/sdio/slot1"); #if defined(__LIBUSB__) || defined(_WIN32) - g_DeviceMap[i] = std::make_shared(i, "/dev/usb/hid"); i++; + AddDevice("/dev/usb/hid"); #else - g_DeviceMap[i] = std::make_shared(i, "/dev/usb/hid"); i++; + AddDevice("/dev/usb/hid"); #endif - g_DeviceMap[i] = std::make_shared(i, "/dev/usb/oh1"); i++; - g_DeviceMap[i] = std::make_shared(i, "_Unimplemented_Device_"); i++; + AddDevice("/dev/usb/oh1"); + AddDevice("_Unimplemented_Device_"); event_enqueue = CoreTiming::RegisterEvent("IPCEvent", EnqueueEvent); } From ce1052505684afbfe7cbdd564fd81ca0aeda863b Mon Sep 17 00:00:00 2001 From: Sintendo Date: Sun, 5 Jul 2015 11:18:59 +0200 Subject: [PATCH 052/583] Eliminate branch in GenFres --- .../Core/Core/PowerPC/Jit64Common/Jit64AsmCommon.cpp | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/Source/Core/Core/PowerPC/Jit64Common/Jit64AsmCommon.cpp b/Source/Core/Core/PowerPC/Jit64Common/Jit64AsmCommon.cpp index 64adf9b4de..b0f38ca1ec 100644 --- a/Source/Core/Core/PowerPC/Jit64Common/Jit64AsmCommon.cpp +++ b/Source/Core/Core/PowerPC/Jit64Common/Jit64AsmCommon.cpp @@ -119,13 +119,12 @@ void CommonAsmRoutines::GenFres() MOV(32, R(RSCRATCH2), R(RSCRATCH_EXTRA)); AND(32, R(RSCRATCH_EXTRA), Imm32(0x7FF)); // exp AND(32, R(RSCRATCH2), Imm32(0x800)); // sign - CMP(32, R(RSCRATCH_EXTRA), Imm32(895)); + SUB(32, R(RSCRATCH_EXTRA), Imm32(895)); + CMP(32, R(RSCRATCH_EXTRA), Imm32(1149 - 895)); // Take the complex path for very large/small exponents. - FixupBranch complex1 = J_CC(CC_L); - CMP(32, R(RSCRATCH_EXTRA), Imm32(1149)); - FixupBranch complex2 = J_CC(CC_GE); + FixupBranch complex = J_CC(CC_AE); // if (exp < 895 || exp >= 1149) - SUB(32, R(RSCRATCH_EXTRA), Imm32(0x7FD)); + SUB(32, R(RSCRATCH_EXTRA), Imm32(0x7FD - 895)); NEG(32, R(RSCRATCH_EXTRA)); OR(32, R(RSCRATCH_EXTRA), R(RSCRATCH2)); SHL(64, R(RSCRATCH_EXTRA), Imm8(52)); // vali = sign | exponent @@ -154,8 +153,7 @@ void CommonAsmRoutines::GenFres() OR(32, PPCSTATE(fpscr), Imm32(FPSCR_FX | FPSCR_ZX)); SetJumpTarget(skip_set_fx1); - SetJumpTarget(complex1); - SetJumpTarget(complex2); + SetJumpTarget(complex); ABI_PushRegistersAndAdjustStack(QUANTIZED_REGS_TO_SAVE, 8); ABI_CallFunction((void *)&MathUtil::ApproximateReciprocal); ABI_PopRegistersAndAdjustStack(QUANTIZED_REGS_TO_SAVE, 8); From 2b2af124661c0d383279ef910c61ab70336414fe Mon Sep 17 00:00:00 2001 From: Michael Ehrenreich Date: Fri, 26 Jun 2015 01:33:41 +0200 Subject: [PATCH 053/583] Prevent nullptr dereference on a crash with no JIT present JitInterface::HandleFault would dereference jit which is NULL, causing a stack overflow through infinite exception recursion. --- Source/Core/Core/PowerPC/JitInterface.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Source/Core/Core/PowerPC/JitInterface.cpp b/Source/Core/Core/PowerPC/JitInterface.cpp index 13a1df05ea..0a8b89213a 100644 --- a/Source/Core/Core/PowerPC/JitInterface.cpp +++ b/Source/Core/Core/PowerPC/JitInterface.cpp @@ -203,6 +203,12 @@ namespace JitInterface bool HandleFault(uintptr_t access_address, SContext* ctx) { + // Prevent nullptr dereference on a crash with no JIT present + if (!jit) + { + return false; + } + return jit->HandleFault(access_address, ctx); } From c2bbcdd16c015e47a18cd0193fca69c821108685 Mon Sep 17 00:00:00 2001 From: Stevoisiak Date: Thu, 19 Mar 2015 22:37:41 -0400 Subject: [PATCH 054/583] Read custom titles from wiitdb.txt if titles.txt is not found --- Source/Core/DolphinWX/GameListCtrl.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Source/Core/DolphinWX/GameListCtrl.cpp b/Source/Core/DolphinWX/GameListCtrl.cpp index 1b967a5f7c..5983238240 100644 --- a/Source/Core/DolphinWX/GameListCtrl.cpp +++ b/Source/Core/DolphinWX/GameListCtrl.cpp @@ -388,9 +388,16 @@ void CGameListCtrl::InsertItemInReportView(long _Index) wxString name = StrToWxStr(rISOFile.GetName()); + // Attempt to load game titles from titles.txt + // http://www.gametdb.com/Wii/Downloads std::ifstream titlestxt; OpenFStream(titlestxt, File::GetUserPath(D_LOAD_IDX) + "titles.txt", std::ios::in); + if (!titlestxt.is_open()) + { + OpenFStream(titlestxt, File::GetUserPath(D_LOAD_IDX) + "wiitdb.txt", std::ios::in); + } + if (titlestxt.is_open() && rISOFile.GetUniqueID().size() > 3) { while (!titlestxt.eof()) From 90167abe0fb7a3dd0ec142096dff14efef192685 Mon Sep 17 00:00:00 2001 From: Stevoisiak Date: Sat, 21 Mar 2015 17:31:29 -0400 Subject: [PATCH 055/583] Improve parsing custom game titles from titles.txt Read game ID based on position of the "=" sign, rather than assuming game IDs are 6 characters in length. --- Source/Core/DolphinWX/GameListCtrl.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Source/Core/DolphinWX/GameListCtrl.cpp b/Source/Core/DolphinWX/GameListCtrl.cpp index 5983238240..f997b2a9e7 100644 --- a/Source/Core/DolphinWX/GameListCtrl.cpp +++ b/Source/Core/DolphinWX/GameListCtrl.cpp @@ -407,9 +407,10 @@ void CGameListCtrl::InsertItemInReportView(long _Index) if (!std::getline(titlestxt, line) && titlestxt.eof()) break; - if (line.substr(0,rISOFile.GetUniqueID().size()) == rISOFile.GetUniqueID()) + const size_t equals_index = line.find('='); + if (line.substr(0, equals_index - 1) == rISOFile.GetUniqueID()) { - name = StrToWxStr(line.substr(rISOFile.GetUniqueID().size() + 3)); + name = StrToWxStr(line.substr(equals_index + 2)); break; } } From afc1398fbd46a3b9d04eb0aab186b3d944c8becb Mon Sep 17 00:00:00 2001 From: Stevoisiak Date: Sun, 22 Mar 2015 19:48:52 -0400 Subject: [PATCH 056/583] Fix reading custom titles from WAD files --- Source/Core/DolphinWX/GameListCtrl.cpp | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/Source/Core/DolphinWX/GameListCtrl.cpp b/Source/Core/DolphinWX/GameListCtrl.cpp index f997b2a9e7..7e2f769e90 100644 --- a/Source/Core/DolphinWX/GameListCtrl.cpp +++ b/Source/Core/DolphinWX/GameListCtrl.cpp @@ -408,9 +408,15 @@ void CGameListCtrl::InsertItemInReportView(long _Index) break; const size_t equals_index = line.find('='); - if (line.substr(0, equals_index - 1) == rISOFile.GetUniqueID()) + std::string game_id = rISOFile.GetUniqueID(); + + // Ignore publisher ID for WAD files + if (rISOFile.GetPlatform() == DiscIO::IVolume::WII_WAD) + game_id.erase(game_id.size() - 2); + + if (line.substr(0, equals_index - 1) == game_id) { - name = StrToWxStr(line.substr(equals_index + 2)); + name = StrToWxStr(StripSpaces(line.substr(equals_index + 1))); break; } } From 0b0f70aad4b21b0fcc55b79d735d9c5c767e8d0d Mon Sep 17 00:00:00 2001 From: Scott Mansell Date: Mon, 6 Jul 2015 09:05:25 +1200 Subject: [PATCH 057/583] Revert "Merge pull request #2358 from Tilka/pie" This reverts commit 0f7f8f87747ae825c3b5adeae35cbb66114d2ba1, reversing changes made to 9f1505435877cf8f5abe7b66fb2717c7e39c1988. --- CMakeLists.txt | 6 - Source/Core/Common/CodeBlock.h | 4 +- Source/Core/Common/MemoryUtil.cpp | 120 +++++++++++++++--- Source/Core/Common/MemoryUtil.h | 2 +- Source/Core/Common/x64Emitter.h | 21 ++- Source/Core/Core/DSP/Jit/DSPJitUtil.cpp | 16 +-- Source/Core/Core/PowerPC/Jit64/JitAsm.cpp | 39 +++--- Source/Core/Core/PowerPC/Jit64/JitAsm.h | 2 +- .../Core/Core/PowerPC/Jit64/Jit_Integer.cpp | 2 +- .../PowerPC/Jit64/Jit_LoadStorePaired.cpp | 6 +- .../PowerPC/Jit64/Jit_SystemRegisters.cpp | 4 +- .../PowerPC/Jit64Common/Jit64AsmCommon.cpp | 46 +++---- Source/Core/Core/PowerPC/Jit64IL/IR_X86.cpp | 4 +- Source/Core/Core/PowerPC/Jit64IL/JitIL.cpp | 2 +- Source/Core/Core/PowerPC/JitCommon/JitBase.h | 12 -- .../Core/Core/PowerPC/JitCommon/Jit_Util.cpp | 4 +- Source/Core/Core/PowerPC/JitCommon/Jit_Util.h | 10 +- .../PowerPC/JitCommon/TrampolineCache.cpp | 2 +- Source/UnitTests/Common/x64EmitterTest.cpp | 3 +- 19 files changed, 186 insertions(+), 119 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index d6c1c4b05f..789060e8a6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -11,7 +11,6 @@ option(USE_UPNP "Enables UPnP port mapping support" ON) option(DISABLE_WX "Disable wxWidgets (use Qt or CLI interface)" OFF) option(ENABLE_QT "Enable Qt (use the experimental Qt interface)" OFF) option(ENABLE_PCH "Use PCH to speed up compilation" ON) -option(ENABLE_PIE "Build a Position-Independent Executable (PIE)" ON) option(ENABLE_LTO "Enables Link Time Optimization" OFF) option(ENABLE_GENERIC "Enables generic build that should run on any little-endian host" OFF) @@ -227,11 +226,6 @@ if(UNIX AND NOT APPLE) check_and_add_flag(VISIBILITY_HIDDEN -fvisibility=hidden) endif() -if(ENABLE_PIE) - add_definitions(-fPIE) - set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -pie") -endif() - if(ENABLE_LTO) check_and_add_flag(LTO -flto) if(CMAKE_CXX_COMPILER_ID STREQUAL GNU) diff --git a/Source/Core/Common/CodeBlock.h b/Source/Core/Common/CodeBlock.h index ed1f464904..972fc707d6 100644 --- a/Source/Core/Common/CodeBlock.h +++ b/Source/Core/Common/CodeBlock.h @@ -28,10 +28,10 @@ public: virtual ~CodeBlock() { if (region) FreeCodeSpace(); } // Call this before you generate any code. - void AllocCodeSpace(int size, void* hint = nullptr) + void AllocCodeSpace(int size) { region_size = size; - region = (u8*)AllocateExecutableMemory(region_size, hint); + region = (u8*)AllocateExecutableMemory(region_size); T::SetCodePtr(region); } diff --git a/Source/Core/Common/MemoryUtil.cpp b/Source/Core/Common/MemoryUtil.cpp index e4563e3409..510b258b09 100644 --- a/Source/Core/Common/MemoryUtil.cpp +++ b/Source/Core/Common/MemoryUtil.cpp @@ -27,29 +27,71 @@ #endif #endif -void* AllocateExecutableMemory(size_t size, void* map_hint) +// Valgrind doesn't support MAP_32BIT. +// Uncomment the following line to be able to run Dolphin in Valgrind. +//#undef MAP_32BIT + +#if !defined(_WIN32) && defined(_M_X86_64) && !defined(MAP_32BIT) +#include +#define PAGE_MASK (getpagesize() - 1) +#define round_page(x) ((((unsigned long)(x)) + PAGE_MASK) & ~(PAGE_MASK)) +#endif + +// This is purposely not a full wrapper for virtualalloc/mmap, but it +// provides exactly the primitive operations that Dolphin needs. + +void* AllocateExecutableMemory(size_t size, bool low) { #if defined(_WIN32) void* ptr = VirtualAlloc(0, size, MEM_COMMIT, PAGE_EXECUTE_READWRITE); #else + static char *map_hint = nullptr; +#if defined(_M_X86_64) && !defined(MAP_32BIT) + // This OS has no flag to enforce allocation below the 4 GB boundary, + // but if we hint that we want a low address it is very likely we will + // get one. + // An older version of this code used MAP_FIXED, but that has the side + // effect of discarding already mapped pages that happen to be in the + // requested virtual memory range (such as the emulated RAM, sometimes). + if (low && (!map_hint)) + map_hint = (char*)round_page(512*1024*1024); /* 0.5 GB rounded up to the next page */ +#endif void* ptr = mmap(map_hint, size, PROT_READ | PROT_WRITE | PROT_EXEC, - MAP_ANON | MAP_PRIVATE, -1, 0); + MAP_ANON | MAP_PRIVATE +#if defined(_M_X86_64) && defined(MAP_32BIT) + | (low ? MAP_32BIT : 0) +#endif + , -1, 0); #endif /* defined(_WIN32) */ + // printf("Mapped executable memory at %p (size %ld)\n", ptr, + // (unsigned long)size); + #ifdef _WIN32 if (ptr == nullptr) + { #else if (ptr == MAP_FAILED) -#endif { ptr = nullptr; - PanicAlert("Failed to allocate executable memory."); +#endif + PanicAlert("Failed to allocate executable memory. If you are running Dolphin in Valgrind, try '#undef MAP_32BIT'."); } +#if !defined(_WIN32) && defined(_M_X86_64) && !defined(MAP_32BIT) + else + { + if (low) + { + map_hint += size; + map_hint = (char*)round_page(map_hint); /* round up to the next page */ + // printf("Next map will (hopefully) be at %p\n", map_hint); + } + } +#endif -#ifdef _X86_64 - ptrdiff_t ofs = (u8*)ptr - (u8*)map_hint; - if (ofs < -0x80000000ll || ofs + size > 0x80000000ll) - PanicAlert("Executable range can't be used for RIP-relative addressing."); +#if _M_X86_64 + if ((u64)ptr >= 0x80000000 && low == true) + PanicAlert("Executable memory ended up above 2GB!"); #endif return ptr; @@ -75,12 +117,18 @@ void* AllocateMemoryPages(size_t size) void* AllocateAlignedMemory(size_t size, size_t alignment) { - void* ptr = nullptr; #ifdef _WIN32 - if (!(ptr = _aligned_malloc(size, alignment))) + void* ptr = _aligned_malloc(size, alignment); #else - if (posix_memalign(&ptr, alignment, size)) + void* ptr = nullptr; + if (posix_memalign(&ptr, alignment, size) != 0) + ERROR_LOG(MEMMAP, "Failed to allocate aligned memory"); #endif + + // printf("Mapped memory at %p (size %ld)\n", ptr, + // (unsigned long)size); + + if (ptr == nullptr) PanicAlert("Failed to allocate aligned memory"); return ptr; @@ -88,12 +136,23 @@ void* AllocateAlignedMemory(size_t size, size_t alignment) void FreeMemoryPages(void* ptr, size_t size) { + if (ptr) + { + bool error_occurred = false; + #ifdef _WIN32 - if (ptr && !VirtualFree(ptr, 0, MEM_RELEASE)) + if (!VirtualFree(ptr, 0, MEM_RELEASE)) + error_occurred = true; #else - if (ptr && munmap(ptr, size)) + int retval = munmap(ptr, size); + + if (retval != 0) + error_occurred = true; #endif - PanicAlert("FreeMemoryPages failed!\n%s", GetLastErrorMsg().c_str()); + + if (error_occurred) + PanicAlert("FreeMemoryPages failed!\n%s", GetLastErrorMsg().c_str()); + } } void FreeAlignedMemory(void* ptr) @@ -110,34 +169,58 @@ void FreeAlignedMemory(void* ptr) void ReadProtectMemory(void* ptr, size_t size) { + bool error_occurred = false; + #ifdef _WIN32 DWORD oldValue; if (!VirtualProtect(ptr, size, PAGE_NOACCESS, &oldValue)) + error_occurred = true; #else - if (mprotect(ptr, size, PROT_NONE)) + int retval = mprotect(ptr, size, PROT_NONE); + + if (retval != 0) + error_occurred = true; #endif + + if (error_occurred) PanicAlert("ReadProtectMemory failed!\n%s", GetLastErrorMsg().c_str()); } void WriteProtectMemory(void* ptr, size_t size, bool allowExecute) { + bool error_occurred = false; + #ifdef _WIN32 DWORD oldValue; if (!VirtualProtect(ptr, size, allowExecute ? PAGE_EXECUTE_READ : PAGE_READONLY, &oldValue)) + error_occurred = true; #else - if (mprotect(ptr, size, PROT_READ | (allowExecute ? PROT_EXEC : 0))) + int retval = mprotect(ptr, size, allowExecute ? (PROT_READ | PROT_EXEC) : PROT_READ); + + if (retval != 0) + error_occurred = true; #endif + + if (error_occurred) PanicAlert("WriteProtectMemory failed!\n%s", GetLastErrorMsg().c_str()); } void UnWriteProtectMemory(void* ptr, size_t size, bool allowExecute) { + bool error_occurred = false; + #ifdef _WIN32 DWORD oldValue; if (!VirtualProtect(ptr, size, allowExecute ? PAGE_EXECUTE_READWRITE : PAGE_READWRITE, &oldValue)) + error_occurred = true; #else - if (mprotect(ptr, size, PROT_READ | PROT_WRITE | (allowExecute ? PROT_EXEC : 0))) + int retval = mprotect(ptr, size, allowExecute ? (PROT_READ | PROT_WRITE | PROT_EXEC) : PROT_WRITE | PROT_READ); + + if (retval != 0) + error_occurred = true; #endif + + if (error_occurred) PanicAlert("UnWriteProtectMemory failed!\n%s", GetLastErrorMsg().c_str()); } @@ -153,8 +236,7 @@ std::string MemUsage() // Print information about the memory usage of the process. hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, processID); - if (nullptr == hProcess) - return "MemUsage Error"; + if (nullptr == hProcess) return "MemUsage Error"; if (GetProcessMemoryInfo(hProcess, &pmc, sizeof(pmc))) Ret = StringFromFormat("%s K", ThousandSeparate(pmc.WorkingSetSize / 1024, 7).c_str()); diff --git a/Source/Core/Common/MemoryUtil.h b/Source/Core/Common/MemoryUtil.h index 248937611d..e986069d24 100644 --- a/Source/Core/Common/MemoryUtil.h +++ b/Source/Core/Common/MemoryUtil.h @@ -7,7 +7,7 @@ #include #include -void* AllocateExecutableMemory(size_t size, void* map_hint); +void* AllocateExecutableMemory(size_t size, bool low = true); void* AllocateMemoryPages(size_t size); void FreeMemoryPages(void* ptr, size_t size); void* AllocateAlignedMemory(size_t size,size_t alignment); diff --git a/Source/Core/Common/x64Emitter.h b/Source/Core/Common/x64Emitter.h index 627c940cdb..f6faea44bd 100644 --- a/Source/Core/Common/x64Emitter.h +++ b/Source/Core/Common/x64Emitter.h @@ -218,17 +218,17 @@ inline OpArg M(const T* ptr) {return OpArg((u64)(const void*)ptr, (int)SCALE_ inline OpArg R(X64Reg value) {return OpArg(0, SCALE_NONE, value);} inline OpArg MatR(X64Reg value) {return OpArg(0, SCALE_ATREG, value);} -inline OpArg MDisp(X64Reg value, ptrdiff_t offset) +inline OpArg MDisp(X64Reg value, int offset) { - return OpArg(offset, SCALE_ATREG, value); + return OpArg((u32)offset, SCALE_ATREG, value); } -inline OpArg MComplex(X64Reg base, X64Reg scaled, int scale, ptrdiff_t offset) +inline OpArg MComplex(X64Reg base, X64Reg scaled, int scale, int offset) { return OpArg(offset, scale, base, scaled); } -inline OpArg MScaled(X64Reg scaled, int scale, ptrdiff_t offset) +inline OpArg MScaled(X64Reg scaled, int scale, int offset) { if (scale == SCALE_1) return OpArg(offset, SCALE_ATREG, scaled); @@ -247,10 +247,17 @@ inline OpArg Imm32(u32 imm) {return OpArg(imm, SCALE_IMM32);} inline OpArg Imm64(u64 imm) {return OpArg(imm, SCALE_IMM64);} inline OpArg ImmPtr(const void* imm) {return Imm64((u64)imm);} -inline bool FitsInS32(const ptrdiff_t distance) +inline u32 PtrOffset(const void* ptr, const void* base) { - return distance < 0x80000000LL && - distance >= -0x80000000LL; + s64 distance = (s64)ptr-(s64)base; + if (distance >= 0x80000000LL || + distance < -0x80000000LL) + { + _assert_msg_(DYNA_REC, 0, "pointer offset out of range"); + return 0; + } + + return (u32)distance; } //usage: int a[]; ARRAY_OFFSET(a,10) diff --git a/Source/Core/Core/DSP/Jit/DSPJitUtil.cpp b/Source/Core/Core/DSP/Jit/DSPJitUtil.cpp index 64761455e3..51b0ffc7d0 100644 --- a/Source/Core/Core/DSP/Jit/DSPJitUtil.cpp +++ b/Source/Core/Core/DSP/Jit/DSPJitUtil.cpp @@ -20,16 +20,14 @@ void DSPEmitter::dsp_reg_stack_push(int stack_reg) AND(8, R(AL), Imm8(DSP_STACK_MASK)); MOV(8, M(&g_dsp.reg_stack_ptr[stack_reg]), R(AL)); - X64Reg tmp1, tmp2; + X64Reg tmp1; gpr.getFreeXReg(tmp1); - gpr.getFreeXReg(tmp2); //g_dsp.reg_stack[stack_reg][g_dsp.reg_stack_ptr[stack_reg]] = g_dsp.r[DSP_REG_ST0 + stack_reg]; MOV(16, R(tmp1), M(&g_dsp.r.st[stack_reg])); MOVZX(64, 8, RAX, R(AL)); - MOV(64, R(tmp2), ImmPtr(g_dsp.reg_stack[stack_reg])); - MOV(16, MComplex(tmp2, EAX, SCALE_2, 0), R(tmp1)); + MOV(16, MComplex(EAX, EAX, 1, + PtrOffset(&g_dsp.reg_stack[stack_reg][0],nullptr)), R(tmp1)); gpr.putXReg(tmp1); - gpr.putXReg(tmp2); } //clobbers: @@ -39,15 +37,13 @@ void DSPEmitter::dsp_reg_stack_pop(int stack_reg) { //g_dsp.r[DSP_REG_ST0 + stack_reg] = g_dsp.reg_stack[stack_reg][g_dsp.reg_stack_ptr[stack_reg]]; MOV(8, R(AL), M(&g_dsp.reg_stack_ptr[stack_reg])); - X64Reg tmp1, tmp2; + X64Reg tmp1; gpr.getFreeXReg(tmp1); - gpr.getFreeXReg(tmp2); MOVZX(64, 8, RAX, R(AL)); - MOV(64, R(tmp2), ImmPtr(g_dsp.reg_stack[stack_reg])); - MOV(16, R(tmp1), MComplex(tmp2, EAX, SCALE_2, 0)); + MOV(16, R(tmp1), MComplex(EAX, EAX, 1, + PtrOffset(&g_dsp.reg_stack[stack_reg][0],nullptr))); MOV(16, M(&g_dsp.r.st[stack_reg]), R(tmp1)); gpr.putXReg(tmp1); - gpr.putXReg(tmp2); //g_dsp.reg_stack_ptr[stack_reg]--; //g_dsp.reg_stack_ptr[stack_reg] &= DSP_STACK_MASK; diff --git a/Source/Core/Core/PowerPC/Jit64/JitAsm.cpp b/Source/Core/Core/PowerPC/Jit64/JitAsm.cpp index f194098bbc..fa4acdc922 100644 --- a/Source/Core/Core/PowerPC/Jit64/JitAsm.cpp +++ b/Source/Core/Core/PowerPC/Jit64/JitAsm.cpp @@ -40,7 +40,7 @@ void Jit64AsmRoutineManager::Generate() // Two statically allocated registers. //MOV(64, R(RMEM), Imm64((u64)Memory::physical_base)); - MOV(64, R(RPPCSTATE), ImmPtr(PPCSTATE_BASE)); + MOV(64, R(RPPCSTATE), Imm64((u64)&PowerPC::ppcState + 0x80)); const u8* outerLoop = GetCodePtr(); ABI_PushRegistersAndAdjustStack({}, 0); @@ -103,9 +103,9 @@ void Jit64AsmRoutineManager::Generate() // optimizations safe, because IR and DR are usually set/cleared together. // TODO: Branching based on the 20 most significant bits of instruction // addresses without translating them is wrong. - u8* icache = jit->GetBlockCache()->iCache.data(); - u8* icacheVmem = jit->GetBlockCache()->iCacheVMEM.data(); - u8* icacheEx = jit->GetBlockCache()->iCacheEx.data(); + u64 icache = (u64)jit->GetBlockCache()->iCache.data(); + u64 icacheVmem = (u64)jit->GetBlockCache()->iCacheVMEM.data(); + u64 icacheEx = (u64)jit->GetBlockCache()->iCacheEx.data(); u32 mask = 0; FixupBranch no_mem; FixupBranch exit_mem; @@ -117,13 +117,13 @@ void Jit64AsmRoutineManager::Generate() no_mem = J_CC(CC_NZ); AND(32, R(RSCRATCH), Imm32(JIT_ICACHE_MASK)); - if (FitsInS32(PPCSTATE_OFS(icache))) + if (icache <= INT_MAX) { - MOV(32, R(RSCRATCH), MPIC(icache, RSCRATCH)); + MOV(32, R(RSCRATCH), MDisp(RSCRATCH, (s32)icache)); } else { - MOV(64, R(RSCRATCH2), ImmPtr(icache)); + MOV(64, R(RSCRATCH2), Imm64(icache)); MOV(32, R(RSCRATCH), MRegSum(RSCRATCH2, RSCRATCH)); } @@ -132,14 +132,13 @@ void Jit64AsmRoutineManager::Generate() TEST(32, R(RSCRATCH), Imm32(JIT_ICACHE_VMEM_BIT)); FixupBranch no_vmem = J_CC(CC_Z); AND(32, R(RSCRATCH), Imm32(JIT_ICACHE_MASK)); - - if (FitsInS32(PPCSTATE_OFS(icacheVmem))) + if (icacheVmem <= INT_MAX) { - MOV(32, R(RSCRATCH), MPIC(icacheVmem, RSCRATCH)); + MOV(32, R(RSCRATCH), MDisp(RSCRATCH, (s32)icacheVmem)); } else { - MOV(64, R(RSCRATCH2), ImmPtr(icacheVmem)); + MOV(64, R(RSCRATCH2), Imm64(icacheVmem)); MOV(32, R(RSCRATCH), MRegSum(RSCRATCH2, RSCRATCH)); } @@ -150,13 +149,14 @@ void Jit64AsmRoutineManager::Generate() TEST(32, R(RSCRATCH), Imm32(JIT_ICACHE_EXRAM_BIT)); FixupBranch no_exram = J_CC(CC_Z); AND(32, R(RSCRATCH), Imm32(JIT_ICACHEEX_MASK)); - if (FitsInS32(PPCSTATE_OFS(icacheEx))) + + if (icacheEx <= INT_MAX) { - MOV(32, R(RSCRATCH), MPIC(icacheEx, RSCRATCH)); + MOV(32, R(RSCRATCH), MDisp(RSCRATCH, (s32)icacheEx)); } else { - MOV(64, R(RSCRATCH2), ImmPtr(icacheEx)); + MOV(64, R(RSCRATCH2), Imm64(icacheEx)); MOV(32, R(RSCRATCH), MRegSum(RSCRATCH2, RSCRATCH)); } @@ -169,17 +169,16 @@ void Jit64AsmRoutineManager::Generate() TEST(32, R(RSCRATCH), R(RSCRATCH)); FixupBranch notfound = J_CC(CC_L); //grab from list and jump to it - const u8** codePointers = jit->GetBlockCache()->GetCodePointers(); - if (FitsInS32(PPCSTATE_OFS(codePointers))) + u64 codePointers = (u64)jit->GetBlockCache()->GetCodePointers(); + if (codePointers <= INT_MAX) { - JMPptr(MPIC(codePointers, RSCRATCH, SCALE_8)); + JMPptr(MScaled(RSCRATCH, SCALE_8, (s32)codePointers)); } else { - MOV(64, R(RSCRATCH2), ImmPtr(codePointers)); + MOV(64, R(RSCRATCH2), Imm64(codePointers)); JMPptr(MComplex(RSCRATCH2, RSCRATCH, SCALE_8, 0)); } - SetJumpTarget(notfound); //Ok, no block, let's jit @@ -272,7 +271,7 @@ void Jit64AsmRoutineManager::GenerateCommon() CMP(32, R(ABI_PARAM2), Imm32(0xCC008000)); FixupBranch skip_fast_write = J_CC(CC_NE, false); MOV(32, RSCRATCH, M(&m_gatherPipeCount)); - MOV(8, MPIC(&m_gatherPipe, RSCRATCH), ABI_PARAM1); + MOV(8, MDisp(RSCRATCH, (u32)&m_gatherPipe), ABI_PARAM1); ADD(32, 1, M(&m_gatherPipeCount)); RET(); SetJumpTarget(skip_fast_write); diff --git a/Source/Core/Core/PowerPC/Jit64/JitAsm.h b/Source/Core/Core/PowerPC/Jit64/JitAsm.h index 6b0ae28ebe..8c33c8bace 100644 --- a/Source/Core/Core/PowerPC/Jit64/JitAsm.h +++ b/Source/Core/Core/PowerPC/Jit64/JitAsm.h @@ -34,7 +34,7 @@ public: m_stack_top = stack_top; // NOTE: When making large additions to the AsmCommon code, you might // want to ensure this number is big enough. - AllocCodeSpace(16384, PPCSTATE_BASE); + AllocCodeSpace(16384); Generate(); WriteProtect(); } diff --git a/Source/Core/Core/PowerPC/Jit64/Jit_Integer.cpp b/Source/Core/Core/PowerPC/Jit64/Jit_Integer.cpp index 00d8fd52b3..407a39b867 100644 --- a/Source/Core/Core/PowerPC/Jit64/Jit_Integer.cpp +++ b/Source/Core/Core/PowerPC/Jit64/Jit_Integer.cpp @@ -45,7 +45,7 @@ void Jit64::GenerateOverflow() //rare). static const u8 ovtable[4] = {0, 0, XER_SO_MASK, XER_SO_MASK}; MOVZX(32, 8, RSCRATCH, PPCSTATE(xer_so_ov)); - MOV(8, R(RSCRATCH), MPIC(ovtable, RSCRATCH)); + MOV(8, R(RSCRATCH), MDisp(RSCRATCH, (u32)(u64)ovtable)); MOV(8, PPCSTATE(xer_so_ov), R(RSCRATCH)); SetJumpTarget(exit); } diff --git a/Source/Core/Core/PowerPC/Jit64/Jit_LoadStorePaired.cpp b/Source/Core/Core/PowerPC/Jit64/Jit_LoadStorePaired.cpp index 824e7f96e6..4d875323eb 100644 --- a/Source/Core/Core/PowerPC/Jit64/Jit_LoadStorePaired.cpp +++ b/Source/Core/Core/PowerPC/Jit64/Jit_LoadStorePaired.cpp @@ -132,13 +132,13 @@ void Jit64::psq_stXX(UGeckoInstruction inst) { // One value CVTSD2SS(XMM0, fpr.R(s)); - CALLptr(MPIC(asm_routines.singleStoreQuantized, RSCRATCH, SCALE_8)); + CALLptr(MScaled(RSCRATCH, SCALE_8, (u32)(u64)asm_routines.singleStoreQuantized)); } else { // Pair of values CVTPD2PS(XMM0, fpr.R(s)); - CALLptr(MPIC(asm_routines.pairedStoreQuantized, RSCRATCH, SCALE_8)); + CALLptr(MScaled(RSCRATCH, SCALE_8, (u32)(u64)asm_routines.pairedStoreQuantized)); } if (update && jo.memcheck) @@ -306,7 +306,7 @@ void Jit64::psq_lXX(UGeckoInstruction inst) AND(32, R(RSCRATCH2), gqr); MOVZX(32, 8, RSCRATCH, R(RSCRATCH2)); - CALLptr(MPIC(&asm_routines.pairedLoadQuantized[w * 8], RSCRATCH, SCALE_8)); + CALLptr(MScaled(RSCRATCH, SCALE_8, (u32)(u64)(&asm_routines.pairedLoadQuantized[w * 8]))); MemoryExceptionCheck(); CVTPS2PD(fpr.RX(s), R(XMM0)); diff --git a/Source/Core/Core/PowerPC/Jit64/Jit_SystemRegisters.cpp b/Source/Core/Core/PowerPC/Jit64/Jit_SystemRegisters.cpp index e798237311..d7c56fbe10 100644 --- a/Source/Core/Core/PowerPC/Jit64/Jit_SystemRegisters.cpp +++ b/Source/Core/Core/PowerPC/Jit64/Jit_SystemRegisters.cpp @@ -458,7 +458,7 @@ void Jit64::mtcrf(UGeckoInstruction inst) SHR(32, R(RSCRATCH), Imm8(28 - (i * 4))); if (i != 0) AND(32, R(RSCRATCH), Imm8(0xF)); - MOV(64, R(RSCRATCH), MPIC(m_crTable, RSCRATCH, SCALE_8)); + MOV(64, R(RSCRATCH), MScaled(RSCRATCH, SCALE_8, (u32)(u64)m_crTable)); MOV(64, PPCSTATE(cr_val[i]), R(RSCRATCH)); } } @@ -493,7 +493,7 @@ void Jit64::mcrxr(UGeckoInstruction inst) // [SO OV CA 0] << 3 SHL(32, R(RSCRATCH), Imm8(4)); - MOV(64, R(RSCRATCH), MPIC(m_crTable, RSCRATCH)); + MOV(64, R(RSCRATCH), MDisp(RSCRATCH, (u32)(u64)m_crTable)); MOV(64, PPCSTATE(cr_val[inst.CRFD]), R(RSCRATCH)); // Clear XER[0-3] diff --git a/Source/Core/Core/PowerPC/Jit64Common/Jit64AsmCommon.cpp b/Source/Core/Core/PowerPC/Jit64Common/Jit64AsmCommon.cpp index d7fb70f5fe..64adf9b4de 100644 --- a/Source/Core/Core/PowerPC/Jit64Common/Jit64AsmCommon.cpp +++ b/Source/Core/Core/PowerPC/Jit64Common/Jit64AsmCommon.cpp @@ -24,8 +24,10 @@ void CommonAsmRoutines::GenFifoWrite(int size) const void* start = GetCodePtr(); // Assume value in RSCRATCH + u32 gather_pipe = (u32)(u64)GPFifo::m_gatherPipe; + _assert_msg_(DYNA_REC, gather_pipe <= 0x7FFFFFFF, "Gather pipe not in low 2GB of memory!"); MOV(32, R(RSCRATCH2), M(&GPFifo::m_gatherPipeCount)); - SwapAndStore(size, MPIC(GPFifo::m_gatherPipe, RSCRATCH2), RSCRATCH); + SwapAndStore(size, MDisp(RSCRATCH2, gather_pipe), RSCRATCH); ADD(32, R(RSCRATCH2), Imm8(size >> 3)); MOV(32, M(&GPFifo::m_gatherPipeCount), R(RSCRATCH2)); RET(); @@ -66,8 +68,8 @@ void CommonAsmRoutines::GenFrsqrte() SHR(64, R(RSCRATCH), Imm8(37)); AND(32, R(RSCRATCH), Imm32(0x7FF)); - IMUL(32, RSCRATCH, MPIC(MathUtil::frsqrte_expected_dec, RSCRATCH_EXTRA, SCALE_4)); - MOV(32, R(RSCRATCH_EXTRA), MPIC(MathUtil::frsqrte_expected_base, RSCRATCH_EXTRA, SCALE_4)); + IMUL(32, RSCRATCH, MScaled(RSCRATCH_EXTRA, SCALE_4, (u32)(u64)MathUtil::frsqrte_expected_dec)); + MOV(32, R(RSCRATCH_EXTRA), MScaled(RSCRATCH_EXTRA, SCALE_4, (u32)(u64)MathUtil::frsqrte_expected_base)); SUB(32, R(RSCRATCH_EXTRA), R(RSCRATCH)); SHL(64, R(RSCRATCH_EXTRA), Imm8(26)); OR(64, R(RSCRATCH2), R(RSCRATCH_EXTRA)); // vali |= (s64)(frsqrte_expected_base[index] - frsqrte_expected_dec[index] * (i % 2048)) << 26; @@ -134,11 +136,11 @@ void CommonAsmRoutines::GenFres() AND(32, R(RSCRATCH), Imm32(0x3FF)); // i % 1024 AND(32, R(RSCRATCH2), Imm8(0x1F)); // i / 1024 - IMUL(32, RSCRATCH, MPIC(MathUtil::fres_expected_dec, RSCRATCH2, SCALE_4)); + IMUL(32, RSCRATCH, MScaled(RSCRATCH2, SCALE_4, (u32)(u64)MathUtil::fres_expected_dec)); ADD(32, R(RSCRATCH), Imm8(1)); SHR(32, R(RSCRATCH), Imm8(1)); - MOV(32, R(RSCRATCH2), MPIC(MathUtil::fres_expected_base, RSCRATCH2, SCALE_4)); + MOV(32, R(RSCRATCH2), MScaled(RSCRATCH2, SCALE_4, (u32)(u64)MathUtil::fres_expected_base)); SUB(32, R(RSCRATCH2), R(RSCRATCH)); SHL(64, R(RSCRATCH2), Imm8(29)); OR(64, R(RSCRATCH2), R(RSCRATCH_EXTRA)); // vali |= (s64)(fres_expected_base[i / 1024] - (fres_expected_dec[i / 1024] * (i % 1024) + 1) / 2) << 29 @@ -197,7 +199,7 @@ void CommonAsmRoutines::GenMfcr() // SO: Bit 61 set; set flag bit 0 // LT: Bit 62 set; set flag bit 3 SHR(64, R(cr_val), Imm8(61)); - OR(32, R(dst), MPIC(m_flagTable, cr_val, SCALE_4)); + OR(32, R(dst), MScaled(cr_val, SCALE_4, (u32)(u64)m_flagTable)); } RET(); @@ -245,7 +247,7 @@ void CommonAsmRoutines::GenQuantizedStores() const u8* storePairedU8 = AlignCode4(); SHR(32, R(RSCRATCH2), Imm8(5)); - MOVQ_xmm(XMM1, MPIC(m_quantizeTableS, RSCRATCH2)); + MOVQ_xmm(XMM1, MDisp(RSCRATCH2, (u32)(u64)m_quantizeTableS)); MULPS(XMM0, R(XMM1)); #ifdef QUANTIZE_OVERFLOW_SAFE MINPS(XMM0, M(m_65535)); @@ -260,7 +262,7 @@ void CommonAsmRoutines::GenQuantizedStores() const u8* storePairedS8 = AlignCode4(); SHR(32, R(RSCRATCH2), Imm8(5)); - MOVQ_xmm(XMM1, MPIC(m_quantizeTableS, RSCRATCH2)); + MOVQ_xmm(XMM1, MDisp(RSCRATCH2, (u32)(u64)m_quantizeTableS)); MULPS(XMM0, R(XMM1)); #ifdef QUANTIZE_OVERFLOW_SAFE MINPS(XMM0, M(m_65535)); @@ -276,7 +278,7 @@ void CommonAsmRoutines::GenQuantizedStores() const u8* storePairedU16 = AlignCode4(); SHR(32, R(RSCRATCH2), Imm8(5)); - MOVQ_xmm(XMM1, MPIC(m_quantizeTableS, RSCRATCH2)); + MOVQ_xmm(XMM1, MDisp(RSCRATCH2, (u32)(u64)m_quantizeTableS)); MULPS(XMM0, R(XMM1)); if (cpu_info.bSSE4_1) @@ -308,7 +310,7 @@ void CommonAsmRoutines::GenQuantizedStores() const u8* storePairedS16 = AlignCode4(); SHR(32, R(RSCRATCH2), Imm8(5)); - MOVQ_xmm(XMM1, MPIC(m_quantizeTableS, RSCRATCH2)); + MOVQ_xmm(XMM1, MDisp(RSCRATCH2, (u32)(u64)m_quantizeTableS)); MULPS(XMM0, R(XMM1)); #ifdef QUANTIZE_OVERFLOW_SAFE MINPS(XMM0, M(m_65535)); @@ -353,7 +355,7 @@ void CommonAsmRoutines::GenQuantizedSingleStores() const u8* storeSingleU8 = AlignCode4(); // Used by MKWii SHR(32, R(RSCRATCH2), Imm8(5)); - MULSS(XMM0, MPIC(m_quantizeTableS, RSCRATCH2)); + MULSS(XMM0, MDisp(RSCRATCH2, (u32)(u64)m_quantizeTableS)); XORPS(XMM1, R(XMM1)); MAXSS(XMM0, R(XMM1)); MINSS(XMM0, M(&m_255)); @@ -363,7 +365,7 @@ void CommonAsmRoutines::GenQuantizedSingleStores() const u8* storeSingleS8 = AlignCode4(); SHR(32, R(RSCRATCH2), Imm8(5)); - MULSS(XMM0, MPIC(m_quantizeTableS, RSCRATCH2)); + MULSS(XMM0, MDisp(RSCRATCH2, (u32)(u64)m_quantizeTableS)); MAXSS(XMM0, M(&m_m128)); MINSS(XMM0, M(&m_127)); CVTTSS2SI(RSCRATCH, R(XMM0)); @@ -372,7 +374,7 @@ void CommonAsmRoutines::GenQuantizedSingleStores() const u8* storeSingleU16 = AlignCode4(); // Used by MKWii SHR(32, R(RSCRATCH2), Imm8(5)); - MULSS(XMM0, MPIC(m_quantizeTableS, RSCRATCH2)); + MULSS(XMM0, MDisp(RSCRATCH2, (u32)(u64)m_quantizeTableS)); XORPS(XMM1, R(XMM1)); MAXSS(XMM0, R(XMM1)); MINSS(XMM0, M(m_65535)); @@ -382,7 +384,7 @@ void CommonAsmRoutines::GenQuantizedSingleStores() const u8* storeSingleS16 = AlignCode4(); SHR(32, R(RSCRATCH2), Imm8(5)); - MULSS(XMM0, MPIC(m_quantizeTableS, RSCRATCH2)); + MULSS(XMM0, MDisp(RSCRATCH2, (u32)(u64)m_quantizeTableS)); MAXSS(XMM0, M(&m_m32768)); MINSS(XMM0, M(&m_32767)); CVTTSS2SI(RSCRATCH, R(XMM0)); @@ -482,7 +484,7 @@ void CommonAsmRoutines::GenQuantizedLoads() } CVTDQ2PS(XMM0, R(XMM0)); SHR(32, R(RSCRATCH2), Imm8(5)); - MOVQ_xmm(XMM1, MPIC(m_dequantizeTableS, RSCRATCH2)); + MOVQ_xmm(XMM1, MDisp(RSCRATCH2, (u32)(u64)m_dequantizeTableS)); MULPS(XMM0, R(XMM1)); RET(); @@ -493,7 +495,7 @@ void CommonAsmRoutines::GenQuantizedLoads() UnsafeLoadRegToRegNoSwap(RSCRATCH_EXTRA, RSCRATCH_EXTRA, 8, 0); // RSCRATCH_EXTRA = 0x000000xx CVTSI2SS(XMM0, R(RSCRATCH_EXTRA)); SHR(32, R(RSCRATCH2), Imm8(5)); - MULSS(XMM0, MPIC(m_dequantizeTableS, RSCRATCH2)); + MULSS(XMM0, MDisp(RSCRATCH2, (u32)(u64)m_dequantizeTableS)); UNPCKLPS(XMM0, M(m_one)); RET(); @@ -521,7 +523,7 @@ void CommonAsmRoutines::GenQuantizedLoads() } CVTDQ2PS(XMM0, R(XMM0)); SHR(32, R(RSCRATCH2), Imm8(5)); - MOVQ_xmm(XMM1, MPIC(m_dequantizeTableS, RSCRATCH2)); + MOVQ_xmm(XMM1, MDisp(RSCRATCH2, (u32)(u64)m_dequantizeTableS)); MULPS(XMM0, R(XMM1)); RET(); @@ -532,7 +534,7 @@ void CommonAsmRoutines::GenQuantizedLoads() UnsafeLoadRegToRegNoSwap(RSCRATCH_EXTRA, RSCRATCH_EXTRA, 8, 0, true); CVTSI2SS(XMM0, R(RSCRATCH_EXTRA)); SHR(32, R(RSCRATCH2), Imm8(5)); - MULSS(XMM0, MPIC(m_dequantizeTableS, RSCRATCH2)); + MULSS(XMM0, MDisp(RSCRATCH2, (u32)(u64)m_dequantizeTableS)); UNPCKLPS(XMM0, M(m_one)); RET(); @@ -555,7 +557,7 @@ void CommonAsmRoutines::GenQuantizedLoads() } CVTDQ2PS(XMM0, R(XMM0)); SHR(32, R(RSCRATCH2), Imm8(5)); - MOVQ_xmm(XMM1, MPIC(m_dequantizeTableS, RSCRATCH2)); + MOVQ_xmm(XMM1, MDisp(RSCRATCH2, (u32)(u64)m_dequantizeTableS)); MULPS(XMM0, R(XMM1)); RET(); @@ -566,7 +568,7 @@ void CommonAsmRoutines::GenQuantizedLoads() UnsafeLoadRegToReg(RSCRATCH_EXTRA, RSCRATCH_EXTRA, 16, 0, false); CVTSI2SS(XMM0, R(RSCRATCH_EXTRA)); SHR(32, R(RSCRATCH2), Imm8(5)); - MULSS(XMM0, MPIC(m_dequantizeTableS, RSCRATCH2)); + MULSS(XMM0, MDisp(RSCRATCH2, (u32)(u64)m_dequantizeTableS)); UNPCKLPS(XMM0, M(m_one)); RET(); @@ -588,7 +590,7 @@ void CommonAsmRoutines::GenQuantizedLoads() } CVTDQ2PS(XMM0, R(XMM0)); SHR(32, R(RSCRATCH2), Imm8(5)); - MOVQ_xmm(XMM1, MPIC(m_dequantizeTableS, RSCRATCH2)); + MOVQ_xmm(XMM1, MDisp(RSCRATCH2, (u32)(u64)m_dequantizeTableS)); MULPS(XMM0, R(XMM1)); RET(); @@ -599,7 +601,7 @@ void CommonAsmRoutines::GenQuantizedLoads() UnsafeLoadRegToReg(RSCRATCH_EXTRA, RSCRATCH_EXTRA, 16, 0, true); CVTSI2SS(XMM0, R(RSCRATCH_EXTRA)); SHR(32, R(RSCRATCH2), Imm8(5)); - MULSS(XMM0, MPIC(m_dequantizeTableS, RSCRATCH2)); + MULSS(XMM0, MDisp(RSCRATCH2, (u32)(u64)m_dequantizeTableS)); UNPCKLPS(XMM0, M(m_one)); RET(); diff --git a/Source/Core/Core/PowerPC/Jit64IL/IR_X86.cpp b/Source/Core/Core/PowerPC/Jit64IL/IR_X86.cpp index 51763de8a9..17007be31f 100644 --- a/Source/Core/Core/PowerPC/Jit64IL/IR_X86.cpp +++ b/Source/Core/Core/PowerPC/Jit64IL/IR_X86.cpp @@ -1611,7 +1611,7 @@ static void DoWriteCode(IRBuilder* ibuild, JitIL* Jit, u32 exitAddress) Jit->OR(32, R(RSCRATCH), Imm8(w << 3)); Jit->MOV(32, R(RSCRATCH_EXTRA), regLocForInst(RI, getOp1(I))); - Jit->CALLptr(MPIC(Jit->asm_routines.pairedLoadQuantized, RSCRATCH, SCALE_8)); + Jit->CALLptr(MScaled(RSCRATCH, SCALE_8, (u32)(u64)(Jit->asm_routines.pairedLoadQuantized))); Jit->MOVAPD(reg, R(XMM0)); RI.fregs[reg] = I; regNormalRegClear(RI, I); @@ -1669,7 +1669,7 @@ static void DoWriteCode(IRBuilder* ibuild, JitIL* Jit, u32 exitAddress) Jit->MOV(32, R(RSCRATCH_EXTRA), regLocForInst(RI, getOp2(I))); Jit->MOVAPD(XMM0, fregLocForInst(RI, getOp1(I))); - Jit->CALLptr(MPIC(Jit->asm_routines.pairedStoreQuantized, RSCRATCH, SCALE_8)); + Jit->CALLptr(MScaled(RSCRATCH, SCALE_8, (u32)(u64)(Jit->asm_routines.pairedStoreQuantized))); if (RI.IInfo[I - RI.FirstI] & 4) fregClearInst(RI, getOp1(I)); if (RI.IInfo[I - RI.FirstI] & 8) diff --git a/Source/Core/Core/PowerPC/Jit64IL/JitIL.cpp b/Source/Core/Core/PowerPC/Jit64IL/JitIL.cpp index aea7d9446f..1edb0591bc 100644 --- a/Source/Core/Core/PowerPC/Jit64IL/JitIL.cpp +++ b/Source/Core/Core/PowerPC/Jit64IL/JitIL.cpp @@ -250,7 +250,7 @@ void JitIL::Init() UpdateMemoryOptions(); trampolines.Init(jo.memcheck ? TRAMPOLINE_CODE_SIZE_MMU : TRAMPOLINE_CODE_SIZE); - AllocCodeSpace(CODE_SIZE, PPCSTATE_BASE); + AllocCodeSpace(CODE_SIZE); blocks.Init(); asm_routines.Init(nullptr); diff --git a/Source/Core/Core/PowerPC/JitCommon/JitBase.h b/Source/Core/Core/PowerPC/JitCommon/JitBase.h index 8476a6dbb5..133350cd98 100644 --- a/Source/Core/Core/PowerPC/JitCommon/JitBase.h +++ b/Source/Core/Core/PowerPC/JitCommon/JitBase.h @@ -43,18 +43,6 @@ // to address as much as possible in a one-byte offset form. #define RPPCSTATE RBP -namespace Gen -{ - -inline OpArg MPIC(const void* address, X64Reg scale_reg, int scale = SCALE_1) -{ - ptrdiff_t offset = PPCSTATE_OFS(address); - _dbg_assert_(DYNA_REC, FitsInS32(offset)); - return MComplex(RPPCSTATE, scale_reg, scale, offset); -} - -} - // Use these to control the instruction selection // #define INSTRUCTION_START FallBackToInterpreter(inst); return; // #define INSTRUCTION_START PPCTables::CountInstruction(inst); diff --git a/Source/Core/Core/PowerPC/JitCommon/Jit_Util.cpp b/Source/Core/Core/PowerPC/JitCommon/Jit_Util.cpp index 404c673d20..e4a95b272e 100644 --- a/Source/Core/Core/PowerPC/JitCommon/Jit_Util.cpp +++ b/Source/Core/Core/PowerPC/JitCommon/Jit_Util.cpp @@ -173,11 +173,11 @@ private: u32 all_ones = (1ULL << sbits) - 1; if ((all_ones & mask) == all_ones) { - MoveOpArgToReg(sbits, MatR(RSCRATCH)); + MoveOpArgToReg(sbits, MDisp(RSCRATCH, 0)); } else { - m_code->MOVZX(32, sbits, m_dst_reg, MatR(RSCRATCH)); + m_code->MOVZX(32, sbits, m_dst_reg, MDisp(RSCRATCH, 0)); m_code->AND(32, R(m_dst_reg), Imm32(mask)); if (m_sign_extend) m_code->MOVSX(32, sbits, m_dst_reg, R(m_dst_reg)); diff --git a/Source/Core/Core/PowerPC/JitCommon/Jit_Util.h b/Source/Core/Core/PowerPC/JitCommon/Jit_Util.h index 5dc67d9f3c..21d19a88f6 100644 --- a/Source/Core/Core/PowerPC/JitCommon/Jit_Util.h +++ b/Source/Core/Core/PowerPC/JitCommon/Jit_Util.h @@ -9,15 +9,15 @@ #include "Common/BitSet.h" #include "Common/CPUDetect.h" #include "Common/x64Emitter.h" -#include "Core/PowerPC/PowerPC.h" namespace MMIO { class Mapping; } // We offset by 0x80 because the range of one byte memory offsets is // -0x80..0x7f. -#define PPCSTATE_BASE ((u8*)&PowerPC::ppcState + 0x80) -#define PPCSTATE_OFS(x) ((u8*)(x) - PPCSTATE_BASE) -#define PPCSTATE(x) MDisp(RPPCSTATE, PPCSTATE_OFS(&PowerPC::ppcState.x)) +#define PPCSTATE(x) MDisp(RPPCSTATE, \ + (int) ((char *) &PowerPC::ppcState.x - (char *) &PowerPC::ppcState) - 0x80) +// In case you want to disable the ppcstate register: +// #define PPCSTATE(x) M(&PowerPC::ppcState.x) #define PPCSTATE_LR PPCSTATE(spr[SPR_LR]) #define PPCSTATE_CTR PPCSTATE(spr[SPR_CTR]) #define PPCSTATE_SRR0 PPCSTATE(spr[SPR_SRR0]) @@ -31,7 +31,7 @@ private: bool m_enabled = false; public: bool Enabled() { return m_enabled; } - void Init(int size) { AllocCodeSpace(size, PPCSTATE_BASE); m_enabled = true; } + void Init(int size) { AllocCodeSpace(size); m_enabled = true; } void Shutdown() { FreeCodeSpace(); m_enabled = false; } }; diff --git a/Source/Core/Core/PowerPC/JitCommon/TrampolineCache.cpp b/Source/Core/Core/PowerPC/JitCommon/TrampolineCache.cpp index 0a02764142..f9b7e219e2 100644 --- a/Source/Core/Core/PowerPC/JitCommon/TrampolineCache.cpp +++ b/Source/Core/Core/PowerPC/JitCommon/TrampolineCache.cpp @@ -22,7 +22,7 @@ using namespace Gen; void TrampolineCache::Init(int size) { - AllocCodeSpace(size, PPCSTATE_BASE); + AllocCodeSpace(size); } void TrampolineCache::ClearCodeSpace() diff --git a/Source/UnitTests/Common/x64EmitterTest.cpp b/Source/UnitTests/Common/x64EmitterTest.cpp index 6659542dee..766fc0436c 100644 --- a/Source/UnitTests/Common/x64EmitterTest.cpp +++ b/Source/UnitTests/Common/x64EmitterTest.cpp @@ -19,7 +19,6 @@ #include "Common/CPUDetect.h" #include "Common/x64Emitter.h" -#include "Core/PowerPC/JitCommon/Jit_Util.h" namespace Gen { @@ -95,7 +94,7 @@ protected: memset(&cpu_info, 0xFF, sizeof (cpu_info)); emitter.reset(new X64CodeBlock()); - emitter->AllocCodeSpace(4096, PPCSTATE_BASE); + emitter->AllocCodeSpace(4096); code_buffer = emitter->GetWritableCodePtr(); disasm.reset(new disassembler); From c7193fcd419f206a20ad4616e72b7e14c0dfd297 Mon Sep 17 00:00:00 2001 From: Lioncash Date: Mon, 6 Jul 2015 05:29:41 -0400 Subject: [PATCH 058/583] MMIO: Add missing override specifiers --- Source/Core/Core/HW/MMIO.cpp | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/Source/Core/Core/HW/MMIO.cpp b/Source/Core/Core/HW/MMIO.cpp index 2e82db2656..1ee72b892f 100644 --- a/Source/Core/Core/HW/MMIO.cpp +++ b/Source/Core/Core/HW/MMIO.cpp @@ -43,7 +43,7 @@ public: virtual ~ConstantHandlingMethod() {} - virtual void AcceptReadVisitor(ReadHandlingMethodVisitor& v) const + void AcceptReadVisitor(ReadHandlingMethodVisitor& v) const override { v.VisitConstant(value_); } @@ -66,7 +66,8 @@ class NopHandlingMethod : public WriteHandlingMethod public: NopHandlingMethod() {} virtual ~NopHandlingMethod() {} - virtual void AcceptWriteVisitor(WriteHandlingMethodVisitor& v) const + + void AcceptWriteVisitor(WriteHandlingMethodVisitor& v) const override { v.VisitNop(); } @@ -91,12 +92,12 @@ public: virtual ~DirectHandlingMethod() {} - virtual void AcceptReadVisitor(ReadHandlingMethodVisitor& v) const + void AcceptReadVisitor(ReadHandlingMethodVisitor& v) const override { v.VisitDirect(addr_, mask_); } - virtual void AcceptWriteVisitor(WriteHandlingMethodVisitor& v) const + void AcceptWriteVisitor(WriteHandlingMethodVisitor& v) const override { v.VisitDirect(addr_, mask_); } @@ -146,12 +147,12 @@ public: virtual ~ComplexHandlingMethod() {} - virtual void AcceptReadVisitor(ReadHandlingMethodVisitor& v) const + void AcceptReadVisitor(ReadHandlingMethodVisitor& v) const override { v.VisitComplex(&read_lambda_); } - virtual void AcceptWriteVisitor(WriteHandlingMethodVisitor& v) const + void AcceptWriteVisitor(WriteHandlingMethodVisitor& v) const override { v.VisitComplex(&write_lambda_); } @@ -300,17 +301,17 @@ void ReadHandler::ResetMethod(ReadHandlingMethod* method) { std::function ret; - virtual void VisitConstant(T value) + void VisitConstant(T value) override { ret = [value](u32) { return value; }; } - virtual void VisitDirect(const T* addr, u32 mask) + void VisitDirect(const T* addr, u32 mask) override { ret = [addr, mask](u32) { return *addr & mask; }; } - virtual void VisitComplex(const std::function* lambda) + void VisitComplex(const std::function* lambda) override { ret = *lambda; } @@ -356,17 +357,17 @@ void WriteHandler::ResetMethod(WriteHandlingMethod* method) { std::function ret; - virtual void VisitNop() + void VisitNop() override { ret = [](u32, T) {}; } - virtual void VisitDirect(T* ptr, u32 mask) + void VisitDirect(T* ptr, u32 mask) override { ret = [ptr, mask](u32, T val) { *ptr = val & mask; }; } - virtual void VisitComplex(const std::function* lambda) + void VisitComplex(const std::function* lambda) override { ret = *lambda; } From af4cfd32d48f57c6dd177c8ca46afe1dc9b175c7 Mon Sep 17 00:00:00 2001 From: Lioncash Date: Mon, 6 Jul 2015 06:25:48 -0400 Subject: [PATCH 059/583] Core: Change a volatile into an atomic Also changes s_drawn_video into an atomic, as it's used across threads as well. --- Source/Core/Core/Core.cpp | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/Source/Core/Core/Core.cpp b/Source/Core/Core/Core.cpp index c7a1ba9914..bcf2fc5842 100644 --- a/Source/Core/Core/Core.cpp +++ b/Source/Core/Core/Core.cpp @@ -2,6 +2,7 @@ // Licensed under GPLv2+ // Refer to the license.txt file included. +#include #include #ifdef _WIN32 @@ -10,7 +11,6 @@ #include "AudioCommon/AudioCommon.h" -#include "Common/Atomic.h" #include "Common/CommonPaths.h" #include "Common/CommonTypes.h" #include "Common/CPUDetect.h" @@ -83,8 +83,8 @@ bool g_want_determinism; // Declarations and definitions static Common::Timer s_timer; -static volatile u32 s_drawn_frame = 0; -static u32 s_drawn_video = 0; +static std::atomic s_drawn_frame; +static std::atomic s_drawn_video; // Function forwarding void Callback_WiimoteInterruptChannel(int _number, u16 _channelID, const void* _pData, u32 _Size); @@ -725,14 +725,14 @@ void VideoThrottle() { // Update info per second u32 ElapseTime = (u32)s_timer.GetTimeDifference(); - if ((ElapseTime >= 1000 && s_drawn_video > 0) || s_request_refresh_info) + if ((ElapseTime >= 1000 && s_drawn_video.load() > 0) || s_request_refresh_info) { UpdateTitle(); // Reset counter s_timer.Update(); - Common::AtomicStore(s_drawn_frame, 0); - s_drawn_video = 0; + s_drawn_frame.store(0); + s_drawn_video.store(0); } s_drawn_video++; @@ -746,7 +746,7 @@ bool ShouldSkipFrame(int skipped) const u32 TargetFPS = (SConfig::GetInstance().m_Framelimit > 1) ? (SConfig::GetInstance().m_Framelimit - 1) * 5 : VideoInterface::TargetRefreshRate; - const u32 frames = Common::AtomicLoad(s_drawn_frame); + const u32 frames = s_drawn_frame.load(); const bool fps_slow = !(s_timer.GetTimeDifference() < (frames + skipped) * 1000 / TargetFPS); return fps_slow; @@ -758,7 +758,8 @@ bool ShouldSkipFrame(int skipped) void Callback_VideoCopiedToXFB(bool video_update) { if (video_update) - Common::AtomicIncrement(s_drawn_frame); + s_drawn_frame++; + Movie::FrameUpdate(); } @@ -771,9 +772,9 @@ void UpdateTitle() if (ElapseTime == 0) ElapseTime = 1; - float FPS = (float) (Common::AtomicLoad(s_drawn_frame) * 1000.0 / ElapseTime); - float VPS = (float) (s_drawn_video * 1000.0 / ElapseTime); - float Speed = (float) (s_drawn_video * (100 * 1000.0) / (VideoInterface::TargetRefreshRate * ElapseTime)); + float FPS = (float)(s_drawn_frame.load() * 1000.0 / ElapseTime); + float VPS = (float)(s_drawn_video.load() * 1000.0 / ElapseTime); + float Speed = (float)(s_drawn_video.load() * (100 * 1000.0) / (VideoInterface::TargetRefreshRate * ElapseTime)); // Settings are shown the same for both extended and summary info std::string SSettings = StringFromFormat("%s %s | %s | %s", cpu_core_base->GetName(), _CoreParameter.bCPUThread ? "DC" : "SC", From 614a656b83c5f242724a4ab58321de02276cb7d5 Mon Sep 17 00:00:00 2001 From: Lioncash Date: Mon, 6 Jul 2015 06:47:10 -0400 Subject: [PATCH 060/583] DSPInterpreter: Remove an unused typedef DSPTables already has an equivalent of this, which it uses. --- Source/Core/Core/DSP/DSPInterpreter.h | 3 --- 1 file changed, 3 deletions(-) diff --git a/Source/Core/Core/DSP/DSPInterpreter.h b/Source/Core/Core/DSP/DSPInterpreter.h index d6316fc77e..a584dc43c2 100644 --- a/Source/Core/Core/DSP/DSPInterpreter.h +++ b/Source/Core/Core/DSP/DSPInterpreter.h @@ -25,9 +25,6 @@ int RunCyclesDebug(int cycles); void WriteCR(u16 val); u16 ReadCR(); - -typedef void (*DSPInterpreterFunc)(const UDSPInstruction opc); - // All the opcode functions. void call(const UDSPInstruction opc); void callr(const UDSPInstruction opc); From 9018b546c71932a46a85222a3de7a989184361ec Mon Sep 17 00:00:00 2001 From: JosJuice Date: Mon, 6 Jul 2015 15:41:37 +0200 Subject: [PATCH 061/583] WbfsBlob: Don't enter an infinite loop when reading beyond end of disc read_size remained 0 when the "Read beyond end of disc" error occurs, which made the while (nbytes) loop never end. As a fix, SeekToCluster now explicitly sets available to 0 when the error occurs, and Read checks for it. --- Source/Core/DiscIO/WbfsBlob.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Source/Core/DiscIO/WbfsBlob.cpp b/Source/Core/DiscIO/WbfsBlob.cpp index ef90026621..5c0ac028ea 100644 --- a/Source/Core/DiscIO/WbfsBlob.cpp +++ b/Source/Core/DiscIO/WbfsBlob.cpp @@ -115,8 +115,10 @@ bool WbfsFileReader::Read(u64 offset, u64 nbytes, u8* out_ptr) { while (nbytes) { - u64 read_size = 0; + u64 read_size; File::IOFile& data_file = SeekToCluster(offset, &read_size); + if (read_size == 0) + return false; read_size = (read_size > nbytes) ? nbytes : read_size; if (!data_file.ReadBytes(out_ptr, read_size)) @@ -160,6 +162,8 @@ File::IOFile& WbfsFileReader::SeekToCluster(u64 offset, u64* available) } PanicAlert("Read beyond end of disc"); + if (available) + *available = 0; m_files[0]->file.Seek(0, SEEK_SET); return m_files[0]->file; } From e3c6eb2a8552ddc5a14f6c682286565312a9ab41 Mon Sep 17 00:00:00 2001 From: Lioncash Date: Mon, 6 Jul 2015 13:20:06 -0400 Subject: [PATCH 062/583] WiimoteEmu: Fix use of spaces. There should be a tab here instead. --- Source/Core/Core/HW/WiimoteEmu/WiimoteEmu.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/Core/Core/HW/WiimoteEmu/WiimoteEmu.cpp b/Source/Core/Core/HW/WiimoteEmu/WiimoteEmu.cpp index 5083b8b05f..1d54096bc0 100644 --- a/Source/Core/Core/HW/WiimoteEmu/WiimoteEmu.cpp +++ b/Source/Core/Core/HW/WiimoteEmu/WiimoteEmu.cpp @@ -37,7 +37,7 @@ static const u8 eeprom_data_0[] = { 0xA1, 0xAA, 0x8B, 0x99, 0xAE, 0x9E, 0x78, 0x30, 0xA7, /*0x74, 0xD3,*/ 0x00, 0x00, // messing up the checksum on purpose 0xA1, 0xAA, 0x8B, 0x99, 0xAE, 0x9E, 0x78, 0x30, 0xA7, /*0x74, 0xD3,*/ 0x00, 0x00, // Accelerometer - // Important: checksum is required for tilt games + // Important: checksum is required for tilt games ACCEL_ZERO_G, ACCEL_ZERO_G, ACCEL_ZERO_G, 0, ACCEL_ONE_G, ACCEL_ONE_G, ACCEL_ONE_G, 0, 0, 0xA3, ACCEL_ZERO_G, ACCEL_ZERO_G, ACCEL_ZERO_G, 0, ACCEL_ONE_G, ACCEL_ONE_G, ACCEL_ONE_G, 0, 0, 0xA3, }; From 25bd55b7aae4aedac60d60a2890172f329e8e2c4 Mon Sep 17 00:00:00 2001 From: Lioncash Date: Mon, 6 Jul 2015 13:34:11 -0400 Subject: [PATCH 063/583] Core: Use clamps for nunchuk and wiimote x,y,z values --- .../Core/HW/WiimoteEmu/Attachment/Nunchuk.cpp | 16 ++++------------ Source/Core/Core/HW/WiimoteEmu/WiimoteEmu.cpp | 16 ++++------------ 2 files changed, 8 insertions(+), 24 deletions(-) diff --git a/Source/Core/Core/HW/WiimoteEmu/Attachment/Nunchuk.cpp b/Source/Core/Core/HW/WiimoteEmu/Attachment/Nunchuk.cpp index 3af7359897..2796e473f3 100644 --- a/Source/Core/Core/HW/WiimoteEmu/Attachment/Nunchuk.cpp +++ b/Source/Core/Core/HW/WiimoteEmu/Attachment/Nunchuk.cpp @@ -2,6 +2,7 @@ // Licensed under GPLv2+ // Refer to the license.txt file included. +#include "Common/MathUtil.h" #include "Core/HW/WiimoteEmu/WiimoteEmu.h" #include "Core/HW/WiimoteEmu/Attachment/Nunchuk.h" @@ -93,18 +94,9 @@ void Nunchuk::GetState(u8* const data) s16 accel_y = (s16)(4 * (accel.y * ACCEL_RANGE + ACCEL_ZERO_G)); s16 accel_z = (s16)(4 * (accel.z * ACCEL_RANGE + ACCEL_ZERO_G)); - if (accel_x > 1024) - accel_x = 1024; - else if (accel_x < 0) - accel_x = 0; - if (accel_y > 1024) - accel_y = 1024; - else if (accel_y < 0) - accel_y = 0; - if (accel_z > 1024) - accel_z = 1024; - else if (accel_z < 0) - accel_z = 0; + accel_x = MathUtil::Clamp(accel_x, 0, 1024); + accel_y = MathUtil::Clamp(accel_y, 0, 1024); + accel_z = MathUtil::Clamp(accel_z, 0, 1024); ncdata->ax = (accel_x >> 2) & 0xFF; ncdata->ay = (accel_y >> 2) & 0xFF; diff --git a/Source/Core/Core/HW/WiimoteEmu/WiimoteEmu.cpp b/Source/Core/Core/HW/WiimoteEmu/WiimoteEmu.cpp index 1d54096bc0..3f79f5363f 100644 --- a/Source/Core/Core/HW/WiimoteEmu/WiimoteEmu.cpp +++ b/Source/Core/Core/HW/WiimoteEmu/WiimoteEmu.cpp @@ -6,6 +6,7 @@ #include "Common/ChunkFile.h" #include "Common/CommonTypes.h" +#include "Common/MathUtil.h" #include "Common/Timer.h" #include "Core/ConfigManager.h" #include "Core/Host.h" @@ -403,18 +404,9 @@ void Wiimote::GetAccelData(u8* const data, const ReportFeatures& rptf) s16 y = (s16)(4 * (m_accel.y * ACCEL_RANGE + ACCEL_ZERO_G)); s16 z = (s16)(4 * (m_accel.z * ACCEL_RANGE + ACCEL_ZERO_G)); - if (x > 1024) - x = 1024; - else if (x < 0) - x = 0; - if (y > 1024) - y = 1024; - else if (y < 0) - y = 0; - if (z > 1024) - z = 1024; - else if (z < 0) - z = 0; + x = MathUtil::Clamp(x, 0, 1024); + y = MathUtil::Clamp(y, 0, 1024); + z = MathUtil::Clamp(z, 0, 1024); accel.x = (x >> 2) & 0xFF; accel.y = (y >> 2) & 0xFF; From effb626befdad919020e9e1655b68af692b16f76 Mon Sep 17 00:00:00 2001 From: degasus Date: Mon, 6 Jul 2015 23:40:20 +0200 Subject: [PATCH 064/583] JitArm64: Implement EXCEPTION_FPU_UNAVAILABLE support. Seems like this flag was missed. This patch was mostly done by HdkR. --- Source/Core/Core/PowerPC/JitArm64/Jit.cpp | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/Source/Core/Core/PowerPC/JitArm64/Jit.cpp b/Source/Core/Core/PowerPC/JitArm64/Jit.cpp index a658252043..c1bf82b05d 100644 --- a/Source/Core/Core/PowerPC/JitArm64/Jit.cpp +++ b/Source/Core/Core/PowerPC/JitArm64/Jit.cpp @@ -303,6 +303,7 @@ const u8* JitArm64::DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buf, JitB } js.isLastInstruction = false; + js.firstFPInstructionFound = false; js.blockStart = em_address; js.fifoBytesThisBlock = 0; js.downcountAmount = 0; @@ -389,6 +390,28 @@ const u8* JitArm64::DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buf, JitB if (!ops[i].skip) { + if ((opinfo->flags & FL_USE_FPU) && !js.firstFPInstructionFound) + { + //This instruction uses FPU - needs to add FP exception bailout + ARM64Reg WA = gpr.GetReg(); + LDR(INDEX_UNSIGNED, WA, X29, PPCSTATE_OFF(msr)); + FixupBranch b1 = TBNZ(WA, 13); // Test FP enabled bit + + gpr.Flush(FLUSH_MAINTAIN_STATE); + fpr.Flush(FLUSH_MAINTAIN_STATE); + + LDR(INDEX_UNSIGNED, WA, X29, PPCSTATE_OFF(Exceptions)); + ORR(WA, WA, 26, 0); // EXCEPTION_FPU_UNAVAILABLE + STR(INDEX_UNSIGNED, WA, X29, PPCSTATE_OFF(Exceptions)); + + MOVI2R(WA, js.compilerPC); + WriteExceptionExit(WA); + + SetJumpTarget(b1); + + js.firstFPInstructionFound = true; + } + if (jo.memcheck && (opinfo->flags & FL_USE_FPU)) { // Don't do this yet From 6e969133f5e0f5fe9551a0ace39b242c5c3aac78 Mon Sep 17 00:00:00 2001 From: Scott Mansell Date: Mon, 6 Jul 2015 07:57:31 +1200 Subject: [PATCH 065/583] evdev: Delete rumble effects on the correct file descriptor. Was using m_id insted of m_fd. Also re-arrange the code so rumble effects always get deleted instead of just on stop commands. --- .../ControllerInterface/evdev/evdev.cpp | 15 +++++++++++++-- .../InputCommon/ControllerInterface/evdev/evdev.h | 1 + 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/Source/Core/InputCommon/ControllerInterface/evdev/evdev.cpp b/Source/Core/InputCommon/ControllerInterface/evdev/evdev.cpp index 9b31da73c4..6ee55ba0e5 100644 --- a/Source/Core/InputCommon/ControllerInterface/evdev/evdev.cpp +++ b/Source/Core/InputCommon/ControllerInterface/evdev/evdev.cpp @@ -216,6 +216,12 @@ void evdevDevice::ForceFeedback::SetState(ControlState state) // libevdev doesn't have nice helpers for forcefeedback // we will use the file descriptors directly. + if (m_id != -1) // delete the previous effect (which also stops it) + { + ioctl(m_fd, EVIOCRMFF, m_id); + m_id = -1; + } + if (state > 0) // Upload and start an effect. { ff_effect effect; @@ -260,9 +266,14 @@ void evdevDevice::ForceFeedback::SetState(ControlState state) write(m_fd, (const void*) &play, sizeof(play)); } - else if (m_id != -1) // delete the effect (which also stops it) +} + +evdevDevice::ForceFeedback::~ForceFeedback() +{ + // delete the uploaded effect, so we don't leak it. + if (m_id != -1) { - ioctl(m_id, EVIOCRMFF, m_id); + ioctl(m_fd, EVIOCRMFF, m_id); } } diff --git a/Source/Core/InputCommon/ControllerInterface/evdev/evdev.h b/Source/Core/InputCommon/ControllerInterface/evdev/evdev.h index d1555c8cce..2926e44805 100644 --- a/Source/Core/InputCommon/ControllerInterface/evdev/evdev.h +++ b/Source/Core/InputCommon/ControllerInterface/evdev/evdev.h @@ -52,6 +52,7 @@ private: public: std::string GetName() const override; ForceFeedback(u16 type, libevdev* dev) : m_type(type), m_dev(dev), m_id(-1) { m_fd = libevdev_get_fd(dev); } + ~ForceFeedback(); void SetState(ControlState state) override; private: const u16 m_type; From 4ffeb057cc581f7139060bba9a6ebc9983fef899 Mon Sep 17 00:00:00 2001 From: Scott Mansell Date: Tue, 7 Jul 2015 22:20:36 +1200 Subject: [PATCH 066/583] Interpreter: Fix bug with icache emulation. The constructor sets up way_from_valid and way_from_plur as fast lookup tables for implementing the PLRU algrothm. Then the Init function memsets them to zero, meaning the instruction cache will now always choose the first way in each set. This degrades the cache from 128 sets, 8 way to 128 sets, 1 way. Not only does fixing this bug increase accuracy, but it increases preformance too, giving a 1% speedup to interpreter. --- Source/Core/Core/PowerPC/PPCCache.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/Source/Core/Core/PowerPC/PPCCache.cpp b/Source/Core/Core/PowerPC/PPCCache.cpp index 57c798c91c..7244e775bb 100644 --- a/Source/Core/Core/PowerPC/PPCCache.cpp +++ b/Source/Core/Core/PowerPC/PPCCache.cpp @@ -71,8 +71,6 @@ namespace PowerPC { memset(data, 0, sizeof(data)); memset(tags, 0, sizeof(tags)); - memset(way_from_valid, 0, sizeof(way_from_valid)); - memset(way_from_plru, 0, sizeof(way_from_plru)); Reset(); } From a31ebb9bcd8365e19a1003032b8ed1ed30c7ed55 Mon Sep 17 00:00:00 2001 From: Scott Mansell Date: Tue, 7 Jul 2015 22:11:21 +1200 Subject: [PATCH 067/583] PPCAnalyst: Don't swap instruction which might cause interrupts. fcmpo and fcmpu can be matched by the REORDER_CMP pass, as they set CR0 and they can cause interrupts if the fpu is disabled. So we add an extra check to make sure op a is an integer op too. --- Source/Core/Core/PowerPC/PPCAnalyst.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Source/Core/Core/PowerPC/PPCAnalyst.cpp b/Source/Core/Core/PowerPC/PPCAnalyst.cpp index cdd7fcc19b..f08b0f4216 100644 --- a/Source/Core/Core/PowerPC/PPCAnalyst.cpp +++ b/Source/Core/Core/PowerPC/PPCAnalyst.cpp @@ -250,6 +250,10 @@ static bool CanSwapAdjacentOps(const CodeOp &a, const CodeOp &b) if (b_info->type != OPTYPE_INTEGER) return false; + // And it's possible a might raise an interrupt too (fcmpo/fcmpu) + if (a_info->type != OPTYPE_INTEGER) + return false; + // Check that we have no register collisions. // That is, check that none of b's outputs matches any of a's inputs, // and that none of a's outputs matches any of b's inputs. From df379dabae6cd214aa56c1fecdb55133249a1847 Mon Sep 17 00:00:00 2001 From: Lioncash Date: Tue, 7 Jul 2015 18:12:14 -0400 Subject: [PATCH 068/583] VertexLoaderBase: Adjust the scope of a boolean variable if a or b do actually turn out to be null, this can cause a null pointer dereference. --- Source/Core/VideoCommon/VertexLoaderBase.cpp | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/Source/Core/VideoCommon/VertexLoaderBase.cpp b/Source/Core/VideoCommon/VertexLoaderBase.cpp index d5831bc8e5..7f8134b85b 100644 --- a/Source/Core/VideoCommon/VertexLoaderBase.cpp +++ b/Source/Core/VideoCommon/VertexLoaderBase.cpp @@ -131,13 +131,14 @@ public: : VertexLoaderBase(vtx_desc, vtx_attr), a(_a), b(_b) { m_initialized = a && b && a->IsInitialized() && b->IsInitialized(); - bool can_test = a->m_VertexSize == b->m_VertexSize && - a->m_native_components == b->m_native_components && - a->m_native_vtx_decl.stride == b->m_native_vtx_decl.stride; if (m_initialized) { - if (can_test) + m_initialized = a->m_VertexSize == b->m_VertexSize && + a->m_native_components == b->m_native_components && + a->m_native_vtx_decl.stride == b->m_native_vtx_decl.stride; + + if (m_initialized) { m_VertexSize = a->m_VertexSize; m_native_components = a->m_native_components; @@ -152,8 +153,6 @@ public: b->m_VertexSize, b->m_native_components, b->m_native_vtx_decl.stride); } } - - m_initialized &= can_test; } ~VertexLoaderTester() override { From 2559a6f25c8b728aefe570ed1980c4d85b689828 Mon Sep 17 00:00:00 2001 From: Tillmann Karras Date: Wed, 8 Jul 2015 07:17:28 +0200 Subject: [PATCH 069/583] VertexLoader: avoid empty lines in perf-$pid.map --- Source/Core/VideoCommon/VertexLoaderBase.cpp | 2 +- Source/Core/VideoCommon/VertexLoaderManager.cpp | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/Source/Core/VideoCommon/VertexLoaderBase.cpp b/Source/Core/VideoCommon/VertexLoaderBase.cpp index d5831bc8e5..34fa375ee1 100644 --- a/Source/Core/VideoCommon/VertexLoaderBase.cpp +++ b/Source/Core/VideoCommon/VertexLoaderBase.cpp @@ -120,7 +120,7 @@ void VertexLoaderBase::AppendToString(std::string *dest) const i, m_VtxAttr.texCoord[i].Elements, posMode[tex_mode[i]], posFormats[m_VtxAttr.texCoord[i].Format])); } } - dest->append(StringFromFormat(" - %i v\n", m_numLoadedVertices)); + dest->append(StringFromFormat(" - %i v", m_numLoadedVertices)); } // a hacky implementation to compare two vertex loaders diff --git a/Source/Core/VideoCommon/VertexLoaderManager.cpp b/Source/Core/VideoCommon/VertexLoaderManager.cpp index 46a0eeaab0..0099064ca5 100644 --- a/Source/Core/VideoCommon/VertexLoaderManager.cpp +++ b/Source/Core/VideoCommon/VertexLoaderManager.cpp @@ -109,7 +109,8 @@ void AppendListToString(std::string *dest) dest->reserve(dest->size() + total_size); for (const entry& entry : entries) { - dest->append(entry.text); + *dest += entry.text; + *dest += '\n'; } } From b8706791d5c2c13f5a9712f433d491f320b5369b Mon Sep 17 00:00:00 2001 From: Lioncash Date: Wed, 8 Jul 2015 09:48:07 -0400 Subject: [PATCH 070/583] DolphinWX: Pass string by const reference in CISOProperties constructor --- Source/Core/DolphinWX/ISOProperties.cpp | 2 +- Source/Core/DolphinWX/ISOProperties.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Source/Core/DolphinWX/ISOProperties.cpp b/Source/Core/DolphinWX/ISOProperties.cpp index 0be1535f09..8479b6eb6d 100644 --- a/Source/Core/DolphinWX/ISOProperties.cpp +++ b/Source/Core/DolphinWX/ISOProperties.cpp @@ -99,7 +99,7 @@ BEGIN_EVENT_TABLE(CISOProperties, wxDialog) EVT_CHOICE(ID_LANG, CISOProperties::OnChangeBannerLang) END_EVENT_TABLE() -CISOProperties::CISOProperties(const std::string fileName, wxWindow* parent, wxWindowID id, const wxString& title, const wxPoint& position, const wxSize& size, long style) +CISOProperties::CISOProperties(const std::string& fileName, wxWindow* parent, wxWindowID id, const wxString& title, const wxPoint& position, const wxSize& size, long style) : wxDialog(parent, id, title, position, size, style) { // Load ISO data diff --git a/Source/Core/DolphinWX/ISOProperties.h b/Source/Core/DolphinWX/ISOProperties.h index 2f07ec8c10..fff7ba3352 100644 --- a/Source/Core/DolphinWX/ISOProperties.h +++ b/Source/Core/DolphinWX/ISOProperties.h @@ -51,7 +51,7 @@ struct PHackData class CISOProperties : public wxDialog { public: - CISOProperties(const std::string fileName, + CISOProperties(const std::string& fileName, wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = _("Properties"), From c38ae5236e082c0b635085fced60559170ee9a8e Mon Sep 17 00:00:00 2001 From: Rohit Nirmal Date: Wed, 8 Jul 2015 13:09:08 -0500 Subject: [PATCH 071/583] Fix building with PCH disabled. --- Source/Core/Common/Logging/Log.h | 3 +++ Source/Core/InputCommon/ControllerInterface/evdev/evdev.cpp | 1 + 2 files changed, 4 insertions(+) diff --git a/Source/Core/Common/Logging/Log.h b/Source/Core/Common/Logging/Log.h index 23fd6fca10..b95b7048b5 100644 --- a/Source/Core/Common/Logging/Log.h +++ b/Source/Core/Common/Logging/Log.h @@ -4,6 +4,9 @@ #pragma once +#include "Common/CommonFuncs.h" +#include "Common/MsgHandler.h" + namespace LogTypes { diff --git a/Source/Core/InputCommon/ControllerInterface/evdev/evdev.cpp b/Source/Core/InputCommon/ControllerInterface/evdev/evdev.cpp index 9b31da73c4..75384393b6 100644 --- a/Source/Core/InputCommon/ControllerInterface/evdev/evdev.cpp +++ b/Source/Core/InputCommon/ControllerInterface/evdev/evdev.cpp @@ -2,6 +2,7 @@ // Licensed under GPLv2+ // Refer to the license.txt file included. +#include #include #include From b3a0b6def442561e768eeeceaea356b0294d5401 Mon Sep 17 00:00:00 2001 From: Justin Chadwick Date: Wed, 8 Jul 2015 16:06:11 -0400 Subject: [PATCH 072/583] Disables assert messages that seem to be invalid. --- Source/Core/VideoCommon/VertexShaderGen.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Source/Core/VideoCommon/VertexShaderGen.cpp b/Source/Core/VideoCommon/VertexShaderGen.cpp index 97ac15e887..b495e62a93 100644 --- a/Source/Core/VideoCommon/VertexShaderGen.cpp +++ b/Source/Core/VideoCommon/VertexShaderGen.cpp @@ -241,7 +241,8 @@ static inline void GenerateVertexShader(T& out, u32 components, API_TYPE api_typ switch (texinfo.sourcerow) { case XF_SRCGEOM_INROW: - _assert_(texinfo.inputform == XF_TEXINPUT_ABC1); + // The following assert was triggered in Super Smash Bros. Project M 3.6. + //_assert_(texinfo.inputform == XF_TEXINPUT_ABC1); out.Write("coord = rawpos;\n"); // pos.w is 1 break; case XF_SRCNORMAL_INROW: @@ -291,7 +292,8 @@ static inline void GenerateVertexShader(T& out, u32 components, API_TYPE api_typ } else { - _assert_(0); // should have normals + // The following assert was triggered in House of the Dead Overkill and Star Wars Rogue Squadron 2 + //_assert_(0); // should have normals uid_data->texMtxInfo[i].embosssourceshift = xfmem.texMtxInfo[i].embosssourceshift; out.Write("o.tex%d.xyz = o.tex%d.xyz;\n", i, texinfo.embosssourceshift); } From 576816105237b4d25b511ad86b730760cc400ce5 Mon Sep 17 00:00:00 2001 From: Lioncash Date: Thu, 9 Jul 2015 07:24:30 -0400 Subject: [PATCH 073/583] Core: Pass string by const reference in SaveScreenShot --- Source/Core/Core/Core.cpp | 2 +- Source/Core/Core/Core.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Source/Core/Core/Core.cpp b/Source/Core/Core/Core.cpp index c7a1ba9914..74920e99a6 100644 --- a/Source/Core/Core/Core.cpp +++ b/Source/Core/Core/Core.cpp @@ -678,7 +678,7 @@ void SaveScreenShot() SetState(CORE_RUN); } -void SaveScreenShot(const std::string name) +void SaveScreenShot(const std::string& name) { const bool bPaused = (GetState() == CORE_PAUSE); diff --git a/Source/Core/Core/Core.h b/Source/Core/Core/Core.h index dafa35d5f3..11d4fa2e98 100644 --- a/Source/Core/Core/Core.h +++ b/Source/Core/Core/Core.h @@ -52,7 +52,7 @@ void SetState(EState _State); EState GetState(); void SaveScreenShot(); -void SaveScreenShot(std::string name); +void SaveScreenShot(const std::string& name); void Callback_WiimoteInterruptChannel(int _number, u16 _channelID, const void* _pData, u32 _Size); From 81878d7b5641f28338fac62b24d43d9bff3f502e Mon Sep 17 00:00:00 2001 From: Lioncash Date: Thu, 9 Jul 2015 07:47:51 -0400 Subject: [PATCH 074/583] DolphinWX: Get rid of some magic numbers in MemoryView and MemoryWindow --- Source/Core/DolphinWX/Debugger/MemoryView.cpp | 9 +++++---- Source/Core/DolphinWX/Debugger/MemoryView.h | 15 +++++++++++++-- Source/Core/DolphinWX/Debugger/MemoryWindow.cpp | 11 ++++------- 3 files changed, 22 insertions(+), 13 deletions(-) diff --git a/Source/Core/DolphinWX/Debugger/MemoryView.cpp b/Source/Core/DolphinWX/Debugger/MemoryView.cpp index b5ecfa339b..812c1a8eda 100644 --- a/Source/Core/DolphinWX/Debugger/MemoryView.cpp +++ b/Source/Core/DolphinWX/Debugger/MemoryView.cpp @@ -43,7 +43,6 @@ enum CMemoryView::CMemoryView(DebugInterface* debuginterface, wxWindow* parent) : wxControl(parent, wxID_ANY) - , curAddress(debuginterface->GetPC()) , debugger(debuginterface) , align(debuginterface->GetInstructionSize(0)) , rowHeight(13) @@ -51,6 +50,8 @@ CMemoryView::CMemoryView(DebugInterface* debuginterface, wxWindow* parent) , oldSelection(0) , selecting(false) , memory(0) + , curAddress(debuginterface->GetPC()) + , dataType(MemoryDataType::U8) , viewAsType(VIEWAS_FP) { Bind(wxEVT_PAINT, &CMemoryView::OnPaint, this); @@ -364,21 +365,21 @@ void CMemoryView::OnPaint(wxPaintEvent& event) { switch (dataType) { - case 0: + case MemoryDataType::U8: dis += StringFromFormat(" %02X %02X %02X %02X", ((word & 0xff000000) >> 24) & 0xFF, ((word & 0xff0000) >> 16) & 0xFF, ((word & 0xff00) >> 8) & 0xFF, word & 0xff); break; - case 1: + case MemoryDataType::U16: dis += StringFromFormat(" %02X%02X %02X%02X", ((word & 0xff000000) >> 24) & 0xFF, ((word & 0xff0000) >> 16) & 0xFF, ((word & 0xff00) >> 8) & 0xFF, word & 0xff); break; - case 2: + case MemoryDataType::U32: dis += StringFromFormat(" %02X%02X%02X%02X", ((word & 0xff000000) >> 24) & 0xFF, ((word & 0xff0000) >> 16) & 0xFF, diff --git a/Source/Core/DolphinWX/Debugger/MemoryView.h b/Source/Core/DolphinWX/Debugger/MemoryView.h index 00108285d9..42adc677c0 100644 --- a/Source/Core/DolphinWX/Debugger/MemoryView.h +++ b/Source/Core/DolphinWX/Debugger/MemoryView.h @@ -9,6 +9,11 @@ class DebugInterface; +enum class MemoryDataType +{ + U8, U16, U32 +}; + class CMemoryView : public wxControl { public: @@ -22,8 +27,12 @@ public: curAddress = addr; Refresh(); } - int dataType; // u8,u16,u32 - int curAddress; // Will be accessed by parent + + void SetDataType(MemoryDataType data_type) + { + dataType = data_type; + Refresh(); + } private: void OnPaint(wxPaintEvent& event); @@ -47,6 +56,8 @@ private: bool selecting; int memory; + int curAddress; + MemoryDataType dataType; enum EViewAsType { diff --git a/Source/Core/DolphinWX/Debugger/MemoryWindow.cpp b/Source/Core/DolphinWX/Debugger/MemoryWindow.cpp index 37f9730ec6..83fba126af 100644 --- a/Source/Core/DolphinWX/Debugger/MemoryWindow.cpp +++ b/Source/Core/DolphinWX/Debugger/MemoryWindow.cpp @@ -79,7 +79,7 @@ CMemoryWindow::CMemoryWindow(wxWindow* parent, wxWindowID id, // wxSize(20, 100), 0, nullptr, wxLB_SORT); //sizerLeft->Add(symbols, 1, wxEXPAND); memview = new CMemoryView(di, this); - memview->dataType = 0; + //sizerBig->Add(sizerLeft, 1, wxEXPAND); sizerBig->Add(memview, 20, wxEXPAND); sizerBig->Add(sizerRight, 0, wxEXPAND | wxALL, 3); @@ -281,24 +281,21 @@ void CMemoryWindow::U8(wxCommandEvent& event) { chk16->SetValue(0); chk32->SetValue(0); - memview->dataType = 0; - memview->Refresh(); + memview->SetDataType(MemoryDataType::U8); } void CMemoryWindow::U16(wxCommandEvent& event) { chk8->SetValue(0); chk32->SetValue(0); - memview->dataType = 1; - memview->Refresh(); + memview->SetDataType(MemoryDataType::U16); } void CMemoryWindow::U32(wxCommandEvent& event) { chk16->SetValue(0); chk8->SetValue(0); - memview->dataType = 2; - memview->Refresh(); + memview->SetDataType(MemoryDataType::U32); } void CMemoryWindow::onSearch(wxCommandEvent& event) From 6e90d1e433811ceca4bf37473ac1c76770afdf7c Mon Sep 17 00:00:00 2001 From: Lioncash Date: Thu, 9 Jul 2015 13:08:37 -0400 Subject: [PATCH 075/583] SI_DeviceGCController: Remedy undefined behavior regarding shifts Left shifting a negative left-hand operand is undefined behavior per section 5.8.2 of the C++11 standard. --- Source/Core/Core/HW/SI_DeviceGCController.h | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Source/Core/Core/HW/SI_DeviceGCController.h b/Source/Core/Core/HW/SI_DeviceGCController.h index f738ad16fd..1a341051e4 100644 --- a/Source/Core/Core/HW/SI_DeviceGCController.h +++ b/Source/Core/Core/HW/SI_DeviceGCController.h @@ -118,7 +118,11 @@ public: virtual bool GetData(u32& _Hi, u32& _Low) override { CSIDevice_GCController::GetData(_Hi, _Low); - _Hi &= ~PAD_USE_ORIGIN << 16; + + // Unset all bits except those that represent + // A, B, X, Y, Start and the error bits, as they + // are not used. + _Hi &= ~0x20FFFFFF; return true; } }; From 6d2f85f18354238cab86bb059a748648e50c59c2 Mon Sep 17 00:00:00 2001 From: skidau Date: Fri, 10 Jul 2015 10:26:24 +1000 Subject: [PATCH 076/583] Removed the ability for PAL televisions to be set to progressive mode. --- Source/Core/Core/HW/VideoInterface.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/Core/Core/HW/VideoInterface.cpp b/Source/Core/Core/HW/VideoInterface.cpp index c41c6a24cd..25747cb4ae 100644 --- a/Source/Core/Core/HW/VideoInterface.cpp +++ b/Source/Core/Core/HW/VideoInterface.cpp @@ -137,7 +137,7 @@ void Preset(bool _bNTSC) m_VBeamPos = 0; // RG4JC0 checks for a zero VBeamPos // 54MHz, capable of progressive scan - m_Clock = SConfig::GetInstance().bProgressive; + m_Clock = SConfig::GetInstance().bNTSC; // Say component cable is plugged m_DTVStatus.component_plugged = SConfig::GetInstance().bProgressive; From e462422ef7c99d752dd3505044fbc9c43969a071 Mon Sep 17 00:00:00 2001 From: "Admiral H. Curtiss" Date: Wed, 8 Jul 2015 04:10:18 +0200 Subject: [PATCH 077/583] Wiimote: (Re-)Connect a disconnected emulated Wiimote when a mapped button is pressed. --- Source/Core/Core/HW/Wiimote.cpp | 22 +++++++++---------- Source/Core/Core/HW/Wiimote.h | 2 +- Source/Core/Core/HW/WiimoteEmu/WiimoteEmu.cpp | 22 +++++++++++++++++++ Source/Core/Core/HW/WiimoteEmu/WiimoteEmu.h | 5 +++++ .../Core/IPC_HLE/WII_IPC_HLE_Device_usb.cpp | 7 +++--- 5 files changed, 41 insertions(+), 17 deletions(-) diff --git a/Source/Core/Core/HW/Wiimote.cpp b/Source/Core/Core/HW/Wiimote.cpp index 378cc6f52f..a49689dd4e 100644 --- a/Source/Core/Core/HW/Wiimote.cpp +++ b/Source/Core/Core/HW/Wiimote.cpp @@ -114,22 +114,20 @@ void InterruptChannel(int _number, u16 _channelID, const void* _pData, u32 _Size // input: _number: [Description needed] // output: none // -void Update(int _number) +void Update(int _number, bool _connected) { - //PanicAlert( "Wiimote_Update" ); - - // if we are on the next input cycle, update output and input - static int _last_number = 4; - if (_number <= _last_number) + if (_connected) { - g_controller_interface.UpdateInput(); + if (WIIMOTE_SRC_EMU & g_wiimote_sources[_number]) + ((WiimoteEmu::Wiimote*)s_config.controllers[_number])->Update(); + else + WiimoteReal::Update(_number); } - _last_number = _number; - - if (WIIMOTE_SRC_EMU & g_wiimote_sources[_number]) - ((WiimoteEmu::Wiimote*)s_config.controllers[_number])->Update(); else - WiimoteReal::Update(_number); + { + if (WIIMOTE_SRC_EMU & g_wiimote_sources[_number]) + ((WiimoteEmu::Wiimote*)s_config.controllers[_number])->ConnectOnInput(); + } } // __________________________________________________________________________________________________ diff --git a/Source/Core/Core/HW/Wiimote.h b/Source/Core/Core/HW/Wiimote.h index 4d64f902b3..051d7cc3e8 100644 --- a/Source/Core/Core/HW/Wiimote.h +++ b/Source/Core/Core/HW/Wiimote.h @@ -48,7 +48,7 @@ InputConfig* GetConfig(); void ControlChannel(int _number, u16 _channelID, const void* _pData, u32 _Size); void InterruptChannel(int _number, u16 _channelID, const void* _pData, u32 _Size); -void Update(int _number); +void Update(int _number, bool _connected); } diff --git a/Source/Core/Core/HW/WiimoteEmu/WiimoteEmu.cpp b/Source/Core/Core/HW/WiimoteEmu/WiimoteEmu.cpp index 1d54096bc0..2744cd3156 100644 --- a/Source/Core/Core/HW/WiimoteEmu/WiimoteEmu.cpp +++ b/Source/Core/Core/HW/WiimoteEmu/WiimoteEmu.cpp @@ -249,6 +249,7 @@ void Wiimote::Reset() Wiimote::Wiimote( const unsigned int index ) : m_index(index) + , m_last_connect_request_counter(0) , ir_sin(0) , ir_cos(1) // , m_sound_stream( nullptr ) @@ -876,6 +877,27 @@ void Wiimote::InterruptChannel(const u16 _channelID, const void* _pData, u32 _Si } } +void Wiimote::ConnectOnInput() +{ + if (m_last_connect_request_counter > 0) + { + --m_last_connect_request_counter; + return; + } + + u16 buttons = 0; + m_buttons->GetState(&buttons, button_bitmasks); + m_dpad->GetState(&buttons, dpad_bitmasks); + + if (buttons != 0) + { + Host_ConnectWiimote(m_index, true); + // arbitrary value so it doesn't try to send multiple requests before Dolphin can react + // if Wiimotes are polled at 200Hz then this results in one request being sent per 500ms + m_last_connect_request_counter = 100; + } +} + void Wiimote::LoadDefaults(const ControllerInterface& ciface) { ControllerEmu::LoadDefaults(ciface); diff --git a/Source/Core/Core/HW/WiimoteEmu/WiimoteEmu.h b/Source/Core/Core/HW/WiimoteEmu/WiimoteEmu.h index f0ce9a5e38..a62d2919cd 100644 --- a/Source/Core/Core/HW/WiimoteEmu/WiimoteEmu.h +++ b/Source/Core/Core/HW/WiimoteEmu/WiimoteEmu.h @@ -121,6 +121,7 @@ public: void Update(); void InterruptChannel(const u16 _channelID, const void* _pData, u32 _Size); void ControlChannel(const u16 _channelID, const void* _pData, u32 _Size); + void ConnectOnInput(); void DoState(PointerWrap& p); void RealState(); @@ -239,6 +240,10 @@ private: u8 play; u8 unk_9; } m_reg_speaker; + + // limits the amount of connect requests we send when a button is pressed in disconnected state + u8 m_last_connect_request_counter; + #pragma pack(pop) }; diff --git a/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_usb.cpp b/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_usb.cpp index bfd90e4652..9cf809afdd 100644 --- a/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_usb.cpp +++ b/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_usb.cpp @@ -15,6 +15,7 @@ #include "Core/IPC_HLE/WII_IPC_HLE.h" #include "Core/IPC_HLE/WII_IPC_HLE_Device_usb.h" #include "Core/IPC_HLE/WII_IPC_HLE_WiiMote.h" +#include "InputCommon/ControllerInterface/ControllerInterface.h" void CWII_IPC_HLE_Device_usb_oh1_57e_305::EnqueueReply(u32 CommandAddress) @@ -490,11 +491,9 @@ u32 CWII_IPC_HLE_Device_usb_oh1_57e_305::Update() if (now - m_last_ticks > interval) { + g_controller_interface.UpdateInput(); for (unsigned int i = 0; i < m_WiiMotes.size(); i++) - if (m_WiiMotes[i].IsConnected()) - { - Wiimote::Update(i); - } + Wiimote::Update(i, m_WiiMotes[i].IsConnected()); m_last_ticks = now; } From 93e46631a303be7c284f8f49f13e0e56b1e4c919 Mon Sep 17 00:00:00 2001 From: MaJoRoesch Date: Fri, 10 Jul 2015 23:54:05 -0700 Subject: [PATCH 078/583] Adding new flag icons. Forgot the HiDPI icons. >_> MaJoR broke the Taiwan flag. --- Data/Sys/Resources/Flag_Europe.png | Bin 612 -> 425 bytes Data/Sys/Resources/Flag_Europe@2x.png | Bin 0 -> 645 bytes Data/Sys/Resources/Flag_Europe@4x.png | Bin 0 -> 1192 bytes Data/Sys/Resources/Flag_France.png | Bin 187 -> 141 bytes Data/Sys/Resources/Flag_France@2x.png | Bin 0 -> 156 bytes Data/Sys/Resources/Flag_France@4x.png | Bin 0 -> 193 bytes Data/Sys/Resources/Flag_Germany.png | Bin 196 -> 140 bytes Data/Sys/Resources/Flag_Germany@2x.png | Bin 0 -> 156 bytes Data/Sys/Resources/Flag_Germany@4x.png | Bin 0 -> 204 bytes Data/Sys/Resources/Flag_International.png | Bin 0 -> 496 bytes Data/Sys/Resources/Flag_International@2x.png | Bin 0 -> 754 bytes Data/Sys/Resources/Flag_International@4x.png | Bin 0 -> 1919 bytes Data/Sys/Resources/Flag_Italy.png | Bin 187 -> 142 bytes Data/Sys/Resources/Flag_Italy@2x.png | Bin 0 -> 157 bytes Data/Sys/Resources/Flag_Italy@4x.png | Bin 0 -> 192 bytes Data/Sys/Resources/Flag_Japan.png | Bin 399 -> 339 bytes Data/Sys/Resources/Flag_Japan@2x.png | Bin 0 -> 463 bytes Data/Sys/Resources/Flag_Japan@4x.png | Bin 0 -> 736 bytes Data/Sys/Resources/Flag_Korea.png | Bin 918 -> 598 bytes Data/Sys/Resources/Flag_Korea@2x.png | Bin 0 -> 953 bytes Data/Sys/Resources/Flag_Korea@4x.png | Bin 0 -> 2078 bytes Data/Sys/Resources/Flag_Netherlands.png | Bin 214 -> 140 bytes Data/Sys/Resources/Flag_Netherlands@2x.png | Bin 0 -> 157 bytes Data/Sys/Resources/Flag_Netherlands@4x.png | Bin 0 -> 179 bytes Data/Sys/Resources/Flag_Russia.png | Bin 201 -> 140 bytes Data/Sys/Resources/Flag_Russia@2x.png | Bin 0 -> 156 bytes Data/Sys/Resources/Flag_Russia@4x.png | Bin 0 -> 178 bytes Data/Sys/Resources/Flag_Spain.png | Bin 411 -> 434 bytes Data/Sys/Resources/Flag_Spain@2x.png | Bin 0 -> 852 bytes Data/Sys/Resources/Flag_Spain@4x.png | Bin 0 -> 2051 bytes Data/Sys/Resources/Flag_Taiwan.png | Bin 401 -> 333 bytes Data/Sys/Resources/Flag_Taiwan@2x.png | Bin 0 -> 419 bytes Data/Sys/Resources/Flag_Taiwan@4x.png | Bin 0 -> 805 bytes Data/Sys/Resources/Flag_USA.png | Bin 638 -> 536 bytes Data/Sys/Resources/Flag_USA@2x.png | Bin 0 -> 940 bytes Data/Sys/Resources/Flag_USA@4x.png | Bin 0 -> 2091 bytes Data/Sys/Resources/Flag_Unknown.png | Bin 462 -> 193 bytes Data/Sys/Resources/Flag_Unknown@2x.png | Bin 0 -> 312 bytes Data/Sys/Resources/Flag_Unknown@4x.png | Bin 0 -> 485 bytes 39 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 Data/Sys/Resources/Flag_Europe@2x.png create mode 100644 Data/Sys/Resources/Flag_Europe@4x.png create mode 100644 Data/Sys/Resources/Flag_France@2x.png create mode 100644 Data/Sys/Resources/Flag_France@4x.png create mode 100644 Data/Sys/Resources/Flag_Germany@2x.png create mode 100644 Data/Sys/Resources/Flag_Germany@4x.png create mode 100644 Data/Sys/Resources/Flag_International.png create mode 100644 Data/Sys/Resources/Flag_International@2x.png create mode 100644 Data/Sys/Resources/Flag_International@4x.png create mode 100644 Data/Sys/Resources/Flag_Italy@2x.png create mode 100644 Data/Sys/Resources/Flag_Italy@4x.png create mode 100644 Data/Sys/Resources/Flag_Japan@2x.png create mode 100644 Data/Sys/Resources/Flag_Japan@4x.png create mode 100644 Data/Sys/Resources/Flag_Korea@2x.png create mode 100644 Data/Sys/Resources/Flag_Korea@4x.png create mode 100644 Data/Sys/Resources/Flag_Netherlands@2x.png create mode 100644 Data/Sys/Resources/Flag_Netherlands@4x.png create mode 100644 Data/Sys/Resources/Flag_Russia@2x.png create mode 100644 Data/Sys/Resources/Flag_Russia@4x.png create mode 100644 Data/Sys/Resources/Flag_Spain@2x.png create mode 100644 Data/Sys/Resources/Flag_Spain@4x.png create mode 100644 Data/Sys/Resources/Flag_Taiwan@2x.png create mode 100644 Data/Sys/Resources/Flag_Taiwan@4x.png create mode 100644 Data/Sys/Resources/Flag_USA@2x.png create mode 100644 Data/Sys/Resources/Flag_USA@4x.png create mode 100644 Data/Sys/Resources/Flag_Unknown@2x.png create mode 100644 Data/Sys/Resources/Flag_Unknown@4x.png diff --git a/Data/Sys/Resources/Flag_Europe.png b/Data/Sys/Resources/Flag_Europe.png index e1b4dbba5af715d5a22e2e464a37e34ec3ca1cef..34282db4afd1b0277f3c35219664d79ee0c20102 100644 GIT binary patch delta 410 zcmV;L0cHN=1gQg%8Gi!+005SUZgv0w02y>eSaefwW^{L9a%BKPWN%_+AW3auXJt}l zVPtu6$z?nM003Z6OjJbxFP#fHlfV*hP0HqHR z-hYVFODq6tpMQQUOwF^QLxn|d6TU=QfdR7N5PgYEaX_y9a@B&a8_p;j=iEw5X=!+6ciEz<> zR^&kJ9(KOf^Z4k+`8_Zs_TH^#eKpuuv0CjGn^TcqCq; zaAI-U^<+1Z9Sh}x5pzFw&AxKxJM-Rr-}}CK0+7ULNdV3-#pC_e4HROwWTyv(kenN+ zAQ8N-oI*;`(LHT3V5WDul`YV3){s)LFt*I%*fLTI`pp_Qv#Xft-T%jc_an)KwL*EP zhfg(=>|DOFcYk5vBNNtRmY!Z}k4ZqbQiMIa%NJKiQ33#h;7{@nuJ2ycj zy6O=G%3sd+9S4Deu6n$kxKM@l@b2@8Ltp(b zv)^YLDG99tD^ud-b}aB(;b}( zVr|8S<}o@{B$e1}icKZ<7#(_pp?T4D!u&{qh4F_ZMDxN*h=9fMN8~OSqH9E5st-Wj zS24Bk)V%cJt@`)gL3|`BsQW5)U!_-f*qEN-N@fFqqepzYQoo#CJ-g2O^bEba)4)gm z8C6|_`A;XqY<@k45E46g4?A}sAtdFU!aSx?G0el3w7xq+#g8%>k07*qoM6N<$g3C7&;{X5v diff --git a/Data/Sys/Resources/Flag_Europe@2x.png b/Data/Sys/Resources/Flag_Europe@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..cc50dcabd78942d54af7603d3eb19911af9c554e GIT binary patch literal 645 zcmV;00($+4P)XI+6e`p17hb12va!bXXBLmBy|Hyi!&|*05F=){q660fs7#>0}Q+Awag*vVbBpr0FuS!p;vN-=b%*g zJOqrk`Zn0r!0NVLl9xU?8Kqy1H`AJB#9*Y&q9a017IrH?!-BX&fcHm1gzsn@V1=~% z07$MXwiN@{wMFN!3wYl8ing2}rqoCJM?k#Guo(nmAshfk584T$C-TQh!zum3DWS~* z5Pk~rQYRU+$AtuTErMP<$_dVeJM2d2qQ9-`AHwAlGD?|B-mSMY6t(}AIk<*vcj{(pD)qXj)=dtj$|QEX6q3$dELN&^ z%2+MSI{9J;#qFufl_Zm?7!X=jrJQ=9mld#Iwn_iy2t3p*Aw=}4_W?|@gue8|A;N$E f%=_bj?*a?}7;7?NJW^u^00000NkvXXu0mjfVG5;~n~jJ?{>=dZ zC#9&EHUH88R%K^1QG2+eE5oTI-@6n4*#HA?*EEuRZIlK064n~**5#0dm8 zmJmCU3OAJoGMe(p2x4wu=DrYpeog>0nb41R3;+NF-bqA3RCwC#ndz3JI1Ght3xqdp zB0^Zg^8RnxP9??koKxvwmdW%v;b$cZUs=+%ugs=5KkNhW0r&uX0Ji=Bycd9UL2m^> zR^b}~fY1&=uq7dEebRwv#+*}QjE40Du>er^{}5>5($o!V{tGD%hXMeQ&Rh6?33Wos z!Q=cXSVaIwt^nca3WWOc#^!Q8N&V=98j#BjX{wI`fOfRzB!#j4{of=eG`Gne0F*I8 zUW`o|IBEp~K`K*uW!?Q1P&7nS(ZW3eYLICvD-Q?O047dKg)nFR){CpaL`gvLTBlq+AP$_oHE_sV6S^L8Nt)FC8s zV+g5XI{*|SJ*VmUIxYt2`csHV&!@iI0bn9-g8mMQ7N;QWnIeP;y&z;s5u%pzsr)?^ zMd^CnsSB`@Nj|hOeL(h-oGtCt1&t}tn;3}&ZZ&GlVJ84j6V)+?E%0RsY5YC_cXf?B zX)O==c*DN|0M`4@U5XHRxt5^Tdnh4gYYi}Xvw1TL_Om>Xh!njDK!i$iB-#Q1nyEwz z)%Q*GfkgGnxJ>oMCID_+FdOd7y4WS?)DS|Y6EEuEWeQj@JJzq5LQs<&qR&5j+0_WKv3o zJ2@j{E|+mza@dN6t9Ek7xA|YI@|ZpVFIdOKPTmlFfq*<_{s&w?pC_&`r_1Mm-{1NQ zp<~SHpN{$~=84f)Hh%mA05N^|l}&MJp3MIsJb7rn1E=M+FT2F`UD^EPT$`rT(sZpq z?#iZP`EX7zLq6Y=K{-2DD8%WKro$;|kGrxVb-K;}in+e2=x2E#ZG(%tMw+O|BD`JM zIE8c4F)=uo#MeAAJM_v1KnzK09@k`z<~+Y@t{;krqpQTFJQ9Gk;i&EXh2X2NA#!T& ziU+Mx*kR|DNig)WpGT%PfAtr%uP&B4N6T+sVqF1 zY6Dcn8Q>G*`c~7DL3!%`|NrODEV%#_l=5_O45_%4l+ePgrgETxVKJARD32*C10x%Q Yp%&BI9eUP}fvOlhUHx3vIVCg!0D~4Lw*UYD delta 170 zcmeBW+|4*avYw5Bfnj0fJQpCvmgMd3!tfsi7wla=87RV8;1OBOz`!jG!i)^F=12eq z*-JcqUD@w(2@9xLXd0YN2MT$3x;Tb-98XS3NceHyprN6)5eOVBwF0~T-#@A3b=O)~ zd(jonc>8k)ju;$BxWc%YPong|3T8K11Lao@f$Tk2K(QX?yBe$vX diff --git a/Data/Sys/Resources/Flag_France@2x.png b/Data/Sys/Resources/Flag_France@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..a5f2d4d6a396a46fed5222fd52c047aa4389f1f9 GIT binary patch literal 156 zcmeAS@N?(olHy`uVBq!ia0vp^4nVBK!3-oHHTs8U}fi7AzZCsS>JiZ}y&LR{Z!S~4h4{r~^}{Fx;efP$KyE{-7;x89s#e$o|Fsy#X-P-d0ff!H|gQu&X%Q~loCIB>H BFNXjC literal 0 HcmV?d00001 diff --git a/Data/Sys/Resources/Flag_France@4x.png b/Data/Sys/Resources/Flag_France@4x.png new file mode 100644 index 0000000000000000000000000000000000000000..4f66b5db26874273494fef2532aad584509fb624 GIT binary patch literal 193 zcmeAS@N?(olHy`uVBq!ia0vp^4L}^h!3-q1dii$)DajJoh?3y^w370~qErUQl>DSr z1<%~X^wgl##FWaylc_d9MVtXXA+B#VEg6)j{{R1f{>+jKKtVrG7srr_TW`)8GBPl5 zFe_}W&(J<|nq4SBc6N6cCkN4>hCPgdk&WS^gKpxll!m)NlNmf+{an^LB{Ts5OC2t0 literal 0 HcmV?d00001 diff --git a/Data/Sys/Resources/Flag_Germany.png b/Data/Sys/Resources/Flag_Germany.png index 7ae967139989fec470317a9b7691cfed75ca5071..28470211b4878aea30e54542e48abe129568a99b 100644 GIT binary patch delta 122 zcmX@Y*uywMvY45Hfni#EUKx;*EOCt}3C>R|DNig)WpGT%PfAtr%uP&B4N6T+sVqF1 zY6Dcn8Q>G*`u`lmT_Br*fqTLJdLSj~>EaktaVsf7i9y1xgUO94VTOi;B!j{MhHHUL U57)k(BL`CK>FVdQ&MBb@0N86J{Qv*} delta 179 zcmeBSJi<6ZvYw5Bfnj0fJQpCvmgMd3!tfsi7wla=87RV8;1OBOz`!jG!i)^F=12eq z*-JcqUD@w(2@9ym{kHX(1r!SOba4#vIG&u6knrQYK|@1lV#C1|%x;lbbpLd$JpH^qZ|3Zl{{?_E;sbST__dkY38b Xp2s%1B)NtKXgY(ZtDnm{r-UW|x*9j5 diff --git a/Data/Sys/Resources/Flag_Germany@2x.png b/Data/Sys/Resources/Flag_Germany@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..cc4aa1714debc65a1d0929c77a77d0cf7cca5d45 GIT binary patch literal 156 zcmeAS@N?(olHy`uVBq!ia0vp^4nVBK!3-oHHTs8U}fi7AzZCsS>JiZ}y&LR|l!1F{(IGB79vioFH0G(BA$Ln>~)Ib+Dkz`((* yu(dwJ`OQs6#u>c54hk8ZdMW}OSxgI#a2qfj+{o=%Rrodnq~Fuk&t;ucLK6TwWh-_7 literal 0 HcmV?d00001 diff --git a/Data/Sys/Resources/Flag_Germany@4x.png b/Data/Sys/Resources/Flag_Germany@4x.png new file mode 100644 index 0000000000000000000000000000000000000000..ccb67794aa1bfa8b54e97e39b9c6d0c78e177df6 GIT binary patch literal 204 zcmeAS@N?(olHy`uVBq!ia0vp^4L}^h!3-q1dii$)DajJoh?3y^w370~qErUQl>DSr z1<%~X^wgl##FWaylc_d9MM42SA+Apu816AJ{J+8Q{~W_zpdbT7c2tQEkP7g0aSW-r z_2!&ABZGm!fd#KW>zSLHqy! literal 0 HcmV?d00001 diff --git a/Data/Sys/Resources/Flag_International.png b/Data/Sys/Resources/Flag_International.png new file mode 100644 index 0000000000000000000000000000000000000000..10ab085f5383b05bf1bafa82f6ba1f41d23ff377 GIT binary patch literal 496 zcmVy}klLEU>-+uwYNX*? zoZh|4+uhCuf$%XG%ukLlMPAO7{tf8u)}`d`n-73uKN94&z?hDX^c7GS zbk3q1HA2fOIC=%tO$ChU-Lz2>069Iy6X?jY@KrQOVbh&OeF4-Jxumf}Yo=Ds(qhY_ z#RH^hLG&ERDmS9LfIW&cz`BRqQ}x4{=6tQ*1ncn(Ok8uGiJF+?!_vndVm$+z8#v#VF8prCGdOS_rq*@stneQ-nrUEo`3D4PSxX{Algc$_ zC0xOQI+Dxa&c%^)^q|Ep}O{(@X6s2ypk=t{s;M1%Tb$l%rQy=#_GO~rl)mce@%xUt>D=o0%;5DgyfK1S`?%Rx3@EZ&L6v}Ob4y^$G)sN z=i8P_t63lJVW#?b=c)=X}-Nx6Y43K4gvs(2CJ05 zHe9^lc1uyUHol)_B7_50H#)i8SpvI83S|cV>MLT&Ia5X&{7x*Ie%huvS+kUI27{LD z>l-<}6B9rE;>^`eE#0V7=0q=jE&jgd)W{+cVpSE#L>Y2UXFW73F9bSr-l@~?`NHsoa9nYOeV{wS=iUHcm{MoI(>~r` k*wc@_{{a38;Fkac0B9N|pB}xAegFUf07*qoM6N<$g33R10RR91 literal 0 HcmV?d00001 diff --git a/Data/Sys/Resources/Flag_International@4x.png b/Data/Sys/Resources/Flag_International@4x.png new file mode 100644 index 0000000000000000000000000000000000000000..0bc6e4e884fff211b9e18ff1ed0fae153ccd1de1 GIT binary patch literal 1919 zcmV-_2Y~pAP){glGQI_1z;q`p5 zK56v3ZqsBYu^$`z}7#s+q zqXla@hcPi;+Whc|-EV<)ADc>y2?>`KB0|;hT`VqaLJtSrb=7CH`sr1?g#A0JQn#^)8h2IFkRN1_2 z(pdaj7Ay1c3o00RuIL1m2#M$pWoKAllL2|n01Je*jXlRJ3pgwSRG8j#u9yZe z4Rv!2;9H}aadC3dXds*B_W}4;=&W5TX!_(4!lEEde|Q&B1~wZKVXP&f_84*9!ZtvY zHv-7!D2SCujB^YF4ubbsqV7)(6kmKkV;$E~J`#^I^8$>6 zGpfa-t+xR%y!&yO!C1_GC<87k{w_mQs-gDRxlv5gB+0}H3iK4_+?I$&yUhZgENjEu zD^4^pVLA4Ut6m4i1kt{ZO|KI_1-n9pIK+a>S$6y*gBa+F^9BO$kdK#m@ z0Vw!ny1=>^8OFrCrmJ+{12E{)s`6&H&MD!9JXX84Hiv*n@MVixK6ZhpopX{oI?a~M zHv#k>&;+GvJ^~?oAw`Jsfy)LJ>CS3+0xaben!t{ijGZ($61n7?05A$mqOJ0n(FGG$ zU7eirTU%q>`$@lCpejZ}j##QuBHJ**YjOAzfWSsz4p)}NJVbgx!Bu+_G=NRyTZG#R zBD0Da3bO@YTlH<{w}oLFY}+$;7=nbH*X?#JIuMU|Nb~?kA%@_D3xn=Y2+<;K82=1u`WYM>y-VUpiicT z14GU&f#RndWz&c$z+>pg+UbNw0a0%fAzPs|IW3s*)w+BU!08jVV~Kir$PflKMe@wi zxq5ys#5Y^RZBa08N$jOz*J=5;=%h%TPZn=<+b|)hg@Wm6%$=8FFbc)qgSt_Kp%#IO zp!+GqSJ-)ML-^kQI%Wlx#j9WPnPWAC^F9$i6G6xp>kZd-;&~q~KU^lKe*gwh^y(7u z3PW@o8NIU{V>M`NX~GKQ31h}n>0uHcfNtSi6!g4I&dwb-Zn`u_8WzjkV&!RI7P%Z0})T_J0R{_%2Bq60KO$_YUI0VxG zIJ--0p~AIOtWleKjF^GQIM3w8&Ecz?Q+}0wMd%FJ45uj4b11>D5e+&5f0FR0fdE4w za&8;kyg5Yzlwn)OP57n_2Y(Gla9wQ6uh(kFf<5{yk7dWGSkIT|G;d5uPPcCJu)uH; zbih~y)WBmRfZODP?IJ9Aa+{ac)?b*AAOLQM$uSD723UMKPZgYqQMf|V_1?7w-0nys zn5}+eNX5~=QaoJI>$Ym#0+~Mt?ih>Or~~(~dw6kM`u>!RPwKlH7|_f_?`n_2#!<`b#Yt%?nXz=>j;xK- zK4_F)P-nbyp`ETtp6>6BO5X*@K75%vXq3csjYl%w%2$)H4Pl>tbyRzK;S`FlBQS@p zG5?xi?oBY_@#9$E9$LRYEq~@8w0u*4Jt<(=86D4r_=B1GkDnK0{qJhS`jLP7JwJb7 z@gH}~``-`n-|@`o1MmU(0DJ&G03U!4zz5*}0N`H&3;;g`xjGINZG8X$002ovPDHLk FV1oFKl868R literal 0 HcmV?d00001 diff --git a/Data/Sys/Resources/Flag_Italy.png b/Data/Sys/Resources/Flag_Italy.png index 9e87c615bfd14ad05cc13f19f7c963f239f24a5b..5840f9fb36a03d31843d335e1e9d774029477527 100644 GIT binary patch delta 124 zcmdnZ*vB|QvXq&Dfni#EUKx;*EOCt}3C>R|DNig)WpGT%PfAtr%uP&B4N6T+sVqF1 zY6Dcn8Q>G*`v3obhDmPcw9V~AEFS;`r9E97Ln>}1CAcuKStK|yv<0#*=4zY8)WE>Z Y@UMgEdV870G@vpDPgg&ebxsLQ0GFpHasU7T delta 170 zcmeBU+|4*avYw5Bfnj0fJQpCvmgMd3!tfsi7wla=87RV8;1OBOz`!jG!i)^F=12eq z*-JcqUD@w(2@9xNuT)w)2Pov>>EamTaXdLCA>qe)gNBCIMj%L>BpulG|M@!=ue+79 z+>5SA#@e1daKzw1!WG8Fd=jMxRxrEC8YsVN2xRZE0*du8-_>AcNHgNlzQ3jX6wpux MPgg&ebxsLQ0JX6>CIA2c diff --git a/Data/Sys/Resources/Flag_Italy@2x.png b/Data/Sys/Resources/Flag_Italy@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..39e18d95e84b85dc5c120352e2680a02932031a8 GIT binary patch literal 157 zcmeAS@N?(olHy`uVBq!ia0vp^4nVBK!3-oHHTs8U}fi7AzZCsS>JiZ}y&LR=Xpxt-HC|NsBL<(j!yfPz|{E{-7;x89s#DSr z1<%~X^wgl##FWaylc_d9MVtXXA+8LQ+|Fs6|NsBra?RW;KtW$m7srr_TW`)8GBPl5 zFfYjbeeSaefwW^{L9a%BKPWN%_+AW3auXJt}l zVPtu6$z?nM003Z6OjJew`uqIx^tb>btkgDO|uip&M=dEXWHg`S4x4VxS7=IWT7`RmA7^IQ|8KjZ| z85mhfGm;UK28m0AKcBv0xagb1@cH}=tn$1@nhg4zr!cTfi4vU%iFUxhA3qsRn@2Nz zxpWJ!I$i?}29py@7?{}EsGAF(OkYLNas~zlhR+vnFg%^Hn)-?G<+5!=8~S4THtIXz z>-Bp?8~XLyy?9|*4sdHJ6KyDuwleh{AQ|sRw4oAle$;n>R7wy7kDeMqb-V@|3{uH~ z)OP?AI~#++wrLE!h8nmnH_~L#-#V3niH(&uB_VoI{N?g(NSy1bkyR9vR1%K12ZpT! d7zesh3IMs=TL?GwF-HIZ002ovPDHLkV1hhBnZ^JB diff --git a/Data/Sys/Resources/Flag_Japan@2x.png b/Data/Sys/Resources/Flag_Japan@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..1c386afb55aca0bd792c8c21481a42237a21915d GIT binary patch literal 463 zcmV;=0WkiFP)%X555Ez8Vn}HMf2f$d%+k6-hg*DFkk9%1i0kl;J>NAL@ zxa9)X9U**2;j-lc!;0ZoK$SVbxUY|s0G$CeFZEIIk_~JSh+xYFE|vrW2qqxt`hX1+ zD3At}8F@fr1yK+zU^FTLV95domjrqiP`?XQJ_$@L;IgJZB5b@}Xj0qg1|Faj0JO}5 z)GhQHP;)QSL{0(LnG4L8y3XWXO7sKiUlyULLy&H1SA+ZdBCn}Ri$9MOx+%A1;^@;>3#~WVo&N_X@K>G!3;>b_MzZ?y8xsHk002ovPDHLk FV1g$3(Hj5& literal 0 HcmV?d00001 diff --git a/Data/Sys/Resources/Flag_Japan@4x.png b/Data/Sys/Resources/Flag_Japan@4x.png new file mode 100644 index 0000000000000000000000000000000000000000..b8664e957b4e962e95002d0f3e6d6da7c19d92bf GIT binary patch literal 736 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

73G1Ta^xr zc0hIOE^gi2;GBPb=Yo=ugq#HP>ppls=uZuKpPc7?&n?>EH*U5YfE$1tfd4tb&`94A zcBc9Om;@0=vaj%YABg5m1H={q0NK6(T<8vd(*RlY>8LH8sF;lINx-8By2neC0F(H` z_u)LSPnwGFj)NsQfbOx8GX+2dxClmh*+l#)5;_*|Ey1QEV6cKQW@0v@op6-P)6gTm zCD`-@AdGRi7;!WVgirb|L$@W28wQXF07C@Bm12*NKfD8d9SQq}0VD!ka2aDfV()-d z0f){v+7gh%WupKx0hI}y2Szd=E%TpsK)5z;2tX>}Di4gbAocHS7vZuU>>2`?R|ps~ zSOq?*gnSf$h}!_bY?)QS;e$gK2^c4nWCyUb2soH?jvZfITpW)%=Z1A8kV+^p1FR7N zsa^txpB-=VJYU2OeOnnD{h}hlz6=|Zo^Ue)=nEKjuJFZbv(u_PzwoRJA#F#=e{?Bf zKtqBGKuk|SWpss?MyIXFU(6})Zoit2Vi|P_DggI&1PqVy#im*-^3DhHG$`XrXirCY zZUQ4L0E4@igKu;YDh0e-;F}t)${)+JF_)26!aj&(J#0z1RG>MWpaZf@z|)mtQ@imO z-%BqZk>16#8(<%Z8d_87hs|E`5y8TNazG>fXlx{m?Zm-`r=eI(3@`MKj|iSWP!8!R zlk5S5vthD8OJ^f5&HpjJsn>X?%B1GVnpqQ$fNlY!`th69;?r&k<#BV1(p;fSz}J_!~n9Ue}d=xblgoV#{PquGwufC{JgzCx{D**oC zUI=ROh0iDFUfN2lHF8PyofQDLxNS86Ve8cEZMB=XL?HP&D*!%mrJB-#aJO_79us&^ z1VdS90N^{$yQ=5{;k7J2MnHWapAW7NpjF!HA_zBccg05*YT=^O8U-!yc}}{D%JQ=D*&eJq=Qd3(V#<~KD>2XEk4SEA3sah+<{j7|WY zmdpht3t5`?)l+K#?vz9(0P&~8>jLmRiggV|EUo^xY-PEYG7Au!$^eJ-7Y~_wKs@^@ z{m?#`2$%#2;uW>*f=?`2P@nETFEzI;pRzUZKHV<;-Ct+=eZYmJCz{C&*_8!@Mgj5# z6q=k=$c_i!aC!vdFL&eu@VP{CBQl>h1dv`Nq1O}=rgbEU+_fXK}X5R8N6c4#8O(M6zbK@?^2F9py%NC3Ny2_Qj2+sYae z;JuR8a8N&cqbQ@cfJ`zMMR#I4qOnCu=to)-;KPt=Cvf#Av+@h~vXPDeKl&PHJEFl| zP@bisD=HFTWBPraQ-lw#cON&-!V!PcLj_=rNPsa3T^$K)Y7)>cX*$H!FH2Gsxw;to zXHW6UCVC%z+wJ7R0BaQtUP*A-pqd0cPQSesdM|RgmEJ#@{-~TsGURLo1}CrpjIkJF z9tRTisaXpFu&J0z+ zK5(Ilz_XztKog){g!r6Py%O|VdkCVh?qFpgqAoytE}%u2)*O!X8Ws@WBdNC!12!12 zyA95USi%Gx$LTmvj*lZoUZf|eb5i^1{6^Vfd^(nfo}`7z{t9`II)6#I{o3cGz19Om zozROFRG3CyAgA1M5Rc_3#uCtcVbps?G($p@p2)(4u@r!N13@aFk;fQ5GfOgw1YqXn z^-f1Xe9zRH@Jd42)W1>We3455L6ggJA|W>GH}m}Dpw-{V^%kH5(3a3oqlIXCV}c}@ z{O^gY5jhS(u#c^ozrW|lV!Z literal 0 HcmV?d00001 diff --git a/Data/Sys/Resources/Flag_Netherlands.png b/Data/Sys/Resources/Flag_Netherlands.png index 4f5cd1ab16ee20a9ffca9775fdc03653f5addeed..7c4719d5665e77afa8e6fa060bdcd0d2685ac265 100644 GIT binary patch delta 122 zcmcb{*uywMvY45Hfni#EUKx;*EOCt}3C>R|DNig)WpGT%PfAtr%uP&B4N6T+sVqF1 zY6Dcn8Q>G*s_53ePDbPZ|Nj$A7R~|b^mK6yskoJtpu!;0*3P8Hl(0lYLXtt@0K8U}fi7AzZCsS>JiZ}y&LR=Nyy4T5Q{Qv)dg2}=;KtU}}7srr_TW`)d3NkRT zFc^H{*Ja^i^0>?&t;ucLK6To C9WMg_ literal 0 HcmV?d00001 diff --git a/Data/Sys/Resources/Flag_Netherlands@4x.png b/Data/Sys/Resources/Flag_Netherlands@4x.png new file mode 100644 index 0000000000000000000000000000000000000000..e808f7e6931ddb37e652b6e05e493246fc1b41e9 GIT binary patch literal 179 zcmeAS@N?(olHy`uVBq!ia0vp^4L}^h!3-q1dii$)DajJoh?3y^w370~qErUQl>DSr z1<%~X^wgl##FWaylc_d9MVtXXA+CyU-RopD{{R0!!DQhaprC`Ni(^Q|tvBZk85tNj zm=|RJzi{k^qKZPW7$Y)h)D;#$0USWR@8>cwGcZ2aZTz>_Ndm}c@O1TaS?83{1ONqr BEvf(j literal 0 HcmV?d00001 diff --git a/Data/Sys/Resources/Flag_Russia.png b/Data/Sys/Resources/Flag_Russia.png index b6e926a982f5da674891f3d84b31d0a4a34e6755..1c1b1985ab597a4525b8c82622350b6876257c6d 100644 GIT binary patch delta 122 zcmX@f*uywMvY45Hfni#EUKx;*EOCt}3C>R|DNig)WpGT%PfAtr%uP&B4N6T+sVqF1 zY6Dcn8Q>G*`v3p`tJ-o5mdm(ZCdz|!db&7B bdodQT<~=sy)WK;$D;PXo{an^LB{Ts57T`fa diff --git a/Data/Sys/Resources/Flag_Russia@2x.png b/Data/Sys/Resources/Flag_Russia@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..00c07d7cd4045163d83ebf01ebf09ff355ba91b8 GIT binary patch literal 156 zcmeAS@N?(olHy`uVBq!ia0vp^4nVBK!3-oHHTs8U}fi7AzZCsS>JiZ}y&LR_zE%Q09k`~UxcSK~QJprEFwi(^Q|tv6>385tNj zm=(6xXE?vP$;dc^yVpS>gVRh!fFp}(!4Yl)2Chroj&G`#YXCJdc)I$ztaD0e0s!<^ BEx7;y literal 0 HcmV?d00001 diff --git a/Data/Sys/Resources/Flag_Russia@4x.png b/Data/Sys/Resources/Flag_Russia@4x.png new file mode 100644 index 0000000000000000000000000000000000000000..f462e3e001865df310ece07d57a59e58f782f931 GIT binary patch literal 178 zcmeAS@N?(olHy`uVBq!ia0vp^4L}^h!3-q1dii$)DajJoh?3y^w370~qErUQl>DSr z1<%~X^wgl##FWaylc_d9MVtXXA+G=b|G%m&$6&dP+hw9WP|)7f#WAGf)|+#Nj0_AM z2Nbr}XC%LAWH|$ra(J7>gaT?4l2Q0f`Ue<_kLonOzb2RoRL|h)>gTe~DWM4f(~2#> literal 0 HcmV?d00001 diff --git a/Data/Sys/Resources/Flag_Spain.png b/Data/Sys/Resources/Flag_Spain.png index 1a89e7a198336512367c0a2e3e3280df6837a2d7..47b4d4250d931feca4932dcd1090b2b2d03992e6 100644 GIT binary patch delta 419 zcmV;U0bKr@1F{2<8Gi!+005SUZgv0w02y>eSaefwW^{L9a%BKPWN%_+AW3auXJt}l zVPtu6$z?nM006*HOjJd~cLchqGnO+8=(!BzrW^mp0IOtZsa6aB%K`bs1+iEYky8%& z!2z3M63nL>zj+eZuol9jA;^S5y_c%lu0*|aI`Oyw)~Q_0v40`dkq5(D3FEB**s&kl zw;9%&ImL}j+`V7QrGxv%1EyXxxp7Czf;8KhBYQU{ZbcbQN?@!_39U*N$%ziDTouV@ z0Pw&G#;z=`rbg9|AFX+Hl13b#T@>D_0LYJ0;iL!XtpL!g5z4Sa#R(q93?Bc)0LBX* zJ9(tz0001pNqDMgP{yAH%J)p$XK)RFv{W%D4Zc_O8_v~5F7w>NDlx31^}ujo)PRBX50V( N002ovPDHLkV1iOitn>f? delta 396 zcmV;70dxMc1DgYo8Gi-<005y`oM%C z;~c*83&3D83ZUaPtqk7{2S_X@1F#Mt0AnsK4d4I82F5{wQBX`r!=Dl_96A?e=CcS8 zJo+W}4&KSDIDLSpUXCPAP&#DjNnD^o%&?yTlFgP*7ogOrGmjO+vw*xXl#WioD?sHK zDK#)i*MjL?jekkE%5=@)#jWwyA0Z-_$&JtWb}9W66v__9aaf6ROp*rA-E-=_Q diff --git a/Data/Sys/Resources/Flag_Spain@2x.png b/Data/Sys/Resources/Flag_Spain@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..ebb37e2704c1e031b6dbd7abd3f0bf305240be17 GIT binary patch literal 852 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 N002ovPDHLkV1jR(w1WTu literal 0 HcmV?d00001 diff --git a/Data/Sys/Resources/Flag_Taiwan@4x.png b/Data/Sys/Resources/Flag_Taiwan@4x.png new file mode 100644 index 0000000000000000000000000000000000000000..54ea7d555b51d78273abd181d50a3378df78c2f6 GIT binary patch literal 805 zcmV+=1KRwFP)TS-JgRCwC#n8}i(Fbsyl7%;1W z1}xc$`u*Q>g8XR6vdBo%VdXY1EScKuts-0l5I%M!qU4uCHPKw(}4fcK+g zCh$);5flL3jR191g8vQ9U{nAYYG99`DDwayG8_2@B;`y1HC2|s#9BjSfUfcc-Ap6_ zL{B0zfImAEIP#zDe|eNZFaY$yze35rmCm<8>51-2K*R_DD1`w))U=dNY{Q_O*l7Ud zhf>)H0D7N_jk9pjWkuflT5l4xs>eljF+yNkqNY-i(T6S4?khh$DlwP{(e6Z*+3Cwx z$(o!_nGh}uJb@VKyN!10&zTr74bkShKLC&_A1XmG4Y1yAS04S-4%X*EcmS>fZYvg* zp8zU7wu7($fdNnyi}xpr6F}p9PWF5GRT9J8fKzq5{sv%m3%ymvCT;K#0N0#CoI@}g zc78pmAYdA@3dISau)aRWN<)yd9*+RB$N^*30gw|7$15mwLuZ0u0Ny_z`FkmB&3u~- zVzgtPzZ&Z2TtfL-3=5;TjMK9|5CoeC+CphAIIYt4*wEXO3AYQc%VFN4%mZHUek!G1 zc1}8D>Xpy#bA$hj(hF{Z*nI!z+sJYs{}vwClfXl1M%;f{`&0sV=T&3mvE1}4_g~n# z380@3ROGR|6W%{BNHn9L585m;0BpA-vlMSD5t`gYUQ8_BBQf3Y9xpcbdj7E>x!0`c zpQbNA{1wfQcuRJ9(w+wBp0Ixc@cv>;00|%gB!C2v01`j~NB{{S0VIF~kN^@u0!RP} jAOR$R1n_czUjhsO`8pwn7PKzX00000NkvXXu0mjfjdo)> literal 0 HcmV?d00001 diff --git a/Data/Sys/Resources/Flag_USA.png b/Data/Sys/Resources/Flag_USA.png index 6e438c4b022b705e7261d00959dd154df7d5620c..a5fa17ad076cad4c0d16c1af6384b7a3c9ceec8f 100644 GIT binary patch delta 522 zcmV+l0`>j=1egSn8Gi!+005SUZgv0w02y>eSaefwW^{L9a%BKPWN%_+AW3auXJt}l zVPtu6$z?nM006*HOjJcRG--i=p;lFa+n1j@Ic@#_|0^nDmX@(oQh#A!iIS17Sy_aR zjjPajgT6&nWn_$fe4fc;a56DxiixOtd7UODUR_*=tPv!z9e*!NN_ls7nuUa&a8FKrSXY8xU5AH;rZ_iiWMho47Ag1Y>+saqJUebwQ-Fkn zqfASB`0MOIKXLKZ*f1|;a&eYvXph~Vrrw^W?#Dc#< zPH*de?py}ZIlkLyE+5dhs625kLuuxZW@N0XVQ&K43V)K_?*0@6aeOokTaS^TapGm^S%wbKezrqM6qE-@P1%F-=hz~TeQX|}ZUb|y) zkjnBT$HXls+5BeaoBhoSptN{=fQuJah~to=wD_LET8D@rMsQX!o}nr&LFkcZ1OHGcyw;X-rvEctL=3iin~rD2itcW$73n59xM0 zJUz46>XTik|d@q zD}3Kzoy8afDpZvv2mP3y)IDC zoxQ>A>?BE&P!uJ8V6avZ6fuUfup~*yV34!D{gIci9ya_6PIpMtgyAqJ2m;E&;(3A? zLsdGW*lFkRFee>}>2^E3zH+Tu1l8w#z8?khzj*WT$clda37lxoiUm;BcGkf$f;Y>z z+g(P#c0aV1z`udu-JQGbBKWqp@t-5uy7#DE1iPzG+C|Xjr}Q^WoYBb5yMVj^0000< KMNUMnLSTY)H5-`# diff --git a/Data/Sys/Resources/Flag_USA@2x.png b/Data/Sys/Resources/Flag_USA@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..57d26f17f07f4eb8dbf3fe91d05f80d6f41aba7e GIT binary patch literal 940 zcmV;d15^BoP)NYiLT3LltQGa`TojyHpu^%zf(cQBoHdR%D?(XtzYm(%# zw=ywjv=%6>tisumn)~+m@z>jNahCV?`IC~b_2cDrbeQSC#5gx=@$&UFGiWq7Y)?*n zIXP`!U57I=XLxs;fPbJ#NO<0$sI@CRyFE-mKXFG!c41(N&U1eJ_V>h9W5iZtygg0M zaec5HFR~&uuNf<@7AgP#|A?PDm;e9*f=NU{RCwCVmSJ<#Fbsy3;3iJ0B&Kx58xTtI z)HqH9IAJix*#G}ms4ctO@xg)1mpvbJIxEpN();=fV9){p8V>f98idD#W9?@cfOS0Z zYhBIH_i@QlRtmt!Bb;kf4Jf`S(5O{p4atj+5U=t9F!a9c z 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 diff --git a/Data/Sys/Resources/Flag_Unknown@2x.png b/Data/Sys/Resources/Flag_Unknown@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..a450f2a4a91332ed48dab588db711a5d6a6aa7fe GIT binary patch literal 312 zcmV-80muG{P)QN3MQ(0xZ*OmHZEb&le`aQ8fPjE_ z!F6~5006v6L_t(|+U(Xr5`!QRMA6oX_rG$IRbc3z9?M+{md5`o2$bS_IIw|#1LAo7 z#u?*nf#D~F`Ug_beVT$0iatLBDpdXQ5Q$Ls>nbcl-IHZZg6Y{lm<7|*jWh|S=R1)L zv=>{M3A|TlVHHF#4^tLYuTSGF$i4u^^-E{7H3iI5IB!lN_gX-+mjb%I643620Mp|z z0!$xa1epGFr50d&Bf$5yfUEQVCmxx6>VE%(GT7Yz)6(HUx z1<3a~0bb}+0=&^@1bC%S2w?W>(-gq$1Ev6GU;a;(dObhC|9Jw~eNzCx?+Fm-TLL8d zjsTIqAwZ_D3lQ7?Q1@7J`!AXR!TlF)mnXXaBM6Y(|B?2Yl6^(6JEsd+zycPqfCVhz bM}PqUzwY?44pveE00000NkvXXu0mjfLJP~& literal 0 HcmV?d00001 From 08516ee09ea357d4363ce17b7e9b1611107c094a Mon Sep 17 00:00:00 2001 From: sigmabeta Date: Fri, 10 Jul 2015 18:58:54 -0400 Subject: [PATCH 079/583] Android: Add detailed instructions for setting up a build environment --- AndroidSetup.md | 68 +++++++++++++++++++++++++++++++++++++++++++++++++ Readme.md | 42 +++++++++++++++++------------- 2 files changed, 93 insertions(+), 17 deletions(-) create mode 100644 AndroidSetup.md diff --git a/AndroidSetup.md b/AndroidSetup.md new file mode 100644 index 0000000000..5dfa85d5a9 --- /dev/null +++ b/AndroidSetup.md @@ -0,0 +1,68 @@ +# How to Set Up an Android Development Environment + +If you'd like to contribute to the Android project, but do not currently have a development environment setup, follow the instructions in this guide. + +## Prerequisites + +* A Linux VM or host, or a Mac. +* JDK 7 for your platform. +* CMake +* [Android NDK](https://developer.android.com/tools/sdk/ndk/index.html) +* [Android Studio](http://developer.android.com/tools/studio/index.html) **OR** +* [Android SDK Tools](http://developer.android.com/sdk/index.html#Other) (for command-line usage) + +If you downloaded Android Studio, extract it and then see [Setting up Android Studio](#setting-up-android-studio). + +If you instead chose to download the commoand-line SDK tools, see [Setting up the SDK Tools](#setting-up-the-sdk-tools). + +## Setting up Android Studio + +1. Launch Android Studio, which will start a first-launch wizard. +2. Choose a custom installation. +3. If offered a choice of themes, select your preference. +4. When offered a choice of components, uncheck the "Android Virtual Device" option. ![Android Studio Components][components] +5. Accept all licenses, and click Finish. Android Studio will download the SDK Tools package automatically. (Ubuntu users, if you get an error running the `mksdcard` tool, make sure the `lib32stdc++6` package is installed.) +6. At the Android Studio welcome screen, click "Configure", then "SDK Manager". +7. Use the SDK Manager to get necessary dependencies, as described in [Getting Dependencies](#getting-dependencies). +8. When done, follow the steps in [Readme.md](Readme.md#installation-on-android) to compile and deploy the application. + +## Setting up the SDK Tools + +1. In `Source/Android`, create a file called `local.properties`. +2. Add a single line: `sdk.dir=`, where `` is the path where you extracted the SDK Tools package. +3. Follow the steps in [Readme.md](Readme.md#installation-on-android) to compile and deploy the application. + +## Executing Gradle Tasks + +In Android Studio, you can find a list of possible Gradle tasks in a tray at the top right of the screen: + +![Gradle Tasks][gradle] + +Double clicking any of these tasks will execute it, and also add it to a short list in the main toolbar: + +![Gradle Task Shortcuts][shortcut] + +Clicking the green triangle next to this list will execute the currently selected task. + +For command-line users, any task may be executed with `Source/Android/gradlew `. + +## Getting Dependencies + +Most dependencies for the Android project are supplied by Gradle automatically. However, Android platform libraries (and a few Google-supplied supplementary libraries) must be downloaded through the Android package manager. + +1. Launch the Android SDK Manager from the commandline by executing `/tools/android`, or by clicking on its icon in Android Studio's main toolbar: +![Android Studio Package Icon][package-icon] +2. At the bottom of the window, click "Deselect All", and then "Updates". +3. Install or update the following packages: + +* SDK Platform, under "Android 5.0.1 (API 21)". This will allow compiling apps that target Lollipop. +* Android Support Repository +* Android Support Library +* Google Repository + +In the future, if the project targets a newer version of Android, or use newer versions of the tools/build-tools packages, it will be necessary to use this tool to download updates. + +[components]: http://i.imgur.com/Oo1Fs93.png +[package-icon]: http://i.imgur.com/NUpkAH8.png +[gradle]: http://i.imgur.com/dXIH6o3.png +[shortcut]: http://i.imgur.com/eCWP4Yy.png \ No newline at end of file diff --git a/Readme.md b/Readme.md index 81fe9a38c4..78323e06ef 100644 --- a/Readme.md +++ b/Readme.md @@ -50,29 +50,37 @@ On OS X, an application bundle will be created in `./Binaries`. On Linux, it's strongly recommended to perform a global installation via `sudo make install`. ## Installation on Android -Dolphin requires [Android Studio](http://developer.android.com/tools/studio/index.html) to build -the Android UI. Import the Gradle project located in `./Source/Android`, and then execute the -Gradle task `assembleDebug` to build, or `installDebug` to install the UI onto a connected device. -In order to launch the app, you must build and include the native Dolphin libraries into the UI project. -(Building native code requires the [Android NDK](https://developer.android.com/tools/sdk/ndk/index.html).) -Android Studio will do this for you if you create `Source/Android/build.properties`, and place the -following inside: +These instructions assume familiarity with Android development. If you do not have an +Android dev environment set up, see [AndroidSetup.md](AndroidSetup.md). + +If using Android Studio, import the Gradle project located in `./Source/Android`. + +Android apps are compiled using a build system called Gradle. Dolphin's native component, +however, is compiled using CMake. The Gradle script will attempt to run a CMake build +automatically while building the Java code, if you create the file `Source/Android/build.properties`, +and place the following inside: ``` -makeArgs= +# Specifies arguments for the 'make' command. Can be blank. +makeArgs= + +# The path to your machine's Git executable. Will autodetect if blank. +gitPath= + +# The path to the extracted NDK package. Will autodetect if blank. +ndkPath= + +# The path to the CMake executable. Will autodetect if blank. +cmakePath= ``` -Replace `` with any arguments you want to pass to `make`. If you need to use a specific -version of git, cmake, or the NDK, you can also add `gitPath=`, `cmakePath=` or -`ndkPath=`, replacing `` with the actual paths. Otherwise, these will be found -automatically. Then execute the `assembleDebug` or `installDebug` task corresponding to the -hardware platform you are targeting. For example, to deploy to a Nexus 9, which runs the AArch64 -architecture, execute `installArm_64Debug`. A list of available tasks can be found in Android -Studio in the Gradle tray, located at the top-right corner of the IDE by default. +If you prefer, you can run the CMake step manually, and it will copy the resulting +binary into the correct location for inclusion in the Android APK. -The native libraries will be compiled, and copied into `./Source/Android/app/libs`. Android Studio -and Gradle will include any libraries in that folder into the APK at build time. +Execute the Gradle task `assembleArm_64Debug` to build, or `installArm_64Debug` to +install the application onto a connected device. If other ABIs are eventually supported, +execute the tasks corresponding to the desired ABI. ## Uninstalling When Dolphin has been installed with the NSIS installer, you can uninstall From b3471e0abce3b407654a2398c55c8a8c7567ab3e Mon Sep 17 00:00:00 2001 From: "Admiral H. Curtiss" Date: Sun, 12 Jul 2015 04:09:23 +0200 Subject: [PATCH 080/583] DolphinWX: Add options to Load Last Slot 9/10 to menu. --- Source/Core/DolphinWX/Frame.cpp | 2 +- Source/Core/DolphinWX/FrameTools.cpp | 2 ++ Source/Core/DolphinWX/Globals.h | 2 ++ 3 files changed, 5 insertions(+), 1 deletion(-) diff --git a/Source/Core/DolphinWX/Frame.cpp b/Source/Core/DolphinWX/Frame.cpp index 759c2bdc6e..dc4c3e6808 100644 --- a/Source/Core/DolphinWX/Frame.cpp +++ b/Source/Core/DolphinWX/Frame.cpp @@ -308,7 +308,7 @@ EVT_MENU(IDM_SAVE_SELECTED_SLOT, CFrame::OnSaveCurrentSlot) EVT_MENU(IDM_LOAD_SELECTED_SLOT, CFrame::OnLoadCurrentSlot) EVT_MENU_RANGE(IDM_LOAD_SLOT_1, IDM_LOAD_SLOT_10, CFrame::OnLoadState) -EVT_MENU_RANGE(IDM_LOAD_LAST_1, IDM_LOAD_LAST_8, CFrame::OnLoadLastState) +EVT_MENU_RANGE(IDM_LOAD_LAST_1, IDM_LOAD_LAST_10, CFrame::OnLoadLastState) EVT_MENU_RANGE(IDM_SAVE_SLOT_1, IDM_SAVE_SLOT_10, CFrame::OnSaveState) EVT_MENU_RANGE(IDM_SELECT_SLOT_1, IDM_SELECT_SLOT_10, CFrame::OnSelectSlot) EVT_MENU_RANGE(IDM_FRAME_SKIP_0, IDM_FRAME_SKIP_9, CFrame::OnFrameSkip) diff --git a/Source/Core/DolphinWX/FrameTools.cpp b/Source/Core/DolphinWX/FrameTools.cpp index ee726e79af..c7074df4c3 100644 --- a/Source/Core/DolphinWX/FrameTools.cpp +++ b/Source/Core/DolphinWX/FrameTools.cpp @@ -489,6 +489,8 @@ wxString CFrame::GetMenuLabel(int Id) case HK_LOAD_LAST_STATE_6: case HK_LOAD_LAST_STATE_7: case HK_LOAD_LAST_STATE_8: + case HK_LOAD_LAST_STATE_9: + case HK_LOAD_LAST_STATE_10: Label = wxString::Format(_("Last %i"), Id - HK_LOAD_LAST_STATE_1 + 1); break; diff --git a/Source/Core/DolphinWX/Globals.h b/Source/Core/DolphinWX/Globals.h index 2b327b0fad..eb96117ecc 100644 --- a/Source/Core/DolphinWX/Globals.h +++ b/Source/Core/DolphinWX/Globals.h @@ -60,6 +60,8 @@ enum IDM_LOAD_LAST_6, IDM_LOAD_LAST_7, IDM_LOAD_LAST_8, + IDM_LOAD_LAST_9, + IDM_LOAD_LAST_10, IDM_SELECT_SLOT_1, IDM_SELECT_SLOT_2, IDM_SELECT_SLOT_3, From 878629a2bf7a4626733f974f5c4c5b595057482b Mon Sep 17 00:00:00 2001 From: "Admiral H. Curtiss" Date: Sun, 12 Jul 2015 05:16:42 +0200 Subject: [PATCH 081/583] DolphinWX: GetCmdForHotkey() should have Load Last Slot 9/10 as well. --- Source/Core/DolphinWX/Frame.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Source/Core/DolphinWX/Frame.cpp b/Source/Core/DolphinWX/Frame.cpp index dc4c3e6808..b9df32bd0d 100644 --- a/Source/Core/DolphinWX/Frame.cpp +++ b/Source/Core/DolphinWX/Frame.cpp @@ -988,6 +988,8 @@ int GetCmdForHotkey(unsigned int key) case HK_LOAD_LAST_STATE_6: return IDM_LOAD_LAST_6; case HK_LOAD_LAST_STATE_7: return IDM_LOAD_LAST_7; case HK_LOAD_LAST_STATE_8: return IDM_LOAD_LAST_8; + case HK_LOAD_LAST_STATE_9: return IDM_LOAD_LAST_9; + case HK_LOAD_LAST_STATE_10: return IDM_LOAD_LAST_10; case HK_SAVE_FIRST_STATE: return IDM_SAVE_FIRST_STATE; case HK_UNDO_LOAD_STATE: return IDM_UNDO_LOAD_STATE; From 5c0033e6d98bacda85ea16f07616d8e754644903 Mon Sep 17 00:00:00 2001 From: "Admiral H. Curtiss" Date: Sun, 12 Jul 2015 05:18:54 +0200 Subject: [PATCH 082/583] DolphinWX: ParseHotkeys() should use the State::NUM_STATES constant instead of a hardcoded 10. --- Source/Core/DolphinWX/Frame.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/Core/DolphinWX/Frame.cpp b/Source/Core/DolphinWX/Frame.cpp index b9df32bd0d..5c187b07ce 100644 --- a/Source/Core/DolphinWX/Frame.cpp +++ b/Source/Core/DolphinWX/Frame.cpp @@ -1442,7 +1442,7 @@ void CFrame::ParseHotkeys() VertexShaderManager::ResetView(); // Savestates - for (int i = 0; i < 10; i++) + for (int i = 0; i < State::NUM_STATES; i++) { if (IsHotkey(HK_LOAD_STATE_SLOT_1 + i)) State::Load(1 + i); From 2eb553fdb72d5605c3f17324580859127a93d674 Mon Sep 17 00:00:00 2001 From: Jeffrey Pfau Date: Wed, 10 Jun 2015 22:15:11 -0700 Subject: [PATCH 083/583] Fix FreeBSD build --- Source/Core/Common/FileUtil.cpp | 2 +- Source/Core/Common/MemoryUtil.cpp | 8 ++++++-- Source/Core/Common/Thread.cpp | 10 ++++++++-- Source/Core/Core/HW/EXI_DeviceEthernet.h | 2 +- Source/Core/Core/IPC_HLE/WII_Socket.h | 2 +- Source/Core/DolphinWX/CMakeLists.txt | 6 +++++- Source/Core/VideoBackends/OGL/CMakeLists.txt | 4 +++- Source/Core/VideoCommon/DriverDetails.cpp | 2 ++ Source/Core/VideoCommon/DriverDetails.h | 1 + 9 files changed, 28 insertions(+), 9 deletions(-) diff --git a/Source/Core/Common/FileUtil.cpp b/Source/Core/Common/FileUtil.cpp index 925e3f1ed3..4709c011b2 100644 --- a/Source/Core/Common/FileUtil.cpp +++ b/Source/Core/Common/FileUtil.cpp @@ -42,7 +42,7 @@ #define S_ISDIR(m) (((m)&S_IFMT) == S_IFDIR) #endif -#ifdef BSD4_4 +#if defined BSD4_4 || defined __FreeBSD__ #define stat64 stat #define fstat64 fstat #endif diff --git a/Source/Core/Common/MemoryUtil.cpp b/Source/Core/Common/MemoryUtil.cpp index 510b258b09..c2befe56a6 100644 --- a/Source/Core/Common/MemoryUtil.cpp +++ b/Source/Core/Common/MemoryUtil.cpp @@ -20,7 +20,7 @@ #include #include #include -#ifdef __APPLE__ +#if defined __APPLE__ || defined __FreeBSD__ #include #else #include @@ -256,11 +256,15 @@ size_t MemPhysical() memInfo.dwLength = sizeof(MEMORYSTATUSEX); GlobalMemoryStatusEx(&memInfo); return memInfo.ullTotalPhys; -#elif defined(__APPLE__) +#elif defined __APPLE__ || defined __FreeBSD__ int mib[2]; size_t physical_memory; mib[0] = CTL_HW; +#ifdef __APPLE__ mib[1] = HW_MEMSIZE; +#elif defined __FreeBSD__ + mib[1] = HW_REALMEM; +#endif size_t length = sizeof(size_t); sysctl(mib, 2, &physical_memory, &length, NULL, 0); return physical_memory; diff --git a/Source/Core/Common/Thread.cpp b/Source/Core/Common/Thread.cpp index fb091ee2a7..1e60fbb29f 100644 --- a/Source/Core/Common/Thread.cpp +++ b/Source/Core/Common/Thread.cpp @@ -8,7 +8,7 @@ #ifdef __APPLE__ #include -#elif defined BSD4_4 +#elif defined BSD4_4 || defined __FreeBSD__ #include #endif @@ -94,8 +94,12 @@ void SetThreadAffinity(std::thread::native_handle_type thread, u32 mask) #ifdef __APPLE__ thread_policy_set(pthread_mach_thread_np(thread), THREAD_AFFINITY_POLICY, (integer_t *)&mask, 1); -#elif (defined __linux__ || defined BSD4_4) && !(defined ANDROID) +#elif (defined __linux__ || defined BSD4_4 || defined __FreeBSD__) && !(defined ANDROID) +#ifdef __FreeBSD__ + cpuset_t cpu_set; +#else cpu_set_t cpu_set; +#endif CPU_ZERO(&cpu_set); for (int i = 0; i != sizeof(mask) * 8; ++i) @@ -125,6 +129,8 @@ void SetCurrentThreadName(const char* szThreadName) { #ifdef __APPLE__ pthread_setname_np(szThreadName); +#elif defined __FreeBSD__ + pthread_set_name_np(pthread_self(), szThreadName); #else pthread_setname_np(pthread_self(), szThreadName); #endif diff --git a/Source/Core/Core/HW/EXI_DeviceEthernet.h b/Source/Core/Core/HW/EXI_DeviceEthernet.h index db5e92bc43..465bf40893 100644 --- a/Source/Core/Core/HW/EXI_DeviceEthernet.h +++ b/Source/Core/Core/HW/EXI_DeviceEthernet.h @@ -327,7 +327,7 @@ public: DWORD mMtu; OVERLAPPED mReadOverlapped; static VOID CALLBACK ReadWaitCallback(PVOID lpParameter, BOOLEAN TimerFired); -#elif defined(__linux__) || defined(__APPLE__) +#elif defined(__linux__) || defined(__APPLE__) || defined(__FreeBSD__) int fd; std::thread readThread; std::atomic readEnabled; diff --git a/Source/Core/Core/IPC_HLE/WII_Socket.h b/Source/Core/Core/IPC_HLE/WII_Socket.h index a38d1bb60d..edbb6ee60d 100644 --- a/Source/Core/Core/IPC_HLE/WII_Socket.h +++ b/Source/Core/Core/IPC_HLE/WII_Socket.h @@ -15,7 +15,7 @@ typedef pollfd pollfd_t; #define MALLOC(x) HeapAlloc(GetProcessHeap(), 0, (x)) #define FREE(x) HeapFree(GetProcessHeap(), 0, (x)) -#elif defined(__linux__) or defined(__APPLE__) +#elif defined(__linux__) or defined(__APPLE__) or defined(__FreeBSD__) #include #include #include diff --git a/Source/Core/DolphinWX/CMakeLists.txt b/Source/Core/DolphinWX/CMakeLists.txt index f378716dd2..d9cdb9bd9b 100644 --- a/Source/Core/DolphinWX/CMakeLists.txt +++ b/Source/Core/DolphinWX/CMakeLists.txt @@ -64,7 +64,11 @@ if(USE_X11) set(NOGUI_SRCS ${NOGUI_SRCS} X11Utils.cpp) endif() -set(WXLIBS ${wxWidgets_LIBRARIES} dl) +set(WXLIBS ${wxWidgets_LIBRARIES}) + +if(NOT CMAKE_SYSTEM_NAME MATCHES FreeBSD) + set(WXLIBS ${WXLIBS} dl) +endif() list(APPEND LIBS core uicommon) diff --git a/Source/Core/VideoBackends/OGL/CMakeLists.txt b/Source/Core/VideoBackends/OGL/CMakeLists.txt index 85964a3185..b4ece69de1 100644 --- a/Source/Core/VideoBackends/OGL/CMakeLists.txt +++ b/Source/Core/VideoBackends/OGL/CMakeLists.txt @@ -45,8 +45,10 @@ set(LIBS ${LIBS} videocommon SOIL common - dl ${X11_LIBRARIES}) +if(NOT CMAKE_SYSTEM_NAME MATCHES FreeBSD) + set(LIBS ${LIBS} dl) +endif() if(USE_EGL) set(LIBS ${LIBS} EGL) endif() diff --git a/Source/Core/VideoCommon/DriverDetails.cpp b/Source/Core/VideoCommon/DriverDetails.cpp index aa2e34d184..d3b1883cb3 100644 --- a/Source/Core/VideoCommon/DriverDetails.cpp +++ b/Source/Core/VideoCommon/DriverDetails.cpp @@ -30,6 +30,8 @@ namespace DriverDetails const u32 m_os = OS_ALL | OS_OSX; #elif __linux__ const u32 m_os = OS_ALL | OS_LINUX; +#elif __FreeBSD__ + const u32 m_os = OS_ALL | OS_FREEBSD; #endif static Vendor m_vendor = VENDOR_UNKNOWN; diff --git a/Source/Core/VideoCommon/DriverDetails.h b/Source/Core/VideoCommon/DriverDetails.h index 86fc2b04b6..cdc5026dc2 100644 --- a/Source/Core/VideoCommon/DriverDetails.h +++ b/Source/Core/VideoCommon/DriverDetails.h @@ -14,6 +14,7 @@ namespace DriverDetails OS_LINUX = (1 << 2), OS_OSX = (1 << 3), OS_ANDROID = (1 << 4), + OS_FREEBSD = (1 << 5), }; // Enum of known vendors // Tegra and Nvidia are separated out due to such substantial differences From a6437f629c68169983bf61c2188b743937f19ff3 Mon Sep 17 00:00:00 2001 From: Jeffrey Pfau Date: Thu, 11 Jun 2015 00:44:37 -0700 Subject: [PATCH 084/583] Common: Use more portable invocation of shm_open --- Source/Core/Common/MemArena.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/Core/Common/MemArena.cpp b/Source/Core/Common/MemArena.cpp index 291a23ed1f..31ed7f9c8f 100644 --- a/Source/Core/Common/MemArena.cpp +++ b/Source/Core/Common/MemArena.cpp @@ -63,7 +63,7 @@ void MemArena::GrabSHMSegment(size_t size) #else for (int i = 0; i < 10000; i++) { - std::string file_name = StringFromFormat("dolphinmem.%d", i); + std::string file_name = StringFromFormat("/dolphinmem.%d", i); fd = shm_open(file_name.c_str(), O_RDWR | O_CREAT | O_EXCL, 0600); if (fd != -1) { From fff113b64ffbb673d803d18c28f833c7d2b6c02d Mon Sep 17 00:00:00 2001 From: Jeffrey Pfau Date: Thu, 11 Jun 2015 23:34:16 -0700 Subject: [PATCH 085/583] Fix 64-bit FreeBSD build --- CMakeLists.txt | 1 + Source/Core/Core/MemTools.cpp | 7 +++++++ 2 files changed, 8 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 789060e8a6..98d4a7bec3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -160,6 +160,7 @@ endif() if(NOT ENABLE_GENERIC) if(${CMAKE_SYSTEM_PROCESSOR} MATCHES "^x86" OR ${CMAKE_SYSTEM_PROCESSOR} MATCHES "i.86" OR + ${CMAKE_SYSTEM_PROCESSOR} MATCHES "amd64" OR APPLE) if(_ARCH_64) set(_M_X86 1) diff --git a/Source/Core/Core/MemTools.cpp b/Source/Core/Core/MemTools.cpp index e028b40faa..2c1f688d5b 100644 --- a/Source/Core/Core/MemTools.cpp +++ b/Source/Core/Core/MemTools.cpp @@ -18,6 +18,9 @@ #ifndef _M_GENERIC #include "Core/PowerPC/JitCommon/JitBase.h" #endif +#ifdef __FreeBSD__ +#include +#endif namespace EMM { @@ -256,7 +259,11 @@ static void sigsegv_handler(int sig, siginfo_t *info, void *raw_context) void InstallExceptionHandler() { stack_t signal_stack; +#ifdef __FreeBSD__ + signal_stack.ss_sp = (char*)malloc(SIGSTKSZ); +#else signal_stack.ss_sp = malloc(SIGSTKSZ); +#endif signal_stack.ss_size = SIGSTKSZ; signal_stack.ss_flags = 0; if (sigaltstack(&signal_stack, nullptr)) From b8dd68beef384f2717a70d5d5d0235ee13701e98 Mon Sep 17 00:00:00 2001 From: degasus Date: Sat, 11 Jul 2015 12:22:13 +0200 Subject: [PATCH 086/583] JitArm64: Far Code Cache --- Source/Core/Common/Arm64Emitter.cpp | 7 +++++-- Source/Core/Common/Arm64Emitter.h | 4 +--- Source/Core/Core/PowerPC/JitArm64/Jit.cpp | 7 ++++++- Source/Core/Core/PowerPC/JitArm64/Jit.h | 25 +++++++++++++++++++++++ 4 files changed, 37 insertions(+), 6 deletions(-) diff --git a/Source/Core/Common/Arm64Emitter.cpp b/Source/Core/Common/Arm64Emitter.cpp index 6eaa4fdfca..f5b00de3cc 100644 --- a/Source/Core/Common/Arm64Emitter.cpp +++ b/Source/Core/Common/Arm64Emitter.cpp @@ -271,8 +271,8 @@ bool IsImmLogical(uint64_t value, unsigned int width, unsigned int *n, unsigned void ARM64XEmitter::SetCodePtr(u8* ptr) { m_code = ptr; - m_startcode = m_code; - m_lastCacheFlushEnd = ptr; + if (!m_lastCacheFlushEnd) + m_lastCacheFlushEnd = ptr; } const u8* ARM64XEmitter::GetCodePtr() const @@ -315,6 +315,9 @@ void ARM64XEmitter::FlushIcache() void ARM64XEmitter::FlushIcacheSection(u8* start, u8* end) { + if (start == end) + return; + #if defined(IOS) // Header file says this is equivalent to: sys_icache_invalidate(start, end - start); sys_cache_control(kCacheFunctionPrepareForExecution, start, end - start); diff --git a/Source/Core/Common/Arm64Emitter.h b/Source/Core/Common/Arm64Emitter.h index 6939984308..c4ce6ab253 100644 --- a/Source/Core/Common/Arm64Emitter.h +++ b/Source/Core/Common/Arm64Emitter.h @@ -324,7 +324,6 @@ class ARM64XEmitter private: u8* m_code; - u8* m_startcode; u8* m_lastCacheFlushEnd; void EncodeCompareBranchInst(u32 op, ARM64Reg Rt, const void* ptr); @@ -365,14 +364,13 @@ protected: public: ARM64XEmitter() - : m_code(nullptr), m_startcode(nullptr), m_lastCacheFlushEnd(nullptr) + : m_code(nullptr), m_lastCacheFlushEnd(nullptr) { } ARM64XEmitter(u8* code_ptr) { m_code = code_ptr; m_lastCacheFlushEnd = code_ptr; - m_startcode = code_ptr; } virtual ~ARM64XEmitter() diff --git a/Source/Core/Core/PowerPC/JitArm64/Jit.cpp b/Source/Core/Core/PowerPC/JitArm64/Jit.cpp index c1bf82b05d..e346ea198e 100644 --- a/Source/Core/Core/PowerPC/JitArm64/Jit.cpp +++ b/Source/Core/Core/PowerPC/JitArm64/Jit.cpp @@ -17,6 +17,7 @@ using namespace Arm64Gen; void JitArm64::Init() { AllocCodeSpace(CODE_SIZE); + farcode.Init(SConfig::GetInstance().bMMU ? FARCODE_SIZE_MMU : FARCODE_SIZE); jo.enableBlocklink = true; jo.optimizeGatherPipe = true; UpdateMemoryOptions(); @@ -36,6 +37,7 @@ void JitArm64::Init() void JitArm64::ClearCache() { ClearCodeSpace(); + farcode.ClearCodeSpace(); blocks.Clear(); UpdateMemoryOptions(); } @@ -43,6 +45,7 @@ void JitArm64::ClearCache() void JitArm64::Shutdown() { FreeCodeSpace(); + farcode.Shutdown(); blocks.Shutdown(); asm_routines.Shutdown(); } @@ -276,7 +279,8 @@ void JitArm64::SingleStep() void JitArm64::Jit(u32) { - if (GetSpaceLeft() < 0x10000 || blocks.IsFull() || SConfig::GetInstance().bJITNoBlockCache) + if (GetSpaceLeft() < 0x10000 || farcode.GetSpaceLeft() < 0x10000 || blocks.IsFull() || + SConfig::GetInstance().bJITNoBlockCache) { ClearCache(); } @@ -450,5 +454,6 @@ const u8* JitArm64::DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buf, JitB b->originalSize = code_block.m_num_instructions; FlushIcache(); + farcode.FlushIcache(); return start; } diff --git a/Source/Core/Core/PowerPC/JitArm64/Jit.h b/Source/Core/Core/PowerPC/JitArm64/Jit.h index 6b2d0c3fe8..476af4c3d8 100644 --- a/Source/Core/Core/PowerPC/JitArm64/Jit.h +++ b/Source/Core/Core/PowerPC/JitArm64/Jit.h @@ -18,6 +18,15 @@ #define PPCSTATE_OFF(elem) (offsetof(PowerPC::PowerPCState, elem)) +// A place to throw blocks of code we don't want polluting the cache, e.g. rarely taken +// exception branches. +class FarCodeCacheArm64 : public Arm64Gen::ARM64CodeBlock +{ +public: + void Init(int size) { AllocCodeSpace(size); } + void Shutdown() { FreeCodeSpace(); } +}; + // Some asserts to make sure we will be able to load everything static_assert(PPCSTATE_OFF(spr[1023]) <= 16380, "LDR(32bit) can't reach the last SPR"); static_assert((PPCSTATE_OFF(ps[0][0]) % 8) == 0, "LDR(64bit VFP) requires FPRs to be 8 byte aligned"); @@ -185,6 +194,22 @@ private: ARM64FloatEmitter m_float_emit; + FarCodeCacheArm64 farcode; + u8* nearcode; // Backed up when we switch to far code. + + // Simple functions to switch between near and far code emitting + void SwitchToFarCode() + { + nearcode = GetWritableCodePtr(); + SetCodePtr(farcode.GetWritableCodePtr()); + } + + void SwitchToNearCode() + { + farcode.SetCodePtr(GetWritableCodePtr()); + SetCodePtr(nearcode); + } + // Dump a memory range of code void DumpCode(const u8* start, const u8* end); From 7196901b404163fd9209c7afdae027f6cc5c4249 Mon Sep 17 00:00:00 2001 From: degasus Date: Sat, 11 Jul 2015 12:30:05 +0200 Subject: [PATCH 087/583] JitArm64: Move all FLUSH_MAINTAIN_STATE to the far cache --- Source/Core/Core/PowerPC/JitArm64/Jit.cpp | 6 ++++++ .../Core/Core/PowerPC/JitArm64/JitArm64_Branch.cpp | 12 ++++++++++++ .../Core/PowerPC/JitArm64/JitArm64_LoadStore.cpp | 6 ++++++ .../PowerPC/JitArm64/JitArm64_SystemRegisters.cpp | 6 ++++++ 4 files changed, 30 insertions(+) diff --git a/Source/Core/Core/PowerPC/JitArm64/Jit.cpp b/Source/Core/Core/PowerPC/JitArm64/Jit.cpp index e346ea198e..edc8fb8b14 100644 --- a/Source/Core/Core/PowerPC/JitArm64/Jit.cpp +++ b/Source/Core/Core/PowerPC/JitArm64/Jit.cpp @@ -401,6 +401,10 @@ const u8* JitArm64::DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buf, JitB LDR(INDEX_UNSIGNED, WA, X29, PPCSTATE_OFF(msr)); FixupBranch b1 = TBNZ(WA, 13); // Test FP enabled bit + FixupBranch far = B(); + SwitchToFarCode(); + SetJumpTarget(far); + gpr.Flush(FLUSH_MAINTAIN_STATE); fpr.Flush(FLUSH_MAINTAIN_STATE); @@ -411,6 +415,8 @@ const u8* JitArm64::DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buf, JitB MOVI2R(WA, js.compilerPC); WriteExceptionExit(WA); + SwitchToNearCode(); + SetJumpTarget(b1); js.firstFPInstructionFound = true; diff --git a/Source/Core/Core/PowerPC/JitArm64/JitArm64_Branch.cpp b/Source/Core/Core/PowerPC/JitArm64/JitArm64_Branch.cpp index 4dfd88b92e..2f5cb1b049 100644 --- a/Source/Core/Core/PowerPC/JitArm64/JitArm64_Branch.cpp +++ b/Source/Core/Core/PowerPC/JitArm64/JitArm64_Branch.cpp @@ -142,6 +142,10 @@ void JitArm64::bcx(UGeckoInstruction inst) !(inst.BO_2 & BO_BRANCH_IF_TRUE)); } + FixupBranch far = B(); + SwitchToFarCode(); + SetJumpTarget(far); + if (inst.LK) { u32 Jumpto = js.compilerPC + 4; @@ -161,6 +165,8 @@ void JitArm64::bcx(UGeckoInstruction inst) WriteExit(destination); + SwitchToNearCode(); + if ((inst.BO & BO_DONT_CHECK_CONDITION) == 0) SetJumpTarget( pConditionDontBranch ); if ((inst.BO & BO_DONT_DECREMENT_FLAG) == 0) @@ -235,6 +241,10 @@ void JitArm64::bclrx(UGeckoInstruction inst) !(inst.BO_2 & BO_BRANCH_IF_TRUE)); } + FixupBranch far = B(); + SwitchToFarCode(); + SetJumpTarget(far); + LDR(INDEX_UNSIGNED, WA, X29, PPCSTATE_OFF(spr[SPR_LR])); AND(WA, WA, 30, 29); // Wipe the bottom 2 bits. @@ -252,6 +262,8 @@ void JitArm64::bclrx(UGeckoInstruction inst) WriteExitDestInR(WA); + SwitchToNearCode(); + if ((inst.BO & BO_DONT_CHECK_CONDITION) == 0) SetJumpTarget( pConditionDontBranch ); if ((inst.BO & BO_DONT_DECREMENT_FLAG) == 0) diff --git a/Source/Core/Core/PowerPC/JitArm64/JitArm64_LoadStore.cpp b/Source/Core/Core/PowerPC/JitArm64/JitArm64_LoadStore.cpp index 4964e2e3e1..133ff3e936 100644 --- a/Source/Core/Core/PowerPC/JitArm64/JitArm64_LoadStore.cpp +++ b/Source/Core/Core/PowerPC/JitArm64/JitArm64_LoadStore.cpp @@ -411,6 +411,10 @@ void JitArm64::lXX(UGeckoInstruction inst) // if it's still 0, we can wait until the next event FixupBranch noIdle = CBNZ(gpr.R(d)); + FixupBranch far = B(); + SwitchToFarCode(); + SetJumpTarget(far); + gpr.Flush(FLUSH_MAINTAIN_STATE); fpr.Flush(FLUSH_MAINTAIN_STATE); @@ -423,6 +427,8 @@ void JitArm64::lXX(UGeckoInstruction inst) gpr.Unlock(WA); WriteExceptionExit(); + SwitchToNearCode(); + SetJumpTarget(noIdle); //js.compilerPC += 8; diff --git a/Source/Core/Core/PowerPC/JitArm64/JitArm64_SystemRegisters.cpp b/Source/Core/Core/PowerPC/JitArm64/JitArm64_SystemRegisters.cpp index 212c12fa8c..058a9f1d9d 100644 --- a/Source/Core/Core/PowerPC/JitArm64/JitArm64_SystemRegisters.cpp +++ b/Source/Core/Core/PowerPC/JitArm64/JitArm64_SystemRegisters.cpp @@ -184,6 +184,10 @@ void JitArm64::twx(UGeckoInstruction inst) SetJumpTarget(fixup); } + FixupBranch far = B(); + SwitchToFarCode(); + SetJumpTarget(far); + gpr.Flush(FlushMode::FLUSH_MAINTAIN_STATE); fpr.Flush(FlushMode::FLUSH_MAINTAIN_STATE); @@ -196,6 +200,8 @@ void JitArm64::twx(UGeckoInstruction inst) // WA is unlocked in this function WriteExceptionExit(WA); + SwitchToNearCode(); + SetJumpTarget(dont_trap); if (!analyzer.HasOption(PPCAnalyst::PPCAnalyzer::OPTION_CONDITIONAL_CONTINUE)) From a5c10ded559672e3ab57eded40d2c64a409640f7 Mon Sep 17 00:00:00 2001 From: degasus Date: Sun, 12 Jul 2015 09:38:30 +0200 Subject: [PATCH 088/583] JitArm64: Fix copy&paste issue --- Source/Core/Core/PowerPC/JitArm64/JitArm64_LoadStorePaired.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/Core/Core/PowerPC/JitArm64/JitArm64_LoadStorePaired.cpp b/Source/Core/Core/PowerPC/JitArm64/JitArm64_LoadStorePaired.cpp index 703241fa64..cce98aee07 100644 --- a/Source/Core/Core/PowerPC/JitArm64/JitArm64_LoadStorePaired.cpp +++ b/Source/Core/Core/PowerPC/JitArm64/JitArm64_LoadStorePaired.cpp @@ -156,7 +156,7 @@ void JitArm64::psq_st(UGeckoInstruction inst) m_float_emit.ABI_PushRegisters(fprs_in_use, X30); BLR(EncodeRegTo64(type_reg)); m_float_emit.ABI_PopRegisters(fprs_in_use, X30); - ABI_PushRegisters(gprs_in_use); + ABI_PopRegisters(gprs_in_use); SetJumpTarget(continue1); } From 658c49fab32af5e053480518e88dc1c4857e7972 Mon Sep 17 00:00:00 2001 From: sigmabeta Date: Sat, 11 Jul 2015 17:13:55 -0400 Subject: [PATCH 089/583] Android:Changes to simplify command-line building of the app, and bugfixes to the Gradle script --- Readme.md | 10 +++++----- Source/Android/.gitignore | 1 - Source/Android/app/build.gradle | 17 ++++++++++++++--- .../Android/gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 49896 bytes .../gradle/wrapper/gradle-wrapper.properties | 6 ++++++ 5 files changed, 25 insertions(+), 9 deletions(-) create mode 100644 Source/Android/gradle/wrapper/gradle-wrapper.jar create mode 100644 Source/Android/gradle/wrapper/gradle-wrapper.properties diff --git a/Readme.md b/Readme.md index 78323e06ef..a2fbc3f576 100644 --- a/Readme.md +++ b/Readme.md @@ -65,14 +65,14 @@ and place the following inside: # Specifies arguments for the 'make' command. Can be blank. makeArgs= -# The path to your machine's Git executable. Will autodetect if blank. +# The path to your machine's Git executable. Will autodetect if blank (on Linux only). gitPath= -# The path to the extracted NDK package. Will autodetect if blank. -ndkPath= - -# The path to the CMake executable. Will autodetect if blank. +# The path to the CMake executable. Will autodetect if blank (on Linux only). cmakePath= + +# The path to the extracted NDK package. Will autodetect if blank (on Linux only). +ndkPath= ``` If you prefer, you can run the CMake step manually, and it will copy the resulting diff --git a/Source/Android/.gitignore b/Source/Android/.gitignore index a053548512..3fbf1ea2ff 100644 --- a/Source/Android/.gitignore +++ b/Source/Android/.gitignore @@ -36,7 +36,6 @@ workspace.xml tasks.xml .gradle/* .idea -gradle/ build/ *.so *.iml diff --git a/Source/Android/app/build.gradle b/Source/Android/app/build.gradle index b936e0604d..8f5ce60a76 100644 --- a/Source/Android/app/build.gradle +++ b/Source/Android/app/build.gradle @@ -134,7 +134,11 @@ task compileNative(type: Exec, dependsOn: 'setupCMake') { executable 'make' - args buildProperties.makeArgs + if (buildProperties.makeArgs == null || buildProperties.makeArgs.isEmpty()) { + // TODO + } else { + args buildProperties.makeArgs + } } else { executable 'echo' args 'No build.properties found; skipping native build.' @@ -144,13 +148,15 @@ task compileNative(type: Exec, dependsOn: 'setupCMake') { String getExecutablePath(String command) { def propsFile = rootProject.file("build.properties") def path = null + if (propsFile.canRead()) { def buildProperties = new Properties() buildProperties.load(new FileInputStream(propsFile)) println buildProperties path = buildProperties[command + "Path"] } - if (path == null) { + + if (path == null || path.isEmpty()) { try { def stdout = new ByteArrayOutputStream() @@ -164,21 +170,25 @@ String getExecutablePath(String command) { project.logger.error("Gradle error: Couldn't find " + command + " executable.") } } + if (path != null) { project.logger.quiet("Gradle: Found " + command + " executuable:" + path) } + return path } String getNdkPath() { def propsFile = rootProject.file("build.properties") def ndkPath = null + if (propsFile.canRead()) { def buildProperties = new Properties() buildProperties.load(new FileInputStream(propsFile)) ndkPath = buildProperties.ndkPath } - if (ndkPath == null) { + + if (ndkPath == null || ndkPath.isEmpty()) { try { def stdout = new ByteArrayOutputStream() @@ -194,6 +204,7 @@ String getNdkPath() { project.logger.error("Gradle error: Couldn't find NDK.") } } + if (ndkPath != null) { project.logger.quiet("Gradle: Found Android NDK: " + ndkPath) } diff --git a/Source/Android/gradle/wrapper/gradle-wrapper.jar b/Source/Android/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000000000000000000000000000000000000..8c0fb64a8698b08ecc4158d828ca593c4928e9dd GIT binary patch literal 49896 zcmagFb986H(k`5d^NVfUwr$(C?M#x1ZQHiZiEVpg+jrjgoQrerx!>1o_ul)D>ebz~ zs=Mmxr&>W81QY-S1PKWQ%N-;H^tS;2*XwVA`dej1RRn1z<;3VgfE4~kaG`A%QSPsR z#ovnZe+tS9%1MfeDyz`RirvdjPRK~p(#^q2(^5@O&NM19EHdvN-A&StN>0g6QA^VN z0Gx%Gq#PD$QMRFzmK+utjS^Y1F0e8&u&^=w5K<;4Rz|i3A=o|IKLY+g`iK6vfr9?+ z-`>gmU&i?FGSL5&F?TXFu`&Js6h;15QFkXp2M1H9|Eq~bpov-GU(uz%mH0n55wUl- zv#~ccAz`F5wlQ>e_KlJS3@{)B?^v*EQM=IxLa&76^y51a((wq|2-`qON>+4dLc{Oo z51}}o^Zen(oAjxDK7b++9_Yg`67p$bPo3~BCpGM7uAWmvIhWc5Gi+gQZ|Pwa-Gll@<1xmcPy z|NZmu6m)g5Ftu~BG&Xdxclw7Cij{xbBMBn-LMII#Slp`AElb&2^Hw+w>(3crLH!;I zN+Vk$D+wP1#^!MDCiad@vM>H#6+`Ct#~6VHL4lzmy;lSdk>`z6)=>Wh15Q2)dQtGqvn0vJU@+(B5{MUc*qs4!T+V=q=wy)<6$~ z!G>e_4dN@lGeF_$q9`Ju6Ncb*x?O7=l{anm7Eahuj_6lA{*#Gv*TaJclevPVbbVYu z(NY?5q+xxbO6%g1xF0r@Ix8fJ~u)VRUp`S%&rN$&e!Od`~s+64J z5*)*WSi*i{k%JjMSIN#X;jC{HG$-^iX+5f5BGOIHWAl*%15Z#!xntpk($-EGKCzKa zT7{siZ9;4TICsWQ$pu&wKZQTCvpI$Xvzwxoi+XkkpeE&&kFb!B?h2hi%^YlXt|-@5 zHJ~%AN!g_^tmn1?HSm^|gCE#!GRtK2(L{9pL#hp0xh zME}|DB>(5)`iE7CM)&_+S}-Bslc#@B5W4_+k4Cp$l>iVyg$KP>CN?SVGZ(&02>iZK zB<^HP$g$Lq*L$BWd?2(F?-MUbNWTJVQdW7$#8a|k_30#vHAD1Z{c#p;bETk0VnU5A zBgLe2HFJ3032$G<`m*OB!KM$*sdM20jm)It5OSru@tXpK5LT>#8)N!*skNu1$TpIw zufjjdp#lyH5bZ%|Iuo|iu9vG1HrIVWLH>278xo>aVBkPN3V$~!=KnlXQ4eDqS7%E% zQ!z^$Q$b^6Q)g#cLpwur(|<0gWHo6A6jc;n`t(V9T;LzTAU{IAu*uEQ%Ort1k+Kn+f_N`9|bxYC+~Z1 zCC1UCWv*Orx$_@ydv9mIe(liLfOr7mhbV@tKw{6)q^1DH1nmvZ0cj215R<~&I<4S| zgnr;9Cdjqpz#o8i0CQjtl`}{c*P)aSdH|abxGdrR)-3z+02-eX(k*B)Uqv6~^nh** z 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 Date: Mon, 13 Jul 2015 23:33:21 -0700 Subject: [PATCH 090/583] Added some warning text about fractional IRs. --- Source/Core/DolphinWX/VideoConfigDiag.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/Core/DolphinWX/VideoConfigDiag.cpp b/Source/Core/DolphinWX/VideoConfigDiag.cpp index 853edb4c44..ecd625ec33 100644 --- a/Source/Core/DolphinWX/VideoConfigDiag.cpp +++ b/Source/Core/DolphinWX/VideoConfigDiag.cpp @@ -112,7 +112,7 @@ static wxString fast_depth_calc_desc = wxTRANSLATE("Use a less accurate algorith static wxString disable_bbox_desc = wxTRANSLATE("Disable the bounding box emulation.\nThis may improve the GPU performance a lot, but some games will break.\n\nIf unsure, leave this checked."); static wxString force_filtering_desc = wxTRANSLATE("Filter all textures, including any that the game explicitly set as unfiltered.\nMay improve quality of certain textures in some games, but will cause issues in others.\nOn Direct3D, setting Anisotropic Filtering above 1x will also have the same effect as enabling this option.\n\nIf unsure, leave this unchecked."); static wxString borderless_fullscreen_desc = wxTRANSLATE("Implement fullscreen mode with a borderless window spanning the whole screen instead of using exclusive mode.\nAllows for faster transitions between fullscreen and windowed mode, but slightly increases input latency, makes movement less smooth and slightly decreases performance.\nExclusive mode is required for Nvidia 3D Vision to work in the Direct3D backend.\n\nIf unsure, leave this unchecked."); -static wxString internal_res_desc = wxTRANSLATE("Specifies the resolution used to render at. A high resolution greatly improves visual quality, but also greatly increases GPU load and can cause issues in certain games.\n\"Multiple of 640x528\" will result in a size slightly larger than \"Window Size\" but yield fewer issues. Generally speaking, the lower the internal resolution is, the better your performance will be.\n\nIf unsure, select 640x528."); +static wxString internal_res_desc = wxTRANSLATE("Specifies the resolution used to render at. A high resolution greatly improves visual quality, but also greatly increases GPU load and can cause issues in certain games.\n\"Multiple of 640x528\" will result in a size slightly larger than \"Window Size\" but yield fewer issues. Generally speaking, the lower the internal resolution is, the better your performance will be. Auto (Window Size), 1.5x, and 2.5x may cause issues in some games.\n\nIf unsure, select Native."); static wxString efb_access_desc = wxTRANSLATE("Ignore any requests from the CPU to read from or write to the EFB.\nImproves performance in some games, but might disable some gameplay-related features or graphical effects.\n\nIf unsure, leave this unchecked."); static wxString efb_emulate_format_changes_desc = wxTRANSLATE("Ignore any changes to the EFB format.\nImproves performance in many games without any negative effect. Causes graphical defects in a small number of other games.\n\nIf unsure, leave this checked."); static wxString skip_efb_copy_to_ram_desc = wxTRANSLATE("Stores EFB Copies exclusively on the GPU, bypassing system memory. Causes graphical defects in a small number of games.\n\nEnabled = EFB Copies to Texture\nDisabled = EFB Copies to RAM (and Texture)\n\nIf unsure, leave this checked."); From ac8621ccabcdff890e0f1844e8a1b2362cb7f1c3 Mon Sep 17 00:00:00 2001 From: mathieui Date: Tue, 14 Jul 2015 12:34:16 +0200 Subject: [PATCH 091/583] GCAdapter: Disable the scanning thread when direct connect is disabled MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The goal of this commit is to let people who experience driver issues with libusb and windows disable the scanning thread (to avoid mouse issues, keyboard issues, and audio issues). Also disable the rumble setting when the adapter driver is not detected, and don’t do anything if libusb can’t init for some reason. --- Source/Core/Core/HW/SI_GCAdapter.cpp | 1 + Source/Core/DolphinWX/ControllerConfigDiag.cpp | 1 + Source/Core/DolphinWX/ControllerConfigDiag.h | 4 ++++ 3 files changed, 6 insertions(+) diff --git a/Source/Core/Core/HW/SI_GCAdapter.cpp b/Source/Core/Core/HW/SI_GCAdapter.cpp index b54c07ef74..9b4482c452 100644 --- a/Source/Core/Core/HW/SI_GCAdapter.cpp +++ b/Source/Core/Core/HW/SI_GCAdapter.cpp @@ -146,6 +146,7 @@ void Init() if (ret) { ERROR_LOG(SERIALINTERFACE, "libusb_init failed with error: %d", ret); + s_libusb_driver_not_supported = true; Shutdown(); } else diff --git a/Source/Core/DolphinWX/ControllerConfigDiag.cpp b/Source/Core/DolphinWX/ControllerConfigDiag.cpp index ff5bafc44e..170439f1f5 100644 --- a/Source/Core/DolphinWX/ControllerConfigDiag.cpp +++ b/Source/Core/DolphinWX/ControllerConfigDiag.cpp @@ -174,6 +174,7 @@ wxStaticBoxSizer* ControllerConfigDiag::CreateGamecubeSizer() m_adapter_status->SetLabelText(_("Driver Not Detected")); gamecube_adapter->Disable(); gamecube_adapter->SetValue(false); + gamecube_rumble->Disable(); } } else diff --git a/Source/Core/DolphinWX/ControllerConfigDiag.h b/Source/Core/DolphinWX/ControllerConfigDiag.h index 5fa2c0f52e..3c6582a5e1 100644 --- a/Source/Core/DolphinWX/ControllerConfigDiag.h +++ b/Source/Core/DolphinWX/ControllerConfigDiag.h @@ -73,6 +73,10 @@ private: void OnGameCubeAdapter(wxCommandEvent& event) { SConfig::GetInstance().m_GameCubeAdapter = event.IsChecked(); + if (event.IsChecked()) + SI_GCAdapter::StartScanThread(); + else + SI_GCAdapter::StopScanThread(); event.Skip(); } void OnAdapterRumble(wxCommandEvent& event) From cae00254a5c6c1d177b13552243613a92bf37738 Mon Sep 17 00:00:00 2001 From: mathieui Date: Tue, 14 Jul 2015 17:15:26 +0200 Subject: [PATCH 092/583] GCAdapter: Only start the thread on startup if direct connect is enabled --- Source/Core/Core/HW/SI_GCAdapter.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Source/Core/Core/HW/SI_GCAdapter.cpp b/Source/Core/Core/HW/SI_GCAdapter.cpp index 9b4482c452..8660f44d65 100644 --- a/Source/Core/Core/HW/SI_GCAdapter.cpp +++ b/Source/Core/Core/HW/SI_GCAdapter.cpp @@ -151,7 +151,8 @@ void Init() } else { - StartScanThread(); + if (SConfig::GetInstance().m_GameCubeAdapter) + StartScanThread(); } } From 957691444d2c59939ecbf96b2ea0a52bccf720a9 Mon Sep 17 00:00:00 2001 From: sigmabeta Date: Thu, 2 Jul 2015 23:54:32 -0400 Subject: [PATCH 093/583] Android TV: Replace toolbar on EmulationActivity with a full-screen menu. --- .../activities/EmulationActivity.java | 225 ++++++++++++------ .../fragments/EmulationFragment.java | 7 +- .../dolphinemu/fragments/MenuFragment.java | 38 +++ .../layout-television/activity_emulation.xml | 45 ++++ .../layout-television/fragment_emulation.xml | 14 ++ .../main/res/layout/fragment_ingame_menu.xml | 64 +++++ .../app/src/main/res/values/styles.xml | 34 +++ 7 files changed, 357 insertions(+), 70 deletions(-) create mode 100644 Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/fragments/MenuFragment.java create mode 100644 Source/Android/app/src/main/res/layout-television/activity_emulation.xml create mode 100644 Source/Android/app/src/main/res/layout-television/fragment_emulation.xml create mode 100644 Source/Android/app/src/main/res/layout/fragment_ingame_menu.xml diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/activities/EmulationActivity.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/activities/EmulationActivity.java index 6b27c08c4a..00501e10d6 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/activities/EmulationActivity.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/activities/EmulationActivity.java @@ -15,6 +15,7 @@ import android.view.View; import android.view.ViewTreeObserver; import android.widget.FrameLayout; import android.widget.ImageView; +import android.widget.LinearLayout; import com.squareup.picasso.Callback; import com.squareup.picasso.Picasso; @@ -29,10 +30,13 @@ public final class EmulationActivity extends AppCompatActivity { private View mDecorView; private ImageView mImageView; + private FrameLayout mFrameEmulation; + private LinearLayout mMenuLayout; private boolean mDeviceHasTouchScreen; private boolean mSystemUiVisible; + private boolean mMenuVisible; // So that MainActivity knows which view to invalidate before the return animation. private int mPosition; @@ -56,49 +60,61 @@ public final class EmulationActivity extends AppCompatActivity @Override protected void onCreate(Bundle savedInstanceState) { + mDeviceHasTouchScreen = getPackageManager().hasSystemFeature("android.hardware.touchscreen"); + + int themeId; + if (mDeviceHasTouchScreen) + { + themeId = R.style.DolphinEmulationGamecube; + + // Get a handle to the Window containing the UI. + mDecorView = getWindow().getDecorView(); + + // Set these options now so that the SurfaceView the game renders into is the right size. + mDecorView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE | + View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION | + View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN); + + // Set the ActionBar to follow the navigation/status bar's visibility changes. + mDecorView.setOnSystemUiVisibilityChangeListener( + new View.OnSystemUiVisibilityChangeListener() + { + @Override + public void onSystemUiVisibilityChange(int flags) + { + mSystemUiVisible = (flags & View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) == 0; + + if (mSystemUiVisible) + { + getSupportActionBar().show(); + hideSystemUiAfterDelay(); + } + else + { + getSupportActionBar().hide(); + } + } + } + ); + } + else + { + themeId = R.style.DolphinEmulationTvGamecube; + } + + setTheme(themeId); super.onCreate(savedInstanceState); // Picasso will take a while to load these big-ass screenshots. So don't run // the animation until we say so. postponeEnterTransition(); - mDeviceHasTouchScreen = getPackageManager().hasSystemFeature("android.hardware.touchscreen"); - - // Get a handle to the Window containing the UI. - mDecorView = getWindow().getDecorView(); - - // Set these options now so that the SurfaceView the game renders into is the right size. - mDecorView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE | - View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION | - View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN); - - // Set the ActionBar to follow the navigation/status bar's visibility changes. - mDecorView.setOnSystemUiVisibilityChangeListener( - new View.OnSystemUiVisibilityChangeListener() - { - @Override - public void onSystemUiVisibilityChange(int flags) - { - mSystemUiVisible = (flags & View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) == 0; - - if (mSystemUiVisible) - { - getSupportActionBar().show(); - hideSystemUiAfterDelay(); - } - else - { - getSupportActionBar().hide(); - } - } - } - ); - setContentView(R.layout.activity_emulation); mImageView = (ImageView) findViewById(R.id.image_screenshot); mFrameContent = (FrameLayout) findViewById(R.id.frame_content); mFrameEmulation = (FrameLayout) findViewById(R.id.frame_emulation_fragment); + mMenuLayout = (LinearLayout) findViewById(R.id.layout_ingame_menu); Intent gameToEmulate = getIntent(); String path = gameToEmulate.getStringExtra("SelectedGame"); @@ -181,8 +197,11 @@ public final class EmulationActivity extends AppCompatActivity { super.onPostCreate(savedInstanceState); - // Give the user a few seconds to see what the controls look like, then hide them. - hideSystemUiAfterDelay(); + if (mDeviceHasTouchScreen) + { + // Give the user a few seconds to see what the controls look like, then hide them. + hideSystemUiAfterDelay(); + } } @Override @@ -190,36 +209,88 @@ public final class EmulationActivity extends AppCompatActivity { super.onWindowFocusChanged(hasFocus); - if (hasFocus) + if (mDeviceHasTouchScreen) { - hideSystemUiAfterDelay(); - } - else - { - // If the window loses focus (i.e. a dialog box, or a popup menu is on screen - // stop hiding the UI. - mSystemUiHider.removeMessages(0); + if (hasFocus) + { + hideSystemUiAfterDelay(); + } + else + { + // If the window loses focus (i.e. a dialog box, or a popup menu is on screen + // stop hiding the UI. + mSystemUiHider.removeMessages(0); + } } } @Override public void onBackPressed() { - if (!mDeviceHasTouchScreen && !mSystemUiVisible) + if (!mDeviceHasTouchScreen) { - showSystemUI(); + toggleMenu(); } else { - // Let the system handle it; i.e. quit the activity TODO or show "are you sure?" dialog. - EmulationFragment fragment = (EmulationFragment) getFragmentManager() - .findFragmentByTag(EmulationFragment.FRAGMENT_TAG); - fragment.notifyEmulationStopped(); - - NativeLibrary.StopEmulation(); + stopEmulation(); } } + private void toggleMenu() + { + if (mMenuVisible) + { + mMenuLayout.animate() + .withLayer() + .setDuration(200) + .alpha(0.0f) + .scaleX(1.1f) + .scaleY(1.1f) + .withEndAction(new Runnable() + { + @Override + public void run() + { + mMenuLayout.setVisibility(View.GONE); + mMenuVisible = false; + } + }); + } + else + { + mMenuLayout.setVisibility(View.VISIBLE); + + mMenuLayout.setScaleX(1.1f); + mMenuLayout.setScaleY(1.1f); + mMenuLayout.setAlpha(0.0f); + + mMenuLayout.animate() + .withLayer() + .setDuration(300) + .alpha(1.0f) + .scaleX(1.0f) + .scaleY(1.0f) + .withEndAction(new Runnable() + { + @Override + public void run() + { + mMenuVisible = true; + } + }); + } + } + + private void stopEmulation() + { + EmulationFragment fragment = (EmulationFragment) getFragmentManager() + .findFragmentByTag(EmulationFragment.FRAGMENT_TAG); + fragment.notifyEmulationStopped(); + + NativeLibrary.StopEmulation(); + } + public void exitWithAnimation() { runOnUiThread(new Runnable() @@ -257,7 +328,7 @@ public final class EmulationActivity extends AppCompatActivity mImageView.setVisibility(View.VISIBLE); mImageView.animate() .withLayer() - .setDuration(500) + .setDuration(100) .alpha(1.0f) .withEndAction(afterShowingScreenshot); } @@ -284,7 +355,13 @@ public final class EmulationActivity extends AppCompatActivity @Override public boolean onOptionsItemSelected(MenuItem item) { - switch (item.getItemId()) + onMenuItemClicked(item.getItemId()); + return true; + } + + public void onMenuItemClicked(int id) + { + switch (id) { // Enable/Disable input overlay. case R.id.menu_emulation_input_overlay: @@ -294,67 +371,69 @@ public final class EmulationActivity extends AppCompatActivity emulationFragment.toggleInputOverlayVisibility(); - return true; + return; } // Screenshot capturing case R.id.menu_emulation_screenshot: NativeLibrary.SaveScreenShot(); - return true; + return; // Quicksave / Load case R.id.menu_quicksave: NativeLibrary.SaveState(9); - return true; + return; case R.id.menu_quickload: NativeLibrary.LoadState(9); - return true; + return; // Save state slots case R.id.menu_emulation_save_1: NativeLibrary.SaveState(0); - return true; + return; case R.id.menu_emulation_save_2: NativeLibrary.SaveState(1); - return true; + return; case R.id.menu_emulation_save_3: NativeLibrary.SaveState(2); - return true; + return; case R.id.menu_emulation_save_4: NativeLibrary.SaveState(3); - return true; + return; case R.id.menu_emulation_save_5: NativeLibrary.SaveState(4); - return true; + return; // Load state slots case R.id.menu_emulation_load_1: NativeLibrary.LoadState(0); - return true; + return; case R.id.menu_emulation_load_2: NativeLibrary.LoadState(1); - return true; + return; case R.id.menu_emulation_load_3: NativeLibrary.LoadState(2); - return true; + return; case R.id.menu_emulation_load_4: NativeLibrary.LoadState(3); - return true; + return; case R.id.menu_emulation_load_5: NativeLibrary.LoadState(4); - return true; + return; - default: - return super.onOptionsItemSelected(item); + case R.id.menu_exit: + toggleMenu(); + stopEmulation(); + return; } } @@ -362,6 +441,11 @@ public final class EmulationActivity extends AppCompatActivity @Override public boolean dispatchKeyEvent(KeyEvent event) { + if (mMenuVisible) + { + return super.dispatchKeyEvent(event); + } + int action = 0; switch (event.getAction()) @@ -391,6 +475,11 @@ public final class EmulationActivity extends AppCompatActivity @Override public boolean dispatchGenericMotionEvent(MotionEvent event) { + if (mMenuVisible) + { + return false; + } + if (((event.getSource() & InputDevice.SOURCE_CLASS_JOYSTICK) == 0)) { return super.dispatchGenericMotionEvent(event); diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/fragments/EmulationFragment.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/fragments/EmulationFragment.java index 9d23736cb6..1eb1684531 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/fragments/EmulationFragment.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/fragments/EmulationFragment.java @@ -81,9 +81,12 @@ public final class EmulationFragment extends Fragment implements SurfaceHolder.C mSurfaceView.getHolder().addCallback(this); // If the input overlay was previously disabled, then don't show it. - if (!mPreferences.getBoolean("showInputOverlay", true)) + if (mInputOverlay != null) { - mInputOverlay.setVisibility(View.GONE); + if (!mPreferences.getBoolean("showInputOverlay", true)) + { + mInputOverlay.setVisibility(View.GONE); + } } diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/fragments/MenuFragment.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/fragments/MenuFragment.java new file mode 100644 index 0000000000..f57ca36ede --- /dev/null +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/fragments/MenuFragment.java @@ -0,0 +1,38 @@ +package org.dolphinemu.dolphinemu.fragments; + +import android.app.Fragment; +import android.os.Bundle; +import android.support.annotation.Nullable; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.Button; +import android.widget.LinearLayout; + +import org.dolphinemu.dolphinemu.R; +import org.dolphinemu.dolphinemu.activities.EmulationActivity; + +public final class MenuFragment extends Fragment implements View.OnClickListener +{ + @Nullable + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) + { + LinearLayout rootView = (LinearLayout) inflater.inflate(R.layout.fragment_ingame_menu, container, false); + + for (int childIndex = 0; childIndex < rootView.getChildCount(); childIndex++) + { + Button button = (Button) rootView.getChildAt(childIndex); + + button.setOnClickListener(this); + } + + return rootView; + } + + @Override + public void onClick(View button) + { + ((EmulationActivity) getActivity()).onMenuItemClicked(button.getId()); + } +} diff --git a/Source/Android/app/src/main/res/layout-television/activity_emulation.xml b/Source/Android/app/src/main/res/layout-television/activity_emulation.xml new file mode 100644 index 0000000000..8770751fee --- /dev/null +++ b/Source/Android/app/src/main/res/layout-television/activity_emulation.xml @@ -0,0 +1,45 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Source/Android/app/src/main/res/layout-television/fragment_emulation.xml b/Source/Android/app/src/main/res/layout-television/fragment_emulation.xml new file mode 100644 index 0000000000..787de65186 --- /dev/null +++ b/Source/Android/app/src/main/res/layout-television/fragment_emulation.xml @@ -0,0 +1,14 @@ + + + + + diff --git a/Source/Android/app/src/main/res/layout/fragment_ingame_menu.xml b/Source/Android/app/src/main/res/layout/fragment_ingame_menu.xml new file mode 100644 index 0000000000..76572112fb --- /dev/null +++ b/Source/Android/app/src/main/res/layout/fragment_ingame_menu.xml @@ -0,0 +1,64 @@ + + + +