From 1b32751367faba6cf88a5b6572adeeebf905ad9d Mon Sep 17 00:00:00 2001 From: Emmanuel Gil Peyrot Date: Mon, 7 Aug 2017 20:12:50 +0200 Subject: [PATCH 001/224] VideoCommon: Round values in swizzlers. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This was breaking Metroid Prime 2: Echoes’s scanner in some rooms, such as the one in https://fifoci.dolphin-emu.org/dff/mp2-scanner/ It was found on Ivy Bridge on Mesa, the alpha value read back from the EFB was off-by-4 in multiple objects, which was a conversion error because int4() is equivalent to floor() and the value wasn’t always higher. --- Source/Core/VideoCommon/TextureConversionShader.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Source/Core/VideoCommon/TextureConversionShader.cpp b/Source/Core/VideoCommon/TextureConversionShader.cpp index ab1b284b78fa..4bd243ee2744 100644 --- a/Source/Core/VideoCommon/TextureConversionShader.cpp +++ b/Source/Core/VideoCommon/TextureConversionShader.cpp @@ -74,13 +74,13 @@ static void WriteSwizzler(char*& p, EFBCopyFormat format, APIType ApiType) WRITE(p, "float4 RGBA8ToRGBA6(float4 src)\n"); WRITE(p, "{\n"); - WRITE(p, " int4 val = int4(src * 255.0) >> 2;\n"); + WRITE(p, " int4 val = int4(roundEven(src * 255.0)) >> 2;\n"); WRITE(p, " return float4(val) / 63.0;\n"); WRITE(p, "}\n"); WRITE(p, "float4 RGBA8ToRGB565(float4 src)\n"); WRITE(p, "{\n"); - WRITE(p, " int4 val = int4(src * 255.0);\n"); + WRITE(p, " int4 val = int4(roundEven(src * 255.0));\n"); WRITE(p, " val = int4(val.r >> 3, val.g >> 2, val.b >> 3, 1);\n"); WRITE(p, " return float4(val) / float4(31.0, 63.0, 31.0, 1.0);\n"); WRITE(p, "}\n"); From 24e7b465be75a4bd431cb855d81cb1f69186c249 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9o=20Lam?= Date: Sat, 19 Aug 2017 11:21:00 +0200 Subject: [PATCH 002/224] IOS: Rename MemoryValues to VersionInfo --- Source/Core/Core/CMakeLists.txt | 2 +- Source/Core/Core/Core.vcxproj | 4 ++-- Source/Core/Core/Core.vcxproj.filters | 8 ++++---- Source/Core/Core/IOS/IOS.cpp | 2 +- .../Core/Core/IOS/{MemoryValues.cpp => VersionInfo.cpp} | 2 +- Source/Core/Core/IOS/{MemoryValues.h => VersionInfo.h} | 0 6 files changed, 9 insertions(+), 9 deletions(-) rename Source/Core/Core/IOS/{MemoryValues.cpp => VersionInfo.cpp} (99%) rename Source/Core/Core/IOS/{MemoryValues.h => VersionInfo.h} (100%) diff --git a/Source/Core/Core/CMakeLists.txt b/Source/Core/Core/CMakeLists.txt index 96bbe1d15c95..2ac4c204c111 100644 --- a/Source/Core/Core/CMakeLists.txt +++ b/Source/Core/Core/CMakeLists.txt @@ -155,8 +155,8 @@ set(SRCS IOS/DeviceStub.cpp IOS/IOS.cpp IOS/IOSC.cpp - IOS/MemoryValues.cpp IOS/MIOS.cpp + IOS/VersionInfo.cpp IOS/DI/DI.cpp IOS/ES/ES.cpp IOS/ES/Formats.cpp diff --git a/Source/Core/Core/Core.vcxproj b/Source/Core/Core/Core.vcxproj index 5e275711dea2..10e0e019b9e9 100644 --- a/Source/Core/Core/Core.vcxproj +++ b/Source/Core/Core/Core.vcxproj @@ -185,8 +185,8 @@ - + @@ -442,8 +442,8 @@ - + diff --git a/Source/Core/Core/Core.vcxproj.filters b/Source/Core/Core/Core.vcxproj.filters index 167fcec00770..c9f2ea8deb3a 100644 --- a/Source/Core/Core/Core.vcxproj.filters +++ b/Source/Core/Core/Core.vcxproj.filters @@ -769,10 +769,10 @@ IOS - + IOS - + IOS @@ -1511,10 +1511,10 @@ IOS - + IOS - + IOS diff --git a/Source/Core/Core/IOS/IOS.cpp b/Source/Core/Core/IOS/IOS.cpp index 3d372c7688b6..464093018c7a 100644 --- a/Source/Core/Core/IOS/IOS.cpp +++ b/Source/Core/Core/IOS/IOS.cpp @@ -32,7 +32,6 @@ #include "Core/IOS/FS/FS.h" #include "Core/IOS/FS/FileIO.h" #include "Core/IOS/MIOS.h" -#include "Core/IOS/MemoryValues.h" #include "Core/IOS/Network/IP/Top.h" #include "Core/IOS/Network/KD/NetKDRequest.h" #include "Core/IOS/Network/KD/NetKDTime.h" @@ -50,6 +49,7 @@ #include "Core/IOS/USB/USB_HID/HIDv5.h" #include "Core/IOS/USB/USB_KBD.h" #include "Core/IOS/USB/USB_VEN/VEN.h" +#include "Core/IOS/VersionInfo.h" #include "Core/IOS/WFS/WFSI.h" #include "Core/IOS/WFS/WFSSRV.h" #include "Core/PowerPC/PowerPC.h" diff --git a/Source/Core/Core/IOS/MemoryValues.cpp b/Source/Core/Core/IOS/VersionInfo.cpp similarity index 99% rename from Source/Core/Core/IOS/MemoryValues.cpp rename to Source/Core/Core/IOS/VersionInfo.cpp index ec05088df584..8008998be74e 100644 --- a/Source/Core/Core/IOS/MemoryValues.cpp +++ b/Source/Core/Core/IOS/VersionInfo.cpp @@ -2,7 +2,7 @@ // Licensed under GPLv2+ // Refer to the license.txt file included. -#include "Core/IOS/MemoryValues.h" +#include "Core/IOS/VersionInfo.h" #include diff --git a/Source/Core/Core/IOS/MemoryValues.h b/Source/Core/Core/IOS/VersionInfo.h similarity index 100% rename from Source/Core/Core/IOS/MemoryValues.h rename to Source/Core/Core/IOS/VersionInfo.h From e4ea4da78215918371ad85a798d20de4d81e7f01 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9o=20Lam?= Date: Sat, 19 Aug 2017 15:55:10 +0200 Subject: [PATCH 003/224] IOS: Check for available features when adding devices Prevents resource managers that shouldn't be visible from being exposed to titles. This adds a new function to get features for an IOS version, and also moves the version checks from the modules themselves to VersionInfo. This hopefully documents some of the differences between IOS better and should be slightly cleaner than having random version checks. --- Source/Core/Core/IOS/IOS.cpp | 68 +++++++++++++++++----- Source/Core/Core/IOS/SDIO/SDIOSlot0.cpp | 23 +------- Source/Core/Core/IOS/USB/OH0/OH0.cpp | 4 +- Source/Core/Core/IOS/USB/OH0/OH0Device.cpp | 4 -- Source/Core/Core/IOS/USB/USB_VEN/VEN.cpp | 8 --- Source/Core/Core/IOS/USB/USB_VEN/VEN.h | 1 - Source/Core/Core/IOS/VersionInfo.cpp | 39 +++++++++++++ Source/Core/Core/IOS/VersionInfo.h | 46 +++++++++++++++ 8 files changed, 142 insertions(+), 51 deletions(-) diff --git a/Source/Core/Core/IOS/IOS.cpp b/Source/Core/Core/IOS/IOS.cpp index 464093018c7a..d782c3f5b636 100644 --- a/Source/Core/Core/IOS/IOS.cpp +++ b/Source/Core/Core/IOS/IOS.cpp @@ -345,32 +345,69 @@ void Kernel::AddStaticDevices() { std::lock_guard lock(m_device_map_mutex); + const Feature features = GetFeatures(GetVersion()); + + // OH1 (Bluetooth) + AddDevice(std::make_unique(*this, "/dev/usb/oh1")); if (!SConfig::GetInstance().m_bt_passthrough_enabled) AddDevice(std::make_unique(*this, "/dev/usb/oh1/57e/305")); else AddDevice(std::make_unique(*this, "/dev/usb/oh1/57e/305")); + // Other core modules AddDevice(std::make_unique(*this, "/dev/stm/immediate")); AddDevice(std::make_unique(*this, "/dev/stm/eventhook")); AddDevice(std::make_unique(*this, "/dev/di")); - AddDevice(std::make_unique(*this, "/dev/net/kd/request")); - AddDevice(std::make_unique(*this, "/dev/net/kd/time")); - AddDevice(std::make_unique(*this, "/dev/net/ncd/manage")); - AddDevice(std::make_unique(*this, "/dev/net/wd/command")); - AddDevice(std::make_unique(*this, "/dev/net/ip/top")); - AddDevice(std::make_unique(*this, "/dev/net/ssl")); - AddDevice(std::make_unique(*this, "/dev/usb/kbd")); AddDevice(std::make_unique(*this, "/dev/sdio/slot0")); AddDevice(std::make_unique(*this, "/dev/sdio/slot1")); - if (GetVersion() == 59) + + // Network modules + if (HasFeature(features, Feature::KD)) + { + AddDevice(std::make_unique(*this, "/dev/net/kd/request")); + AddDevice(std::make_unique(*this, "/dev/net/kd/time")); + } + if (HasFeature(features, Feature::NCD)) + { + AddDevice(std::make_unique(*this, "/dev/net/ncd/manage")); + } + if (HasFeature(features, Feature::WiFi)) + { + AddDevice(std::make_unique(*this, "/dev/net/wd/command")); + } + if (HasFeature(features, Feature::SO)) + { + AddDevice(std::make_unique(*this, "/dev/net/ip/top")); + } + if (HasFeature(features, Feature::SSL)) + { + AddDevice(std::make_unique(*this, "/dev/net/ssl")); + } + + // USB modules + // OH0 is unconditionally added because this device path is registered in all cases. + AddDevice(std::make_unique(*this, "/dev/usb/oh0")); + if (HasFeature(features, Feature::NewUSB)) + { AddDevice(std::make_unique(*this, "/dev/usb/hid")); + AddDevice(std::make_unique(*this, "/dev/usb/ven")); + + // TODO(IOS): register /dev/usb/usb, /dev/usb/msc, /dev/usb/hub and /dev/usb/ehc + // as stubs that return IPC_EACCES. + } else - AddDevice(std::make_unique(*this, "/dev/usb/hid")); - AddDevice(std::make_unique(*this, "/dev/usb/oh0")); - AddDevice(std::make_unique(*this, "/dev/usb/oh1")); - AddDevice(std::make_unique(*this, "/dev/usb/ven")); - AddDevice(std::make_unique(*this, "/dev/usb/wfssrv")); - AddDevice(std::make_unique(*this, "/dev/wfsi")); + { + if (HasFeature(features, Feature::USB_HIDv4)) + AddDevice(std::make_unique(*this, "/dev/usb/hid")); + if (HasFeature(features, Feature::USB_KBD)) + AddDevice(std::make_unique(*this, "/dev/usb/kbd")); + } + + if (HasFeature(features, Feature::WFS)) + { + AddDevice(std::make_unique(*this, "/dev/usb/wfssrv")); + AddDevice(std::make_unique(*this, "/dev/wfsi")); + } } s32 Kernel::GetFreeDeviceID() @@ -411,7 +448,8 @@ s32 Kernel::OpenDevice(OpenRequest& request) request.fd = new_fd; std::shared_ptr device; - if (request.path.find("/dev/usb/oh0/") == 0 && !GetDeviceByName(request.path)) + if (request.path.find("/dev/usb/oh0/") == 0 && !GetDeviceByName(request.path) && + !HasFeature(GetVersion(), Feature::NewUSB)) { device = std::make_shared(*this, request.path); } diff --git a/Source/Core/Core/IOS/SDIO/SDIOSlot0.cpp b/Source/Core/Core/IOS/SDIO/SDIOSlot0.cpp index a832c66b3879..362d6284dcce 100644 --- a/Source/Core/Core/IOS/SDIO/SDIOSlot0.cpp +++ b/Source/Core/Core/IOS/SDIO/SDIOSlot0.cpp @@ -18,6 +18,7 @@ #include "Core/ConfigManager.h" #include "Core/HW/Memmap.h" #include "Core/IOS/IOS.h" +#include "Core/IOS/VersionInfo.h" namespace IOS { @@ -25,28 +26,8 @@ namespace HLE { namespace Device { -constexpr bool SupportsSDHC(u32 ios_version) -{ - switch (ios_version) - { - // Known versions to support SDHC - case 48: - case 56: - case 57: - case 58: - case 59: - case 60: - case 61: - case 70: - case 80: - return true; - default: - return false; - }; -} - SDIOSlot0::SDIOSlot0(Kernel& ios, const std::string& device_name) - : Device(ios, device_name), m_sdhc_supported(SupportsSDHC(ios.GetVersion())) + : Device(ios, device_name), m_sdhc_supported(HasFeature(ios.GetVersion(), Feature::SDv2)) { } diff --git a/Source/Core/Core/IOS/USB/OH0/OH0.cpp b/Source/Core/Core/IOS/USB/OH0/OH0.cpp index 85760299bd18..3b574bcc5c73 100644 --- a/Source/Core/Core/IOS/USB/OH0/OH0.cpp +++ b/Source/Core/Core/IOS/USB/OH0/OH0.cpp @@ -18,6 +18,7 @@ #include "Core/HW/Memmap.h" #include "Core/IOS/USB/Common.h" #include "Core/IOS/USB/USBV0.h" +#include "Core/IOS/VersionInfo.h" namespace IOS { @@ -36,8 +37,7 @@ OH0::~OH0() ReturnCode OH0::Open(const OpenRequest& request) { - const u32 ios_major_version = m_ios.GetVersion(); - if (ios_major_version == 57 || ios_major_version == 58 || ios_major_version == 59) + if (HasFeature(m_ios.GetVersion(), Feature::NewUSB)) return IPC_EACCES; return USBHost::Open(request); } diff --git a/Source/Core/Core/IOS/USB/OH0/OH0Device.cpp b/Source/Core/Core/IOS/USB/OH0/OH0Device.cpp index ab1cafc25ba0..0b8c56d0eae1 100644 --- a/Source/Core/Core/IOS/USB/OH0/OH0Device.cpp +++ b/Source/Core/Core/IOS/USB/OH0/OH0Device.cpp @@ -57,10 +57,6 @@ void OH0Device::DoState(PointerWrap& p) ReturnCode OH0Device::Open(const OpenRequest& request) { - const u32 ios_major_version = m_ios.GetVersion(); - if (ios_major_version == 57 || ios_major_version == 58 || ios_major_version == 59) - return IPC_ENOENT; - if (m_vid == 0 && m_pid == 0) return IPC_ENOENT; diff --git a/Source/Core/Core/IOS/USB/USB_VEN/VEN.cpp b/Source/Core/Core/IOS/USB/USB_VEN/VEN.cpp index 955710f1768a..e2a327a7b785 100644 --- a/Source/Core/Core/IOS/USB/USB_VEN/VEN.cpp +++ b/Source/Core/Core/IOS/USB/USB_VEN/VEN.cpp @@ -35,14 +35,6 @@ USB_VEN::~USB_VEN() StopThreads(); } -ReturnCode USB_VEN::Open(const OpenRequest& request) -{ - const u32 ios_major_version = m_ios.GetVersion(); - if (ios_major_version != 57 && ios_major_version != 58 && ios_major_version != 59) - return IPC_ENOENT; - return USBHost::Open(request); -} - IPCCommandResult USB_VEN::IOCtl(const IOCtlRequest& request) { request.Log(GetDeviceName(), LogTypes::IOS_USB); diff --git a/Source/Core/Core/IOS/USB/USB_VEN/VEN.h b/Source/Core/Core/IOS/USB/USB_VEN/VEN.h index ed8d71a8d7bd..dc128d01f96f 100644 --- a/Source/Core/Core/IOS/USB/USB_VEN/VEN.h +++ b/Source/Core/Core/IOS/USB/USB_VEN/VEN.h @@ -31,7 +31,6 @@ class USB_VEN final : public USBHost USB_VEN(Kernel& ios, const std::string& device_name); ~USB_VEN() override; - ReturnCode Open(const OpenRequest& request) override; IPCCommandResult IOCtl(const IOCtlRequest& request) override; IPCCommandResult IOCtlV(const IOCtlVRequest& request) override; diff --git a/Source/Core/Core/IOS/VersionInfo.cpp b/Source/Core/Core/IOS/VersionInfo.cpp index 8008998be74e..38e4eb003ece 100644 --- a/Source/Core/Core/IOS/VersionInfo.cpp +++ b/Source/Core/Core/IOS/VersionInfo.cpp @@ -335,5 +335,44 @@ const std::array& GetMemoryValues() { return ios_memory_values; } + +Feature GetFeatures(u32 version) +{ + // Common features that are present in most versions. + Feature features = Feature::Core | Feature::SDIO | Feature::SO | Feature::Ethernet; + + // IOS4 is a tiny IOS that was presumably used during manufacturing. It lacks network support. + if (version != 4) + features |= Feature::KD | Feature::SSL | Feature::NCD | Feature::WiFi; + + if (version == 48 || (version >= 56 && version <= 62) || version == 70 || version == 80) + features |= Feature::SDv2; + + if (version == 57 || version == 58 || version == 59) + features |= Feature::NewUSB; + if (version == 58 || version == 59) + features |= Feature::EHCI; + if (version == 59) + features |= Feature::WFS; + + // No IOS earlier than IOS30 has USB_KBD. Any IOS with the new USB modules lacks this module. + // TODO(IOS): it is currently unknown which other versions don't have it. + if (version >= 30 && !HasFeature(features, Feature::NewUSB)) + features |= Feature::USB_KBD; + + // Just like KBD, USB_HIDv4 is not present on any IOS with the new USB modules + // (since it's been replaced with USB_HIDv5 there). + // Additionally, it appears that HIDv4 and KBD are never both present. + // TODO(IOS): figure out which versions have HIDv4. For now we just include both KBD and HIDv4. + if (!HasFeature(features, Feature::NewUSB)) + features |= Feature::USB_HIDv4; + + return features; +} + +bool HasFeature(u32 major_version, Feature feature) +{ + return HasFeature(GetFeatures(major_version), feature); +} } } diff --git a/Source/Core/Core/IOS/VersionInfo.h b/Source/Core/Core/IOS/VersionInfo.h index d04dedd9c5b1..1b64b8b2aa94 100644 --- a/Source/Core/Core/IOS/VersionInfo.h +++ b/Source/Core/Core/IOS/VersionInfo.h @@ -37,5 +37,51 @@ struct MemoryValues }; const std::array& GetMemoryValues(); + +enum class Feature +{ + // Kernel, ES, FS, STM, DI, OH0, OH1 + Core = 1 << 0, + // SDIO + SDIO = 1 << 1, + // Network (base support: SO, Ethernet; KD, SSL, NCD, Wi-Fi) + SO = 1 << 2, + Ethernet = 1 << 3, + KD = 1 << 4, + SSL = 1 << 5, + NCD = 1 << 6, + WiFi = 1 << 7, + // KBD + USB_KBD = 1 << 8, + // USB_HID v4 + USB_HIDv4 = 1 << 9, + // SDv2 support + SDv2 = 1 << 10, + // New USB modules (USB, USB_VEN, USB_HUB, USB_MSC, OHCI0, USB_HIDv5) + NewUSB = 1 << 11, + // EHCI + EHCI = 1 << 12, + // WFS (WFSSRV, WFSI, USB_SHARED) + WFS = 1 << 13, +}; + +constexpr Feature operator|(Feature lhs, Feature rhs) +{ + return static_cast(static_cast(lhs) | static_cast(rhs)); +} + +constexpr Feature& operator|=(Feature& lhs, Feature rhs) +{ + lhs = lhs | rhs; + return lhs; +} + +constexpr bool HasFeature(Feature features, Feature feature) +{ + return (static_cast(features) & static_cast(feature)) != 0; +} + +bool HasFeature(u32 major_version, Feature feature); +Feature GetFeatures(u32 major_version); } } From b58f8d19ab20c2b4511e3516e69a26a28d4d642c Mon Sep 17 00:00:00 2001 From: Michael M Date: Wed, 23 Aug 2017 16:45:42 -0700 Subject: [PATCH 004/224] Rename Common::FifoQueue to Common::SPSCQueue Since all queues are FIFO data structures, the name wasn't informative as to why you'd use it over a normal queue. I originally thought it had something to do with the hardware graphics FIFO. This renames it using the common acronym SPSC, which stands for single-producer single-consumer, and is most commonly used to talk about lock-free data structures, both of which this is. --- Source/Core/Common/Analytics.h | 4 ++-- Source/Core/Common/Common.vcxproj | 4 ++-- Source/Core/Common/Common.vcxproj.filters | 4 ++-- Source/Core/Common/{FifoQueue.h => SPSCQueue.h} | 10 +++++----- Source/Core/Core/CoreTiming.cpp | 4 ++-- Source/Core/Core/HW/DVD/DVDThread.cpp | 8 ++++---- Source/Core/Core/HW/WiimoteReal/WiimoteReal.h | 6 +++--- Source/Core/Core/NetPlayClient.h | 8 ++++---- Source/Core/Core/NetPlayServer.h | 4 ++-- Source/Core/DolphinWX/NetPlay/NetWindow.cpp | 2 +- Source/Core/DolphinWX/NetPlay/NetWindow.h | 4 ++-- Source/UnitTests/Common/CMakeLists.txt | 2 +- .../Common/{FifoQueueTest.cpp => SPSCQueueTest.cpp} | 10 +++++----- 13 files changed, 35 insertions(+), 35 deletions(-) rename Source/Core/Common/{FifoQueue.h => SPSCQueue.h} (91%) rename Source/UnitTests/Common/{FifoQueueTest.cpp => SPSCQueueTest.cpp} (88%) diff --git a/Source/Core/Common/Analytics.h b/Source/Core/Common/Analytics.h index de87d21f1dbc..f4269d0c67f0 100644 --- a/Source/Core/Common/Analytics.h +++ b/Source/Core/Common/Analytics.h @@ -14,9 +14,9 @@ #include "Common/CommonTypes.h" #include "Common/Event.h" -#include "Common/FifoQueue.h" #include "Common/Flag.h" #include "Common/HttpRequest.h" +#include "Common/SPSCQueue.h" // Utilities for analytics reporting in Dolphin. This reporting is designed to // provide anonymous data about how well Dolphin performs in the wild. It also @@ -157,7 +157,7 @@ class AnalyticsReporter std::thread m_reporter_thread; Common::Event m_reporter_event; Common::Flag m_reporter_stop_request; - FifoQueue m_reports_queue; + SPSCQueue m_reports_queue; }; // Analytics backend to be used for debugging purpose, which dumps reports to diff --git a/Source/Core/Common/Common.vcxproj b/Source/Core/Common/Common.vcxproj index 71f500abf2da..7c3a86c643da 100644 --- a/Source/Core/Common/Common.vcxproj +++ b/Source/Core/Common/Common.vcxproj @@ -62,7 +62,6 @@ - @@ -142,6 +141,7 @@ + @@ -237,4 +237,4 @@ - \ No newline at end of file + diff --git a/Source/Core/Common/Common.vcxproj.filters b/Source/Core/Common/Common.vcxproj.filters index ceef3ae8e06c..4dedd6eca91e 100644 --- a/Source/Core/Common/Common.vcxproj.filters +++ b/Source/Core/Common/Common.vcxproj.filters @@ -41,7 +41,6 @@ - @@ -62,6 +61,7 @@ + @@ -336,4 +336,4 @@ - \ No newline at end of file + diff --git a/Source/Core/Common/FifoQueue.h b/Source/Core/Common/SPSCQueue.h similarity index 91% rename from Source/Core/Common/FifoQueue.h rename to Source/Core/Common/SPSCQueue.h index 1a3c5d817d2b..3e761d936ed5 100644 --- a/Source/Core/Common/FifoQueue.h +++ b/Source/Core/Common/SPSCQueue.h @@ -5,7 +5,7 @@ #pragma once // a simple lockless thread-safe, -// single reader, single writer queue +// single producer, single consumer queue #include #include @@ -16,11 +16,11 @@ namespace Common { template -class FifoQueue +class SPSCQueue { public: - FifoQueue() : m_size(0) { m_write_ptr = m_read_ptr = new ElementPtr(); } - ~FifoQueue() + SPSCQueue() : m_size(0) { m_write_ptr = m_read_ptr = new ElementPtr(); } + ~SPSCQueue() { // this will empty out the whole queue delete m_read_ptr; @@ -28,7 +28,7 @@ class FifoQueue u32 Size() const { - static_assert(NeedSize, "using Size() on FifoQueue without NeedSize"); + static_assert(NeedSize, "using Size() on SPSCQueue without NeedSize"); return m_size.load(); } diff --git a/Source/Core/Core/CoreTiming.cpp b/Source/Core/Core/CoreTiming.cpp index 3da6bc12d34d..62e3ce31f033 100644 --- a/Source/Core/Core/CoreTiming.cpp +++ b/Source/Core/Core/CoreTiming.cpp @@ -13,8 +13,8 @@ #include "Common/Assert.h" #include "Common/ChunkFile.h" -#include "Common/FifoQueue.h" #include "Common/Logging/Log.h" +#include "Common/SPSCQueue.h" #include "Common/StringUtil.h" #include "Common/Thread.h" @@ -63,7 +63,7 @@ static std::unordered_map s_event_types; static std::vector s_event_queue; static u64 s_event_fifo_id; static std::mutex s_ts_write_lock; -static Common::FifoQueue s_ts_queue; +static Common::SPSCQueue s_ts_queue; static float s_last_OC_factor; static constexpr int MAX_SLICE_LENGTH = 20000; diff --git a/Source/Core/Core/HW/DVD/DVDThread.cpp b/Source/Core/Core/HW/DVD/DVDThread.cpp index 33fdc279c497..57be86c73b53 100644 --- a/Source/Core/Core/HW/DVD/DVDThread.cpp +++ b/Source/Core/Core/HW/DVD/DVDThread.cpp @@ -16,10 +16,10 @@ #include "Common/ChunkFile.h" #include "Common/CommonTypes.h" #include "Common/Event.h" -#include "Common/FifoQueue.h" #include "Common/Flag.h" #include "Common/Logging/Log.h" #include "Common/MsgHandler.h" +#include "Common/SPSCQueue.h" #include "Common/Thread.h" #include "Common/Timer.h" @@ -83,8 +83,8 @@ static Common::Event s_request_queue_expanded; // Is set by CPU thread static Common::Event s_result_queue_expanded; // Is set by DVD thread static Common::Flag s_dvd_thread_exiting(false); // Is set by CPU thread -static Common::FifoQueue s_request_queue; -static Common::FifoQueue s_result_queue; +static Common::SPSCQueue s_request_queue; +static Common::SPSCQueue s_result_queue; static std::map s_result_map; static std::unique_ptr s_disc; @@ -140,7 +140,7 @@ void DoState(PointerWrap& p) WaitUntilIdle(); // Move all results from s_result_queue to s_result_map because - // PointerWrap::Do supports std::map but not Common::FifoQueue. + // PointerWrap::Do supports std::map but not Common::SPSCQueue. // This won't affect the behavior of FinishRead. ReadResult result; while (s_result_queue.Pop(result)) diff --git a/Source/Core/Core/HW/WiimoteReal/WiimoteReal.h b/Source/Core/Core/HW/WiimoteReal/WiimoteReal.h index 98754a8ae37d..d1b4c650869d 100644 --- a/Source/Core/Core/HW/WiimoteReal/WiimoteReal.h +++ b/Source/Core/Core/HW/WiimoteReal/WiimoteReal.h @@ -12,8 +12,8 @@ #include "Common/Common.h" #include "Common/Event.h" -#include "Common/FifoQueue.h" #include "Common/Flag.h" +#include "Common/SPSCQueue.h" #include "Core/HW/Wiimote.h" #include "Core/HW/WiimoteCommon/WiimoteConstants.h" #include "Core/HW/WiimoteCommon/WiimoteHid.h" @@ -112,8 +112,8 @@ class Wiimote // Triggered when the thread has finished ConnectInternal. Common::Event m_thread_ready_event; - Common::FifoQueue m_read_reports; - Common::FifoQueue m_write_reports; + Common::SPSCQueue m_read_reports; + Common::SPSCQueue m_write_reports; }; class WiimoteScannerBackend diff --git a/Source/Core/Core/NetPlayClient.h b/Source/Core/Core/NetPlayClient.h index 978cec9cb4ba..36134d5eb81c 100644 --- a/Source/Core/Core/NetPlayClient.h +++ b/Source/Core/Core/NetPlayClient.h @@ -13,7 +13,7 @@ #include #include "Common/CommonTypes.h" #include "Common/Event.h" -#include "Common/FifoQueue.h" +#include "Common/SPSCQueue.h" #include "Common/TraversalClient.h" #include "Core/NetPlayProto.h" #include "InputCommon/GCPadStatus.h" @@ -109,10 +109,10 @@ class NetPlayClient : public TraversalClientClient std::recursive_mutex async_queue_write; } m_crit; - Common::FifoQueue m_async_queue; + Common::SPSCQueue m_async_queue; - std::array, 4> m_pad_buffer; - std::array, 4> m_wiimote_buffer; + std::array, 4> m_pad_buffer; + std::array, 4> m_wiimote_buffer; NetPlayUI* m_dialog = nullptr; diff --git a/Source/Core/Core/NetPlayServer.h b/Source/Core/Core/NetPlayServer.h index 84bb2fba6e2e..e67aaf126648 100644 --- a/Source/Core/Core/NetPlayServer.h +++ b/Source/Core/Core/NetPlayServer.h @@ -12,7 +12,7 @@ #include #include #include -#include "Common/FifoQueue.h" +#include "Common/SPSCQueue.h" #include "Common/Timer.h" #include "Common/TraversalClient.h" #include "Core/NetPlayProto.h" @@ -114,7 +114,7 @@ class NetPlayServer : public TraversalClientClient std::string m_selected_game; std::thread m_thread; - Common::FifoQueue m_async_queue; + Common::SPSCQueue m_async_queue; ENetHost* m_server = nullptr; TraversalClient* m_traversal_client = nullptr; diff --git a/Source/Core/DolphinWX/NetPlay/NetWindow.cpp b/Source/Core/DolphinWX/NetPlay/NetWindow.cpp index 5aaf6ecbf762..ec6b6bba0b15 100644 --- a/Source/Core/DolphinWX/NetPlay/NetWindow.cpp +++ b/Source/Core/DolphinWX/NetPlay/NetWindow.cpp @@ -33,9 +33,9 @@ #include "Common/CommonPaths.h" #include "Common/CommonTypes.h" #include "Common/Config/Config.h" -#include "Common/FifoQueue.h" #include "Common/FileUtil.h" #include "Common/MsgHandler.h" +#include "Common/SPSCQueue.h" #include "Common/StringUtil.h" #include "Core/Config/SYSCONFSettings.h" diff --git a/Source/Core/DolphinWX/NetPlay/NetWindow.h b/Source/Core/DolphinWX/NetPlay/NetWindow.h index e3ccbf952f8e..599ffa4facbb 100644 --- a/Source/Core/DolphinWX/NetPlay/NetWindow.h +++ b/Source/Core/DolphinWX/NetPlay/NetWindow.h @@ -9,7 +9,7 @@ #include #include "Common/CommonTypes.h" -#include "Common/FifoQueue.h" +#include "Common/SPSCQueue.h" #include "Core/NetPlayClient.h" #include "Core/NetPlayProto.h" #include "Core/NetPlayServer.h" @@ -161,7 +161,7 @@ class NetPlayDialog : public wxFrame, public NetPlayUI std::string m_desync_player; std::vector m_playerids; - Common::FifoQueue m_chat_msgs; + Common::SPSCQueue m_chat_msgs; const GameListCtrl* const m_game_list; diff --git a/Source/UnitTests/Common/CMakeLists.txt b/Source/UnitTests/Common/CMakeLists.txt index 8b0eed1abff0..6736348c8b31 100644 --- a/Source/UnitTests/Common/CMakeLists.txt +++ b/Source/UnitTests/Common/CMakeLists.txt @@ -5,11 +5,11 @@ add_dolphin_test(BlockingLoopTest BlockingLoopTest.cpp) add_dolphin_test(BusyLoopTest BusyLoopTest.cpp) add_dolphin_test(CommonFuncsTest CommonFuncsTest.cpp) add_dolphin_test(EventTest EventTest.cpp) -add_dolphin_test(FifoQueueTest FifoQueueTest.cpp) add_dolphin_test(FixedSizeQueueTest FixedSizeQueueTest.cpp) add_dolphin_test(FlagTest FlagTest.cpp) add_dolphin_test(MathUtilTest MathUtilTest.cpp) add_dolphin_test(NandPathsTest NandPathsTest.cpp) +add_dolphin_test(SPSCQueueTest SPSCQueueTest.cpp) add_dolphin_test(StringUtilTest StringUtilTest.cpp) add_dolphin_test(SwapTest SwapTest.cpp) add_dolphin_test(x64EmitterTest x64EmitterTest.cpp) diff --git a/Source/UnitTests/Common/FifoQueueTest.cpp b/Source/UnitTests/Common/SPSCQueueTest.cpp similarity index 88% rename from Source/UnitTests/Common/FifoQueueTest.cpp rename to Source/UnitTests/Common/SPSCQueueTest.cpp index e4f3c913c1ae..0a4fbfcc1ca6 100644 --- a/Source/UnitTests/Common/FifoQueueTest.cpp +++ b/Source/UnitTests/Common/SPSCQueueTest.cpp @@ -5,11 +5,11 @@ #include #include -#include "Common/FifoQueue.h" +#include "Common/SPSCQueue.h" -TEST(FifoQueue, Simple) +TEST(SPSCQueue, Simple) { - Common::FifoQueue q; + Common::SPSCQueue q; EXPECT_EQ(0u, q.Size()); EXPECT_TRUE(q.Empty()); @@ -43,9 +43,9 @@ TEST(FifoQueue, Simple) EXPECT_TRUE(q.Empty()); } -TEST(FifoQueue, MultiThreaded) +TEST(SPSCQueue, MultiThreaded) { - Common::FifoQueue q; + Common::SPSCQueue q; auto inserter = [&q]() { for (u32 i = 0; i < 100000; ++i) From e0a326a493c68682cee3180f2edd60617878db53 Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Sun, 1 Oct 2017 12:09:16 -0700 Subject: [PATCH 005/224] VideoCommon: Fix overflow trying to access outside of EFB bounds --- Source/Core/VideoCommon/MainBase.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/Core/VideoCommon/MainBase.cpp b/Source/Core/VideoCommon/MainBase.cpp index 5f5ce785efe7..7530b9da8dd2 100644 --- a/Source/Core/VideoCommon/MainBase.cpp +++ b/Source/Core/VideoCommon/MainBase.cpp @@ -67,7 +67,7 @@ void VideoBackendBase::Video_BeginField(u32 xfbAddr, u32 fbWidth, u32 fbStride, u32 VideoBackendBase::Video_AccessEFB(EFBAccessType type, u32 x, u32 y, u32 InputData) { - if (!g_ActiveConfig.bEFBAccessEnable) + if (!g_ActiveConfig.bEFBAccessEnable || x >= EFB_WIDTH || y >= EFB_HEIGHT) { return 0; } From ec7ed7b47a8e89c6befa55a8c3af954fa706d62a Mon Sep 17 00:00:00 2001 From: JosJuice Date: Sun, 8 Oct 2017 11:43:48 +0200 Subject: [PATCH 006/224] TGCBlob: Improve variable names --- Source/Core/DiscIO/TGCBlob.cpp | 44 ++++++++++++++++++---------------- Source/Core/DiscIO/TGCBlob.h | 18 +++++++------- 2 files changed, 33 insertions(+), 29 deletions(-) diff --git a/Source/Core/DiscIO/TGCBlob.cpp b/Source/Core/DiscIO/TGCBlob.cpp index aed55f9c8a50..1a29174f5a65 100644 --- a/Source/Core/DiscIO/TGCBlob.cpp +++ b/Source/Core/DiscIO/TGCBlob.cpp @@ -71,45 +71,47 @@ TGCFileReader::TGCFileReader(File::IOFile file) : m_file(std::move(file)) { m_file.Seek(0, SEEK_SET); m_file.ReadArray(&m_header, 1); - u32 header_size = Common::swap32(m_header.header_size); + u32 header_size = Common::swap32(m_header.tgc_header_size); m_size = m_file.GetSize(); - m_file_offset = Common::swap32(m_header.unknown_important_2) - - Common::swap32(m_header.unknown_important_1) + header_size; + m_file_area_shift = Common::swap32(m_header.file_area_virtual_offset) - + Common::swap32(m_header.file_area_real_offset) + header_size; } u64 TGCFileReader::GetDataSize() const { - return m_size + Common::swap32(m_header.unknown_important_2) - - Common::swap32(m_header.unknown_important_1); + return m_size + Common::swap32(m_header.file_area_virtual_offset) - + Common::swap32(m_header.file_area_real_offset); } bool TGCFileReader::Read(u64 offset, u64 nbytes, u8* out_ptr) { Interval first_part; Interval empty_part; - Interval last_part; + Interval file_part; - u32 header_size = Common::swap32(m_header.header_size); - SplitInterval(m_file_offset, Interval{offset, nbytes}, &first_part, &last_part); - SplitInterval(m_size - header_size, first_part, &first_part, &empty_part); + const u32 tgc_header_size = Common::swap32(m_header.tgc_header_size); + SplitInterval(m_file_area_shift, Interval{offset, nbytes}, &first_part, &file_part); + SplitInterval(m_size - tgc_header_size, first_part, &first_part, &empty_part); - // Offsets before m_file_offset are read as usual + // Offsets in the initial areas of the disc are unshifted + // (except for InternalRead's constant shift by tgc_header_size). if (!first_part.IsEmpty()) { if (!InternalRead(first_part.start, first_part.length, out_ptr + (first_part.start - offset))) return false; } - // If any offset before m_file_offset isn't actually in the file, - // treat it as 0x00 bytes (so e.g. MD5 calculation of the whole disc won't fail) + // The data between the file area and the area that precedes it is treated as all zeroes. + // The game normally won't attempt to access this part of the virtual disc, but let's not return + // an error if it gets accessed, in case someone wants to copy or hash the whole virtual disc. if (!empty_part.IsEmpty()) std::fill_n(out_ptr + (empty_part.start - offset), empty_part.length, 0); - // Offsets after m_file_offset are read as if they are (offset - m_file_offset) - if (!last_part.IsEmpty()) + // Offsets in the file area are shifted by m_file_area_shift. + if (!file_part.IsEmpty()) { - if (!InternalRead(last_part.start - m_file_offset, last_part.length, - out_ptr + (last_part.start - offset))) + if (!InternalRead(file_part.start - m_file_area_shift, file_part.length, + out_ptr + (file_part.start - offset))) return false; } @@ -118,12 +120,14 @@ bool TGCFileReader::Read(u64 offset, u64 nbytes, u8* out_ptr) bool TGCFileReader::InternalRead(u64 offset, u64 nbytes, u8* out_ptr) { - u32 header_size = Common::swap32(m_header.header_size); + const u32 tgc_header_size = Common::swap32(m_header.tgc_header_size); - if (m_file.Seek(offset + header_size, SEEK_SET) && m_file.ReadBytes(out_ptr, nbytes)) + if (m_file.Seek(offset + tgc_header_size, SEEK_SET) && m_file.ReadBytes(out_ptr, nbytes)) { - Replace32(offset, nbytes, out_ptr, 0x420, SubtractBE32(m_header.dol_offset, header_size)); - Replace32(offset, nbytes, out_ptr, 0x424, SubtractBE32(m_header.fst_offset, header_size)); + Replace32(offset, nbytes, out_ptr, 0x420, + SubtractBE32(m_header.dol_real_offset, tgc_header_size)); + Replace32(offset, nbytes, out_ptr, 0x424, + SubtractBE32(m_header.fst_real_offset, tgc_header_size)); return true; } diff --git a/Source/Core/DiscIO/TGCBlob.h b/Source/Core/DiscIO/TGCBlob.h index 1a2ef6f326cc..0816d27e3b63 100644 --- a/Source/Core/DiscIO/TGCBlob.h +++ b/Source/Core/DiscIO/TGCBlob.h @@ -20,21 +20,21 @@ struct TGCHeader { u32 magic; u32 unknown_1; - u32 header_size; - u32 unknown_2; + u32 tgc_header_size; + u32 disc_header_area_size; - u32 fst_offset; + u32 fst_real_offset; u32 fst_size; u32 fst_max_size; - u32 dol_offset; + u32 dol_real_offset; u32 dol_size; - u32 unknown_important_1; + u32 file_area_real_offset; + u32 unknown_2; u32 unknown_3; - u32 unknown_4; - u32 unknown_5; - u32 unknown_important_2; + u32 unknown_4; + u32 file_area_virtual_offset; }; class TGCFileReader final : public BlobReader @@ -55,7 +55,7 @@ class TGCFileReader final : public BlobReader File::IOFile m_file; u64 m_size; - u64 m_file_offset; + u64 m_file_area_shift; // Stored as big endian in memory, regardless of the host endianness TGCHeader m_header = {}; From 18c76085162bee8b4098fe99b0508b07ff7a174d Mon Sep 17 00:00:00 2001 From: JosJuice Date: Sun, 8 Oct 2017 12:16:10 +0200 Subject: [PATCH 007/224] TGCBlob: Use file_area_real_offset as split point Part one of fixing TGC files where file_area_virtual_offset is smaller than file_area_real_offset, such as Zelda OoT Master Quest. --- Source/Core/DiscIO/TGCBlob.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Source/Core/DiscIO/TGCBlob.cpp b/Source/Core/DiscIO/TGCBlob.cpp index 1a29174f5a65..71d43e76da3b 100644 --- a/Source/Core/DiscIO/TGCBlob.cpp +++ b/Source/Core/DiscIO/TGCBlob.cpp @@ -90,8 +90,9 @@ bool TGCFileReader::Read(u64 offset, u64 nbytes, u8* out_ptr) Interval file_part; const u32 tgc_header_size = Common::swap32(m_header.tgc_header_size); - SplitInterval(m_file_area_shift, Interval{offset, nbytes}, &first_part, &file_part); - SplitInterval(m_size - tgc_header_size, first_part, &first_part, &empty_part); + const u64 split_point = Common::swap32(m_header.file_area_real_offset) - tgc_header_size; + SplitInterval(split_point, Interval{offset, nbytes}, &first_part, &file_part); + SplitInterval(m_file_area_shift - tgc_header_size, file_part, &empty_part, &file_part); // Offsets in the initial areas of the disc are unshifted // (except for InternalRead's constant shift by tgc_header_size). From 0023d5b5cb77779983cc4beb9f7f7f340d8dd6a1 Mon Sep 17 00:00:00 2001 From: JosJuice Date: Sun, 8 Oct 2017 12:30:53 +0200 Subject: [PATCH 008/224] TGCBlob: Make m_file_area_shift signed Part two of fixing TGC files where file_area_virtual_offset is smaller than file_area_real_offset, such as Zelda OoT Master Quest. --- Source/Core/DiscIO/TGCBlob.cpp | 14 +++++++++----- Source/Core/DiscIO/TGCBlob.h | 2 +- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/Source/Core/DiscIO/TGCBlob.cpp b/Source/Core/DiscIO/TGCBlob.cpp index 71d43e76da3b..a7c6b37ccebf 100644 --- a/Source/Core/DiscIO/TGCBlob.cpp +++ b/Source/Core/DiscIO/TGCBlob.cpp @@ -73,7 +73,7 @@ TGCFileReader::TGCFileReader(File::IOFile file) : m_file(std::move(file)) m_file.ReadArray(&m_header, 1); u32 header_size = Common::swap32(m_header.tgc_header_size); m_size = m_file.GetSize(); - m_file_area_shift = Common::swap32(m_header.file_area_virtual_offset) - + m_file_area_shift = static_cast(Common::swap32(m_header.file_area_virtual_offset)) - Common::swap32(m_header.file_area_real_offset) + header_size; } @@ -85,14 +85,18 @@ u64 TGCFileReader::GetDataSize() const bool TGCFileReader::Read(u64 offset, u64 nbytes, u8* out_ptr) { - Interval first_part; - Interval empty_part; - Interval file_part; + Interval first_part = {0, 0}; + Interval empty_part = {0, 0}; + Interval file_part = {0, 0}; const u32 tgc_header_size = Common::swap32(m_header.tgc_header_size); const u64 split_point = Common::swap32(m_header.file_area_real_offset) - tgc_header_size; SplitInterval(split_point, Interval{offset, nbytes}, &first_part, &file_part); - SplitInterval(m_file_area_shift - tgc_header_size, file_part, &empty_part, &file_part); + if (m_file_area_shift > tgc_header_size) + { + SplitInterval(static_cast(m_file_area_shift - tgc_header_size), file_part, &empty_part, + &file_part); + } // Offsets in the initial areas of the disc are unshifted // (except for InternalRead's constant shift by tgc_header_size). diff --git a/Source/Core/DiscIO/TGCBlob.h b/Source/Core/DiscIO/TGCBlob.h index 0816d27e3b63..31a46fca00f6 100644 --- a/Source/Core/DiscIO/TGCBlob.h +++ b/Source/Core/DiscIO/TGCBlob.h @@ -55,7 +55,7 @@ class TGCFileReader final : public BlobReader File::IOFile m_file; u64 m_size; - u64 m_file_area_shift; + s64 m_file_area_shift; // Stored as big endian in memory, regardless of the host endianness TGCHeader m_header = {}; From e743ac80d2757f9c6c8cfb84886586408fda7755 Mon Sep 17 00:00:00 2001 From: JosJuice Date: Sun, 8 Oct 2017 12:38:12 +0200 Subject: [PATCH 009/224] TGCBlob: Fix brace style --- Source/Core/DiscIO/TGCBlob.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Source/Core/DiscIO/TGCBlob.cpp b/Source/Core/DiscIO/TGCBlob.cpp index a7c6b37ccebf..6ee5fd5bb361 100644 --- a/Source/Core/DiscIO/TGCBlob.cpp +++ b/Source/Core/DiscIO/TGCBlob.cpp @@ -32,10 +32,14 @@ void SplitInterval(T split_point, Interval interval, Interval* out_1, Inte *out_1 = {0, 0}; if (interval.End() > split_point) + { *out_2 = {std::max(interval.start, split_point), std::min(interval.length, interval.End() - split_point)}; + } else + { *out_2 = {0, 0}; + } } u32 SubtractBE32(u32 minuend_be, u32 subtrahend_le) @@ -117,7 +121,9 @@ bool TGCFileReader::Read(u64 offset, u64 nbytes, u8* out_ptr) { if (!InternalRead(file_part.start - m_file_area_shift, file_part.length, out_ptr + (file_part.start - offset))) + { return false; + } } return true; From 79188d4f5500f6bb9e663e3d36f0e12ec0dd9532 Mon Sep 17 00:00:00 2001 From: Stenzek Date: Tue, 10 Oct 2017 23:09:12 +1000 Subject: [PATCH 010/224] Vulkan: Use VK_NV_glsl extension where available, and skip glslang --- .../VideoBackends/Vulkan/ShaderCompiler.cpp | 79 ++++++++++++++++++- .../VideoBackends/Vulkan/ShaderCompiler.h | 8 +- .../VideoBackends/Vulkan/TextureConverter.cpp | 2 +- Source/Core/VideoBackends/Vulkan/Util.cpp | 28 ++----- Source/Core/VideoBackends/Vulkan/Util.h | 12 +-- .../VideoBackends/Vulkan/VulkanContext.cpp | 9 ++- .../Core/VideoBackends/Vulkan/VulkanContext.h | 3 + 7 files changed, 103 insertions(+), 38 deletions(-) diff --git a/Source/Core/VideoBackends/Vulkan/ShaderCompiler.cpp b/Source/Core/VideoBackends/Vulkan/ShaderCompiler.cpp index 75bf99a3baae..c97c56f75da9 100644 --- a/Source/Core/VideoBackends/Vulkan/ShaderCompiler.cpp +++ b/Source/Core/VideoBackends/Vulkan/ShaderCompiler.cpp @@ -3,9 +3,11 @@ // Refer to the license.txt file included. #include "VideoBackends/Vulkan/ShaderCompiler.h" +#include "VideoBackends/Vulkan/VulkanContext.h" #include #include +#include #include #include #include @@ -37,6 +39,11 @@ static bool CompileShaderToSPV(SPIRVCodeVector* out_code, EShLanguage stage, const char* stage_filename, const char* source_code, size_t source_code_length, const char* header, size_t header_length); +// Copy GLSL source code to a SPIRVCodeVector, for use with VK_NV_glsl_shader. +static void CopyGLSLToSPVVector(SPIRVCodeVector* out_code, const char* stage_filename, + const char* source_code, size_t source_code_length, + const char* header, size_t header_length); + // Regarding the UBO bind points, we subtract one from the binding index because // the OpenGL backend requires UBO #0 for non-block uniforms (at least on NV). // This allows us to share the same shaders but use bind point #0 in the Vulkan @@ -219,6 +226,42 @@ bool CompileShaderToSPV(SPIRVCodeVector* out_code, EShLanguage stage, const char return true; } +void CopyGLSLToSPVVector(SPIRVCodeVector* out_code, const char* stage_filename, + const char* source_code, size_t source_code_length, const char* header, + size_t header_length) +{ + std::string full_source_code; + if (header_length > 0) + { + full_source_code.reserve(header_length + source_code_length); + full_source_code.append(header, header_length); + full_source_code.append(source_code, source_code_length); + } + else + { + full_source_code.append(source_code, source_code_length); + } + + if (g_ActiveConfig.iLog & CONF_SAVESHADERS) + { + static int counter = 0; + std::string filename = StringFromFormat("%s%s_%04i.txt", File::GetUserPath(D_DUMP_IDX).c_str(), + stage_filename, counter++); + + std::ofstream stream; + File::OpenFStream(stream, filename, std::ios_base::out); + if (stream.good()) + stream << full_source_code << std::endl; + } + + size_t padding = full_source_code.size() % 4; + if (padding != 0) + full_source_code.append(4 - padding, '\n'); + + out_code->resize(full_source_code.size() / 4); + std::memcpy(out_code->data(), full_source_code.c_str(), full_source_code.size()); +} + bool InitializeGlslang() { static bool glslang_initialized = false; @@ -338,29 +381,57 @@ const TBuiltInResource* GetCompilerResourceLimits() } bool CompileVertexShader(SPIRVCodeVector* out_code, const char* source_code, - size_t source_code_length, bool prepend_header) + size_t source_code_length) { + if (g_vulkan_context->SupportsNVGLSLExtension()) + { + CopyGLSLToSPVVector(out_code, "vs", source_code, source_code_length, SHADER_HEADER, + sizeof(SHADER_HEADER) - 1); + return true; + } + return CompileShaderToSPV(out_code, EShLangVertex, "vs", source_code, source_code_length, SHADER_HEADER, sizeof(SHADER_HEADER) - 1); } bool CompileGeometryShader(SPIRVCodeVector* out_code, const char* source_code, - size_t source_code_length, bool prepend_header) + size_t source_code_length) { + if (g_vulkan_context->SupportsNVGLSLExtension()) + { + CopyGLSLToSPVVector(out_code, "gs", source_code, source_code_length, SHADER_HEADER, + sizeof(SHADER_HEADER) - 1); + return true; + } + return CompileShaderToSPV(out_code, EShLangGeometry, "gs", source_code, source_code_length, SHADER_HEADER, sizeof(SHADER_HEADER) - 1); } bool CompileFragmentShader(SPIRVCodeVector* out_code, const char* source_code, - size_t source_code_length, bool prepend_header) + size_t source_code_length) { + if (g_vulkan_context->SupportsNVGLSLExtension()) + { + CopyGLSLToSPVVector(out_code, "ps", source_code, source_code_length, SHADER_HEADER, + sizeof(SHADER_HEADER) - 1); + return true; + } + return CompileShaderToSPV(out_code, EShLangFragment, "ps", source_code, source_code_length, SHADER_HEADER, sizeof(SHADER_HEADER) - 1); } bool CompileComputeShader(SPIRVCodeVector* out_code, const char* source_code, - size_t source_code_length, bool prepend_header) + size_t source_code_length) { + if (g_vulkan_context->SupportsNVGLSLExtension()) + { + CopyGLSLToSPVVector(out_code, "cs", source_code, source_code_length, COMPUTE_SHADER_HEADER, + sizeof(COMPUTE_SHADER_HEADER) - 1); + return true; + } + return CompileShaderToSPV(out_code, EShLangCompute, "cs", source_code, source_code_length, COMPUTE_SHADER_HEADER, sizeof(COMPUTE_SHADER_HEADER) - 1); } diff --git a/Source/Core/VideoBackends/Vulkan/ShaderCompiler.h b/Source/Core/VideoBackends/Vulkan/ShaderCompiler.h index 197dc1787c21..84434b1ad642 100644 --- a/Source/Core/VideoBackends/Vulkan/ShaderCompiler.h +++ b/Source/Core/VideoBackends/Vulkan/ShaderCompiler.h @@ -19,19 +19,19 @@ using SPIRVCodeVector = std::vector; // Compile a vertex shader to SPIR-V. bool CompileVertexShader(SPIRVCodeVector* out_code, const char* source_code, - size_t source_code_length, bool prepend_header = true); + size_t source_code_length); // Compile a geometry shader to SPIR-V. bool CompileGeometryShader(SPIRVCodeVector* out_code, const char* source_code, - size_t source_code_length, bool prepend_header = true); + size_t source_code_length); // Compile a fragment shader to SPIR-V. bool CompileFragmentShader(SPIRVCodeVector* out_code, const char* source_code, - size_t source_code_length, bool prepend_header = true); + size_t source_code_length); // Compile a compute shader to SPIR-V. bool CompileComputeShader(SPIRVCodeVector* out_code, const char* source_code, - size_t source_code_length, bool prepend_header = true); + size_t source_code_length); } // namespace ShaderCompiler } // namespace Vulkan diff --git a/Source/Core/VideoBackends/Vulkan/TextureConverter.cpp b/Source/Core/VideoBackends/Vulkan/TextureConverter.cpp index e0376c3cae95..2ff6f34c3328 100644 --- a/Source/Core/VideoBackends/Vulkan/TextureConverter.cpp +++ b/Source/Core/VideoBackends/Vulkan/TextureConverter.cpp @@ -407,7 +407,7 @@ bool TextureConverter::SupportsTextureDecoding(TextureFormat format, TLUTFormat std::string shader_source = TextureConversionShader::GenerateDecodingShader(format, palette_format, APIType::Vulkan); - pipeline.compute_shader = Util::CompileAndCreateComputeShader(shader_source, true); + pipeline.compute_shader = Util::CompileAndCreateComputeShader(shader_source); if (pipeline.compute_shader == VK_NULL_HANDLE) { m_decoding_pipelines.emplace(key, pipeline); diff --git a/Source/Core/VideoBackends/Vulkan/Util.cpp b/Source/Core/VideoBackends/Vulkan/Util.cpp index 8a94dd42ad93..221fa97cdaf5 100644 --- a/Source/Core/VideoBackends/Vulkan/Util.cpp +++ b/Source/Core/VideoBackends/Vulkan/Util.cpp @@ -249,50 +249,38 @@ VkShaderModule CreateShaderModule(const u32* spv, size_t spv_word_count) return module; } -VkShaderModule CompileAndCreateVertexShader(const std::string& source_code, bool prepend_header) +VkShaderModule CompileAndCreateVertexShader(const std::string& source_code) { ShaderCompiler::SPIRVCodeVector code; - if (!ShaderCompiler::CompileVertexShader(&code, source_code.c_str(), source_code.length(), - prepend_header)) - { + if (!ShaderCompiler::CompileVertexShader(&code, source_code.c_str(), source_code.length())) return VK_NULL_HANDLE; - } return CreateShaderModule(code.data(), code.size()); } -VkShaderModule CompileAndCreateGeometryShader(const std::string& source_code, bool prepend_header) +VkShaderModule CompileAndCreateGeometryShader(const std::string& source_code) { ShaderCompiler::SPIRVCodeVector code; - if (!ShaderCompiler::CompileGeometryShader(&code, source_code.c_str(), source_code.length(), - prepend_header)) - { + if (!ShaderCompiler::CompileGeometryShader(&code, source_code.c_str(), source_code.length())) return VK_NULL_HANDLE; - } return CreateShaderModule(code.data(), code.size()); } -VkShaderModule CompileAndCreateFragmentShader(const std::string& source_code, bool prepend_header) +VkShaderModule CompileAndCreateFragmentShader(const std::string& source_code) { ShaderCompiler::SPIRVCodeVector code; - if (!ShaderCompiler::CompileFragmentShader(&code, source_code.c_str(), source_code.length(), - prepend_header)) - { + if (!ShaderCompiler::CompileFragmentShader(&code, source_code.c_str(), source_code.length())) return VK_NULL_HANDLE; - } return CreateShaderModule(code.data(), code.size()); } -VkShaderModule CompileAndCreateComputeShader(const std::string& source_code, bool prepend_header) +VkShaderModule CompileAndCreateComputeShader(const std::string& source_code) { ShaderCompiler::SPIRVCodeVector code; - if (!ShaderCompiler::CompileComputeShader(&code, source_code.c_str(), source_code.length(), - prepend_header)) - { + if (!ShaderCompiler::CompileComputeShader(&code, source_code.c_str(), source_code.length())) return VK_NULL_HANDLE; - } return CreateShaderModule(code.data(), code.size()); } diff --git a/Source/Core/VideoBackends/Vulkan/Util.h b/Source/Core/VideoBackends/Vulkan/Util.h index 413e3b96c50e..56d8d58ff041 100644 --- a/Source/Core/VideoBackends/Vulkan/Util.h +++ b/Source/Core/VideoBackends/Vulkan/Util.h @@ -57,20 +57,16 @@ void ExecuteCurrentCommandsAndRestoreState(bool execute_off_thread, VkShaderModule CreateShaderModule(const u32* spv, size_t spv_word_count); // Compile a vertex shader and create a shader module, discarding the intermediate SPIR-V. -VkShaderModule CompileAndCreateVertexShader(const std::string& source_code, - bool prepend_header = true); +VkShaderModule CompileAndCreateVertexShader(const std::string& source_code); // Compile a geometry shader and create a shader module, discarding the intermediate SPIR-V. -VkShaderModule CompileAndCreateGeometryShader(const std::string& source_code, - bool prepend_header = true); +VkShaderModule CompileAndCreateGeometryShader(const std::string& source_code); // Compile a fragment shader and create a shader module, discarding the intermediate SPIR-V. -VkShaderModule CompileAndCreateFragmentShader(const std::string& source_code, - bool prepend_header = true); +VkShaderModule CompileAndCreateFragmentShader(const std::string& source_code); // Compile a compute shader and create a shader module, discarding the intermediate SPIR-V. -VkShaderModule CompileAndCreateComputeShader(const std::string& source_code, - bool prepend_header = true); +VkShaderModule CompileAndCreateComputeShader(const std::string& source_code); } // Utility shader vertex format diff --git a/Source/Core/VideoBackends/Vulkan/VulkanContext.cpp b/Source/Core/VideoBackends/Vulkan/VulkanContext.cpp index d4524f5c271a..765a6f33f3dc 100644 --- a/Source/Core/VideoBackends/Vulkan/VulkanContext.cpp +++ b/Source/Core/VideoBackends/Vulkan/VulkanContext.cpp @@ -403,7 +403,8 @@ bool VulkanContext::SelectDeviceExtensions(ExtensionList* extension_list, bool e for (const auto& extension_properties : available_extension_list) INFO_LOG(VIDEO, "Available extension: %s", extension_properties.extensionName); - auto CheckForExtension = [&](const char* name, bool required) -> bool { + auto CheckForExtension = [&](const char* name, bool required, + bool* has_extension = nullptr) -> bool { if (std::find_if(available_extension_list.begin(), available_extension_list.end(), [&](const VkExtensionProperties& properties) { return !strcmp(name, properties.extensionName); @@ -411,9 +412,14 @@ bool VulkanContext::SelectDeviceExtensions(ExtensionList* extension_list, bool e { INFO_LOG(VIDEO, "Enabling extension: %s", name); extension_list->push_back(name); + if (has_extension) + *has_extension = true; return true; } + if (has_extension) + *has_extension = false; + if (required) { ERROR_LOG(VIDEO, "Vulkan: Missing required extension %s.", name); @@ -426,6 +432,7 @@ bool VulkanContext::SelectDeviceExtensions(ExtensionList* extension_list, bool e if (enable_surface && !CheckForExtension(VK_KHR_SWAPCHAIN_EXTENSION_NAME, true)) return false; + CheckForExtension(VK_NV_GLSL_SHADER_EXTENSION_NAME, false, &m_supports_nv_glsl_extension); return true; } diff --git a/Source/Core/VideoBackends/Vulkan/VulkanContext.h b/Source/Core/VideoBackends/Vulkan/VulkanContext.h index 3ac496339d78..fd504560b8a1 100644 --- a/Source/Core/VideoBackends/Vulkan/VulkanContext.h +++ b/Source/Core/VideoBackends/Vulkan/VulkanContext.h @@ -83,6 +83,7 @@ class VulkanContext { return m_device_features.occlusionQueryPrecise == VK_TRUE; } + bool SupportsNVGLSLExtension() const { return m_supports_nv_glsl_extension; } // Helpers for getting constants VkDeviceSize GetUniformBufferAlignment() const { @@ -129,6 +130,8 @@ class VulkanContext VkPhysicalDeviceFeatures m_device_features = {}; VkPhysicalDeviceProperties m_device_properties = {}; VkPhysicalDeviceMemoryProperties m_device_memory_properties = {}; + + bool m_supports_nv_glsl_extension = false; }; extern std::unique_ptr g_vulkan_context; From 06bbf111d97b417aa70565a9629f97376f297ecf Mon Sep 17 00:00:00 2001 From: Stenzek Date: Wed, 11 Oct 2017 23:15:08 +1000 Subject: [PATCH 011/224] Vulkan: Improve readability of device/instance extension checks --- .../VideoBackends/Vulkan/VulkanContext.cpp | 38 ++++++------------- 1 file changed, 12 insertions(+), 26 deletions(-) diff --git a/Source/Core/VideoBackends/Vulkan/VulkanContext.cpp b/Source/Core/VideoBackends/Vulkan/VulkanContext.cpp index 765a6f33f3dc..e2f44b73bee3 100644 --- a/Source/Core/VideoBackends/Vulkan/VulkanContext.cpp +++ b/Source/Core/VideoBackends/Vulkan/VulkanContext.cpp @@ -153,7 +153,7 @@ bool VulkanContext::SelectInstanceExtensions(ExtensionList* extension_list, bool for (const auto& extension_properties : available_extension_list) INFO_LOG(VIDEO, "Available extension: %s", extension_properties.extensionName); - auto CheckForExtension = [&](const char* name, bool required) -> bool { + auto SupportsExtension = [&](const char* name, bool required) { if (std::find_if(available_extension_list.begin(), available_extension_list.end(), [&](const VkExtensionProperties& properties) { return !strcmp(name, properties.extensionName); @@ -165,36 +165,31 @@ bool VulkanContext::SelectInstanceExtensions(ExtensionList* extension_list, bool } if (required) - { ERROR_LOG(VIDEO, "Vulkan: Missing required extension %s.", name); - return false; - } - return true; + return false; }; // Common extensions - if (enable_surface && !CheckForExtension(VK_KHR_SURFACE_EXTENSION_NAME, true)) - { + if (enable_surface && !SupportsExtension(VK_KHR_SURFACE_EXTENSION_NAME, true)) return false; - } #if defined(VK_USE_PLATFORM_WIN32_KHR) - if (enable_surface && !CheckForExtension(VK_KHR_WIN32_SURFACE_EXTENSION_NAME, true)) + if (enable_surface && !SupportsExtension(VK_KHR_WIN32_SURFACE_EXTENSION_NAME, true)) return false; #elif defined(VK_USE_PLATFORM_XLIB_KHR) - if (enable_surface && !CheckForExtension(VK_KHR_XLIB_SURFACE_EXTENSION_NAME, true)) + if (enable_surface && !SupportsExtension(VK_KHR_XLIB_SURFACE_EXTENSION_NAME, true)) return false; #elif defined(VK_USE_PLATFORM_XCB_KHR) - if (enable_surface && !CheckForExtension(VK_KHR_XCB_SURFACE_EXTENSION_NAME, true)) + if (enable_surface && !SupportsExtension(VK_KHR_XCB_SURFACE_EXTENSION_NAME, true)) return false; #elif defined(VK_USE_PLATFORM_ANDROID_KHR) - if (enable_surface && !CheckForExtension(VK_KHR_ANDROID_SURFACE_EXTENSION_NAME, true)) + if (enable_surface && !SupportsExtension(VK_KHR_ANDROID_SURFACE_EXTENSION_NAME, true)) return false; #endif // VK_EXT_debug_report - if (enable_debug_report && !CheckForExtension(VK_EXT_DEBUG_REPORT_EXTENSION_NAME, true)) + if (enable_debug_report && !SupportsExtension(VK_EXT_DEBUG_REPORT_EXTENSION_NAME, false)) WARN_LOG(VIDEO, "Vulkan: Debug report requested, but extension is not available."); return true; @@ -403,8 +398,7 @@ bool VulkanContext::SelectDeviceExtensions(ExtensionList* extension_list, bool e for (const auto& extension_properties : available_extension_list) INFO_LOG(VIDEO, "Available extension: %s", extension_properties.extensionName); - auto CheckForExtension = [&](const char* name, bool required, - bool* has_extension = nullptr) -> bool { + auto SupportsExtension = [&](const char* name, bool required) { if (std::find_if(available_extension_list.begin(), available_extension_list.end(), [&](const VkExtensionProperties& properties) { return !strcmp(name, properties.extensionName); @@ -412,27 +406,19 @@ bool VulkanContext::SelectDeviceExtensions(ExtensionList* extension_list, bool e { INFO_LOG(VIDEO, "Enabling extension: %s", name); extension_list->push_back(name); - if (has_extension) - *has_extension = true; return true; } - if (has_extension) - *has_extension = false; - if (required) - { ERROR_LOG(VIDEO, "Vulkan: Missing required extension %s.", name); - return false; - } - return true; + return false; }; - if (enable_surface && !CheckForExtension(VK_KHR_SWAPCHAIN_EXTENSION_NAME, true)) + if (enable_surface && !SupportsExtension(VK_KHR_SWAPCHAIN_EXTENSION_NAME, true)) return false; - CheckForExtension(VK_NV_GLSL_SHADER_EXTENSION_NAME, false, &m_supports_nv_glsl_extension); + m_supports_nv_glsl_extension = SupportsExtension(VK_NV_GLSL_SHADER_EXTENSION_NAME, false); return true; } From 28d648b80278161e21e370e326be4de4a8645340 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9o=20Lam?= Date: Wed, 11 Oct 2017 17:17:25 +0200 Subject: [PATCH 012/224] MemArena: Use names that are based on the PID Fixes a regression which broke running several Dolphin instances at the same time on Windows. Thanks to exjam for spotting the issue pretty much immediately. Sorry about that! Also changes the file names to be more consistent on all platforms. --- Source/Core/Common/MemArena.cpp | 24 +++++++++--------------- 1 file changed, 9 insertions(+), 15 deletions(-) diff --git a/Source/Core/Common/MemArena.cpp b/Source/Core/Common/MemArena.cpp index d9b3d1a37c89..750a240e19cc 100644 --- a/Source/Core/Common/MemArena.cpp +++ b/Source/Core/Common/MemArena.cpp @@ -55,31 +55,25 @@ static int AshmemCreateFileMapping(const char* name, size_t size) void MemArena::GrabSHMSegment(size_t size) { #ifdef _WIN32 + const std::string name = "dolphin-emu." + std::to_string(GetCurrentProcessId()); hMemoryMapping = CreateFileMapping(INVALID_HANDLE_VALUE, nullptr, PAGE_READWRITE, 0, - static_cast(size), L"Dolphin-emu"); + static_cast(size), UTF8ToTStr(name).c_str()); #elif defined(ANDROID) - fd = AshmemCreateFileMapping("Dolphin-emu", size); + fd = AshmemCreateFileMapping(("dolphin-emu." + std::to_string(getpid())).c_str(), size); if (fd < 0) { NOTICE_LOG(MEMMAP, "Ashmem allocation failed"); return; } #else - for (int i = 0; i < 10000; i++) + const std::string file_name = "/dolphin-emu." + std::to_string(getpid()); + fd = shm_open(file_name.c_str(), O_RDWR | O_CREAT | O_EXCL, 0600); + if (fd == -1) { - 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) - { - shm_unlink(file_name.c_str()); - break; - } - else if (errno != EEXIST) - { - ERROR_LOG(MEMMAP, "shm_open failed: %s", strerror(errno)); - return; - } + ERROR_LOG(MEMMAP, "shm_open failed: %s", strerror(errno)); + return; } + shm_unlink(file_name.c_str()); if (ftruncate(fd, size) < 0) ERROR_LOG(MEMMAP, "Failed to allocate low memory space"); #endif From 9407d9ee0b4deca4ded47ee7528ecaccee2c63e0 Mon Sep 17 00:00:00 2001 From: Mike Harris Date: Thu, 28 Sep 2017 19:06:41 -0700 Subject: [PATCH 013/224] Bump compile SDK and buildtools version to 26 (Oreo). Bump the support lib version to 26. This allows for using property animators (R.animator) in FragmentTransaction.setCustomAnimations. Add the google maven repo, as from support lib 26 onwards, they're only publishing it in there. Bump the gradle version while we're at it, keep Android Studio quiet. --- Source/Android/app/build.gradle | 6 +++--- Source/Android/build.gradle | 5 ++++- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/Source/Android/app/build.gradle b/Source/Android/app/build.gradle index bdb0df444e5b..ae502037b129 100644 --- a/Source/Android/app/build.gradle +++ b/Source/Android/app/build.gradle @@ -1,8 +1,8 @@ apply plugin: 'com.android.application' android { - compileSdkVersion 25 - buildToolsVersion '25.0.2' + compileSdkVersion 26 + buildToolsVersion '26.0.2' lintOptions { // This is important as it will run lint but not abort on error @@ -71,7 +71,7 @@ android { } ext { - androidSupportVersion = '25.3.0' + androidSupportVersion = '26.1.0' } dependencies { diff --git a/Source/Android/build.gradle b/Source/Android/build.gradle index 3f806cd79c8c..aac9f5bae5fd 100644 --- a/Source/Android/build.gradle +++ b/Source/Android/build.gradle @@ -3,12 +3,15 @@ buildscript { jcenter() } dependencies { - classpath 'com.android.tools.build:gradle:2.3.0' + classpath 'com.android.tools.build:gradle:2.3.3' } } allprojects { repositories { jcenter() + maven { + url "https://maven.google.com" + } } } From 9fb0d9a664066adf494a40812ad98a954fe94ffc Mon Sep 17 00:00:00 2001 From: Mike Harris Date: Tue, 3 Oct 2017 23:25:38 -0700 Subject: [PATCH 014/224] Move all Activities and Fragments to the support library versions. In the support lib, the code comes from the SDK, not the device like the framework version. This means we're shipping a more recent and less buggy version. It's also a good idea to keep the entire project on one version. We have a bit of a mix now. I think some of the Fragment animation issues were because of this mixing. For the leanback activities, AppCompatActivity requires AppCompat themes, which they don't ship for Theme.Leanback. So use FragmentActivity instead (that's the parent of AppCompatActivity, but still in the support library). For passed around Activities, use FragmentActivity to work with both. --- .../activities/AddDirectoryActivity.java | 4 +-- .../activities/EmulationActivity.java | 30 ++++++++++--------- .../dolphinemu/adapters/GameAdapter.java | 8 ++--- .../adapters/PlatformPagerAdapter.java | 6 ++-- .../dolphinemu/dialogs/GameDetailsDialog.java | 2 +- .../fragments/EmulationFragment.java | 2 +- .../dolphinemu/fragments/MenuFragment.java | 2 +- .../fragments/SaveLoadStateFragment.java | 2 +- .../dolphinemu/ui/main/MainActivity.java | 8 +++-- .../dolphinemu/ui/main/TvMainActivity.java | 13 ++++---- .../ui/platform/PlatformGamesFragment.java | 2 +- .../ui/settings/SettingsActivity.java | 8 ++--- .../ui/settings/SettingsFragment.java | 2 +- .../ui/settings/SettingsFragmentView.java | 4 +-- .../dolphinemu/utils/PermissionsHandler.java | 8 ++--- .../dolphinemu/utils/StartupHandler.java | 6 ++-- 16 files changed, 56 insertions(+), 51 deletions(-) diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/activities/AddDirectoryActivity.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/activities/AddDirectoryActivity.java index 45e1f87ca9c1..84080854d6e3 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/activities/AddDirectoryActivity.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/activities/AddDirectoryActivity.java @@ -1,12 +1,12 @@ package org.dolphinemu.dolphinemu.activities; -import android.app.Activity; import android.content.AsyncQueryHandler; import android.content.ContentValues; import android.content.Intent; import android.net.Uri; import android.os.Bundle; import android.os.Environment; +import android.support.v4.app.FragmentActivity; import android.support.v7.app.AppCompatActivity; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; @@ -133,7 +133,7 @@ public void updateSubtitle(String path) mToolbar.setSubtitle(path); } - public static void launch(Activity activity) + public static void launch(FragmentActivity activity) { Intent fileChooser = new Intent(activity, AddDirectoryActivity.class); activity.startActivityForResult(fileChooser, MainPresenter.REQUEST_ADD_DIRECTORY); 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 3162b650d369..06370c0028a8 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 @@ -1,9 +1,7 @@ package org.dolphinemu.dolphinemu.activities; -import android.app.Activity; import android.app.ActivityOptions; import android.app.AlertDialog; -import android.app.Fragment; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; @@ -14,6 +12,8 @@ import android.os.Message; import android.preference.PreferenceManager; import android.support.annotation.IntDef; +import android.support.v4.app.Fragment; +import android.support.v4.app.FragmentActivity; import android.support.v7.app.AppCompatActivity; import android.util.SparseIntArray; import android.view.InputDevice; @@ -157,7 +157,7 @@ public void handleMessage(Message msg) buttonsActionsMap.append(R.id.menu_exit, EmulationActivity.MENU_ACTION_EXIT); } - public static void launch(Activity activity, String path, String title, String screenshotPath, int position, View sharedView) + public static void launch(FragmentActivity activity, String path, String title, String screenshotPath, int position, View sharedView) { Intent launcher = new Intent(activity, EmulationActivity.class); @@ -171,6 +171,8 @@ public static void launch(Activity activity, String path, String title, String s sharedView, "image_game_screenshot"); + // I believe this warning is a bug. Activities are FragmentActivity from the support lib + //noinspection RestrictedApi activity.startActivityForResult(launcher, MainPresenter.REQUEST_EMULATE_GAME, options.toBundle()); } @@ -286,7 +288,7 @@ public void run() EmulationFragment emulationFragment = EmulationFragment.newInstance(path); // Add fragment to the activity - this triggers all its lifecycle callbacks. - getFragmentManager().beginTransaction() + getSupportFragmentManager().beginTransaction() .add(R.id.frame_emulation_fragment, emulationFragment, EmulationFragment.FRAGMENT_TAG) .commit(); } @@ -302,7 +304,7 @@ public void run() } else { - MenuFragment menuFragment = (MenuFragment) getFragmentManager() + MenuFragment menuFragment = (MenuFragment) getSupportFragmentManager() .findFragmentById(R.id.fragment_menu); if (menuFragment != null) @@ -413,7 +415,7 @@ public void run() private void stopEmulation() { - EmulationFragment fragment = (EmulationFragment) getFragmentManager() + EmulationFragment fragment = (EmulationFragment) getSupportFragmentManager() .findFragmentByTag(EmulationFragment.FRAGMENT_TAG); fragment.notifyEmulationStopped(); @@ -612,7 +614,7 @@ public void handleMenuAction(@MenuAction int menuAction) private void editControlsPlacement() { - EmulationFragment emulationFragment = (EmulationFragment) getFragmentManager() + EmulationFragment emulationFragment = (EmulationFragment) getSupportFragmentManager() .findFragmentById(R.id.frame_emulation_fragment); if (emulationFragment.isConfiguringControls()) { emulationFragment.stopConfiguringControls(); @@ -707,7 +709,7 @@ public void onClick(DialogInterface dialog, int indexSelected, boolean isChecked builder.setNeutralButton(getString(R.string.emulation_toggle_all), new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialogInterface, int i) { - EmulationFragment emulationFragment = (EmulationFragment) getFragmentManager() + EmulationFragment emulationFragment = (EmulationFragment) getSupportFragmentManager() .findFragmentByTag(EmulationFragment.FRAGMENT_TAG); emulationFragment.toggleInputOverlayVisibility(); } @@ -717,7 +719,7 @@ public void onClick(DialogInterface dialogInterface, int i) { public void onClick(DialogInterface dialogInterface, int i) { editor.apply(); - EmulationFragment emulationFragment = (EmulationFragment) getFragmentManager() + EmulationFragment emulationFragment = (EmulationFragment) getSupportFragmentManager() .findFragmentByTag(EmulationFragment.FRAGMENT_TAG); emulationFragment.refreshInputOverlay(); } @@ -764,7 +766,7 @@ public void onClick(DialogInterface dialogInterface, int i) { editor.putInt("controlScale", seekbar.getProgress()); editor.apply(); - EmulationFragment emulationFragment = (EmulationFragment) getFragmentManager() + EmulationFragment emulationFragment = (EmulationFragment) getSupportFragmentManager() .findFragmentByTag(EmulationFragment.FRAGMENT_TAG); emulationFragment.refreshInputOverlay(); } @@ -793,7 +795,7 @@ public void onClick(DialogInterface dialog, int indexSelected) { public void onClick(DialogInterface dialogInterface, int i) { editor.apply(); - EmulationFragment emulationFragment = (EmulationFragment) getFragmentManager() + EmulationFragment emulationFragment = (EmulationFragment) getSupportFragmentManager() .findFragmentByTag(EmulationFragment.FRAGMENT_TAG); emulationFragment.refreshInputOverlay(); @@ -885,7 +887,7 @@ public boolean onPreDraw() private void showMenu(SaveLoadStateFragment.SaveOrLoad saveOrLoad) { Fragment fragment = SaveLoadStateFragment.newInstance(saveOrLoad); - getFragmentManager().beginTransaction() + getSupportFragmentManager().beginTransaction() .setCustomAnimations(R.animator.menu_slide_in, R.animator.menu_slide_out) .replace(R.id.frame_submenu, fragment, FRAGMENT_SUBMENU_TAG) .commit(); @@ -894,7 +896,7 @@ private void showMenu(SaveLoadStateFragment.SaveOrLoad saveOrLoad) private void removeSubMenu() { - final Fragment fragment = getFragmentManager().findFragmentByTag(FRAGMENT_SUBMENU_TAG); + final Fragment fragment = getSupportFragmentManager().findFragmentByTag(FRAGMENT_SUBMENU_TAG); if (fragment != null) { @@ -908,7 +910,7 @@ public void run() { if (mMenuVisible) { - getFragmentManager().beginTransaction() + getSupportFragmentManager().beginTransaction() .remove(fragment) .commit(); } 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 153470df6ad2..7c5a6ea415fe 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,9 +1,9 @@ package org.dolphinemu.dolphinemu.adapters; -import android.app.Activity; import android.database.Cursor; import android.database.DataSetObserver; import android.graphics.Rect; +import android.support.v4.app.FragmentActivity; import android.support.v7.widget.RecyclerView; import android.view.LayoutInflater; import android.view.View; @@ -202,7 +202,7 @@ public void onClick(View view) { GameViewHolder holder = (GameViewHolder) view.getTag(); - EmulationActivity.launch((Activity) view.getContext(), + EmulationActivity.launch((FragmentActivity) view.getContext(), holder.path, holder.title, holder.screenshotPath, @@ -225,13 +225,13 @@ public boolean onLongClick(View view) // TODO This should be all we need to pass in, eventually. // String gameId = (String) holder.gameId; - Activity activity = (Activity) view.getContext(); + FragmentActivity activity = (FragmentActivity) view.getContext(); GameDetailsDialog.newInstance(holder.title, holder.description, holder.country, holder.company, holder.path, - holder.screenshotPath).show(activity.getFragmentManager(), "game_details"); + holder.screenshotPath).show(activity.getSupportFragmentManager(), "game_details"); return true; } diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/adapters/PlatformPagerAdapter.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/adapters/PlatformPagerAdapter.java index afdf67f34e0f..c5ab5522bba8 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/adapters/PlatformPagerAdapter.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/adapters/PlatformPagerAdapter.java @@ -1,10 +1,10 @@ package org.dolphinemu.dolphinemu.adapters; -import android.app.Fragment; -import android.app.FragmentManager; import android.content.Context; import android.graphics.drawable.Drawable; -import android.support.v13.app.FragmentPagerAdapter; +import android.support.v4.app.FragmentPagerAdapter; +import android.support.v4.app.Fragment; +import android.support.v4.app.FragmentManager; import android.text.Spannable; import android.text.SpannableString; import android.text.style.ImageSpan; diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/dialogs/GameDetailsDialog.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/dialogs/GameDetailsDialog.java index f67ac0c4426f..10c04778d025 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/dialogs/GameDetailsDialog.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/dialogs/GameDetailsDialog.java @@ -2,9 +2,9 @@ import android.app.AlertDialog; import android.app.Dialog; -import android.app.DialogFragment; import android.os.Bundle; import android.support.design.widget.FloatingActionButton; +import android.support.v4.app.DialogFragment; import android.view.View; import android.view.ViewGroup; import android.widget.ImageView; 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 94d411a78d64..f80487b93804 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 @@ -1,9 +1,9 @@ package org.dolphinemu.dolphinemu.fragments; -import android.app.Fragment; import android.content.SharedPreferences; import android.os.Bundle; import android.preference.PreferenceManager; +import android.support.v4.app.Fragment; import android.view.LayoutInflater; import android.view.Surface; import android.view.SurfaceHolder; 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 index 2ab3e0ba6a54..2b718ac58dd7 100644 --- 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 @@ -1,8 +1,8 @@ package org.dolphinemu.dolphinemu.fragments; -import android.app.Fragment; import android.os.Bundle; import android.support.annotation.Nullable; +import android.support.v4.app.Fragment; import android.util.SparseIntArray; import android.view.LayoutInflater; import android.view.View; diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/fragments/SaveLoadStateFragment.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/fragments/SaveLoadStateFragment.java index 2752a8d4b38d..a59e435da089 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/fragments/SaveLoadStateFragment.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/fragments/SaveLoadStateFragment.java @@ -1,8 +1,8 @@ package org.dolphinemu.dolphinemu.fragments; -import android.app.Fragment; import android.os.Bundle; import android.support.annotation.Nullable; +import android.support.v4.app.Fragment; import android.util.SparseIntArray; import android.view.LayoutInflater; import android.view.View; diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/main/MainActivity.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/main/MainActivity.java index 10d76b4e42ed..7c9fa225b171 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/main/MainActivity.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/main/MainActivity.java @@ -70,7 +70,8 @@ public void onClick(View view) if (PermissionsHandler.hasWriteAccess(this)) { - PlatformPagerAdapter platformPagerAdapter = new PlatformPagerAdapter(getFragmentManager(), this); + PlatformPagerAdapter platformPagerAdapter = new PlatformPagerAdapter( + getSupportFragmentManager(), this); mViewPager.setAdapter(platformPagerAdapter); } else { mViewPager.setVisibility(View.INVISIBLE); @@ -162,7 +163,8 @@ public void onRequestPermissionsResult(int requestCode, String[] permissions, in if (grantResults[0] == PackageManager.PERMISSION_GRANTED) { StartupHandler.copyAssetsIfNeeded(this); - PlatformPagerAdapter platformPagerAdapter = new PlatformPagerAdapter(getFragmentManager(), this); + PlatformPagerAdapter platformPagerAdapter = new PlatformPagerAdapter( + getSupportFragmentManager(), this); mViewPager.setAdapter(platformPagerAdapter); mTabLayout.setupWithViewPager(mViewPager); mViewPager.setVisibility(View.VISIBLE); @@ -205,6 +207,6 @@ private PlatformGamesView getPlatformGamesView(Platform platform) { String fragmentTag = "android:switcher:" + mViewPager.getId() + ":" + platform; - return (PlatformGamesView) getFragmentManager().findFragmentByTag(fragmentTag); + return (PlatformGamesView) getSupportFragmentManager().findFragmentByTag(fragmentTag); } } diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/main/TvMainActivity.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/main/TvMainActivity.java index 567e2ca4926b..383b30aeba38 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/main/TvMainActivity.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/main/TvMainActivity.java @@ -1,12 +1,11 @@ package org.dolphinemu.dolphinemu.ui.main; -import android.app.Activity; -import android.app.FragmentManager; import android.content.Intent; import android.content.pm.PackageManager; import android.database.Cursor; import android.os.Bundle; import android.support.v17.leanback.app.BrowseFragment; +import android.support.v17.leanback.app.BrowseSupportFragment; import android.support.v17.leanback.database.CursorMapper; import android.support.v17.leanback.widget.ArrayObjectAdapter; import android.support.v17.leanback.widget.CursorObjectAdapter; @@ -17,6 +16,8 @@ import android.support.v17.leanback.widget.Presenter; import android.support.v17.leanback.widget.Row; import android.support.v17.leanback.widget.RowPresenter; +import android.support.v4.app.FragmentActivity; +import android.support.v4.app.FragmentManager; import android.support.v4.content.ContextCompat; import android.widget.Toast; @@ -33,11 +34,11 @@ import org.dolphinemu.dolphinemu.utils.StartupHandler; import org.dolphinemu.dolphinemu.viewholders.TvGameViewHolder; -public final class TvMainActivity extends Activity implements MainView +public final class TvMainActivity extends FragmentActivity implements MainView { private MainPresenter mPresenter = new MainPresenter(this); - private BrowseFragment mBrowseFragment; + private BrowseSupportFragment mBrowseFragment; private ArrayObjectAdapter mRowsAdapter; @@ -57,8 +58,8 @@ protected void onCreate(Bundle savedInstanceState) } void setupUI() { - final FragmentManager fragmentManager = getFragmentManager(); - mBrowseFragment = new BrowseFragment(); + final FragmentManager fragmentManager = getSupportFragmentManager(); + mBrowseFragment = new BrowseSupportFragment(); fragmentManager .beginTransaction() .add(R.id.content, mBrowseFragment, "BrowseFragment") diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/platform/PlatformGamesFragment.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/platform/PlatformGamesFragment.java index 45bfee591bc3..3325a1ca2371 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/platform/PlatformGamesFragment.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/platform/PlatformGamesFragment.java @@ -1,9 +1,9 @@ package org.dolphinemu.dolphinemu.ui.platform; -import android.app.Fragment; import android.database.Cursor; import android.os.Bundle; import android.support.annotation.Nullable; +import android.support.v4.app.Fragment; import android.support.v7.widget.GridLayoutManager; import android.support.v7.widget.RecyclerView; import android.view.LayoutInflater; diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/settings/SettingsActivity.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/settings/SettingsActivity.java index 7c30cd54f174..43715cecba84 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/settings/SettingsActivity.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/settings/SettingsActivity.java @@ -1,9 +1,9 @@ package org.dolphinemu.dolphinemu.ui.settings; -import android.app.FragmentTransaction; import android.content.Context; import android.content.Intent; import android.os.Bundle; +import android.support.v4.app.FragmentTransaction; import android.support.v7.app.AppCompatActivity; import android.view.Menu; import android.view.MenuInflater; @@ -88,7 +88,7 @@ public void onBackPressed() @Override public void showSettingsFragment(String menuTag, boolean addToStack) { - FragmentTransaction transaction = getFragmentManager().beginTransaction(); + FragmentTransaction transaction = getSupportFragmentManager().beginTransaction(); if (addToStack) { @@ -149,7 +149,7 @@ public void showToastMessage(String message) @Override public void popBackStack() { - getFragmentManager().popBackStackImmediate(); + getSupportFragmentManager().popBackStackImmediate(); } @Override @@ -178,6 +178,6 @@ public void onExtensionSettingChanged(String key, int value) private SettingsFragment getFragment() { - return (SettingsFragment) getFragmentManager().findFragmentByTag(FRAGMENT_TAG); + return (SettingsFragment) getSupportFragmentManager().findFragmentByTag(FRAGMENT_TAG); } } diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/settings/SettingsFragment.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/settings/SettingsFragment.java index dd752c666462..276a26ee9a7e 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/settings/SettingsFragment.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/settings/SettingsFragment.java @@ -1,10 +1,10 @@ package org.dolphinemu.dolphinemu.ui.settings; import android.app.Activity; -import android.app.Fragment; import android.content.Context; import android.os.Bundle; import android.support.annotation.Nullable; +import android.support.v4.app.Fragment; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; import android.view.LayoutInflater; diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/settings/SettingsFragmentView.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/settings/SettingsFragmentView.java index 43453ffb2a80..3029dc2a9dc9 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/settings/SettingsFragmentView.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/settings/SettingsFragmentView.java @@ -1,6 +1,6 @@ package org.dolphinemu.dolphinemu.ui.settings; -import android.app.Activity; +import android.support.v4.app.FragmentActivity; import org.dolphinemu.dolphinemu.model.settings.Setting; import org.dolphinemu.dolphinemu.model.settings.SettingSection; @@ -48,7 +48,7 @@ public interface SettingsFragmentView /** * @return The Fragment's containing activity. */ - Activity getActivity(); + FragmentActivity getActivity(); /** * Tell the Fragment to tell the containing Activity to show a new diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/utils/PermissionsHandler.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/utils/PermissionsHandler.java index 84ea110884b8..ceca9e419539 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/utils/PermissionsHandler.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/utils/PermissionsHandler.java @@ -1,11 +1,11 @@ package org.dolphinemu.dolphinemu.utils; import android.annotation.TargetApi; -import android.app.Activity; import android.app.AlertDialog; import android.content.DialogInterface; import android.content.pm.PackageManager; import android.os.Build; +import android.support.v4.app.FragmentActivity; import android.support.v4.content.ContextCompat; import android.widget.Toast; @@ -17,7 +17,7 @@ public class PermissionsHandler { public static final int REQUEST_CODE_WRITE_PERMISSION = 500; @TargetApi(Build.VERSION_CODES.M) - public static boolean checkWritePermission(final Activity activity) { + public static boolean checkWritePermission(final FragmentActivity activity) { if (android.os.Build.VERSION.SDK_INT < Build.VERSION_CODES.M) { return true; } @@ -45,7 +45,7 @@ public void onClick(DialogInterface dialog, int which) { return true; } - public static boolean hasWriteAccess(Activity activity) { + public static boolean hasWriteAccess(FragmentActivity activity) { if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { int hasWritePermission = ContextCompat.checkSelfPermission(activity, WRITE_EXTERNAL_STORAGE); return hasWritePermission == PackageManager.PERMISSION_GRANTED; @@ -54,7 +54,7 @@ public static boolean hasWriteAccess(Activity activity) { return true; } - private static void showMessageOKCancel(final Activity activity, String message, DialogInterface.OnClickListener okListener) { + private static void showMessageOKCancel(final FragmentActivity activity, String message, DialogInterface.OnClickListener okListener) { new AlertDialog.Builder(activity) .setMessage(message) .setPositiveButton(android.R.string.ok, okListener) diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/utils/StartupHandler.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/utils/StartupHandler.java index 2e31f405d007..34cde9e59ce4 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/utils/StartupHandler.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/utils/StartupHandler.java @@ -1,10 +1,10 @@ package org.dolphinemu.dolphinemu.utils; -import android.app.Activity; import android.content.Intent; import android.content.SharedPreferences; import android.os.Bundle; import android.preference.PreferenceManager; +import android.support.v4.app.FragmentActivity; import android.text.TextUtils; import org.dolphinemu.dolphinemu.NativeLibrary; @@ -13,7 +13,7 @@ public final class StartupHandler { - public static boolean HandleInit(Activity parent) + public static boolean HandleInit(FragmentActivity parent) { NativeLibrary.SetUserDirectory(""); // Auto-Detect @@ -46,7 +46,7 @@ public static boolean HandleInit(Activity parent) return false; } - public static void copyAssetsIfNeeded(Activity parent) { + public static void copyAssetsIfNeeded(FragmentActivity parent) { SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(parent); boolean assetsCopied = preferences.getBoolean("assetsCopied", false); From bb3f61296e8a436cc2543a9211e96081e07943ab Mon Sep 17 00:00:00 2001 From: Mike Harris Date: Wed, 4 Oct 2017 22:48:27 -0700 Subject: [PATCH 015/224] Add a clearEmulation method. This makes it clear that the Activity is being cleared and removes null as a valid param. This improves readability (and logging slightly). Fix spacing between [Tag] and message. This matches the rest of the log messages. --- .../java/org/dolphinemu/dolphinemu/NativeLibrary.java | 10 ++++++++-- .../dolphinemu/activities/EmulationActivity.java | 2 +- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/NativeLibrary.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/NativeLibrary.java index 614a1076f66d..6df525e4bc00 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/NativeLibrary.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/NativeLibrary.java @@ -391,13 +391,19 @@ public void run() public static void endEmulationActivity() { - Log.verbose("[NativeLibrary]Ending EmulationActivity."); + Log.verbose("[NativeLibrary] Ending EmulationActivity."); sEmulationActivity.exitWithAnimation(); } public static void setEmulationActivity(EmulationActivity emulationActivity) { - Log.verbose("[NativeLibrary]Registering EmulationActivity."); + Log.verbose("[NativeLibrary] Registering EmulationActivity."); sEmulationActivity = emulationActivity; } + + public static void clearEmulationActivity() + { + Log.verbose("[NativeLibrary] Unregistering EmulationActivity."); + sEmulationActivity = null; + } } 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 06370c0028a8..773e0a788018 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 @@ -332,7 +332,7 @@ protected void onStop() super.onStop(); Log.debug("[EmulationActivity] EmulationActivity stopping."); - NativeLibrary.setEmulationActivity(null); + NativeLibrary.clearEmulationActivity(); } @Override From 80d51c97abd6c379ca6c587d0e24079ac649626b Mon Sep 17 00:00:00 2001 From: Mike Harris Date: Wed, 4 Oct 2017 23:04:26 -0700 Subject: [PATCH 016/224] Add dummy View that works around a bug with the nVidia Shield. Without this View, the emulation SurfaceView acts like it has the highest Z-value, blocking any other View. This includes the menu fragments and the screenshot ImageView. --- .../ui/NVidiaShieldWorkaroundView.java | 25 +++++++++++++++++++ .../layout-television/activity_emulation.xml | 6 ++++- 2 files changed, 30 insertions(+), 1 deletion(-) create mode 100644 Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/NVidiaShieldWorkaroundView.java diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/NVidiaShieldWorkaroundView.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/NVidiaShieldWorkaroundView.java new file mode 100644 index 000000000000..5d2e4a8bbe99 --- /dev/null +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/NVidiaShieldWorkaroundView.java @@ -0,0 +1,25 @@ +/** + * Copyright 2013 Dolphin Emulator Project + * Licensed under GPLv2+ + * Refer to the license.txt file included. + */ + +package org.dolphinemu.dolphinemu.ui; + +import android.content.Context; +import android.util.AttributeSet; +import android.view.View; + +/** + * Work around a bug with the nVidia Shield. + */ +public final class NVidiaShieldWorkaroundView extends View +{ + public NVidiaShieldWorkaroundView(Context context, AttributeSet attrs) + { + super(context, attrs); + + // Setting this seems to workaround the bug + setWillNotDraw(false); + } +} 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 index a8cba9adb526..59e1ba02eca1 100644 --- a/Source/Android/app/src/main/res/layout-television/activity_emulation.xml +++ b/Source/Android/app/src/main/res/layout-television/activity_emulation.xml @@ -11,6 +11,10 @@ android:layout_height="match_parent" android:visibility="invisible"/> + + - \ No newline at end of file + From cde003c5cc1de6b2caba21baa9e4050a2f30d112 Mon Sep 17 00:00:00 2001 From: Mike Harris Date: Wed, 4 Oct 2017 23:10:49 -0700 Subject: [PATCH 017/224] Remove EmulationActivity.MenuType. This should have been removed when SaveLoadStateFragment was refactored. --- .../dolphinemu/dolphinemu/activities/EmulationActivity.java | 5 ----- 1 file changed, 5 deletions(-) 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 773e0a788018..8102b30e8cbb 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 @@ -72,11 +72,6 @@ public final class EmulationActivity extends AppCompatActivity private static boolean mIsGameCubeGame; - private enum MenuType - { - SAVE, LOAD - } - /** * Handlers are a way to pass a message to an Activity telling it to do something * on the UI thread. This Handler responds to any message, even blank ones, by From 80e1cc56b344a69aca0db07ebb2d9483d2b3d523 Mon Sep 17 00:00:00 2001 From: Mike Harris Date: Thu, 5 Oct 2017 10:11:08 -0700 Subject: [PATCH 018/224] Use weak references for the static Activity in NativeLibrary. Add in null checks as well. --- .../dolphinemu/dolphinemu/NativeLibrary.java | 39 ++++++++++---- .../dolphinemu/utils/Java_GCAdapter.java | 52 +++++++++++++------ .../dolphinemu/utils/Java_WiimoteAdapter.java | 31 +++++++---- 3 files changed, 84 insertions(+), 38 deletions(-) diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/NativeLibrary.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/NativeLibrary.java index 6df525e4bc00..7d55a89e2d34 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/NativeLibrary.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/NativeLibrary.java @@ -12,13 +12,15 @@ import org.dolphinemu.dolphinemu.activities.EmulationActivity; import org.dolphinemu.dolphinemu.utils.Log; +import java.lang.ref.WeakReference; + /** * Class which contains methods that interact * with the native side of the Dolphin code. */ public final class NativeLibrary { - public static EmulationActivity sEmulationActivity; + public static WeakReference sEmulationActivity = new WeakReference<>(null); /** * Button type for use in onTouchEvent @@ -379,31 +381,48 @@ private NativeLibrary() public static void displayAlertMsg(final String alert) { Log.error("[NativeLibrary] Alert: " + alert); - sEmulationActivity.runOnUiThread(new Runnable() + final EmulationActivity emulationActivity = sEmulationActivity.get(); + if (emulationActivity != null) { - @Override - public void run() + emulationActivity.runOnUiThread(new Runnable() { - Toast.makeText(sEmulationActivity, "Panic Alert: " + alert, Toast.LENGTH_LONG).show(); - } - }); + @Override + public void run() + { + Toast.makeText(emulationActivity, "Panic Alert: " + alert, Toast.LENGTH_LONG).show(); + } + }); + } + else + { + Log.warning("[NativeLibrary] EmulationActivity is null, can't do panic toast."); + } } public static void endEmulationActivity() { Log.verbose("[NativeLibrary] Ending EmulationActivity."); - sEmulationActivity.exitWithAnimation(); + EmulationActivity emulationActivity = sEmulationActivity.get(); + if (emulationActivity != null) + { + emulationActivity.exitWithAnimation(); + } + else + { + Log.warning("[NativeLibrary] EmulationActivity is null, can't end."); + } } public static void setEmulationActivity(EmulationActivity emulationActivity) { Log.verbose("[NativeLibrary] Registering EmulationActivity."); - sEmulationActivity = emulationActivity; + sEmulationActivity = new WeakReference<>(emulationActivity); } public static void clearEmulationActivity() { Log.verbose("[NativeLibrary] Unregistering EmulationActivity."); - sEmulationActivity = null; + + sEmulationActivity.clear(); } } diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/utils/Java_GCAdapter.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/utils/Java_GCAdapter.java index d7731b604049..91e2a9ca4622 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/utils/Java_GCAdapter.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/utils/Java_GCAdapter.java @@ -1,6 +1,8 @@ package org.dolphinemu.dolphinemu.utils; +import android.app.Activity; import android.app.PendingIntent; +import android.content.Context; import android.content.Intent; import android.hardware.usb.UsbConfiguration; import android.hardware.usb.UsbConstants; @@ -15,7 +17,6 @@ import org.dolphinemu.dolphinemu.services.USBPermService; import java.util.HashMap; -import java.util.Iterator; import java.util.Map; public class Java_GCAdapter { @@ -29,22 +30,31 @@ public class Java_GCAdapter { private static void RequestPermission() { - HashMap devices = manager.getDeviceList(); - for (Map.Entry pair : devices.entrySet()) + Context context = NativeLibrary.sEmulationActivity.get(); + if (context != null) { - UsbDevice dev = pair.getValue(); - if (dev.getProductId() == 0x0337 && dev.getVendorId() == 0x057e) + HashMap devices = manager.getDeviceList(); + for (Map.Entry pair : devices.entrySet()) { - if (!manager.hasPermission(dev)) + UsbDevice dev = pair.getValue(); + if (dev.getProductId() == 0x0337 && dev.getVendorId() == 0x057e) { - Intent intent = new Intent(); - PendingIntent pend_intent; - intent.setClass(NativeLibrary.sEmulationActivity, USBPermService.class); - pend_intent = PendingIntent.getService(NativeLibrary.sEmulationActivity, 0, intent, 0); - manager.requestPermission(dev, pend_intent); + if (!manager.hasPermission(dev)) + { + Intent intent = new Intent(); + PendingIntent pend_intent; + intent.setClass(context, USBPermService.class); + pend_intent = PendingIntent.getService(context, 0, intent, 0); + manager.requestPermission(dev, pend_intent); + } } } } + else + { + Log.warning("Cannot request GameCube Adapter permission as EmulationActivity is null."); + } + } public static void Shutdown() @@ -124,14 +134,22 @@ public static boolean OpenAdapter() } } - NativeLibrary.sEmulationActivity.runOnUiThread(new Runnable() + final Activity emulationActivity = NativeLibrary.sEmulationActivity.get(); + if (emulationActivity != null) { - @Override - public void run() + emulationActivity.runOnUiThread(new Runnable() { - Toast.makeText(NativeLibrary.sEmulationActivity, "GameCube Adapter couldn't be opened. Please re-plug the device.", Toast.LENGTH_LONG).show(); - } - }); + @Override + public void run() + { + Toast.makeText(emulationActivity, "GameCube Adapter couldn't be opened. Please re-plug the device.", Toast.LENGTH_LONG).show(); + } + }); + } + else + { + Log.warning("Cannot show toast for GameCube Adapter failure."); + } usb_con.close(); } } diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/utils/Java_WiimoteAdapter.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/utils/Java_WiimoteAdapter.java index 5fdc49b021a6..a38f7ecd4b91 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/utils/Java_WiimoteAdapter.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/utils/Java_WiimoteAdapter.java @@ -1,6 +1,7 @@ package org.dolphinemu.dolphinemu.utils; import android.app.PendingIntent; +import android.content.Context; import android.content.Intent; import android.hardware.usb.UsbConfiguration; import android.hardware.usb.UsbDevice; @@ -33,23 +34,31 @@ public class Java_WiimoteAdapter private static void RequestPermission() { - HashMap devices = manager.getDeviceList(); - for (Map.Entry pair : devices.entrySet()) + Context context = NativeLibrary.sEmulationActivity.get(); + if (context != null) { - UsbDevice dev = pair.getValue(); - if (dev.getProductId() == NINTENDO_WIIMOTE_PRODUCT_ID && dev.getVendorId() == NINTENDO_VENDOR_ID) + HashMap devices = manager.getDeviceList(); + for (Map.Entry pair : devices.entrySet()) { - if (!manager.hasPermission(dev)) + UsbDevice dev = pair.getValue(); + if (dev.getProductId() == NINTENDO_WIIMOTE_PRODUCT_ID && dev.getVendorId() == NINTENDO_VENDOR_ID) { - Log.warning("Requesting permission for Wii Remote adapter"); - Intent intent = new Intent(); - PendingIntent pend_intent; - intent.setClass(NativeLibrary.sEmulationActivity, USBPermService.class); - pend_intent = PendingIntent.getService(NativeLibrary.sEmulationActivity, 0, intent, 0); - manager.requestPermission(dev, pend_intent); + if (!manager.hasPermission(dev)) + { + Log.warning("Requesting permission for Wii Remote adapter"); + Intent intent = new Intent(); + PendingIntent pend_intent; + intent.setClass(context, USBPermService.class); + pend_intent = PendingIntent.getService(context, 0, intent, 0); + manager.requestPermission(dev, pend_intent); + } } } } + else + { + Log.warning("Cannot request Wiimote adapter permission as EmulationActivity is null."); + } } public static boolean QueryAdapter() From 25a08fc5ccebb8abac086416871ce27e39f10165 Mon Sep 17 00:00:00 2001 From: Mike Harris Date: Sat, 7 Oct 2017 22:14:37 -0700 Subject: [PATCH 019/224] Only postpone transistions on Activity creation. This is causing bugs (no UI is rendered) when the Activity is rotated. --- .../dolphinemu/activities/EmulationActivity.java | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) 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 8102b30e8cbb..d28e78a8f76f 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 @@ -220,11 +220,6 @@ public void onSystemUiVisibilityChange(int flags) Java_GCAdapter.manager = (UsbManager) getSystemService(Context.USB_SERVICE); Java_WiimoteAdapter.manager = (UsbManager) getSystemService(Context.USB_SERVICE); - - // Picasso will take a while to load these big-ass screenshots. So don't run - // the animation until we say so. - postponeEnterTransition(); - setContentView(R.layout.activity_emulation); mImageView = (ImageView) findViewById(R.id.image_screenshot); @@ -240,6 +235,10 @@ public void onSystemUiVisibilityChange(int flags) if (savedInstanceState == null) { + // Picasso will take a while to load these big-ass screenshots. So don't run + // the animation until we say so. + postponeEnterTransition(); + Picasso.with(this) .load(mScreenPath) .noFade() From d48c64457ad8b08ccd51d60608aa68e5c12a2766 Mon Sep 17 00:00:00 2001 From: Mike Harris Date: Sat, 7 Oct 2017 22:17:46 -0700 Subject: [PATCH 020/224] Start the postponed activity transition as soon as Picasso loads the image. Doing it on the preDraw for the View is too complicated. This works just as well. --- .../activities/EmulationActivity.java | 21 ++----------------- 1 file changed, 2 insertions(+), 19 deletions(-) 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 d28e78a8f76f..0748a34004d6 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 @@ -23,7 +23,6 @@ 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 android.widget.LinearLayout; @@ -248,14 +247,14 @@ public void onSystemUiVisibilityChange(int flags) @Override public void onSuccess() { - scheduleStartPostponedTransition(mImageView); + startPostponedEnterTransition(); } @Override public void onError() { // Still have to do this, or else the app will crash. - scheduleStartPostponedTransition(mImageView); + startPostponedEnterTransition(); } }); @@ -862,22 +861,6 @@ private void showSystemUI() hideSystemUiAfterDelay(); } - - private void scheduleStartPostponedTransition(final View sharedElement) - { - sharedElement.getViewTreeObserver().addOnPreDrawListener( - new ViewTreeObserver.OnPreDrawListener() - { - @Override - public boolean onPreDraw() - { - sharedElement.getViewTreeObserver().removeOnPreDrawListener(this); - startPostponedEnterTransition(); - return true; - } - }); - } - private void showMenu(SaveLoadStateFragment.SaveOrLoad saveOrLoad) { Fragment fragment = SaveLoadStateFragment.newInstance(saveOrLoad); From 4cab718065a126b204f38f1238fa1aae4c0591e3 Mon Sep 17 00:00:00 2001 From: Mike Harris Date: Thu, 5 Oct 2017 00:21:37 -0700 Subject: [PATCH 021/224] Move emulation lifecycle handling into EmulationFragment. The Activity is responsible for just its views and menus and such. It signals the Fragment via setGamePath, StartEmulation and StopEmulation. The Fragment manages the actual emulation lifecycle. It is solely responsible for calling the NativeLibrary lifecycle methods. With this lifecycle simplification, the NativeLibrary no longer needs to kill the Activity. It happens normally now. This simplifies a lot of things, live handling rotation. --- .../dolphinemu/dolphinemu/NativeLibrary.java | 14 -- .../activities/EmulationActivity.java | 100 +++------ .../fragments/EmulationFragment.java | 205 +++++++++++------- .../layout-television/activity_emulation.xml | 8 +- .../main/res/layout/activity_emulation.xml | 8 +- Source/Android/jni/MainAndroid.cpp | 5 - 6 files changed, 162 insertions(+), 178 deletions(-) diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/NativeLibrary.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/NativeLibrary.java index 7d55a89e2d34..3cbbf3299ab4 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/NativeLibrary.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/NativeLibrary.java @@ -399,20 +399,6 @@ public void run() } } - public static void endEmulationActivity() - { - Log.verbose("[NativeLibrary] Ending EmulationActivity."); - EmulationActivity emulationActivity = sEmulationActivity.get(); - if (emulationActivity != null) - { - emulationActivity.exitWithAnimation(); - } - else - { - Log.warning("[NativeLibrary] EmulationActivity is null, can't end."); - } - } - public static void setEmulationActivity(EmulationActivity emulationActivity) { Log.verbose("[NativeLibrary] Registering EmulationActivity."); 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 0748a34004d6..14d0e2c9be72 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 @@ -23,7 +23,6 @@ import android.view.MenuItem; import android.view.MotionEvent; import android.view.View; -import android.widget.FrameLayout; import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.SeekBar; @@ -55,8 +54,8 @@ public final class EmulationActivity extends AppCompatActivity private static final String FRAGMENT_SUBMENU_TAG = "submenu"; private View mDecorView; private ImageView mImageView; + private EmulationFragment mEmulationFragment; - private FrameLayout mFrameEmulation; private LinearLayout mMenuLayout; private SharedPreferences mPreferences; @@ -85,7 +84,6 @@ public void handleMessage(Message msg) } }; private String mScreenPath; - private FrameLayout mFrameContent; private String mSelectedTitle; @Retention(SOURCE) @@ -219,12 +217,13 @@ public void onSystemUiVisibilityChange(int flags) Java_GCAdapter.manager = (UsbManager) getSystemService(Context.USB_SERVICE); Java_WiimoteAdapter.manager = (UsbManager) getSystemService(Context.USB_SERVICE); + 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); + mEmulationFragment = (EmulationFragment) getSupportFragmentManager() + .findFragmentById(R.id.fragment_emulation); Intent gameToEmulate = getIntent(); String path = gameToEmulate.getStringExtra("SelectedGame"); @@ -260,14 +259,6 @@ public void onError() Animations.fadeViewOut(mImageView) .setStartDelay(2000) - .withStartAction(new Runnable() - { - @Override - public void run() - { - mFrameEmulation.setVisibility(View.VISIBLE); - } - }) .withEndAction(new Runnable() { @Override @@ -277,18 +268,12 @@ public void run() } }); - // Instantiate an EmulationFragment. - EmulationFragment emulationFragment = EmulationFragment.newInstance(path); - - // Add fragment to the activity - this triggers all its lifecycle callbacks. - getSupportFragmentManager().beginTransaction() - .add(R.id.frame_emulation_fragment, emulationFragment, EmulationFragment.FRAGMENT_TAG) - .commit(); + mEmulationFragment.setGamePath(path); + mEmulationFragment.startEmulation(); } else { mImageView.setVisibility(View.GONE); - mFrameEmulation.setVisibility(View.VISIBLE); } if (mDeviceHasTouchScreen) @@ -311,23 +296,6 @@ public void run() mIsGameCubeGame = Platform.fromNativeInt(NativeLibrary.GetPlatform(path)) == Platform.GAMECUBE; } - @Override - protected void onStart() - { - super.onStart(); - Log.debug("[EmulationActivity] EmulationActivity starting."); - NativeLibrary.setEmulationActivity(this); - } - - @Override - protected void onStop() - { - super.onStop(); - Log.debug("[EmulationActivity] EmulationActivity stopping."); - - NativeLibrary.clearEmulationActivity(); - } - @Override protected void onPostCreate(Bundle savedInstanceState) { @@ -376,7 +344,8 @@ public void onBackPressed() } else { - stopEmulation(); + mEmulationFragment.stopEmulation(); + exitWithAnimation(); } } @@ -406,15 +375,6 @@ public void run() } } - private void stopEmulation() - { - EmulationFragment fragment = (EmulationFragment) getSupportFragmentManager() - .findFragmentByTag(EmulationFragment.FRAGMENT_TAG); - fragment.notifyEmulationStopped(); - - NativeLibrary.StopEmulation(); - } - public void exitWithAnimation() { runOnUiThread(new Runnable() @@ -458,7 +418,6 @@ private void showScreenshot() @Override public void run() { - mFrameContent.removeView(mFrameEmulation); setResult(mPosition); finishAfterTransition(); } @@ -599,20 +558,23 @@ public void handleMenuAction(@MenuAction int menuAction) return; case MENU_ACTION_EXIT: - toggleMenu(); - stopEmulation(); + toggleMenu(); // Hide the menu (it will be showing since we just clicked it) + mEmulationFragment.stopEmulation(); + exitWithAnimation(); return; } } - private void editControlsPlacement() { - EmulationFragment emulationFragment = (EmulationFragment) getSupportFragmentManager() - .findFragmentById(R.id.frame_emulation_fragment); - if (emulationFragment.isConfiguringControls()) { - emulationFragment.stopConfiguringControls(); - } else { - emulationFragment.startConfiguringControls(); + private void editControlsPlacement() + { + if (mEmulationFragment.isConfiguringControls()) + { + mEmulationFragment.stopConfiguringControls(); + } + else + { + mEmulationFragment.startConfiguringControls(); } } @@ -701,20 +663,18 @@ public void onClick(DialogInterface dialog, int indexSelected, boolean isChecked } builder.setNeutralButton(getString(R.string.emulation_toggle_all), new DialogInterface.OnClickListener() { @Override - public void onClick(DialogInterface dialogInterface, int i) { - EmulationFragment emulationFragment = (EmulationFragment) getSupportFragmentManager() - .findFragmentByTag(EmulationFragment.FRAGMENT_TAG); - emulationFragment.toggleInputOverlayVisibility(); + public void onClick(DialogInterface dialogInterface, int i) + { + mEmulationFragment.toggleInputOverlayVisibility(); } }); builder.setPositiveButton(getString(R.string.ok), new DialogInterface.OnClickListener() { @Override - public void onClick(DialogInterface dialogInterface, int i) { + public void onClick(DialogInterface dialogInterface, int i) + { editor.apply(); - EmulationFragment emulationFragment = (EmulationFragment) getSupportFragmentManager() - .findFragmentByTag(EmulationFragment.FRAGMENT_TAG); - emulationFragment.refreshInputOverlay(); + mEmulationFragment.refreshInputOverlay(); } }); @@ -759,9 +719,7 @@ public void onClick(DialogInterface dialogInterface, int i) { editor.putInt("controlScale", seekbar.getProgress()); editor.apply(); - EmulationFragment emulationFragment = (EmulationFragment) getSupportFragmentManager() - .findFragmentByTag(EmulationFragment.FRAGMENT_TAG); - emulationFragment.refreshInputOverlay(); + mEmulationFragment.refreshInputOverlay(); } }); @@ -788,9 +746,7 @@ public void onClick(DialogInterface dialog, int indexSelected) { public void onClick(DialogInterface dialogInterface, int i) { editor.apply(); - EmulationFragment emulationFragment = (EmulationFragment) getSupportFragmentManager() - .findFragmentByTag(EmulationFragment.FRAGMENT_TAG); - emulationFragment.refreshInputOverlay(); + mEmulationFragment.refreshInputOverlay(); Toast.makeText(getApplication(), R.string.emulation_controller_changed, Toast.LENGTH_SHORT).show(); } 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 f80487b93804..4ba035f95034 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 @@ -1,5 +1,6 @@ package org.dolphinemu.dolphinemu.fragments; +import android.content.Context; import android.content.SharedPreferences; import android.os.Bundle; import android.preference.PreferenceManager; @@ -14,15 +15,12 @@ import org.dolphinemu.dolphinemu.NativeLibrary; import org.dolphinemu.dolphinemu.R; +import org.dolphinemu.dolphinemu.activities.EmulationActivity; import org.dolphinemu.dolphinemu.overlay.InputOverlay; import org.dolphinemu.dolphinemu.utils.Log; public final class EmulationFragment extends Fragment implements SurfaceHolder.Callback { - public static final String FRAGMENT_TAG = "emulation_fragment"; - - private static final String ARG_GAME_PATH = "game_path"; - private SharedPreferences mPreferences; private Surface mSurface; @@ -31,18 +29,22 @@ public final class EmulationFragment extends Fragment implements SurfaceHolder.C private Thread mEmulationThread; - private boolean mEmulationStarted; - private boolean mEmulationRunning; + private String mGamePath; + private final EmulationState mEmulationState = new EmulationState(); - public static EmulationFragment newInstance(String path) + @Override + public void onAttach(Context context) { - EmulationFragment fragment = new EmulationFragment(); + super.onAttach(context); - Bundle arguments = new Bundle(); - arguments.putString(ARG_GAME_PATH, path); - fragment.setArguments(arguments); - - return fragment; + if (context instanceof EmulationActivity) + { + NativeLibrary.setEmulationActivity((EmulationActivity) context); + } + else + { + throw new IllegalStateException("EmulationFragment must have EmulationActivity parent"); + } } /** @@ -67,38 +69,20 @@ public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle sa { View contents = inflater.inflate(R.layout.fragment_emulation, container, false); - SurfaceView surfaceView = (SurfaceView) contents.findViewById(R.id.surface_emulation); - mInputOverlay = (InputOverlay) contents.findViewById(R.id.surface_input_overlay); - + SurfaceView surfaceView = contents.findViewById(R.id.surface_emulation); surfaceView.getHolder().addCallback(this); - // If the input overlay was previously disabled, then don't show it. + mInputOverlay = contents.findViewById(R.id.surface_input_overlay); if (mInputOverlay != null) { + // If the input overlay was previously disabled, then don't show it. if (!mPreferences.getBoolean("showInputOverlay", true)) { mInputOverlay.setVisibility(View.GONE); } } - if (savedInstanceState == null) - { - mEmulationThread = new Thread(mEmulationRunner); - } - else - { - // Likely a rotation occurred. - // TODO Pass native code the Surface, which will have been recreated, from surfaceChanged() - // TODO Also, write the native code that will get the video backend to accept the new Surface as one of its own. - } - - return contents; - } - - @Override - public void onViewCreated(View view, Bundle savedInstanceState) - { - Button doneButton = (Button) view.findViewById(R.id.done_control_config); + Button doneButton = contents.findViewById(R.id.done_control_config); if (doneButton != null) { doneButton.setOnClickListener(new View.OnClickListener() @@ -110,29 +94,29 @@ public void onClick(View v) } }); } - } - @Override - public void onStart() - { - super.onStart(); - startEmulation(); + // The new Surface created here will get passed to the native code via onSurfaceChanged. + + return contents; } @Override public void onStop() { + pauseEmulation(); super.onStop(); } @Override - public void onDestroyView() + public void onDetach() { - super.onDestroyView(); - if (getActivity().isFinishing() && mEmulationStarted) - { - NativeLibrary.StopEmulation(); - } + NativeLibrary.clearEmulationActivity(); + super.onDetach(); + } + + public void setGamePath(String setPath) + { + this.mGamePath = setPath; } public void toggleInputOverlayVisibility() @@ -171,6 +155,12 @@ public void surfaceCreated(SurfaceHolder holder) public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { Log.debug("[EmulationFragment] Surface changed. Resolution: " + width + "x" + height); + + if (mEmulationState.isPaused()) + { + NativeLibrary.UnPauseEmulation(); + } + mSurface = holder.getSurface(); NativeLibrary.SurfaceChanged(mSurface); } @@ -181,45 +171,57 @@ public void surfaceDestroyed(SurfaceHolder holder) Log.debug("[EmulationFragment] Surface destroyed."); NativeLibrary.SurfaceDestroyed(); - if (mEmulationRunning) + if (mEmulationState.isRunning()) { pauseEmulation(); } } - private void startEmulation() + public void startEmulation() { - if (!mEmulationStarted) + synchronized (mEmulationState) { - Log.debug("[EmulationFragment] Starting emulation thread."); + if (mEmulationState.isStopped()) + { + Log.debug("[EmulationFragment] Starting emulation thread."); - mEmulationThread.start(); + mEmulationThread = new Thread(mEmulationRunner, "NativeEmulation"); + mEmulationThread.start(); + // The thread will call mEmulationState.run() + } + else if (mEmulationState.isPaused()) + { + Log.debug("[EmulationFragment] Resuming emulation."); + NativeLibrary.UnPauseEmulation(); + mEmulationState.run(); + } + else + { + Log.debug("[EmulationFragment] Bug, startEmulation called while running."); + } } - else + } + + public void stopEmulation() { + synchronized (mEmulationState) { - Log.debug("[EmulationFragment] Resuming emulation."); - NativeLibrary.UnPauseEmulation(); + if (!mEmulationState.isStopped()) + { + NativeLibrary.StopEmulation(); + mEmulationState.stop(); + } } - - mEmulationRunning = true; } private void pauseEmulation() { - Log.debug("[EmulationFragment] Pausing emulation."); - - NativeLibrary.PauseEmulation(); - mEmulationRunning = false; - } + synchronized (mEmulationState) + { + Log.debug("[EmulationFragment] Pausing emulation."); - /** - * Called by containing activity to tell the Fragment emulation is already stopping, - * so it doesn't try to stop emulation on its way to the garbage collector. - */ - public void notifyEmulationStopped() - { - mEmulationStarted = false; - mEmulationRunning = false; + NativeLibrary.PauseEmulation(); + mEmulationState.pause(); + } } private Runnable mEmulationRunner = new Runnable() @@ -227,18 +229,17 @@ public void notifyEmulationStopped() @Override public void run() { - mEmulationRunning = true; - mEmulationStarted = true; - - while (mSurface == null) - if (!mEmulationRunning) - return; + // Busy-wait for surface to be set + while (mSurface == null) {} - Log.info("[EmulationFragment] Starting emulation: " + mSurface); + synchronized (mEmulationState) + { + Log.info("[EmulationFragment] Starting emulation: " + mSurface); + mEmulationState.run(); + } // Start emulation using the provided Surface. - String path = getArguments().getString(ARG_GAME_PATH); - NativeLibrary.Run(path); + NativeLibrary.Run(mGamePath); } }; @@ -258,4 +259,50 @@ public boolean isConfiguringControls() { return mInputOverlay.isInEditMode(); } + + private static class EmulationState + { + private enum State + { + STOPPED, RUNNING, PAUSED + } + + private State state; + + EmulationState() + { + // Starting state is stopped. + state = State.STOPPED; + } + + public boolean isStopped() + { + return state == State.STOPPED; + } + + public boolean isRunning() + { + return state == State.RUNNING; + } + + public boolean isPaused() + { + return state == State.PAUSED; + } + + public void run() + { + state = State.RUNNING; + } + + public void pause() + { + state = State.PAUSED; + } + + public void stop() + { + state = State.STOPPED; + } + } } 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 index 59e1ba02eca1..ad67bcb05ea1 100644 --- a/Source/Android/app/src/main/res/layout-television/activity_emulation.xml +++ b/Source/Android/app/src/main/res/layout-television/activity_emulation.xml @@ -5,11 +5,11 @@ xmlns:tools="http://schemas.android.com/tools" android:id="@+id/frame_content"> - + android:layout_height="match_parent"/> - + android:layout_height="match_parent"/> GetStaticMethodID(s_jni_class, "displayAlertMsg", "(Ljava/lang/String;)V"); - s_jni_method_end = env->GetStaticMethodID(s_jni_class, "endEmulationActivity", "()V"); } // Surface Handling @@ -816,9 +814,6 @@ JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_Run(JNIEnv* ANativeWindow_release(s_surf); s_surf = nullptr; } - - // Execute the Java method. - env->CallStaticVoidMethod(s_jni_class, s_jni_method_end); } #ifdef __cplusplus From c4d7814afa0e97784c6bc6b97dd9578c06867dd6 Mon Sep 17 00:00:00 2001 From: Mike Harris Date: Sat, 7 Oct 2017 23:12:08 -0700 Subject: [PATCH 022/224] Collapse layouts with a framelayout root then another viewgroup. There's no point to this, and it just slow things down (technically). --- .../layout-television/fragment_emulation.xml | 22 ++-- .../res/layout/fragment_saveload_state.xml | 112 ++++++++---------- 2 files changed, 59 insertions(+), 75 deletions(-) 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 index 276f5ad133bd..27243e841161 100644 --- a/Source/Android/app/src/main/res/layout-television/fragment_emulation.xml +++ b/Source/Android/app/src/main/res/layout-television/fragment_emulation.xml @@ -1,15 +1,7 @@ - - - - - - \ No newline at end of file + \ No newline at end of file diff --git a/Source/Android/app/src/main/res/layout/fragment_saveload_state.xml b/Source/Android/app/src/main/res/layout/fragment_saveload_state.xml index 64ba3315532a..56bb02f01dfa 100644 --- a/Source/Android/app/src/main/res/layout/fragment_saveload_state.xml +++ b/Source/Android/app/src/main/res/layout/fragment_saveload_state.xml @@ -1,60 +1,52 @@ - - - - - -