diff options
Diffstat (limited to 'src')
58 files changed, 985 insertions, 273 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 6c99dd5e2..9aea4af87 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -18,6 +18,9 @@ if (MSVC) # Avoid windows.h from including some usually unused libs like winsocks.h, since this might cause some redefinition errors. add_definitions(-DWIN32_LEAN_AND_MEAN) + # Ensure that projects build with Unicode support. + add_definitions(-DUNICODE -D_UNICODE) + # /W3 - Level 3 warnings # /MP - Multi-threaded compilation # /Zi - Output debugging information diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index c59107102..2ace866ee 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -88,6 +88,10 @@ add_library(core STATIC file_sys/vfs_vector.h file_sys/xts_archive.cpp file_sys/xts_archive.h + frontend/applets/error.cpp + frontend/applets/error.h + frontend/applets/general_frontend.cpp + frontend/applets/general_frontend.h frontend/applets/profile_select.cpp frontend/applets/profile_select.h frontend/applets/software_keyboard.cpp @@ -177,12 +181,14 @@ add_library(core STATIC hle/service/am/applet_oe.h hle/service/am/applets/applets.cpp hle/service/am/applets/applets.h + hle/service/am/applets/error.cpp + hle/service/am/applets/error.h + hle/service/am/applets/general_backend.cpp + hle/service/am/applets/general_backend.h hle/service/am/applets/profile_select.cpp hle/service/am/applets/profile_select.h hle/service/am/applets/software_keyboard.cpp hle/service/am/applets/software_keyboard.h - hle/service/am/applets/stub_applet.cpp - hle/service/am/applets/stub_applet.h hle/service/am/applets/web_browser.cpp hle/service/am/applets/web_browser.h hle/service/am/idle.cpp diff --git a/src/core/core.cpp b/src/core/core.cpp index 175a5f2ea..7106151bd 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp @@ -18,13 +18,18 @@ #include "core/file_sys/registered_cache.h" #include "core/file_sys/vfs_concat.h" #include "core/file_sys/vfs_real.h" +#include "core/frontend/applets/error.h" +#include "core/frontend/applets/general_frontend.h" +#include "core/frontend/applets/profile_select.h" +#include "core/frontend/applets/software_keyboard.h" +#include "core/frontend/applets/web_browser.h" #include "core/gdbstub/gdbstub.h" #include "core/hle/kernel/client_port.h" #include "core/hle/kernel/kernel.h" #include "core/hle/kernel/process.h" #include "core/hle/kernel/scheduler.h" #include "core/hle/kernel/thread.h" -#include "core/hle/service/am/applets/software_keyboard.h" +#include "core/hle/service/am/applets/applets.h" #include "core/hle/service/service.h" #include "core/hle/service/sm/sm.h" #include "core/loader/loader.h" @@ -110,12 +115,7 @@ struct System::Impl { content_provider = std::make_unique<FileSys::ContentProviderUnion>(); /// Create default implementations of applets if one is not provided. - if (profile_selector == nullptr) - profile_selector = std::make_unique<Core::Frontend::DefaultProfileSelectApplet>(); - if (software_keyboard == nullptr) - software_keyboard = std::make_unique<Core::Frontend::DefaultSoftwareKeyboardApplet>(); - if (web_browser == nullptr) - web_browser = std::make_unique<Core::Frontend::DefaultWebBrowserApplet>(); + applet_manager.SetDefaultAppletsIfMissing(); telemetry_session = std::make_unique<Core::TelemetrySession>(); service_manager = std::make_shared<Service::SM::ServiceManager>(); @@ -223,9 +223,7 @@ struct System::Impl { app_loader.reset(); // Clear all applets - profile_selector.reset(); - software_keyboard.reset(); - web_browser.reset(); + applet_manager.ClearAll(); LOG_DEBUG(Core, "Shutdown OK"); } @@ -264,9 +262,7 @@ struct System::Impl { std::unique_ptr<FileSys::CheatEngine> cheat_engine; /// Frontend applets - std::unique_ptr<Core::Frontend::ProfileSelectApplet> profile_selector; - std::unique_ptr<Core::Frontend::SoftwareKeyboardApplet> software_keyboard; - std::unique_ptr<Core::Frontend::WebBrowserApplet> web_browser; + Service::AM::Applets::AppletManager applet_manager; /// Service manager std::shared_ptr<Service::SM::ServiceManager> service_manager; @@ -476,20 +472,20 @@ std::shared_ptr<FileSys::VfsFilesystem> System::GetFilesystem() const { return impl->virtual_filesystem; } -void System::SetProfileSelector(std::unique_ptr<Frontend::ProfileSelectApplet> applet) { - impl->profile_selector = std::move(applet); +void System::SetAppletFrontendSet(Service::AM::Applets::AppletFrontendSet&& set) { + impl->applet_manager.SetAppletFrontendSet(std::move(set)); } -const Frontend::ProfileSelectApplet& System::GetProfileSelector() const { - return *impl->profile_selector; +void System::SetDefaultAppletFrontendSet() { + impl->applet_manager.SetDefaultAppletFrontendSet(); } -void System::SetSoftwareKeyboard(std::unique_ptr<Frontend::SoftwareKeyboardApplet> applet) { - impl->software_keyboard = std::move(applet); +Service::AM::Applets::AppletManager& System::GetAppletManager() { + return impl->applet_manager; } -const Frontend::SoftwareKeyboardApplet& System::GetSoftwareKeyboard() const { - return *impl->software_keyboard; +const Service::AM::Applets::AppletManager& System::GetAppletManager() const { + return impl->applet_manager; } void System::SetContentProvider(std::unique_ptr<FileSys::ContentProviderUnion> provider) { @@ -513,18 +509,6 @@ void System::ClearContentProvider(FileSys::ContentProviderUnionSlot slot) { impl->content_provider->ClearSlot(slot); } -void System::SetWebBrowser(std::unique_ptr<Frontend::WebBrowserApplet> applet) { - impl->web_browser = std::move(applet); -} - -Frontend::WebBrowserApplet& System::GetWebBrowser() { - return *impl->web_browser; -} - -const Frontend::WebBrowserApplet& System::GetWebBrowser() const { - return *impl->web_browser; -} - System::ResultStatus System::Init(Frontend::EmuWindow& emu_window) { return impl->Init(*this, emu_window); } diff --git a/src/core/core.h b/src/core/core.h index 82b2e087e..a9a756a4c 100644 --- a/src/core/core.h +++ b/src/core/core.h @@ -14,9 +14,6 @@ namespace Core::Frontend { class EmuWindow; -class ProfileSelectApplet; -class SoftwareKeyboardApplet; -class WebBrowserApplet; } // namespace Core::Frontend namespace FileSys { @@ -38,9 +35,18 @@ class AppLoader; enum class ResultStatus : u16; } // namespace Loader -namespace Service::SM { +namespace Service { + +namespace AM::Applets { +struct AppletFrontendSet; +class AppletManager; +} // namespace AM::Applets + +namespace SM { class ServiceManager; -} // namespace Service::SM +} // namespace SM + +} // namespace Service namespace Tegra { class DebugContext; @@ -260,18 +266,13 @@ public: void RegisterCheatList(const std::vector<FileSys::CheatList>& list, const std::string& build_id, VAddr code_region_start, VAddr code_region_end); - void SetProfileSelector(std::unique_ptr<Frontend::ProfileSelectApplet> applet); - - const Frontend::ProfileSelectApplet& GetProfileSelector() const; - - void SetSoftwareKeyboard(std::unique_ptr<Frontend::SoftwareKeyboardApplet> applet); + void SetAppletFrontendSet(Service::AM::Applets::AppletFrontendSet&& set); - const Frontend::SoftwareKeyboardApplet& GetSoftwareKeyboard() const; + void SetDefaultAppletFrontendSet(); - void SetWebBrowser(std::unique_ptr<Frontend::WebBrowserApplet> applet); + Service::AM::Applets::AppletManager& GetAppletManager(); - Frontend::WebBrowserApplet& GetWebBrowser(); - const Frontend::WebBrowserApplet& GetWebBrowser() const; + const Service::AM::Applets::AppletManager& GetAppletManager() const; void SetContentProvider(std::unique_ptr<FileSys::ContentProviderUnion> provider); diff --git a/src/core/frontend/applets/error.cpp b/src/core/frontend/applets/error.cpp new file mode 100644 index 000000000..4002a9211 --- /dev/null +++ b/src/core/frontend/applets/error.cpp @@ -0,0 +1,34 @@ +// Copyright 2019 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "core/frontend/applets/error.h" + +namespace Core::Frontend { + +ErrorApplet::~ErrorApplet() = default; + +void DefaultErrorApplet::ShowError(ResultCode error, std::function<void()> finished) const { + LOG_CRITICAL(Service_Fatal, "Application requested error display: {:04}-{:04} (raw={:08X})", + static_cast<u32>(error.module.Value()), error.description.Value(), error.raw); +} + +void DefaultErrorApplet::ShowErrorWithTimestamp(ResultCode error, std::chrono::seconds time, + std::function<void()> finished) const { + LOG_CRITICAL( + Service_Fatal, + "Application requested error display: {:04X}-{:04X} (raw={:08X}) with timestamp={:016X}", + static_cast<u32>(error.module.Value()), error.description.Value(), error.raw, time.count()); +} + +void DefaultErrorApplet::ShowCustomErrorText(ResultCode error, std::string main_text, + std::string detail_text, + std::function<void()> finished) const { + LOG_CRITICAL(Service_Fatal, + "Application requested custom error with error_code={:04X}-{:04X} (raw={:08X})", + static_cast<u32>(error.module.Value()), error.description.Value(), error.raw); + LOG_CRITICAL(Service_Fatal, " Main Text: {}", main_text); + LOG_CRITICAL(Service_Fatal, " Detail Text: {}", detail_text); +} + +} // namespace Core::Frontend diff --git a/src/core/frontend/applets/error.h b/src/core/frontend/applets/error.h new file mode 100644 index 000000000..699df940d --- /dev/null +++ b/src/core/frontend/applets/error.h @@ -0,0 +1,37 @@ +// Copyright 2019 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include <chrono> +#include <functional> + +#include "core/hle/result.h" + +namespace Core::Frontend { + +class ErrorApplet { +public: + virtual ~ErrorApplet(); + + virtual void ShowError(ResultCode error, std::function<void()> finished) const = 0; + + virtual void ShowErrorWithTimestamp(ResultCode error, std::chrono::seconds time, + std::function<void()> finished) const = 0; + + virtual void ShowCustomErrorText(ResultCode error, std::string dialog_text, + std::string fullscreen_text, + std::function<void()> finished) const = 0; +}; + +class DefaultErrorApplet final : public ErrorApplet { +public: + void ShowError(ResultCode error, std::function<void()> finished) const override; + void ShowErrorWithTimestamp(ResultCode error, std::chrono::seconds time, + std::function<void()> finished) const override; + void ShowCustomErrorText(ResultCode error, std::string main_text, std::string detail_text, + std::function<void()> finished) const override; +}; + +} // namespace Core::Frontend diff --git a/src/core/frontend/applets/general_frontend.cpp b/src/core/frontend/applets/general_frontend.cpp new file mode 100644 index 000000000..b974f2289 --- /dev/null +++ b/src/core/frontend/applets/general_frontend.cpp @@ -0,0 +1,27 @@ +// Copyright 2019 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "common/logging/log.h" +#include "core/frontend/applets/general_frontend.h" + +namespace Core::Frontend { + +PhotoViewerApplet::~PhotoViewerApplet() = default; + +DefaultPhotoViewerApplet::~DefaultPhotoViewerApplet() {} + +void DefaultPhotoViewerApplet::ShowPhotosForApplication(u64 title_id, + std::function<void()> finished) const { + LOG_INFO(Service_AM, + "Application requested frontend to display stored photos for title_id={:016X}", + title_id); + finished(); +} + +void DefaultPhotoViewerApplet::ShowAllPhotos(std::function<void()> finished) const { + LOG_INFO(Service_AM, "Application requested frontend to display all stored photos."); + finished(); +} + +} // namespace Core::Frontend diff --git a/src/core/frontend/applets/general_frontend.h b/src/core/frontend/applets/general_frontend.h new file mode 100644 index 000000000..d4506c999 --- /dev/null +++ b/src/core/frontend/applets/general_frontend.h @@ -0,0 +1,28 @@ +// Copyright 2019 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include <functional> +#include "common/common_types.h" + +namespace Core::Frontend { + +class PhotoViewerApplet { +public: + virtual ~PhotoViewerApplet(); + + virtual void ShowPhotosForApplication(u64 title_id, std::function<void()> finished) const = 0; + virtual void ShowAllPhotos(std::function<void()> finished) const = 0; +}; + +class DefaultPhotoViewerApplet final : public PhotoViewerApplet { +public: + ~DefaultPhotoViewerApplet() override; + + void ShowPhotosForApplication(u64 title_id, std::function<void()> finished) const override; + void ShowAllPhotos(std::function<void()> finished) const override; +}; + +} // namespace Core::Frontend diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index 8539fabe4..757e5f21f 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp @@ -46,8 +46,7 @@ static void ThreadWakeupCallback(u64 thread_handle, [[maybe_unused]] s64 cycles_ bool resume = true; - if (thread->GetStatus() == ThreadStatus::WaitSynchAny || - thread->GetStatus() == ThreadStatus::WaitSynchAll || + if (thread->GetStatus() == ThreadStatus::WaitSynch || thread->GetStatus() == ThreadStatus::WaitHLEEvent) { // Remove the thread from each of its waiting objects' waitlists for (const auto& object : thread->GetWaitObjects()) { diff --git a/src/core/hle/kernel/process.cpp b/src/core/hle/kernel/process.cpp index 6d7a7e754..0775a89fb 100644 --- a/src/core/hle/kernel/process.cpp +++ b/src/core/hle/kernel/process.cpp @@ -147,8 +147,7 @@ void Process::PrepareForTermination() { continue; // TODO(Subv): When are the other running/ready threads terminated? - ASSERT_MSG(thread->GetStatus() == ThreadStatus::WaitSynchAny || - thread->GetStatus() == ThreadStatus::WaitSynchAll, + ASSERT_MSG(thread->GetStatus() == ThreadStatus::WaitSynch, "Exiting processes with non-waiting threads is currently unimplemented"); thread->Stop(); @@ -242,7 +241,8 @@ void Process::LoadModule(CodeSet module_, VAddr base_addr) { } Process::Process(Core::System& system) - : WaitObject{system.Kernel()}, address_arbiter{system}, mutex{system}, system{system} {} + : WaitObject{system.Kernel()}, vm_manager{system}, + address_arbiter{system}, mutex{system}, system{system} {} Process::~Process() = default; diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index 4c763b288..2dcf174c5 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -424,7 +424,7 @@ static ResultCode GetProcessId(Core::System& system, u64* process_id, Handle han /// Default thread wakeup callback for WaitSynchronization static bool DefaultThreadWakeupCallback(ThreadWakeupReason reason, SharedPtr<Thread> thread, SharedPtr<WaitObject> object, std::size_t index) { - ASSERT(thread->GetStatus() == ThreadStatus::WaitSynchAny); + ASSERT(thread->GetStatus() == ThreadStatus::WaitSynch); if (reason == ThreadWakeupReason::Timeout) { thread->SetWaitSynchronizationResult(RESULT_TIMEOUT); @@ -502,7 +502,7 @@ static ResultCode WaitSynchronization(Core::System& system, Handle* index, VAddr } thread->SetWaitObjects(std::move(objects)); - thread->SetStatus(ThreadStatus::WaitSynchAny); + thread->SetStatus(ThreadStatus::WaitSynch); // Create an event to wake the thread up after the specified nanosecond delay has passed thread->WakeAfterDelay(nano_seconds); @@ -518,16 +518,14 @@ static ResultCode CancelSynchronization(Core::System& system, Handle thread_hand LOG_TRACE(Kernel_SVC, "called thread=0x{:X}", thread_handle); const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); - const SharedPtr<Thread> thread = handle_table.Get<Thread>(thread_handle); + SharedPtr<Thread> thread = handle_table.Get<Thread>(thread_handle); if (!thread) { LOG_ERROR(Kernel_SVC, "Thread handle does not exist, thread_handle=0x{:08X}", thread_handle); return ERR_INVALID_HANDLE; } - ASSERT(thread->GetStatus() == ThreadStatus::WaitSynchAny); - thread->SetWaitSynchronizationResult(ERR_SYNCHRONIZATION_CANCELED); - thread->ResumeFromWait(); + thread->CancelWait(); return RESULT_SUCCESS; } diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index ca52267b2..2abf9efca 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp @@ -101,8 +101,7 @@ void Thread::ResumeFromWait() { ASSERT_MSG(wait_objects.empty(), "Thread is waking up while waiting for objects"); switch (status) { - case ThreadStatus::WaitSynchAll: - case ThreadStatus::WaitSynchAny: + case ThreadStatus::WaitSynch: case ThreadStatus::WaitHLEEvent: case ThreadStatus::WaitSleep: case ThreadStatus::WaitIPC: @@ -142,6 +141,12 @@ void Thread::ResumeFromWait() { ChangeScheduler(); } +void Thread::CancelWait() { + ASSERT(GetStatus() == ThreadStatus::WaitSynch); + SetWaitSynchronizationResult(ERR_SYNCHRONIZATION_CANCELED); + ResumeFromWait(); +} + /** * Resets a thread context, making it ready to be scheduled and run by the CPU * @param context Thread context to reset diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h index 411a73b49..f07332f02 100644 --- a/src/core/hle/kernel/thread.h +++ b/src/core/hle/kernel/thread.h @@ -49,8 +49,7 @@ enum class ThreadStatus { WaitHLEEvent, ///< Waiting for hle event to finish WaitSleep, ///< Waiting due to a SleepThread SVC WaitIPC, ///< Waiting for the reply from an IPC request - WaitSynchAny, ///< Waiting due to WaitSynch1 or WaitSynchN with wait_all = false - WaitSynchAll, ///< Waiting due to WaitSynchronizationN with wait_all = true + WaitSynch, ///< Waiting due to WaitSynchronization WaitMutex, ///< Waiting due to an ArbitrateLock svc WaitCondVar, ///< Waiting due to an WaitProcessWideKey svc WaitArb, ///< Waiting due to a SignalToAddress/WaitForAddress svc @@ -169,11 +168,17 @@ public: return tls_memory; } - /** - * Resumes a thread from waiting - */ + /// Resumes a thread from waiting void ResumeFromWait(); + /// Cancels a waiting operation that this thread may or may not be within. + /// + /// When the thread is within a waiting state, this will set the thread's + /// waiting result to signal a canceled wait. The function will then resume + /// this thread. + /// + void CancelWait(); + /** * Schedules an event to wake up the specified thread after the specified delay * @param nanoseconds The time this thread will be allowed to sleep for @@ -184,24 +189,27 @@ public: void CancelWakeupTimer(); /** - * Sets the result after the thread awakens (from either WaitSynchronization SVC) + * Sets the result after the thread awakens (from svcWaitSynchronization) * @param result Value to set to the returned result */ void SetWaitSynchronizationResult(ResultCode result); /** - * Sets the output parameter value after the thread awakens (from WaitSynchronizationN SVC only) + * Sets the output parameter value after the thread awakens (from svcWaitSynchronization) * @param output Value to set to the output parameter */ void SetWaitSynchronizationOutput(s32 output); /** * Retrieves the index that this particular object occupies in the list of objects - * that the thread passed to WaitSynchronizationN, starting the search from the last element. - * It is used to set the output value of WaitSynchronizationN when the thread is awakened. + * that the thread passed to WaitSynchronization, starting the search from the last element. + * + * It is used to set the output index of WaitSynchronization when the thread is awakened. + * * When a thread wakes up due to an object signal, the kernel will use the index of the last * matching object in the wait objects list in case of having multiple instances of the same * object in the list. + * * @param object Object to query the index of. */ s32 GetWaitObjectIndex(const WaitObject* object) const; @@ -238,13 +246,9 @@ public: */ VAddr GetCommandBufferAddress() const; - /** - * Returns whether this thread is waiting for all the objects in - * its wait list to become ready, as a result of a WaitSynchronizationN call - * with wait_all = true. - */ - bool IsSleepingOnWaitAll() const { - return status == ThreadStatus::WaitSynchAll; + /// Returns whether this thread is waiting on objects from a WaitSynchronization call. + bool IsSleepingOnWait() const { + return status == ThreadStatus::WaitSynch; } ThreadContext& GetContext() { @@ -418,7 +422,7 @@ private: Process* owner_process; /// Objects that the thread is waiting on, in the same order as they were - /// passed to WaitSynchronization1/N. + /// passed to WaitSynchronization. ThreadWaitObjects wait_objects; /// List of threads that are waiting for a mutex that is held by this thread. @@ -441,7 +445,7 @@ private: Handle callback_handle = 0; /// Callback that will be invoked when the thread is resumed from a waiting state. If the thread - /// was waiting via WaitSynchronizationN then the object will be the last object that became + /// was waiting via WaitSynchronization then the object will be the last object that became /// available. In case of a timeout, the object will be nullptr. WakeupCallback wakeup_callback; diff --git a/src/core/hle/kernel/vm_manager.cpp b/src/core/hle/kernel/vm_manager.cpp index f0c0c12fc..48b13cfdd 100644 --- a/src/core/hle/kernel/vm_manager.cpp +++ b/src/core/hle/kernel/vm_manager.cpp @@ -62,7 +62,7 @@ bool VirtualMemoryArea::CanBeMergedWith(const VirtualMemoryArea& next) const { return true; } -VMManager::VMManager() { +VMManager::VMManager(Core::System& system) : system{system} { // Default to assuming a 39-bit address space. This way we have a sane // starting point with executables that don't provide metadata. Reset(FileSys::ProgramAddressSpaceType::Is39Bit); @@ -111,7 +111,6 @@ ResultVal<VMManager::VMAHandle> VMManager::MapMemoryBlock(VAddr target, VirtualMemoryArea& final_vma = vma_handle->second; ASSERT(final_vma.size == size); - auto& system = Core::System::GetInstance(); system.ArmInterface(0).MapBackingMemory(target, size, block->data() + offset, VMAPermission::ReadWriteExecute); system.ArmInterface(1).MapBackingMemory(target, size, block->data() + offset, @@ -140,7 +139,6 @@ ResultVal<VMManager::VMAHandle> VMManager::MapBackingMemory(VAddr target, u8* me VirtualMemoryArea& final_vma = vma_handle->second; ASSERT(final_vma.size == size); - auto& system = Core::System::GetInstance(); system.ArmInterface(0).MapBackingMemory(target, size, memory, VMAPermission::ReadWriteExecute); system.ArmInterface(1).MapBackingMemory(target, size, memory, VMAPermission::ReadWriteExecute); system.ArmInterface(2).MapBackingMemory(target, size, memory, VMAPermission::ReadWriteExecute); @@ -223,7 +221,6 @@ ResultCode VMManager::UnmapRange(VAddr target, u64 size) { ASSERT(FindVMA(target)->second.size >= size); - auto& system = Core::System::GetInstance(); system.ArmInterface(0).UnmapMemory(target, size); system.ArmInterface(1).UnmapMemory(target, size); system.ArmInterface(2).UnmapMemory(target, size); @@ -376,7 +373,7 @@ ResultCode VMManager::UnmapCodeMemory(VAddr dst_address, VAddr src_address, u64 Reprotect(src_vma_iter, VMAPermission::ReadWrite); if (dst_memory_state == MemoryState::ModuleCode) { - Core::System::GetInstance().InvalidateCpuInstructionCaches(); + system.InvalidateCpuInstructionCaches(); } return unmap_result; diff --git a/src/core/hle/kernel/vm_manager.h b/src/core/hle/kernel/vm_manager.h index 288eb9450..ec84d9a70 100644 --- a/src/core/hle/kernel/vm_manager.h +++ b/src/core/hle/kernel/vm_manager.h @@ -14,6 +14,10 @@ #include "core/hle/result.h" #include "core/memory.h" +namespace Core { +class System; +} + namespace FileSys { enum class ProgramAddressSpaceType : u8; } @@ -321,7 +325,7 @@ class VMManager final { public: using VMAHandle = VMAMap::const_iterator; - VMManager(); + explicit VMManager(Core::System& system); ~VMManager(); /// Clears the address space map, re-initializing with a single free area. @@ -712,5 +716,7 @@ private: // The end of the currently allocated heap. This is not an inclusive // end of the range. This is essentially 'base_address + current_size'. VAddr heap_end = 0; + + Core::System& system; }; } // namespace Kernel diff --git a/src/core/hle/kernel/wait_object.cpp b/src/core/hle/kernel/wait_object.cpp index c8eaf9488..0e96ba872 100644 --- a/src/core/hle/kernel/wait_object.cpp +++ b/src/core/hle/kernel/wait_object.cpp @@ -38,8 +38,7 @@ SharedPtr<Thread> WaitObject::GetHighestPriorityReadyThread() const { const ThreadStatus thread_status = thread->GetStatus(); // The list of waiting threads must not contain threads that are not waiting to be awakened. - ASSERT_MSG(thread_status == ThreadStatus::WaitSynchAny || - thread_status == ThreadStatus::WaitSynchAll || + ASSERT_MSG(thread_status == ThreadStatus::WaitSynch || thread_status == ThreadStatus::WaitHLEEvent, "Inconsistent thread statuses in waiting_threads"); @@ -49,10 +48,10 @@ SharedPtr<Thread> WaitObject::GetHighestPriorityReadyThread() const { if (ShouldWait(thread.get())) continue; - // A thread is ready to run if it's either in ThreadStatus::WaitSynchAny or - // in ThreadStatus::WaitSynchAll and the rest of the objects it is waiting on are ready. + // A thread is ready to run if it's either in ThreadStatus::WaitSynch + // and the rest of the objects it is waiting on are ready. bool ready_to_run = true; - if (thread_status == ThreadStatus::WaitSynchAll) { + if (thread_status == ThreadStatus::WaitSynch) { ready_to_run = thread->AllWaitObjectsReady(); } @@ -68,33 +67,35 @@ SharedPtr<Thread> WaitObject::GetHighestPriorityReadyThread() const { void WaitObject::WakeupWaitingThread(SharedPtr<Thread> thread) { ASSERT(!ShouldWait(thread.get())); - if (!thread) + if (!thread) { return; + } - if (!thread->IsSleepingOnWaitAll()) { - Acquire(thread.get()); - } else { + if (thread->IsSleepingOnWait()) { for (const auto& object : thread->GetWaitObjects()) { ASSERT(!object->ShouldWait(thread.get())); object->Acquire(thread.get()); } + } else { + Acquire(thread.get()); } const std::size_t index = thread->GetWaitObjectIndex(this); - for (const auto& object : thread->GetWaitObjects()) + for (const auto& object : thread->GetWaitObjects()) { object->RemoveWaitingThread(thread.get()); + } thread->ClearWaitObjects(); thread->CancelWakeupTimer(); bool resume = true; - - if (thread->HasWakeupCallback()) + if (thread->HasWakeupCallback()) { resume = thread->InvokeWakeupCallback(ThreadWakeupReason::Signal, thread, this, index); - - if (resume) + } + if (resume) { thread->ResumeFromWait(); + } } void WaitObject::WakeupAllWaitingThreads() { diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp index 1aa4ce1ac..26a665bfd 100644 --- a/src/core/hle/service/am/am.cpp +++ b/src/core/hle/service/am/am.cpp @@ -22,7 +22,6 @@ #include "core/hle/service/am/applets/applets.h" #include "core/hle/service/am/applets/profile_select.h" #include "core/hle/service/am/applets/software_keyboard.h" -#include "core/hle/service/am/applets/stub_applet.h" #include "core/hle/service/am/applets/web_browser.h" #include "core/hle/service/am/idle.h" #include "core/hle/service/am/omm.h" @@ -42,12 +41,6 @@ constexpr ResultCode ERR_NO_DATA_IN_CHANNEL{ErrorModule::AM, 0x2}; constexpr ResultCode ERR_NO_MESSAGES{ErrorModule::AM, 0x3}; constexpr ResultCode ERR_SIZE_OUT_OF_BOUNDS{ErrorModule::AM, 0x1F7}; -enum class AppletId : u32 { - ProfileSelect = 0x10, - SoftwareKeyboard = 0x11, - LibAppletOff = 0x17, -}; - constexpr u32 POP_LAUNCH_PARAMETER_MAGIC = 0xC79497CA; struct LaunchParameters { @@ -886,30 +879,16 @@ ILibraryAppletCreator::ILibraryAppletCreator() : ServiceFramework("ILibraryApple ILibraryAppletCreator::~ILibraryAppletCreator() = default; -static std::shared_ptr<Applets::Applet> GetAppletFromId(AppletId id) { - switch (id) { - case AppletId::ProfileSelect: - return std::make_shared<Applets::ProfileSelect>(); - case AppletId::SoftwareKeyboard: - return std::make_shared<Applets::SoftwareKeyboard>(); - case AppletId::LibAppletOff: - return std::make_shared<Applets::WebBrowser>(); - default: - LOG_ERROR(Service_AM, "Unimplemented AppletId [{:08X}]! -- Falling back to stub!", - static_cast<u32>(id)); - return std::make_shared<Applets::StubApplet>(); - } -} - void ILibraryAppletCreator::CreateLibraryApplet(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; - const auto applet_id = rp.PopRaw<AppletId>(); + const auto applet_id = rp.PopRaw<Applets::AppletId>(); const auto applet_mode = rp.PopRaw<u32>(); LOG_DEBUG(Service_AM, "called with applet_id={:08X}, applet_mode={:08X}", static_cast<u32>(applet_id), applet_mode); - const auto applet = GetAppletFromId(applet_id); + const auto& applet_manager{Core::System::GetInstance().GetAppletManager()}; + const auto applet = applet_manager.GetApplet(applet_id); if (applet == nullptr) { LOG_ERROR(Service_AM, "Applet doesn't exist! applet_id={}", static_cast<u32>(applet_id)); diff --git a/src/core/hle/service/am/applets/applets.cpp b/src/core/hle/service/am/applets/applets.cpp index a6064c63f..7f70b10df 100644 --- a/src/core/hle/service/am/applets/applets.cpp +++ b/src/core/hle/service/am/applets/applets.cpp @@ -5,11 +5,21 @@ #include <cstring> #include "common/assert.h" #include "core/core.h" +#include "core/frontend/applets/error.h" +#include "core/frontend/applets/general_frontend.h" +#include "core/frontend/applets/profile_select.h" +#include "core/frontend/applets/software_keyboard.h" +#include "core/frontend/applets/web_browser.h" #include "core/hle/kernel/readable_event.h" #include "core/hle/kernel/server_session.h" #include "core/hle/kernel/writable_event.h" #include "core/hle/service/am/am.h" #include "core/hle/service/am/applets/applets.h" +#include "core/hle/service/am/applets/error.h" +#include "core/hle/service/am/applets/general_backend.h" +#include "core/hle/service/am/applets/profile_select.h" +#include "core/hle/service/am/applets/software_keyboard.h" +#include "core/hle/service/am/applets/web_browser.h" namespace Service::AM::Applets { @@ -111,4 +121,76 @@ void Applet::Initialize() { initialized = true; } +AppletManager::AppletManager() = default; + +AppletManager::~AppletManager() = default; + +void AppletManager::SetAppletFrontendSet(AppletFrontendSet set) { + if (set.error != nullptr) + frontend.error = std::move(set.error); + if (set.photo_viewer != nullptr) + frontend.photo_viewer = std::move(set.photo_viewer); + if (set.profile_select != nullptr) + frontend.profile_select = std::move(set.profile_select); + if (set.software_keyboard != nullptr) + frontend.software_keyboard = std::move(set.software_keyboard); + if (set.web_browser != nullptr) + frontend.web_browser = std::move(set.web_browser); +} + +void AppletManager::SetDefaultAppletFrontendSet() { + frontend.error = std::make_unique<Core::Frontend::DefaultErrorApplet>(); + frontend.photo_viewer = std::make_unique<Core::Frontend::DefaultPhotoViewerApplet>(); + frontend.profile_select = std::make_unique<Core::Frontend::DefaultProfileSelectApplet>(); + frontend.software_keyboard = std::make_unique<Core::Frontend::DefaultSoftwareKeyboardApplet>(); + frontend.web_browser = std::make_unique<Core::Frontend::DefaultWebBrowserApplet>(); +} + +void AppletManager::SetDefaultAppletsIfMissing() { + if (frontend.error == nullptr) { + frontend.error = std::make_unique<Core::Frontend::DefaultErrorApplet>(); + } + + if (frontend.photo_viewer == nullptr) { + frontend.photo_viewer = std::make_unique<Core::Frontend::DefaultPhotoViewerApplet>(); + } + + if (frontend.profile_select == nullptr) { + frontend.profile_select = std::make_unique<Core::Frontend::DefaultProfileSelectApplet>(); + } + + if (frontend.software_keyboard == nullptr) { + frontend.software_keyboard = + std::make_unique<Core::Frontend::DefaultSoftwareKeyboardApplet>(); + } + + if (frontend.web_browser == nullptr) { + frontend.web_browser = std::make_unique<Core::Frontend::DefaultWebBrowserApplet>(); + } +} + +void AppletManager::ClearAll() { + frontend = {}; +} + +std::shared_ptr<Applet> AppletManager::GetApplet(AppletId id) const { + switch (id) { + case AppletId::Error: + return std::make_shared<Error>(*frontend.error); + case AppletId::ProfileSelect: + return std::make_shared<ProfileSelect>(*frontend.profile_select); + case AppletId::SoftwareKeyboard: + return std::make_shared<SoftwareKeyboard>(*frontend.software_keyboard); + case AppletId::PhotoViewer: + return std::make_shared<PhotoViewer>(*frontend.photo_viewer); + case AppletId::LibAppletOff: + return std::make_shared<WebBrowser>(*frontend.web_browser); + default: + UNIMPLEMENTED_MSG( + "No backend implementation exists for applet_id={:02X}! Falling back to stub applet.", + static_cast<u8>(id)); + return std::make_shared<StubApplet>(); + } +} + } // namespace Service::AM::Applets diff --git a/src/core/hle/service/am/applets/applets.h b/src/core/hle/service/am/applets/applets.h index 37424c379..7f932672c 100644 --- a/src/core/hle/service/am/applets/applets.h +++ b/src/core/hle/service/am/applets/applets.h @@ -12,12 +12,43 @@ union ResultCode; +namespace Core::Frontend { +class ErrorApplet; +class PhotoViewerApplet; +class ProfileSelectApplet; +class SoftwareKeyboardApplet; +class WebBrowserApplet; +} // namespace Core::Frontend + namespace Service::AM { class IStorage; namespace Applets { +enum class AppletId : u32 { + OverlayDisplay = 0x02, + QLaunch = 0x03, + Starter = 0x04, + Auth = 0x0A, + Cabinet = 0x0B, + Controller = 0x0C, + DataErase = 0x0D, + Error = 0x0E, + NetConnect = 0x0F, + ProfileSelect = 0x10, + SoftwareKeyboard = 0x11, + MiiEdit = 0x12, + LibAppletWeb = 0x13, + LibAppletShop = 0x14, + PhotoViewer = 0x15, + Settings = 0x16, + LibAppletOff = 0x17, + LibAppletWhitelisted = 0x18, + LibAppletAuth = 0x19, + MyPage = 0x1A, +}; + class AppletDataBroker final { public: AppletDataBroker(); @@ -105,5 +136,29 @@ protected: bool initialized = false; }; +struct AppletFrontendSet { + std::unique_ptr<Core::Frontend::ErrorApplet> error; + std::unique_ptr<Core::Frontend::PhotoViewerApplet> photo_viewer; + std::unique_ptr<Core::Frontend::ProfileSelectApplet> profile_select; + std::unique_ptr<Core::Frontend::SoftwareKeyboardApplet> software_keyboard; + std::unique_ptr<Core::Frontend::WebBrowserApplet> web_browser; +}; + +class AppletManager { +public: + AppletManager(); + ~AppletManager(); + + void SetAppletFrontendSet(AppletFrontendSet set); + void SetDefaultAppletFrontendSet(); + void SetDefaultAppletsIfMissing(); + void ClearAll(); + + std::shared_ptr<Applet> GetApplet(AppletId id) const; + +private: + AppletFrontendSet frontend; +}; + } // namespace Applets } // namespace Service::AM diff --git a/src/core/hle/service/am/applets/error.cpp b/src/core/hle/service/am/applets/error.cpp new file mode 100644 index 000000000..04774bedc --- /dev/null +++ b/src/core/hle/service/am/applets/error.cpp @@ -0,0 +1,182 @@ +// Copyright 2019 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include <array> +#include <cstring> +#include "common/assert.h" +#include "common/logging/log.h" +#include "common/string_util.h" +#include "core/core.h" +#include "core/frontend/applets/error.h" +#include "core/hle/service/am/am.h" +#include "core/hle/service/am/applets/error.h" + +namespace Service::AM::Applets { + +#pragma pack(push, 4) +struct ShowError { + u8 mode; + bool jump; + INSERT_PADDING_BYTES(4); + bool use_64bit_error_code; + INSERT_PADDING_BYTES(1); + u64 error_code_64; + u32 error_code_32; +}; +static_assert(sizeof(ShowError) == 0x14, "ShowError has incorrect size."); +#pragma pack(pop) + +struct ShowErrorRecord { + u8 mode; + bool jump; + INSERT_PADDING_BYTES(6); + u64 error_code_64; + u64 posix_time; +}; +static_assert(sizeof(ShowErrorRecord) == 0x18, "ShowErrorRecord has incorrect size."); + +struct SystemErrorArg { + u8 mode; + bool jump; + INSERT_PADDING_BYTES(6); + u64 error_code_64; + std::array<char, 8> language_code; + std::array<char, 0x800> main_text; + std::array<char, 0x800> detail_text; +}; +static_assert(sizeof(SystemErrorArg) == 0x1018, "SystemErrorArg has incorrect size."); + +struct ApplicationErrorArg { + u8 mode; + bool jump; + INSERT_PADDING_BYTES(6); + u32 error_code; + std::array<char, 8> language_code; + std::array<char, 0x800> main_text; + std::array<char, 0x800> detail_text; +}; +static_assert(sizeof(ApplicationErrorArg) == 0x1014, "ApplicationErrorArg has incorrect size."); + +union Error::ErrorArguments { + ShowError error; + ShowErrorRecord error_record; + SystemErrorArg system_error; + ApplicationErrorArg application_error; +}; + +namespace { +template <typename T> +void CopyArgumentData(const std::vector<u8>& data, T& variable) { + ASSERT(data.size() >= sizeof(T)); + std::memcpy(&variable, data.data(), sizeof(T)); +} + +ResultCode Decode64BitError(u64 error) { + const auto description = (error >> 32) & 0x1FFF; + auto module = error & 0x3FF; + if (module >= 2000) + module -= 2000; + module &= 0x1FF; + return {static_cast<ErrorModule>(module), static_cast<u32>(description)}; +} + +} // Anonymous namespace + +Error::Error(const Core::Frontend::ErrorApplet& frontend) : frontend(frontend) {} + +Error::~Error() = default; + +void Error::Initialize() { + Applet::Initialize(); + args = std::make_unique<ErrorArguments>(); + complete = false; + + const auto storage = broker.PopNormalDataToApplet(); + ASSERT(storage != nullptr); + const auto data = storage->GetData(); + + ASSERT(!data.empty()); + std::memcpy(&mode, data.data(), sizeof(ErrorAppletMode)); + + switch (mode) { + case ErrorAppletMode::ShowError: + CopyArgumentData(data, args->error); + if (args->error.use_64bit_error_code) { + error_code = Decode64BitError(args->error.error_code_64); + } else { + error_code = ResultCode(args->error.error_code_32); + } + break; + case ErrorAppletMode::ShowSystemError: + CopyArgumentData(data, args->system_error); + error_code = ResultCode(Decode64BitError(args->system_error.error_code_64)); + break; + case ErrorAppletMode::ShowApplicationError: + CopyArgumentData(data, args->application_error); + error_code = ResultCode(args->application_error.error_code); + break; + case ErrorAppletMode::ShowErrorRecord: + CopyArgumentData(data, args->error_record); + error_code = Decode64BitError(args->error_record.error_code_64); + break; + default: + UNIMPLEMENTED_MSG("Unimplemented LibAppletError mode={:02X}!", static_cast<u8>(mode)); + } +} + +bool Error::TransactionComplete() const { + return complete; +} + +ResultCode Error::GetStatus() const { + return RESULT_SUCCESS; +} + +void Error::ExecuteInteractive() { + UNREACHABLE_MSG("Unexpected interactive applet data!"); +} + +void Error::Execute() { + if (complete) { + return; + } + + const auto callback = [this] { DisplayCompleted(); }; + + switch (mode) { + case ErrorAppletMode::ShowError: + frontend.ShowError(error_code, callback); + break; + case ErrorAppletMode::ShowSystemError: + case ErrorAppletMode::ShowApplicationError: { + const auto system = mode == ErrorAppletMode::ShowSystemError; + const auto& main_text = + system ? args->system_error.main_text : args->application_error.main_text; + const auto& detail_text = + system ? args->system_error.detail_text : args->application_error.detail_text; + + frontend.ShowCustomErrorText( + error_code, + Common::StringFromFixedZeroTerminatedBuffer(main_text.data(), main_text.size()), + Common::StringFromFixedZeroTerminatedBuffer(detail_text.data(), detail_text.size()), + callback); + break; + } + case ErrorAppletMode::ShowErrorRecord: + frontend.ShowErrorWithTimestamp( + error_code, std::chrono::seconds{args->error_record.posix_time}, callback); + break; + default: + UNIMPLEMENTED_MSG("Unimplemented LibAppletError mode={:02X}!", static_cast<u8>(mode)); + DisplayCompleted(); + } +} + +void Error::DisplayCompleted() { + complete = true; + broker.PushNormalDataFromApplet(IStorage{{}}); + broker.SignalStateChanged(); +} + +} // namespace Service::AM::Applets diff --git a/src/core/hle/service/am/applets/error.h b/src/core/hle/service/am/applets/error.h new file mode 100644 index 000000000..a3590d181 --- /dev/null +++ b/src/core/hle/service/am/applets/error.h @@ -0,0 +1,47 @@ +// Copyright 2019 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include "core/hle/result.h" +#include "core/hle/service/am/applets/applets.h" + +namespace Service::AM::Applets { + +enum class ErrorAppletMode : u8 { + ShowError = 0, + ShowSystemError = 1, + ShowApplicationError = 2, + ShowEula = 3, + ShowErrorPctl = 4, + ShowErrorRecord = 5, + ShowUpdateEula = 8, +}; + +class Error final : public Applet { +public: + explicit Error(const Core::Frontend::ErrorApplet& frontend); + ~Error() override; + + void Initialize() override; + + bool TransactionComplete() const override; + ResultCode GetStatus() const override; + void ExecuteInteractive() override; + void Execute() override; + + void DisplayCompleted(); + +private: + union ErrorArguments; + + const Core::Frontend::ErrorApplet& frontend; + ResultCode error_code = RESULT_SUCCESS; + ErrorAppletMode mode = ErrorAppletMode::ShowError; + std::unique_ptr<ErrorArguments> args; + + bool complete = false; +}; + +} // namespace Service::AM::Applets diff --git a/src/core/hle/service/am/applets/stub_applet.cpp b/src/core/hle/service/am/applets/general_backend.cpp index ed166b87d..c591b9ac2 100644 --- a/src/core/hle/service/am/applets/stub_applet.cpp +++ b/src/core/hle/service/am/applets/general_backend.cpp @@ -4,11 +4,15 @@ #include <string> +#include "common/assert.h" #include "common/hex_util.h" #include "common/logging/log.h" +#include "core/core.h" +#include "core/frontend/applets/general_frontend.h" +#include "core/hle/kernel/process.h" #include "core/hle/result.h" #include "core/hle/service/am/am.h" -#include "core/hle/service/am/applets/stub_applet.h" +#include "core/hle/service/am/applets/general_backend.h" namespace Service::AM::Applets { @@ -30,6 +34,55 @@ static void LogCurrentStorage(AppletDataBroker& broker, std::string prefix) { } } +PhotoViewer::PhotoViewer(const Core::Frontend::PhotoViewerApplet& frontend) : frontend(frontend) {} + +PhotoViewer::~PhotoViewer() = default; + +void PhotoViewer::Initialize() { + Applet::Initialize(); + complete = false; + + const auto storage = broker.PopNormalDataToApplet(); + ASSERT(storage != nullptr); + const auto data = storage->GetData(); + ASSERT(!data.empty()); + mode = static_cast<PhotoViewerAppletMode>(data[0]); +} + +bool PhotoViewer::TransactionComplete() const { + return complete; +} + +ResultCode PhotoViewer::GetStatus() const { + return RESULT_SUCCESS; +} + +void PhotoViewer::ExecuteInteractive() { + UNREACHABLE_MSG("Unexpected interactive applet data."); +} + +void PhotoViewer::Execute() { + if (complete) + return; + + const auto callback = [this] { ViewFinished(); }; + switch (mode) { + case PhotoViewerAppletMode::CurrentApp: + frontend.ShowPhotosForApplication(Core::CurrentProcess()->GetTitleID(), callback); + break; + case PhotoViewerAppletMode::AllApps: + frontend.ShowAllPhotos(callback); + break; + default: + UNIMPLEMENTED_MSG("Unimplemented PhotoViewer applet mode={:02X}!", static_cast<u8>(mode)); + } +} + +void PhotoViewer::ViewFinished() { + broker.PushNormalDataFromApplet(IStorage{{}}); + broker.SignalStateChanged(); +} + StubApplet::StubApplet() = default; StubApplet::~StubApplet() = default; @@ -67,4 +120,5 @@ void StubApplet::Execute() { broker.PushInteractiveDataFromApplet(IStorage{std::vector<u8>(0x1000)}); broker.SignalStateChanged(); } + } // namespace Service::AM::Applets diff --git a/src/core/hle/service/am/applets/general_backend.h b/src/core/hle/service/am/applets/general_backend.h new file mode 100644 index 000000000..2dd255d7c --- /dev/null +++ b/src/core/hle/service/am/applets/general_backend.h @@ -0,0 +1,48 @@ +// Copyright 2019 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include "core/hle/service/am/applets/applets.h" + +namespace Service::AM::Applets { + +enum class PhotoViewerAppletMode : u8 { + CurrentApp = 0, + AllApps = 1, +}; + +class PhotoViewer final : public Applet { +public: + explicit PhotoViewer(const Core::Frontend::PhotoViewerApplet& frontend); + ~PhotoViewer() override; + + void Initialize() override; + bool TransactionComplete() const override; + ResultCode GetStatus() const override; + void ExecuteInteractive() override; + void Execute() override; + + void ViewFinished(); + +private: + const Core::Frontend::PhotoViewerApplet& frontend; + bool complete = false; + PhotoViewerAppletMode mode = PhotoViewerAppletMode::CurrentApp; +}; + +class StubApplet final : public Applet { +public: + StubApplet(); + ~StubApplet() override; + + void Initialize() override; + + bool TransactionComplete() const override; + ResultCode GetStatus() const override; + void ExecuteInteractive() override; + void Execute() override; +}; + +} // namespace Service::AM::Applets diff --git a/src/core/hle/service/am/applets/profile_select.cpp b/src/core/hle/service/am/applets/profile_select.cpp index 14e2a1fee..d113bd2eb 100644 --- a/src/core/hle/service/am/applets/profile_select.cpp +++ b/src/core/hle/service/am/applets/profile_select.cpp @@ -15,7 +15,9 @@ namespace Service::AM::Applets { constexpr ResultCode ERR_USER_CANCELLED_SELECTION{ErrorModule::Account, 1}; -ProfileSelect::ProfileSelect() = default; +ProfileSelect::ProfileSelect(const Core::Frontend::ProfileSelectApplet& frontend) + : frontend(frontend) {} + ProfileSelect::~ProfileSelect() = default; void ProfileSelect::Initialize() { @@ -51,8 +53,6 @@ void ProfileSelect::Execute() { return; } - const auto& frontend{Core::System::GetInstance().GetProfileSelector()}; - frontend.SelectProfile([this](std::optional<Account::UUID> uuid) { SelectionComplete(uuid); }); } diff --git a/src/core/hle/service/am/applets/profile_select.h b/src/core/hle/service/am/applets/profile_select.h index 787485f22..a2ac6cf50 100644 --- a/src/core/hle/service/am/applets/profile_select.h +++ b/src/core/hle/service/am/applets/profile_select.h @@ -28,7 +28,7 @@ static_assert(sizeof(UserSelectionOutput) == 0x18, "UserSelectionOutput has inco class ProfileSelect final : public Applet { public: - ProfileSelect(); + explicit ProfileSelect(const Core::Frontend::ProfileSelectApplet& frontend); ~ProfileSelect() override; void Initialize() override; @@ -41,6 +41,8 @@ public: void SelectionComplete(std::optional<Account::UUID> uuid); private: + const Core::Frontend::ProfileSelectApplet& frontend; + UserSelectionConfig config; bool complete = false; ResultCode status = RESULT_SUCCESS; diff --git a/src/core/hle/service/am/applets/software_keyboard.cpp b/src/core/hle/service/am/applets/software_keyboard.cpp index 8c5bd6059..e197990f7 100644 --- a/src/core/hle/service/am/applets/software_keyboard.cpp +++ b/src/core/hle/service/am/applets/software_keyboard.cpp @@ -39,7 +39,8 @@ static Core::Frontend::SoftwareKeyboardParameters ConvertToFrontendParameters( return params; } -SoftwareKeyboard::SoftwareKeyboard() = default; +SoftwareKeyboard::SoftwareKeyboard(const Core::Frontend::SoftwareKeyboardApplet& frontend) + : frontend(frontend) {} SoftwareKeyboard::~SoftwareKeyboard() = default; @@ -90,8 +91,6 @@ void SoftwareKeyboard::ExecuteInteractive() { if (status == INTERACTIVE_STATUS_OK) { complete = true; } else { - const auto& frontend{Core::System::GetInstance().GetSoftwareKeyboard()}; - std::array<char16_t, SWKBD_OUTPUT_INTERACTIVE_BUFFER_SIZE / 2 - 2> string; std::memcpy(string.data(), data.data() + 4, string.size() * 2); frontend.SendTextCheckDialog( @@ -106,8 +105,6 @@ void SoftwareKeyboard::Execute() { return; } - const auto& frontend{Core::System::GetInstance().GetSoftwareKeyboard()}; - const auto parameters = ConvertToFrontendParameters(config, initial_text); frontend.RequestText([this](std::optional<std::u16string> text) { WriteText(text); }, diff --git a/src/core/hle/service/am/applets/software_keyboard.h b/src/core/hle/service/am/applets/software_keyboard.h index b93a30d28..0fbc43e51 100644 --- a/src/core/hle/service/am/applets/software_keyboard.h +++ b/src/core/hle/service/am/applets/software_keyboard.h @@ -55,7 +55,7 @@ static_assert(sizeof(KeyboardConfig) == 0x3E0, "KeyboardConfig has incorrect siz class SoftwareKeyboard final : public Applet { public: - SoftwareKeyboard(); + explicit SoftwareKeyboard(const Core::Frontend::SoftwareKeyboardApplet& frontend); ~SoftwareKeyboard() override; void Initialize() override; @@ -68,6 +68,8 @@ public: void WriteText(std::optional<std::u16string> text); private: + const Core::Frontend::SoftwareKeyboardApplet& frontend; + KeyboardConfig config; std::u16string initial_text; bool complete = false; diff --git a/src/core/hle/service/am/applets/stub_applet.h b/src/core/hle/service/am/applets/stub_applet.h deleted file mode 100644 index 7d8dc968d..000000000 --- a/src/core/hle/service/am/applets/stub_applet.h +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright 2018 yuzu emulator team -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#pragma once - -#include "core/hle/service/am/applets/applets.h" - -namespace Service::AM::Applets { - -class StubApplet final : public Applet { -public: - StubApplet(); - ~StubApplet() override; - - void Initialize() override; - - bool TransactionComplete() const override; - ResultCode GetStatus() const override; - void ExecuteInteractive() override; - void Execute() override; -}; - -} // namespace Service::AM::Applets diff --git a/src/core/hle/service/am/applets/web_browser.cpp b/src/core/hle/service/am/applets/web_browser.cpp index 7e17df98a..7878f5136 100644 --- a/src/core/hle/service/am/applets/web_browser.cpp +++ b/src/core/hle/service/am/applets/web_browser.cpp @@ -95,7 +95,7 @@ static FileSys::VirtualFile GetManualRomFS() { return nullptr; } -WebBrowser::WebBrowser() = default; +WebBrowser::WebBrowser(Core::Frontend::WebBrowserApplet& frontend) : frontend(frontend) {} WebBrowser::~WebBrowser() = default; @@ -152,8 +152,6 @@ void WebBrowser::Execute() { return; } - auto& frontend{Core::System::GetInstance().GetWebBrowser()}; - frontend.OpenPage(filename, [this] { UnpackRomFS(); }, [this] { Finalize(); }); } diff --git a/src/core/hle/service/am/applets/web_browser.h b/src/core/hle/service/am/applets/web_browser.h index b9e228fac..7e0f34c7d 100644 --- a/src/core/hle/service/am/applets/web_browser.h +++ b/src/core/hle/service/am/applets/web_browser.h @@ -12,7 +12,7 @@ namespace Service::AM::Applets { class WebBrowser final : public Applet { public: - WebBrowser(); + WebBrowser(Core::Frontend::WebBrowserApplet& frontend); ~WebBrowser() override; void Initialize() override; @@ -32,6 +32,8 @@ public: void Finalize(); private: + Core::Frontend::WebBrowserApplet& frontend; + bool complete = false; bool unpacked = false; ResultCode status = RESULT_SUCCESS; diff --git a/src/core/settings.cpp b/src/core/settings.cpp index 6d32ebea3..c1365879b 100644 --- a/src/core/settings.cpp +++ b/src/core/settings.cpp @@ -90,6 +90,7 @@ void LogSettings() { LogSetting("Renderer_UseResolutionFactor", Settings::values.resolution_factor); LogSetting("Renderer_UseFrameLimit", Settings::values.use_frame_limit); LogSetting("Renderer_FrameLimit", Settings::values.frame_limit); + LogSetting("Renderer_UseCompatibilityProfile", Settings::values.use_compatibility_profile); LogSetting("Renderer_UseDiskShaderCache", Settings::values.use_disk_shader_cache); LogSetting("Renderer_UseAccurateGpuEmulation", Settings::values.use_accurate_gpu_emulation); LogSetting("Renderer_UseAsynchronousGpuEmulation", diff --git a/src/core/settings.h b/src/core/settings.h index b84390745..5ff3634aa 100644 --- a/src/core/settings.h +++ b/src/core/settings.h @@ -390,6 +390,7 @@ struct Values { float resolution_factor; bool use_frame_limit; u16 frame_limit; + bool use_compatibility_profile; bool use_disk_shader_cache; bool use_accurate_gpu_emulation; bool use_asynchronous_gpu_emulation; diff --git a/src/video_core/dma_pusher.cpp b/src/video_core/dma_pusher.cpp index 6674d9405..036e66f05 100644 --- a/src/video_core/dma_pusher.cpp +++ b/src/video_core/dma_pusher.cpp @@ -105,6 +105,8 @@ bool DmaPusher::Step() { dma_state.non_incrementing = false; dma_increment_once = true; break; + default: + break; } } } diff --git a/src/video_core/engines/maxwell_3d.h b/src/video_core/engines/maxwell_3d.h index cc2424d38..85d309d9b 100644 --- a/src/video_core/engines/maxwell_3d.h +++ b/src/video_core/engines/maxwell_3d.h @@ -243,9 +243,10 @@ public: return "10_10_10_2"; case Size::Size_11_11_10: return "11_11_10"; + default: + UNREACHABLE(); + return {}; } - UNREACHABLE(); - return {}; } std::string TypeString() const { diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp index 9a088a503..db73e746c 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp @@ -305,6 +305,8 @@ void RasterizerOpenGL::SetupShaders(GLenum primitive_mode) { case Maxwell::ShaderProgram::Geometry: shader_program_manager->UseTrivialGeometryShader(); break; + default: + break; } continue; } diff --git a/src/video_core/renderer_opengl/maxwell_to_gl.h b/src/video_core/renderer_opengl/maxwell_to_gl.h index a8833c06e..95b773135 100644 --- a/src/video_core/renderer_opengl/maxwell_to_gl.h +++ b/src/video_core/renderer_opengl/maxwell_to_gl.h @@ -27,8 +27,7 @@ using Maxwell = Tegra::Engines::Maxwell3D::Regs; inline GLenum VertexType(Maxwell::VertexAttribute attrib) { switch (attrib.type) { case Maxwell::VertexAttribute::Type::UnsignedInt: - case Maxwell::VertexAttribute::Type::UnsignedNorm: { - + case Maxwell::VertexAttribute::Type::UnsignedNorm: switch (attrib.size) { case Maxwell::VertexAttribute::Size::Size_8: case Maxwell::VertexAttribute::Size::Size_8_8: @@ -47,16 +46,13 @@ inline GLenum VertexType(Maxwell::VertexAttribute attrib) { return GL_UNSIGNED_INT; case Maxwell::VertexAttribute::Size::Size_10_10_10_2: return GL_UNSIGNED_INT_2_10_10_10_REV; + default: + LOG_CRITICAL(Render_OpenGL, "Unimplemented vertex size={}", attrib.SizeString()); + UNREACHABLE(); + return {}; } - - LOG_CRITICAL(Render_OpenGL, "Unimplemented vertex size={}", attrib.SizeString()); - UNREACHABLE(); - return {}; - } - case Maxwell::VertexAttribute::Type::SignedInt: - case Maxwell::VertexAttribute::Type::SignedNorm: { - + case Maxwell::VertexAttribute::Type::SignedNorm: switch (attrib.size) { case Maxwell::VertexAttribute::Size::Size_8: case Maxwell::VertexAttribute::Size::Size_8_8: @@ -75,14 +71,12 @@ inline GLenum VertexType(Maxwell::VertexAttribute attrib) { return GL_INT; case Maxwell::VertexAttribute::Size::Size_10_10_10_2: return GL_INT_2_10_10_10_REV; + default: + LOG_CRITICAL(Render_OpenGL, "Unimplemented vertex size={}", attrib.SizeString()); + UNREACHABLE(); + return {}; } - - LOG_CRITICAL(Render_OpenGL, "Unimplemented vertex size={}", attrib.SizeString()); - UNREACHABLE(); - return {}; - } - - case Maxwell::VertexAttribute::Type::Float: { + case Maxwell::VertexAttribute::Type::Float: switch (attrib.size) { case Maxwell::VertexAttribute::Size::Size_16: case Maxwell::VertexAttribute::Size::Size_16_16: @@ -94,13 +88,16 @@ inline GLenum VertexType(Maxwell::VertexAttribute attrib) { case Maxwell::VertexAttribute::Size::Size_32_32_32: case Maxwell::VertexAttribute::Size::Size_32_32_32_32: return GL_FLOAT; + default: + LOG_CRITICAL(Render_OpenGL, "Unimplemented vertex size={}", attrib.SizeString()); + UNREACHABLE(); + return {}; } + default: + LOG_CRITICAL(Render_OpenGL, "Unimplemented vertex type={}", attrib.TypeString()); + UNREACHABLE(); + return {}; } - } - - LOG_CRITICAL(Render_OpenGL, "Unimplemented vertex type={}", attrib.TypeString()); - UNREACHABLE(); - return {}; } inline GLenum IndexFormat(Maxwell::IndexFormat index_format) { @@ -129,10 +126,11 @@ inline GLenum PrimitiveTopology(Maxwell::PrimitiveTopology topology) { return GL_TRIANGLES; case Maxwell::PrimitiveTopology::TriangleStrip: return GL_TRIANGLE_STRIP; + default: + LOG_CRITICAL(Render_OpenGL, "Unimplemented topology={}", static_cast<u32>(topology)); + UNREACHABLE(); + return {}; } - LOG_CRITICAL(Render_OpenGL, "Unimplemented topology={}", static_cast<u32>(topology)); - UNREACHABLE(); - return {}; } inline GLenum TextureFilterMode(Tegra::Texture::TextureFilter filter_mode, @@ -186,9 +184,10 @@ inline GLenum WrapMode(Tegra::Texture::WrapMode wrap_mode) { } else { return GL_MIRROR_CLAMP_TO_EDGE; } + default: + LOG_ERROR(Render_OpenGL, "Unimplemented texture wrap mode={}", static_cast<u32>(wrap_mode)); + return GL_REPEAT; } - LOG_ERROR(Render_OpenGL, "Unimplemented texture wrap mode={}", static_cast<u32>(wrap_mode)); - return GL_REPEAT; } inline GLenum DepthCompareFunc(Tegra::Texture::DepthCompareFunc func) { diff --git a/src/video_core/renderer_vulkan/maxwell_to_vk.cpp b/src/video_core/renderer_vulkan/maxwell_to_vk.cpp index 34bf26ff2..9fe1e3280 100644 --- a/src/video_core/renderer_vulkan/maxwell_to_vk.cpp +++ b/src/video_core/renderer_vulkan/maxwell_to_vk.cpp @@ -62,9 +62,10 @@ vk::SamplerAddressMode WrapMode(Tegra::Texture::WrapMode wrap_mode) { case Tegra::Texture::WrapMode::MirrorOnceBorder: UNIMPLEMENTED(); return vk::SamplerAddressMode::eMirrorClampToEdge; + default: + UNIMPLEMENTED_MSG("Unimplemented wrap mode={}", static_cast<u32>(wrap_mode)); + return {}; } - UNIMPLEMENTED_MSG("Unimplemented wrap mode={}", static_cast<u32>(wrap_mode)); - return {}; } vk::CompareOp DepthCompareFunction(Tegra::Texture::DepthCompareFunc depth_compare_func) { @@ -225,9 +226,10 @@ vk::PrimitiveTopology PrimitiveTopology(Maxwell::PrimitiveTopology topology) { return vk::PrimitiveTopology::eTriangleList; case Maxwell::PrimitiveTopology::TriangleStrip: return vk::PrimitiveTopology::eTriangleStrip; + default: + UNIMPLEMENTED_MSG("Unimplemented topology={}", static_cast<u32>(topology)); + return {}; } - UNIMPLEMENTED_MSG("Unimplemented topology={}", static_cast<u32>(topology)); - return {}; } vk::Format VertexFormat(Maxwell::VertexAttribute::Type type, Maxwell::VertexAttribute::Size size) { diff --git a/src/video_core/shader/decode.cpp b/src/video_core/shader/decode.cpp index e4c438792..2da595c0d 100644 --- a/src/video_core/shader/decode.cpp +++ b/src/video_core/shader/decode.cpp @@ -116,6 +116,8 @@ ExitMethod ShaderIR::Scan(u32 begin, u32 end, std::set<u32>& labels) { // Continue scanning for an exit method. break; } + default: + break; } } return exit_method = ExitMethod::AlwaysReturn; @@ -206,4 +208,4 @@ u32 ShaderIR::DecodeInstr(NodeBlock& bb, u32 pc) { return pc + 1; } -} // namespace VideoCommon::Shader
\ No newline at end of file +} // namespace VideoCommon::Shader diff --git a/src/video_core/shader/decode/arithmetic_half.cpp b/src/video_core/shader/decode/arithmetic_half.cpp index 9467f9417..2098c1170 100644 --- a/src/video_core/shader/decode/arithmetic_half.cpp +++ b/src/video_core/shader/decode/arithmetic_half.cpp @@ -9,6 +9,7 @@ namespace VideoCommon::Shader { +using Tegra::Shader::HalfType; using Tegra::Shader::Instruction; using Tegra::Shader::OpCode; @@ -22,7 +23,6 @@ u32 ShaderIR::DecodeArithmeticHalf(NodeBlock& bb, u32 pc) { LOG_WARNING(HW_GPU, "{} FTZ not implemented", opcode->get().GetName()); } } - UNIMPLEMENTED_IF_MSG(instr.alu_half.saturate != 0, "Half float saturation not implemented"); const bool negate_a = opcode->get().GetId() != OpCode::Id::HMUL2_R && instr.alu_half.negate_a != 0; @@ -32,35 +32,37 @@ u32 ShaderIR::DecodeArithmeticHalf(NodeBlock& bb, u32 pc) { Node op_a = UnpackHalfFloat(GetRegister(instr.gpr8), instr.alu_half.type_a); op_a = GetOperandAbsNegHalf(op_a, instr.alu_half.abs_a, negate_a); - Node op_b = [&]() { + auto [type_b, op_b] = [&]() -> std::tuple<HalfType, Node> { switch (opcode->get().GetId()) { case OpCode::Id::HADD2_C: case OpCode::Id::HMUL2_C: - return GetConstBuffer(instr.cbuf34.index, instr.cbuf34.GetOffset()); + return {HalfType::F32, GetConstBuffer(instr.cbuf34.index, instr.cbuf34.GetOffset())}; case OpCode::Id::HADD2_R: case OpCode::Id::HMUL2_R: - return GetRegister(instr.gpr20); + return {instr.alu_half.type_b, GetRegister(instr.gpr20)}; default: UNREACHABLE(); - return Immediate(0); + return {HalfType::F32, Immediate(0)}; } }(); - op_b = UnpackHalfFloat(op_b, instr.alu_half.type_b); - op_b = GetOperandAbsNegHalf(op_b, instr.alu_half.abs_b, negate_b); + op_b = UnpackHalfFloat(op_b, type_b); + // redeclaration to avoid a bug in clang with reusing local bindings in lambdas + Node op_b_alt = GetOperandAbsNegHalf(op_b, instr.alu_half.abs_b, negate_b); Node value = [&]() { switch (opcode->get().GetId()) { case OpCode::Id::HADD2_C: case OpCode::Id::HADD2_R: - return Operation(OperationCode::HAdd, PRECISE, op_a, op_b); + return Operation(OperationCode::HAdd, PRECISE, op_a, op_b_alt); case OpCode::Id::HMUL2_C: case OpCode::Id::HMUL2_R: - return Operation(OperationCode::HMul, PRECISE, op_a, op_b); + return Operation(OperationCode::HMul, PRECISE, op_a, op_b_alt); default: UNIMPLEMENTED_MSG("Unhandled half float instruction: {}", opcode->get().GetName()); return Immediate(0); } }(); + value = GetSaturatedHalfFloat(value, instr.alu_half.saturate); value = HalfMerge(GetRegister(instr.gpr0), value, instr.alu_half.merge); SetRegister(bb, instr.gpr0, value); @@ -68,4 +70,4 @@ u32 ShaderIR::DecodeArithmeticHalf(NodeBlock& bb, u32 pc) { return pc; } -} // namespace VideoCommon::Shader
\ No newline at end of file +} // namespace VideoCommon::Shader diff --git a/src/video_core/shader/decode/conversion.cpp b/src/video_core/shader/decode/conversion.cpp index ba15b1115..b5ec9a6f5 100644 --- a/src/video_core/shader/decode/conversion.cpp +++ b/src/video_core/shader/decode/conversion.cpp @@ -120,10 +120,11 @@ u32 ShaderIR::DecodeConversion(NodeBlock& bb, u32 pc) { return Operation(OperationCode::FCeil, PRECISE, value); case Tegra::Shader::F2fRoundingOp::Trunc: return Operation(OperationCode::FTrunc, PRECISE, value); + default: + UNIMPLEMENTED_MSG("Unimplemented F2F rounding mode {}", + static_cast<u32>(instr.conversion.f2f.rounding.Value())); + return Immediate(0); } - UNIMPLEMENTED_MSG("Unimplemented F2F rounding mode {}", - static_cast<u32>(instr.conversion.f2f.rounding.Value())); - return Immediate(0); }(); value = GetSaturatedFloat(value, instr.alu.saturate_d); diff --git a/src/video_core/shader/decode/hfma2.cpp b/src/video_core/shader/decode/hfma2.cpp index 5c1becce5..a425f9eb7 100644 --- a/src/video_core/shader/decode/hfma2.cpp +++ b/src/video_core/shader/decode/hfma2.cpp @@ -34,15 +34,14 @@ u32 ShaderIR::DecodeHfma2(NodeBlock& bb, u32 pc) { case OpCode::Id::HFMA2_CR: neg_b = instr.hfma2.negate_b; neg_c = instr.hfma2.negate_c; - return {instr.hfma2.saturate, instr.hfma2.type_b, + return {instr.hfma2.saturate, HalfType::F32, GetConstBuffer(instr.cbuf34.index, instr.cbuf34.GetOffset()), instr.hfma2.type_reg39, GetRegister(instr.gpr39)}; case OpCode::Id::HFMA2_RC: neg_b = instr.hfma2.negate_b; neg_c = instr.hfma2.negate_c; return {instr.hfma2.saturate, instr.hfma2.type_reg39, GetRegister(instr.gpr39), - instr.hfma2.type_b, - GetConstBuffer(instr.cbuf34.index, instr.cbuf34.GetOffset())}; + HalfType::F32, GetConstBuffer(instr.cbuf34.index, instr.cbuf34.GetOffset())}; case OpCode::Id::HFMA2_RR: neg_b = instr.hfma2.rr.negate_b; neg_c = instr.hfma2.rr.negate_c; @@ -56,13 +55,13 @@ u32 ShaderIR::DecodeHfma2(NodeBlock& bb, u32 pc) { return {false, identity, Immediate(0), identity, Immediate(0)}; } }(); - UNIMPLEMENTED_IF_MSG(saturate, "HFMA2 saturation is not implemented"); const Node op_a = UnpackHalfFloat(GetRegister(instr.gpr8), instr.hfma2.type_a); op_b = GetOperandAbsNegHalf(UnpackHalfFloat(op_b, type_b), false, neg_b); op_c = GetOperandAbsNegHalf(UnpackHalfFloat(op_c, type_c), false, neg_c); Node value = Operation(OperationCode::HFma, PRECISE, op_a, op_b, op_c); + value = GetSaturatedHalfFloat(value, saturate); value = HalfMerge(GetRegister(instr.gpr0), value, instr.hfma2.merge); SetRegister(bb, instr.gpr0, value); @@ -70,4 +69,4 @@ u32 ShaderIR::DecodeHfma2(NodeBlock& bb, u32 pc) { return pc; } -} // namespace VideoCommon::Shader
\ No newline at end of file +} // namespace VideoCommon::Shader diff --git a/src/video_core/shader/decode/texture.cpp b/src/video_core/shader/decode/texture.cpp index fa65ac9a9..819cc6131 100644 --- a/src/video_core/shader/decode/texture.cpp +++ b/src/video_core/shader/decode/texture.cpp @@ -296,7 +296,7 @@ const Sampler& ShaderIR::GetBindlessSampler(const Tegra::Shader::Register& reg, ASSERT(cbuf_offset_imm != nullptr); const auto cbuf_offset = cbuf_offset_imm->GetValue(); const auto cbuf_index = cbuf->GetIndex(); - const u64 cbuf_key = (cbuf_index << 32) | cbuf_offset; + const auto cbuf_key = (static_cast<u64>(cbuf_index) << 32) | static_cast<u64>(cbuf_offset); // If this sampler has already been used, return the existing mapping. const auto itr = diff --git a/src/video_core/shader/decode/xmad.cpp b/src/video_core/shader/decode/xmad.cpp index db15c0718..04a776398 100644 --- a/src/video_core/shader/decode/xmad.cpp +++ b/src/video_core/shader/decode/xmad.cpp @@ -56,9 +56,10 @@ u32 ShaderIR::DecodeXmad(NodeBlock& bb, u32 pc) { instr.xmad.mode, Immediate(static_cast<u32>(instr.xmad.imm20_16)), GetRegister(instr.gpr39)}; + default: + UNIMPLEMENTED_MSG("Unhandled XMAD instruction: {}", opcode->get().GetName()); + return {false, false, false, Tegra::Shader::XmadMode::None, Immediate(0), Immediate(0)}; } - UNIMPLEMENTED_MSG("Unhandled XMAD instruction: {}", opcode->get().GetName()); - return {false, false, false, Tegra::Shader::XmadMode::None, Immediate(0), Immediate(0)}; }(); op_a = BitfieldExtract(op_a, instr.xmad.high_a ? 16 : 0, 16); diff --git a/src/video_core/shader/shader_ir.cpp b/src/video_core/shader/shader_ir.cpp index 17f2f711c..e4eb0dfd9 100644 --- a/src/video_core/shader/shader_ir.cpp +++ b/src/video_core/shader/shader_ir.cpp @@ -439,11 +439,14 @@ Node ShaderIR::BitfieldExtract(Node value, u32 offset, u32 bits) { return OperationCode::LogicalUGreaterEqual; case OperationCode::INegate: UNREACHABLE_MSG("Can't negate an unsigned integer"); + return {}; case OperationCode::IAbsolute: UNREACHABLE_MSG("Can't apply absolute to an unsigned integer"); + return {}; + default: + UNREACHABLE_MSG("Unknown signed operation with code={}", static_cast<u32>(operation_code)); + return {}; } - UNREACHABLE_MSG("Unknown signed operation with code={}", static_cast<u32>(operation_code)); - return {}; } -} // namespace VideoCommon::Shader
\ No newline at end of file +} // namespace VideoCommon::Shader diff --git a/src/video_core/shader/shader_ir.h b/src/video_core/shader/shader_ir.h index 81278fb33..65f1e1de9 100644 --- a/src/video_core/shader/shader_ir.h +++ b/src/video_core/shader/shader_ir.h @@ -251,8 +251,9 @@ public: } bool operator<(const Sampler& rhs) const { - return std::tie(offset, index, type, is_array, is_shadow) < - std::tie(rhs.offset, rhs.index, rhs.type, rhs.is_array, rhs.is_shadow); + return std::tie(index, offset, type, is_array, is_shadow, is_bindless) < + std::tie(rhs.index, rhs.offset, rhs.type, rhs.is_array, rhs.is_shadow, + rhs.is_bindless); } private: diff --git a/src/video_core/surface.cpp b/src/video_core/surface.cpp index 3b022a456..6384fa8d2 100644 --- a/src/video_core/surface.cpp +++ b/src/video_core/surface.cpp @@ -178,39 +178,44 @@ PixelFormat PixelFormatFromTextureFormat(Tegra::Texture::TextureFormat format, return PixelFormat::ABGR8S; case Tegra::Texture::ComponentType::UINT: return PixelFormat::ABGR8UI; + default: + break; } - LOG_CRITICAL(HW_GPU, "Unimplemented component_type={}", static_cast<u32>(component_type)); - UNREACHABLE(); + break; case Tegra::Texture::TextureFormat::B5G6R5: switch (component_type) { case Tegra::Texture::ComponentType::UNORM: return PixelFormat::B5G6R5U; + default: + break; } - LOG_CRITICAL(HW_GPU, "Unimplemented component_type={}", static_cast<u32>(component_type)); - UNREACHABLE(); + break; case Tegra::Texture::TextureFormat::A2B10G10R10: switch (component_type) { case Tegra::Texture::ComponentType::UNORM: return PixelFormat::A2B10G10R10U; + default: + break; } - LOG_CRITICAL(HW_GPU, "Unimplemented component_type={}", static_cast<u32>(component_type)); - UNREACHABLE(); + break; case Tegra::Texture::TextureFormat::A1B5G5R5: switch (component_type) { case Tegra::Texture::ComponentType::UNORM: return PixelFormat::A1B5G5R5U; + default: + break; } - LOG_CRITICAL(HW_GPU, "Unimplemented component_type={}", static_cast<u32>(component_type)); - UNREACHABLE(); + break; case Tegra::Texture::TextureFormat::R8: switch (component_type) { case Tegra::Texture::ComponentType::UNORM: return PixelFormat::R8U; case Tegra::Texture::ComponentType::UINT: return PixelFormat::R8UI; + default: + break; } - LOG_CRITICAL(HW_GPU, "Unimplemented component_type={}", static_cast<u32>(component_type)); - UNREACHABLE(); + break; case Tegra::Texture::TextureFormat::G8R8: // TextureFormat::G8R8 is actually ordered red then green, as such we can use // PixelFormat::RG8U and PixelFormat::RG8S. This was tested with The Legend of Zelda: Breath @@ -220,50 +225,55 @@ PixelFormat PixelFormatFromTextureFormat(Tegra::Texture::TextureFormat format, return PixelFormat::RG8U; case Tegra::Texture::ComponentType::SNORM: return PixelFormat::RG8S; + default: + break; } - LOG_CRITICAL(HW_GPU, "Unimplemented component_type={}", static_cast<u32>(component_type)); - UNREACHABLE(); + break; case Tegra::Texture::TextureFormat::R16_G16_B16_A16: switch (component_type) { case Tegra::Texture::ComponentType::UNORM: return PixelFormat::RGBA16U; case Tegra::Texture::ComponentType::FLOAT: return PixelFormat::RGBA16F; + default: + break; } - LOG_CRITICAL(HW_GPU, "Unimplemented component_type={}", static_cast<u32>(component_type)); - UNREACHABLE(); + break; case Tegra::Texture::TextureFormat::BF10GF11RF11: switch (component_type) { case Tegra::Texture::ComponentType::FLOAT: return PixelFormat::R11FG11FB10F; + default: + break; } - LOG_CRITICAL(HW_GPU, "Unimplemented component_type={}", static_cast<u32>(component_type)); - UNREACHABLE(); case Tegra::Texture::TextureFormat::R32_G32_B32_A32: switch (component_type) { case Tegra::Texture::ComponentType::FLOAT: return PixelFormat::RGBA32F; case Tegra::Texture::ComponentType::UINT: return PixelFormat::RGBA32UI; + default: + break; } - LOG_CRITICAL(HW_GPU, "Unimplemented component_type={}", static_cast<u32>(component_type)); - UNREACHABLE(); + break; case Tegra::Texture::TextureFormat::R32_G32: switch (component_type) { case Tegra::Texture::ComponentType::FLOAT: return PixelFormat::RG32F; case Tegra::Texture::ComponentType::UINT: return PixelFormat::RG32UI; + default: + break; } - LOG_CRITICAL(HW_GPU, "Unimplemented component_type={}", static_cast<u32>(component_type)); - UNREACHABLE(); + break; case Tegra::Texture::TextureFormat::R32_G32_B32: switch (component_type) { case Tegra::Texture::ComponentType::FLOAT: return PixelFormat::RGB32F; + default: + break; } - LOG_CRITICAL(HW_GPU, "Unimplemented component_type={}", static_cast<u32>(component_type)); - UNREACHABLE(); + break; case Tegra::Texture::TextureFormat::R16: switch (component_type) { case Tegra::Texture::ComponentType::FLOAT: @@ -276,18 +286,20 @@ PixelFormat PixelFormatFromTextureFormat(Tegra::Texture::TextureFormat format, return PixelFormat::R16UI; case Tegra::Texture::ComponentType::SINT: return PixelFormat::R16I; + default: + break; } - LOG_CRITICAL(HW_GPU, "Unimplemented component_type={}", static_cast<u32>(component_type)); - UNREACHABLE(); + break; case Tegra::Texture::TextureFormat::R32: switch (component_type) { case Tegra::Texture::ComponentType::FLOAT: return PixelFormat::R32F; case Tegra::Texture::ComponentType::UINT: return PixelFormat::R32UI; + default: + break; } - LOG_CRITICAL(HW_GPU, "Unimplemented component_type={}", static_cast<u32>(component_type)); - UNREACHABLE(); + break; case Tegra::Texture::TextureFormat::ZF32: return PixelFormat::Z32F; case Tegra::Texture::TextureFormat::Z16: @@ -310,9 +322,10 @@ PixelFormat PixelFormatFromTextureFormat(Tegra::Texture::TextureFormat format, return PixelFormat::DXN2UNORM; case Tegra::Texture::ComponentType::SNORM: return PixelFormat::DXN2SNORM; + default: + break; } - LOG_CRITICAL(HW_GPU, "Unimplemented component_type={}", static_cast<u32>(component_type)); - UNREACHABLE(); + break; case Tegra::Texture::TextureFormat::BC7U: return is_srgb ? PixelFormat::BC7U_SRGB : PixelFormat::BC7U; case Tegra::Texture::TextureFormat::BC6H_UF16: @@ -343,15 +356,17 @@ PixelFormat PixelFormatFromTextureFormat(Tegra::Texture::TextureFormat format, return PixelFormat::RG16UI; case Tegra::Texture::ComponentType::SINT: return PixelFormat::RG16I; + default: + break; } - LOG_CRITICAL(HW_GPU, "Unimplemented component_type={}", static_cast<u32>(component_type)); - UNREACHABLE(); + break; default: - LOG_CRITICAL(HW_GPU, "Unimplemented format={}, component_type={}", static_cast<u32>(format), - static_cast<u32>(component_type)); - UNREACHABLE(); - return PixelFormat::ABGR8U; + break; } + LOG_CRITICAL(HW_GPU, "Unimplemented format={}, component_type={}", static_cast<u32>(format), + static_cast<u32>(component_type)); + UNREACHABLE(); + return PixelFormat::ABGR8U; } ComponentType ComponentTypeFromTexture(Tegra::Texture::ComponentType type) { @@ -513,8 +528,9 @@ bool IsFormatBCn(PixelFormat format) { case PixelFormat::DXT45_SRGB: case PixelFormat::BC7U_SRGB: return true; + default: + return false; } - return false; } } // namespace VideoCore::Surface diff --git a/src/yuzu/CMakeLists.txt b/src/yuzu/CMakeLists.txt index 31b65c04c..5138bd9a3 100644 --- a/src/yuzu/CMakeLists.txt +++ b/src/yuzu/CMakeLists.txt @@ -7,6 +7,8 @@ add_executable(yuzu Info.plist about_dialog.cpp about_dialog.h + applets/error.cpp + applets/error.h applets/profile_select.cpp applets/profile_select.h applets/software_keyboard.cpp diff --git a/src/yuzu/applets/error.cpp b/src/yuzu/applets/error.cpp new file mode 100644 index 000000000..1fb2fe277 --- /dev/null +++ b/src/yuzu/applets/error.cpp @@ -0,0 +1,59 @@ +// Copyright 2019 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include <QDateTime> +#include "core/hle/lock.h" +#include "yuzu/applets/error.h" +#include "yuzu/main.h" + +QtErrorDisplay::QtErrorDisplay(GMainWindow& parent) { + connect(this, &QtErrorDisplay::MainWindowDisplayError, &parent, + &GMainWindow::ErrorDisplayDisplayError, Qt::QueuedConnection); + connect(&parent, &GMainWindow::ErrorDisplayFinished, this, + &QtErrorDisplay::MainWindowFinishedError, Qt::DirectConnection); +} + +QtErrorDisplay::~QtErrorDisplay() = default; + +void QtErrorDisplay::ShowError(ResultCode error, std::function<void()> finished) const { + this->callback = std::move(finished); + emit MainWindowDisplayError( + tr("An error has occured.\nPlease try again or contact the developer of the " + "software.\n\nError Code: %1-%2 (0x%3)") + .arg(static_cast<u32>(error.module.Value()) + 2000, 4, 10, QChar::fromLatin1('0')) + .arg(error.description, 4, 10, QChar::fromLatin1('0')) + .arg(error.raw, 8, 16, QChar::fromLatin1('0'))); +} + +void QtErrorDisplay::ShowErrorWithTimestamp(ResultCode error, std::chrono::seconds time, + std::function<void()> finished) const { + this->callback = std::move(finished); + emit MainWindowDisplayError( + tr("An error occured on %1 at %2.\nPlease try again or contact the " + "developer of the software.\n\nError Code: %3-%4 (0x%5)") + .arg(QDateTime::fromSecsSinceEpoch(time.count()).toString("dddd, MMMM d, yyyy")) + .arg(QDateTime::fromSecsSinceEpoch(time.count()).toString("h:mm:ss A")) + .arg(static_cast<u32>(error.module.Value()) + 2000, 4, 10, QChar::fromLatin1('0')) + .arg(error.description, 4, 10, QChar::fromLatin1('0')) + .arg(error.raw, 8, 16, QChar::fromLatin1('0'))); +} + +void QtErrorDisplay::ShowCustomErrorText(ResultCode error, std::string dialog_text, + std::string fullscreen_text, + std::function<void()> finished) const { + this->callback = std::move(finished); + emit MainWindowDisplayError( + tr("An error has occured.\nError Code: %1-%2 (0x%3)\n\n%4\n\n%5") + .arg(static_cast<u32>(error.module.Value()) + 2000, 4, 10, QChar::fromLatin1('0')) + .arg(error.description, 4, 10, QChar::fromLatin1('0')) + .arg(error.raw, 8, 16, QChar::fromLatin1('0')) + .arg(QString::fromStdString(dialog_text)) + .arg(QString::fromStdString(fullscreen_text))); +} + +void QtErrorDisplay::MainWindowFinishedError() { + // Acquire the HLE mutex + std::lock_guard<std::recursive_mutex> lock(HLE::g_hle_lock); + callback(); +} diff --git a/src/yuzu/applets/error.h b/src/yuzu/applets/error.h new file mode 100644 index 000000000..b0932d895 --- /dev/null +++ b/src/yuzu/applets/error.h @@ -0,0 +1,33 @@ +// Copyright 2019 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include <QObject> + +#include "core/frontend/applets/error.h" + +class GMainWindow; + +class QtErrorDisplay final : public QObject, public Core::Frontend::ErrorApplet { + Q_OBJECT + +public: + explicit QtErrorDisplay(GMainWindow& parent); + ~QtErrorDisplay() override; + + void ShowError(ResultCode error, std::function<void()> finished) const override; + void ShowErrorWithTimestamp(ResultCode error, std::chrono::seconds time, + std::function<void()> finished) const override; + void ShowCustomErrorText(ResultCode error, std::string dialog_text, std::string fullscreen_text, + std::function<void()> finished) const override; + +signals: + void MainWindowDisplayError(QString error) const; + +private: + void MainWindowFinishedError(); + + mutable std::function<void()> callback; +}; diff --git a/src/yuzu/bootmanager.cpp b/src/yuzu/bootmanager.cpp index 7eed9fcf3..5c98636c5 100644 --- a/src/yuzu/bootmanager.cpp +++ b/src/yuzu/bootmanager.cpp @@ -377,7 +377,11 @@ void GRenderWindow::InitRenderTarget() { // WA_DontShowOnScreen, WA_DeleteOnClose QSurfaceFormat fmt; fmt.setVersion(4, 3); - fmt.setProfile(QSurfaceFormat::CoreProfile); + if (Settings::values.use_compatibility_profile) { + fmt.setProfile(QSurfaceFormat::CompatibilityProfile); + } else { + fmt.setProfile(QSurfaceFormat::CoreProfile); + } // TODO: expose a setting for buffer value (ie default/single/double/triple) fmt.setSwapBehavior(QSurfaceFormat::DefaultSwapBehavior); shared_context = std::make_unique<QOpenGLContext>(); diff --git a/src/yuzu/configuration/config.cpp b/src/yuzu/configuration/config.cpp index 8725a78dc..6c6f047d8 100644 --- a/src/yuzu/configuration/config.cpp +++ b/src/yuzu/configuration/config.cpp @@ -389,6 +389,8 @@ void Config::ReadValues() { Settings::values.resolution_factor = ReadSetting("resolution_factor", 1.0).toFloat(); Settings::values.use_frame_limit = ReadSetting("use_frame_limit", true).toBool(); Settings::values.frame_limit = ReadSetting("frame_limit", 100).toInt(); + Settings::values.use_compatibility_profile = + ReadSetting("use_compatibility_profile", true).toBool(); Settings::values.use_disk_shader_cache = ReadSetting("use_disk_shader_cache", true).toBool(); Settings::values.use_accurate_gpu_emulation = ReadSetting("use_accurate_gpu_emulation", false).toBool(); @@ -661,6 +663,7 @@ void Config::SaveValues() { WriteSetting("resolution_factor", (double)Settings::values.resolution_factor, 1.0); WriteSetting("use_frame_limit", Settings::values.use_frame_limit, true); WriteSetting("frame_limit", Settings::values.frame_limit, 100); + WriteSetting("use_compatibility_profile", Settings::values.use_compatibility_profile, true); WriteSetting("use_disk_shader_cache", Settings::values.use_disk_shader_cache, true); WriteSetting("use_accurate_gpu_emulation", Settings::values.use_accurate_gpu_emulation, false); WriteSetting("use_asynchronous_gpu_emulation", Settings::values.use_asynchronous_gpu_emulation, diff --git a/src/yuzu/configuration/configure_graphics.cpp b/src/yuzu/configuration/configure_graphics.cpp index 0a9883d37..c299c0b5b 100644 --- a/src/yuzu/configuration/configure_graphics.cpp +++ b/src/yuzu/configuration/configure_graphics.cpp @@ -73,6 +73,7 @@ void ConfigureGraphics::setConfiguration() { static_cast<int>(FromResolutionFactor(Settings::values.resolution_factor))); ui->toggle_frame_limit->setChecked(Settings::values.use_frame_limit); ui->frame_limit->setValue(Settings::values.frame_limit); + ui->use_compatibility_profile->setChecked(Settings::values.use_compatibility_profile); ui->use_disk_shader_cache->setChecked(Settings::values.use_disk_shader_cache); ui->use_accurate_gpu_emulation->setChecked(Settings::values.use_accurate_gpu_emulation); ui->use_asynchronous_gpu_emulation->setEnabled(!Core::System::GetInstance().IsPoweredOn()); @@ -88,6 +89,7 @@ void ConfigureGraphics::applyConfiguration() { ToResolutionFactor(static_cast<Resolution>(ui->resolution_factor_combobox->currentIndex())); Settings::values.use_frame_limit = ui->toggle_frame_limit->isChecked(); Settings::values.frame_limit = ui->frame_limit->value(); + Settings::values.use_compatibility_profile = ui->use_compatibility_profile->isChecked(); Settings::values.use_disk_shader_cache = ui->use_disk_shader_cache->isChecked(); Settings::values.use_accurate_gpu_emulation = ui->use_accurate_gpu_emulation->isChecked(); Settings::values.use_asynchronous_gpu_emulation = diff --git a/src/yuzu/configuration/configure_graphics.ui b/src/yuzu/configuration/configure_graphics.ui index 15ab18ecd..0f6f6c003 100644 --- a/src/yuzu/configuration/configure_graphics.ui +++ b/src/yuzu/configuration/configure_graphics.ui @@ -50,6 +50,13 @@ </layout> </item> <item> + <widget class="QCheckBox" name="use_compatibility_profile"> + <property name="text"> + <string>Use OpenGL compatibility profile</string> + </property> + </widget> + </item> + <item> <widget class="QCheckBox" name="use_disk_shader_cache"> <property name="text"> <string>Use disk shader cache</string> diff --git a/src/yuzu/debugger/wait_tree.cpp b/src/yuzu/debugger/wait_tree.cpp index 593bb681f..85b095688 100644 --- a/src/yuzu/debugger/wait_tree.cpp +++ b/src/yuzu/debugger/wait_tree.cpp @@ -227,8 +227,7 @@ QString WaitTreeThread::GetText() const { case Kernel::ThreadStatus::WaitIPC: status = tr("waiting for IPC reply"); break; - case Kernel::ThreadStatus::WaitSynchAll: - case Kernel::ThreadStatus::WaitSynchAny: + case Kernel::ThreadStatus::WaitSynch: status = tr("waiting for objects"); break; case Kernel::ThreadStatus::WaitMutex: @@ -269,8 +268,7 @@ QColor WaitTreeThread::GetColor() const { return QColor(Qt::GlobalColor::darkRed); case Kernel::ThreadStatus::WaitSleep: return QColor(Qt::GlobalColor::darkYellow); - case Kernel::ThreadStatus::WaitSynchAll: - case Kernel::ThreadStatus::WaitSynchAny: + case Kernel::ThreadStatus::WaitSynch: case Kernel::ThreadStatus::WaitMutex: case Kernel::ThreadStatus::WaitCondVar: case Kernel::ThreadStatus::WaitArb: @@ -325,10 +323,9 @@ std::vector<std::unique_ptr<WaitTreeItem>> WaitTreeThread::GetChildren() const { list.push_back(std::make_unique<WaitTreeText>(tr("not waiting for mutex"))); } - if (thread.GetStatus() == Kernel::ThreadStatus::WaitSynchAny || - thread.GetStatus() == Kernel::ThreadStatus::WaitSynchAll) { + if (thread.GetStatus() == Kernel::ThreadStatus::WaitSynch) { list.push_back(std::make_unique<WaitTreeObjectList>(thread.GetWaitObjects(), - thread.IsSleepingOnWaitAll())); + thread.IsSleepingOnWait())); } list.push_back(std::make_unique<WaitTreeCallstack>(thread)); diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index bdee44b04..e33e3aaaf 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -8,6 +8,7 @@ #include <thread> // VFS includes must be before glad as they will conflict with Windows file api, which uses defines. +#include "applets/error.h" #include "applets/profile_select.h" #include "applets/software_keyboard.h" #include "applets/web_browser.h" @@ -15,6 +16,7 @@ #include "configuration/configure_per_general.h" #include "core/file_sys/vfs.h" #include "core/file_sys/vfs_real.h" +#include "core/frontend/applets/general_frontend.h" #include "core/frontend/scope_acquire_window_context.h" #include "core/hle/service/acc/profile_manager.h" #include "core/hle/service/am/applets/applets.h" @@ -795,9 +797,13 @@ bool GMainWindow::LoadROM(const QString& filename) { system.SetGPUDebugContext(debug_context); - system.SetProfileSelector(std::make_unique<QtProfileSelector>(*this)); - system.SetSoftwareKeyboard(std::make_unique<QtSoftwareKeyboard>(*this)); - system.SetWebBrowser(std::make_unique<QtWebBrowser>(*this)); + system.SetAppletFrontendSet({ + std::make_unique<QtErrorDisplay>(*this), + nullptr, + std::make_unique<QtProfileSelector>(*this), + std::make_unique<QtSoftwareKeyboard>(*this), + std::make_unique<QtWebBrowser>(*this), + }); const Core::System::ResultStatus result{system.Load(*render_window, filename.toStdString())}; @@ -1583,6 +1589,11 @@ void GMainWindow::OnLoadComplete() { loading_screen->OnLoadComplete(); } +void GMainWindow::ErrorDisplayDisplayError(QString body) { + QMessageBox::critical(this, tr("Error Display"), body); + emit ErrorDisplayFinished(); +} + void GMainWindow::OnMenuReportCompatibility() { if (!Settings::values.yuzu_token.empty() && !Settings::values.yuzu_username.empty()) { CompatDB compatdb{this}; diff --git a/src/yuzu/main.h b/src/yuzu/main.h index ce5045819..fb2a193cb 100644 --- a/src/yuzu/main.h +++ b/src/yuzu/main.h @@ -102,6 +102,8 @@ signals: // Signal that tells widgets to update icons to use the current theme void UpdateThemedIcons(); + void ErrorDisplayFinished(); + void ProfileSelectorFinishedSelection(std::optional<Service::Account::UUID> uuid); void SoftwareKeyboardFinishedText(std::optional<std::u16string> text); void SoftwareKeyboardFinishedCheckDialog(); @@ -111,6 +113,7 @@ signals: public slots: void OnLoadComplete(); + void ErrorDisplayDisplayError(QString body); void ProfileSelectorSelectProfile(); void SoftwareKeyboardGetText(const Core::Frontend::SoftwareKeyboardParameters& parameters); void SoftwareKeyboardInvokeCheckDialog(std::u16string error_message); diff --git a/src/yuzu_cmd/config.cpp b/src/yuzu_cmd/config.cpp index f24cc77fe..d0ae058fd 100644 --- a/src/yuzu_cmd/config.cpp +++ b/src/yuzu_cmd/config.cpp @@ -349,6 +349,8 @@ void Config::ReadValues() { Settings::values.use_frame_limit = sdl2_config->GetBoolean("Renderer", "use_frame_limit", true); Settings::values.frame_limit = static_cast<u16>(sdl2_config->GetInteger("Renderer", "frame_limit", 100)); + Settings::values.use_compatibility_profile = + sdl2_config->GetBoolean("Renderer", "use_compatibility_profile", true); Settings::values.use_disk_shader_cache = sdl2_config->GetBoolean("Renderer", "use_disk_shader_cache", false); Settings::values.use_accurate_gpu_emulation = diff --git a/src/yuzu_cmd/yuzu.cpp b/src/yuzu_cmd/yuzu.cpp index 7ea4a1b18..a1d7879b1 100644 --- a/src/yuzu_cmd/yuzu.cpp +++ b/src/yuzu_cmd/yuzu.cpp @@ -32,11 +32,7 @@ #include "yuzu_cmd/config.h" #include "yuzu_cmd/emu_window/emu_window_sdl2.h" -#include <getopt.h> #include "core/file_sys/registered_cache.h" -#ifndef _MSC_VER -#include <unistd.h> -#endif #ifdef _WIN32 // windows.h needs to be included before shellapi.h @@ -45,6 +41,12 @@ #include <shellapi.h> #endif +#undef _UNICODE +#include <getopt.h> +#ifndef _MSC_VER +#include <unistd.h> +#endif + #ifdef _WIN32 extern "C" { // tells Nvidia and AMD drivers to use the dedicated GPU by default on laptops with switchable |