diff options
Diffstat (limited to 'src')
63 files changed, 1251 insertions, 486 deletions
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index f5c92a5aa..20e41038b 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -37,6 +37,8 @@ set(SRCS hle/kernel/wait_object.cpp hle/lock.cpp hle/romfs.cpp + hle/service/acc/acc.cpp + hle/service/acc/acc_u0.cpp hle/service/am/am.cpp hle/service/am/applet_oe.cpp hle/service/aoc/aoc_u.cpp @@ -48,8 +50,8 @@ set(SRCS hle/service/nvdrv/devices/nvdisp_disp0.cpp hle/service/nvdrv/devices/nvhost_as_gpu.cpp hle/service/nvdrv/devices/nvmap.cpp + hle/service/nvdrv/interface.cpp hle/service/nvdrv/nvdrv.cpp - hle/service/nvdrv/nvdrv_a.cpp hle/service/pctl/pctl.cpp hle/service/pctl/pctl_a.cpp hle/service/service.cpp @@ -124,6 +126,8 @@ set(HEADERS hle/lock.h hle/result.h hle/romfs.h + hle/service/acc/acc.h + hle/service/acc/acc_u0.h hle/service/am/am.h hle/service/am/applet_oe.h hle/service/aoc/aoc_u.h @@ -136,8 +140,8 @@ set(HEADERS hle/service/nvdrv/devices/nvdisp_disp0.h hle/service/nvdrv/devices/nvhost_as_gpu.h hle/service/nvdrv/devices/nvmap.h + hle/service/nvdrv/interface.h hle/service/nvdrv/nvdrv.h - hle/service/nvdrv/nvdrv_a.h hle/service/pctl/pctl.h hle/service/pctl/pctl_a.h hle/service/service.h diff --git a/src/core/arm/arm_interface.h b/src/core/arm/arm_interface.h index 531875006..5ae60214e 100644 --- a/src/core/arm/arm_interface.h +++ b/src/core/arm/arm_interface.h @@ -39,7 +39,8 @@ public: Run(1); } - virtual void MapBackingMemory(VAddr address, size_t size, u8* memory, Kernel::VMAPermission perms) {} + virtual void MapBackingMemory(VAddr address, size_t size, u8* memory, + Kernel::VMAPermission perms) {} /// Clear all instruction cache virtual void ClearInstructionCache() = 0; diff --git a/src/core/arm/unicorn/arm_unicorn.cpp b/src/core/arm/unicorn/arm_unicorn.cpp index 13f6c658c..fd64eab39 100644 --- a/src/core/arm/unicorn/arm_unicorn.cpp +++ b/src/core/arm/unicorn/arm_unicorn.cpp @@ -11,7 +11,7 @@ #include "core/hle/kernel/svc.h" // Load Unicorn DLL once on Windows using RAII -#ifdef _WIN32 +#ifdef _MSC_VER #include <unicorn_dynload.h> struct LoadDll { private: diff --git a/src/core/hle/ipc.h b/src/core/hle/ipc.h index ec08be0f4..88ba105e5 100644 --- a/src/core/hle/ipc.h +++ b/src/core/hle/ipc.h @@ -19,7 +19,6 @@ constexpr size_t COMMAND_BUFFER_LENGTH = 0x100 / sizeof(u32); // TODO(yuriks): These will probably go away once translation is implemented inside the kernel. constexpr auto ERR_INVALID_HANDLE = Kernel::ERR_INVALID_HANDLE_OS; - enum class ControlCommand : u32 { ConvertSessionToDomain = 0, ConvertDomainToSession = 1, @@ -81,13 +80,13 @@ struct BufferDescriptorX { u32_le address_bits_0_31; u32_le Counter() const { - u32_le counter{ counter_bits_0_5 }; + u32_le counter{counter_bits_0_5}; counter |= counter_bits_9_11 << 9; return counter; } VAddr Address() const { - VAddr address{ address_bits_0_31 }; + VAddr address{address_bits_0_31}; address |= static_cast<VAddr>(address_bits_32_35) << 32; address |= static_cast<VAddr>(address_bits_36_38) << 36; return address; @@ -107,14 +106,14 @@ struct BufferDescriptorABW { }; VAddr Address() const { - VAddr address{ address_bits_0_31 }; + VAddr address{address_bits_0_31}; address |= static_cast<VAddr>(address_bits_32_35) << 32; address |= static_cast<VAddr>(address_bits_36_38) << 36; return address; } u64 Size() const { - u64 size{ size_bits_0_31 }; + u64 size{size_bits_0_31}; size |= static_cast<u64>(size_bits_32_35) << 32; return size; } @@ -130,7 +129,7 @@ struct BufferDescriptorC { }; VAddr Address() const { - VAddr address{ address_bits_0_31 }; + VAddr address{address_bits_0_31}; address |= static_cast<VAddr>(address_bits_32_47) << 32; return address; } diff --git a/src/core/hle/ipc_helpers.h b/src/core/hle/ipc_helpers.h index 0f1077d9e..25530a3c8 100644 --- a/src/core/hle/ipc_helpers.h +++ b/src/core/hle/ipc_helpers.h @@ -9,10 +9,13 @@ #include <type_traits> #include <utility> #include "core/hle/ipc.h" +#include "core/hle/kernel/client_port.h" +#include "core/hle/kernel/client_session.h" #include "core/hle/kernel/domain.h" #include "core/hle/kernel/handle_table.h" #include "core/hle/kernel/hle_ipc.h" #include "core/hle/kernel/kernel.h" +#include "core/hle/kernel/server_port.h" namespace IPC { @@ -63,13 +66,20 @@ public: : RequestHelperBase(context) { memset(cmdbuf, 0, sizeof(u32) * IPC::COMMAND_BUFFER_LENGTH); + context.ClearIncomingObjects(); + IPC::CommandHeader header{}; // The entire size of the raw data section in u32 units, including the 16 bytes of mandatory // padding. u32 raw_data_size = sizeof(IPC::DataPayloadHeader) / 4 + 4 + normal_params_size; - if (context.IsDomain()) + if (context.IsDomain()) { raw_data_size += sizeof(DomainMessageHeader) / 4 + num_domain_objects; + } else { + // If we're not in a domain, turn the domain object parameters into move handles. + num_handles_to_move += num_domain_objects; + num_domain_objects = 0; + } header.data_size.Assign(raw_data_size); if (num_handles_to_copy || num_handles_to_move) { @@ -100,7 +110,15 @@ public: template <class T, class... Args> void PushIpcInterface(Args&&... args) { - context->AddDomainObject(std::make_shared<T>(std::forward<Args>(args)...)); + auto iface = std::make_shared<T>(std::forward<Args>(args)...); + if (context->IsDomain()) { + context->AddDomainObject(std::move(iface)); + } else { + auto port = iface->CreatePort(); + auto session = port->Connect(); + ASSERT(session.Succeeded()); + context->AddMoveObject(std::move(session).Unwrap()); + } } // Validate on destruction, as there shouldn't be any case where we don't want it diff --git a/src/core/hle/kernel/hle_ipc.h b/src/core/hle/kernel/hle_ipc.h index 09caa43df..6dceb766d 100644 --- a/src/core/hle/kernel/hle_ipc.h +++ b/src/core/hle/kernel/hle_ipc.h @@ -151,13 +151,13 @@ public: return domain != nullptr; } - template<typename T> + template <typename T> SharedPtr<T> GetCopyObject(size_t index) { ASSERT(index < copy_objects.size()); return DynamicObjectCast<T>(copy_objects[index]); } - template<typename T> + template <typename T> SharedPtr<T> GetMoveObject(size_t index) { ASSERT(index < move_objects.size()); return DynamicObjectCast<T>(move_objects[index]); @@ -175,6 +175,14 @@ public: domain_objects.emplace_back(std::move(object)); } + /// Clears the list of objects so that no lingering objects are written accidentally to the + /// response buffer. + void ClearIncomingObjects() { + move_objects.clear(); + copy_objects.clear(); + domain_objects.clear(); + } + private: std::array<u32, IPC::COMMAND_BUFFER_LENGTH> cmd_buf; SharedPtr<Kernel::Domain> domain; diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h index df3b4083e..4d9549e45 100644 --- a/src/core/hle/kernel/kernel.h +++ b/src/core/hle/kernel/kernel.h @@ -105,7 +105,6 @@ public: UNREACHABLE(); } - public: static unsigned int next_object_id; diff --git a/src/core/hle/kernel/memory.cpp b/src/core/hle/kernel/memory.cpp index d990d0569..d2600cdd7 100644 --- a/src/core/hle/kernel/memory.cpp +++ b/src/core/hle/kernel/memory.cpp @@ -95,10 +95,8 @@ MemoryRegionInfo* GetMemoryRegion(MemoryRegion region) { } } -void HandleSpecialMapping(VMManager& address_space, const AddressMapping& mapping) { -} +void HandleSpecialMapping(VMManager& address_space, const AddressMapping& mapping) {} -void MapSharedPages(VMManager& address_space) { -} +void MapSharedPages(VMManager& address_space) {} } // namespace Kernel diff --git a/src/core/hle/kernel/mutex.h b/src/core/hle/kernel/mutex.h index 49b6b454e..38db21005 100644 --- a/src/core/hle/kernel/mutex.h +++ b/src/core/hle/kernel/mutex.h @@ -41,9 +41,9 @@ public: return HANDLE_TYPE; } - u32 priority; ///< The priority of the mutex, used for priority inheritance. - std::string name; ///< Name of mutex (optional) - VAddr guest_addr; ///< Address of the guest mutex value + u32 priority; ///< The priority of the mutex, used for priority inheritance. + std::string name; ///< Name of mutex (optional) + VAddr guest_addr; ///< Address of the guest mutex value /** * Elevate the mutex priority to the best priority diff --git a/src/core/hle/kernel/process.h b/src/core/hle/kernel/process.h index 20b4e401c..add98472f 100644 --- a/src/core/hle/kernel/process.h +++ b/src/core/hle/kernel/process.h @@ -131,6 +131,8 @@ public: /// Bitmask of allowed CPUs that this process' threads can run on. TODO(Subv): Actually parse /// this value from the process header. u32 allowed_processor_mask = THREADPROCESSORID_DEFAULT_MASK; + u32 allowed_thread_priority_mask = 0xFFFFFFFF; + u32 is_virtual_address_memory_enabled = 0; /// Current status of the process ProcessStatus status; diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index 9c60576c1..088058ebc 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -305,14 +305,27 @@ static ResultCode GetInfo(u64* result, u64 info_id, u64 handle, u64 info_sub_id) LOG_TRACE(Kernel_SVC, "called info_id=0x%X, info_sub_id=0x%X, handle=0x%08X", info_id, info_sub_id, handle); - ASSERT(handle == 0 || handle == CurrentProcess); - auto& vm_manager = g_current_process->vm_manager; switch (static_cast<GetInfoType>(info_id)) { case GetInfoType::AllowedCpuIdBitmask: *result = g_current_process->allowed_processor_mask; break; + case GetInfoType::AllowedThreadPrioBitmask: + *result = g_current_process->allowed_thread_priority_mask; + break; + case GetInfoType::MapRegionBaseAddr: + *result = vm_manager.GetAddressSpaceBaseAddr(); + break; + case GetInfoType::MapRegionSize: + *result = vm_manager.GetAddressSpaceSize(); + break; + case GetInfoType::HeapRegionBaseAddr: + *result = vm_manager.GetNewMapRegionBaseAddr() + vm_manager.GetNewMapRegionSize(); + break; + case GetInfoType::HeapRegionSize: + *result = Memory::HEAP_SIZE; + break; case GetInfoType::TotalMemoryUsage: *result = vm_manager.GetTotalMemoryUsage(); break; @@ -334,6 +347,18 @@ static ResultCode GetInfo(u64* result, u64 info_id, u64 handle, u64 info_sub_id) case GetInfoType::NewMapRegionSize: *result = vm_manager.GetNewMapRegionSize(); break; + case GetInfoType::IsVirtualAddressMemoryEnabled: + *result = g_current_process->is_virtual_address_memory_enabled; + break; + case GetInfoType::TitleId: + LOG_WARNING(Kernel_SVC, "(STUBBED) Attempted to query titleid, returned 0"); + *result = 0; + break; + case GetInfoType::PrivilegedProcessId: + LOG_WARNING(Kernel_SVC, + "(STUBBED) Attempted to query priviledged process id bounds, returned 0"); + *result = 0; + break; default: UNIMPLEMENTED(); } @@ -709,6 +734,11 @@ static ResultCode CreateTransferMemory(Handle* handle, VAddr addr, u64 size, u32 return RESULT_SUCCESS; } +static ResultCode SetThreadCoreMask(u64, u64, u64) { + LOG_WARNING(Kernel_SVC, "(STUBBED) called"); + return RESULT_SUCCESS; +} + namespace { struct FunctionDef { using Func = void(); @@ -735,7 +765,7 @@ static const FunctionDef SVC_Table[] = { {0x0C, SvcWrap<GetThreadPriority>, "GetThreadPriority"}, {0x0D, SvcWrap<SetThreadPriority>, "SetThreadPriority"}, {0x0E, nullptr, "GetThreadCoreMask"}, - {0x0F, nullptr, "SetThreadCoreMask"}, + {0x0F, SvcWrap<SetThreadCoreMask>, "SetThreadCoreMask"}, {0x10, SvcWrap<GetCurrentProcessorNumber>, "GetCurrentProcessorNumber"}, {0x11, nullptr, "SignalEvent"}, {0x12, nullptr, "ClearEvent"}, diff --git a/src/core/hle/kernel/svc.h b/src/core/hle/kernel/svc.h index 610cd1d7d..42cc41da3 100644 --- a/src/core/hle/kernel/svc.h +++ b/src/core/hle/kernel/svc.h @@ -24,14 +24,28 @@ struct PageInfo { enum class GetInfoType : u64 { // 1.0.0+ AllowedCpuIdBitmask = 0, + AllowedThreadPrioBitmask = 1, + MapRegionBaseAddr = 2, + MapRegionSize = 3, + HeapRegionBaseAddr = 4, + HeapRegionSize = 5, TotalMemoryUsage = 6, TotalHeapUsage = 7, + IsCurrentProcessBeingDebugged = 8, + ResourceHandleLimit = 9, + IdleTickCount = 10, RandomEntropy = 11, + PerformanceCounter = 0xF0000002, // 2.0.0+ AddressSpaceBaseAddr = 12, AddressSpaceSize = 13, NewMapRegionBaseAddr = 14, NewMapRegionSize = 15, + // 3.0.0+ + IsVirtualAddressMemoryEnabled = 16, + TitleId = 18, + // 4.0.0+ + PrivilegedProcessId = 19, }; void CallSVC(u32 immediate); diff --git a/src/core/hle/kernel/vm_manager.cpp b/src/core/hle/kernel/vm_manager.cpp index dca637dde..bf261699e 100644 --- a/src/core/hle/kernel/vm_manager.cpp +++ b/src/core/hle/kernel/vm_manager.cpp @@ -6,9 +6,9 @@ #include "common/assert.h" #include "common/logging/log.h" #include "core/arm/arm_interface.h" +#include "core/core.h" #include "core/hle/kernel/errors.h" #include "core/hle/kernel/vm_manager.h" -#include "core/core.h" #include "core/memory.h" #include "core/memory_setup.h" #include "core/mmio.h" @@ -86,7 +86,8 @@ ResultVal<VMManager::VMAHandle> VMManager::MapMemoryBlock(VAddr target, VirtualMemoryArea& final_vma = vma_handle->second; ASSERT(final_vma.size == size); - Core::CPU().MapBackingMemory(target, size, block->data() + offset, VMAPermission::ReadWriteExecute); + Core::CPU().MapBackingMemory(target, size, block->data() + offset, + VMAPermission::ReadWriteExecute); final_vma.type = VMAType::AllocatedMemoryBlock; final_vma.permissions = VMAPermission::ReadWrite; @@ -356,12 +357,12 @@ void VMManager::UpdatePageTableForVMA(const VirtualMemoryArea& vma) { u64 VMManager::GetTotalMemoryUsage() { LOG_WARNING(Kernel, "(STUBBED) called"); - return 0x400000; + return 0xBE000000; } u64 VMManager::GetTotalHeapUsage() { LOG_WARNING(Kernel, "(STUBBED) called"); - return 0x10000; + return 0x0; } VAddr VMManager::GetAddressSpaceBaseAddr() { diff --git a/src/core/hle/service/acc/acc.cpp b/src/core/hle/service/acc/acc.cpp new file mode 100644 index 000000000..5716577d6 --- /dev/null +++ b/src/core/hle/service/acc/acc.cpp @@ -0,0 +1,16 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "core/hle/service/acc/acc.h" +#include "core/hle/service/acc/acc_u0.h" + +namespace Service { +namespace Account { + +void InstallInterfaces(SM::ServiceManager& service_manager) { + std::make_shared<ACC_U0>()->InstallAsService(service_manager); +} + +} // namespace Account +} // namespace Service diff --git a/src/core/hle/service/acc/acc.h b/src/core/hle/service/acc/acc.h new file mode 100644 index 000000000..44d024f48 --- /dev/null +++ b/src/core/hle/service/acc/acc.h @@ -0,0 +1,16 @@ +// 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/service.h" + +namespace Service { +namespace Account { + +/// Registers all ACC services with the specified service manager. +void InstallInterfaces(SM::ServiceManager& service_manager); + +} // namespace Account +} // namespace Service diff --git a/src/core/hle/service/acc/acc_u0.cpp b/src/core/hle/service/acc/acc_u0.cpp new file mode 100644 index 000000000..147f4e62e --- /dev/null +++ b/src/core/hle/service/acc/acc_u0.cpp @@ -0,0 +1,26 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "common/logging/log.h" +#include "core/hle/ipc_helpers.h" +#include "core/hle/service/acc/acc_u0.h" + +namespace Service { +namespace Account { + +void ACC_U0::InitializeApplicationInfo(Kernel::HLERequestContext& ctx) { + LOG_WARNING(Service, "(STUBBED) called"); + IPC::RequestBuilder rb{ctx, 2}; + rb.Push(RESULT_SUCCESS); +} + +ACC_U0::ACC_U0() : ServiceFramework("acc:u0") { + static const FunctionInfo functions[] = { + {100, &ACC_U0::InitializeApplicationInfo, "InitializeApplicationInfo"}, + }; + RegisterHandlers(functions); +} + +} // namespace Account +} // namespace Service diff --git a/src/core/hle/service/acc/acc_u0.h b/src/core/hle/service/acc/acc_u0.h new file mode 100644 index 000000000..ac243d5b8 --- /dev/null +++ b/src/core/hle/service/acc/acc_u0.h @@ -0,0 +1,22 @@ +// 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/service.h" + +namespace Service { +namespace Account { + +class ACC_U0 final : public ServiceFramework<ACC_U0> { +public: + ACC_U0(); + ~ACC_U0() = default; + +private: + void InitializeApplicationInfo(Kernel::HLERequestContext& ctx); +}; + +} // namespace Account +} // namespace Service diff --git a/src/core/hle/service/am/applet_oe.cpp b/src/core/hle/service/am/applet_oe.cpp index f65d6b9f5..b360e7e5f 100644 --- a/src/core/hle/service/am/applet_oe.cpp +++ b/src/core/hle/service/am/applet_oe.cpp @@ -6,6 +6,7 @@ #include "core/hle/ipc_helpers.h" #include "core/hle/kernel/event.h" #include "core/hle/service/am/applet_oe.h" +#include "core/hle/service/apm/apm.h" namespace Service { namespace AM { @@ -54,7 +55,14 @@ class ISelfController final : public ServiceFramework<ISelfController> { public: ISelfController() : ServiceFramework("ISelfController") { static const FunctionInfo functions[] = { + {11, &ISelfController::SetOperationModeChangedNotification, + "SetOperationModeChangedNotification"}, + {12, &ISelfController::SetPerformanceModeChangedNotification, + "SetPerformanceModeChangedNotification"}, {13, &ISelfController::SetFocusHandlingMode, "SetFocusHandlingMode"}, + {14, &ISelfController::SetRestartMessageEnabled, "SetRestartMessageEnabled"}, + {16, &ISelfController::SetOutOfFocusSuspendingEnabled, + "SetOutOfFocusSuspendingEnabled"}, }; RegisterHandlers(functions); } @@ -64,11 +72,62 @@ private: // Takes 3 input u8s with each field located immediately after the previous u8, these are // bool flags. No output. + IPC::RequestParser rp{ctx}; + + struct FocusHandlingModeParams { + u8 unknown0; + u8 unknown1; + u8 unknown2; + }; + auto flags = rp.PopRaw<FocusHandlingModeParams>(); + + IPC::RequestBuilder rb{ctx, 2}; + rb.Push(RESULT_SUCCESS); + + LOG_WARNING(Service, "(STUBBED) called"); + } + + void SetRestartMessageEnabled(Kernel::HLERequestContext& ctx) { IPC::RequestBuilder rb{ctx, 2}; rb.Push(RESULT_SUCCESS); LOG_WARNING(Service, "(STUBBED) called"); } + + void SetPerformanceModeChangedNotification(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + + bool flag = rp.Pop<bool>(); + + IPC::RequestBuilder rb{ctx, 2}; + rb.Push(RESULT_SUCCESS); + + LOG_WARNING(Service, "(STUBBED) called flag=%u", static_cast<u32>(flag)); + } + + void SetOperationModeChangedNotification(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + + bool flag = rp.Pop<bool>(); + + IPC::RequestBuilder rb{ctx, 2}; + rb.Push(RESULT_SUCCESS); + + LOG_WARNING(Service, "(STUBBED) called flag=%u", static_cast<u32>(flag)); + } + + void SetOutOfFocusSuspendingEnabled(Kernel::HLERequestContext& ctx) { + // Takes 3 input u8s with each field located immediately after the previous u8, these are + // bool flags. No output. + IPC::RequestParser rp{ctx}; + + bool enabled = rp.Pop<bool>(); + + IPC::RequestBuilder rb{ctx, 2}; + rb.Push(RESULT_SUCCESS); + + LOG_WARNING(Service, "(STUBBED) called enabled=%u", static_cast<u32>(enabled)); + } }; class ICommonStateGetter final : public ServiceFramework<ICommonStateGetter> { @@ -77,6 +136,8 @@ public: static const FunctionInfo functions[] = { {0, &ICommonStateGetter::GetEventHandle, "GetEventHandle"}, {1, &ICommonStateGetter::ReceiveMessage, "ReceiveMessage"}, + {5, &ICommonStateGetter::GetOperationMode, "GetOperationMode"}, + {6, &ICommonStateGetter::GetPerformanceMode, "GetPerformanceMode"}, {9, &ICommonStateGetter::GetCurrentFocusState, "GetCurrentFocusState"}, }; RegisterHandlers(functions); @@ -85,6 +146,16 @@ public: } private: + enum class FocusState : u8 { + InFocus = 1, + NotInFocus = 2, + }; + + enum class OperationMode : u8 { + Handheld = 0, + Docked = 1, + }; + void GetEventHandle(Kernel::HLERequestContext& ctx) { event->Signal(); @@ -106,7 +177,23 @@ private: void GetCurrentFocusState(Kernel::HLERequestContext& ctx) { IPC::RequestBuilder rb{ctx, 3}; rb.Push(RESULT_SUCCESS); - rb.Push<u32>(1); // 1: In focus, 2/3: Out of focus(running in "background") + rb.Push(static_cast<u8>(FocusState::InFocus)); + + LOG_WARNING(Service, "(STUBBED) called"); + } + + void GetOperationMode(Kernel::HLERequestContext& ctx) { + IPC::RequestBuilder rb{ctx, 3}; + rb.Push(RESULT_SUCCESS); + rb.Push(static_cast<u8>(OperationMode::Handheld)); + + LOG_WARNING(Service, "(STUBBED) called"); + } + + void GetPerformanceMode(Kernel::HLERequestContext& ctx) { + IPC::RequestBuilder rb{ctx, 3}; + rb.Push(RESULT_SUCCESS); + rb.Push(static_cast<u32>(APM::PerformanceMode::Handheld)); LOG_WARNING(Service, "(STUBBED) called"); } @@ -119,6 +206,10 @@ public: IApplicationFunctions() : ServiceFramework("IApplicationFunctions") { static const FunctionInfo functions[] = { {22, &IApplicationFunctions::SetTerminateResult, "SetTerminateResult"}, + {66, &IApplicationFunctions::InitializeGamePlayRecording, + "InitializeGamePlayRecording"}, + {67, &IApplicationFunctions::SetGamePlayRecordingState, "SetGamePlayRecordingState"}, + {40, &IApplicationFunctions::NotifyRunning, "NotifyRunning"}, }; RegisterHandlers(functions); } @@ -136,6 +227,27 @@ private: LOG_WARNING(Service, "(STUBBED) called, result=0x%08X", result); } + + void InitializeGamePlayRecording(Kernel::HLERequestContext& ctx) { + IPC::RequestBuilder rb{ctx, 2}; + rb.Push(RESULT_SUCCESS); + LOG_WARNING(Service, "(STUBBED) called"); + } + + void SetGamePlayRecordingState(Kernel::HLERequestContext& ctx) { + IPC::RequestBuilder rb{ctx, 2}; + rb.Push(RESULT_SUCCESS); + + LOG_WARNING(Service, "(STUBBED) called"); + } + + void NotifyRunning(Kernel::HLERequestContext& ctx) { + IPC::RequestBuilder rb{ctx, 3}; + rb.Push(RESULT_SUCCESS); + rb.Push<u8>(0); // Unknown, seems to be ignored by official processes + + LOG_WARNING(Service, "(STUBBED) called"); + } }; class ILibraryAppletCreator final : public ServiceFramework<ILibraryAppletCreator> { diff --git a/src/core/hle/service/apm/apm.cpp b/src/core/hle/service/apm/apm.cpp index f70b9fc10..66d94ff52 100644 --- a/src/core/hle/service/apm/apm.cpp +++ b/src/core/hle/service/apm/apm.cpp @@ -13,13 +13,54 @@ void InstallInterfaces(SM::ServiceManager& service_manager) { std::make_shared<APM>()->InstallAsService(service_manager); } +class ISession final : public ServiceFramework<ISession> { +public: + ISession() : ServiceFramework("ISession") { + static const FunctionInfo functions[] = { + {0, &ISession::SetPerformanceConfiguration, "SetPerformanceConfiguration"}, + {1, &ISession::GetPerformanceConfiguration, "GetPerformanceConfiguration"}, + }; + RegisterHandlers(functions); + } + +private: + void SetPerformanceConfiguration(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + + auto mode = static_cast<PerformanceMode>(rp.Pop<u32>()); + u32 config = rp.Pop<u32>(); + + IPC::RequestBuilder rb{ctx, 2}; + rb.Push(RESULT_SUCCESS); + + LOG_WARNING(Service, "(STUBBED) called mode=%u config=%u", static_cast<u32>(mode), config); + } + + void GetPerformanceConfiguration(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + + auto mode = static_cast<PerformanceMode>(rp.Pop<u32>()); + + IPC::RequestBuilder rb{ctx, 3}; + rb.Push(RESULT_SUCCESS); + rb.Push<u32>(0); // Performance configuration + + LOG_WARNING(Service, "(STUBBED) called mode=%u", static_cast<u32>(mode)); + } +}; + APM::APM() : ServiceFramework("apm") { static const FunctionInfo functions[] = { - {0x00000000, nullptr, "OpenSession"}, - {0x00000001, nullptr, "GetPerformanceMode"}, + {0x00000000, &APM::OpenSession, "OpenSession"}, {0x00000001, nullptr, "GetPerformanceMode"}, }; RegisterHandlers(functions); } +void APM::OpenSession(Kernel::HLERequestContext& ctx) { + IPC::RequestBuilder rb{ctx, 2, 0, 0, 1}; + rb.Push(RESULT_SUCCESS); + rb.PushIpcInterface<ISession>(); +} + } // namespace APM } // namespace Service diff --git a/src/core/hle/service/apm/apm.h b/src/core/hle/service/apm/apm.h index 377db71a4..90a1afbbc 100644 --- a/src/core/hle/service/apm/apm.h +++ b/src/core/hle/service/apm/apm.h @@ -9,10 +9,18 @@ namespace Service { namespace APM { +enum class PerformanceMode : u8 { + Handheld = 0, + Docked = 1, +}; + class APM final : public ServiceFramework<APM> { public: APM(); ~APM() = default; + +private: + void OpenSession(Kernel::HLERequestContext& ctx); }; /// Registers all AM services with the specified service manager. diff --git a/src/core/hle/service/nvdrv/devices/nvdevice.h b/src/core/hle/service/nvdrv/devices/nvdevice.h index 1ee2787c6..5ee33b3d6 100644 --- a/src/core/hle/service/nvdrv/devices/nvdevice.h +++ b/src/core/hle/service/nvdrv/devices/nvdevice.h @@ -8,7 +8,7 @@ #include "common/common_types.h" namespace Service { -namespace NVDRV { +namespace Nvidia { namespace Devices { /// Represents an abstract nvidia device node. It is to be subclassed by concrete device nodes to @@ -29,5 +29,5 @@ public: }; } // namespace Devices -} // namespace NVDRV +} // namespace Nvidia } // namespace Service diff --git a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp index 992f70b45..c42a65b36 100644 --- a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp +++ b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp @@ -10,7 +10,7 @@ #include "video_core/video_core.h" namespace Service { -namespace NVDRV { +namespace Nvidia { namespace Devices { u32 nvdisp_disp0::ioctl(u32 command, const std::vector<u8>& input, std::vector<u8>& output) { @@ -32,5 +32,5 @@ void nvdisp_disp0::flip(u32 buffer_handle, u32 offset, u32 format, u32 width, u3 } } // namespace Devices -} // namespace NVDRV +} // namespace Nvidia } // namespace Service diff --git a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.h b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.h index 601068af1..f5f9de3f4 100644 --- a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.h +++ b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.h @@ -10,7 +10,7 @@ #include "core/hle/service/nvdrv/devices/nvdevice.h" namespace Service { -namespace NVDRV { +namespace Nvidia { namespace Devices { class nvmap; @@ -30,5 +30,5 @@ private: }; } // namespace Devices -} // namespace NVDRV +} // namespace Nvidia } // namespace Service diff --git a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp index c7bf79050..9db08339a 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp @@ -7,7 +7,7 @@ #include "core/hle/service/nvdrv/devices/nvhost_as_gpu.h" namespace Service { -namespace NVDRV { +namespace Nvidia { namespace Devices { u32 nvhost_as_gpu::ioctl(u32 command, const std::vector<u8>& input, std::vector<u8>& output) { @@ -16,5 +16,5 @@ u32 nvhost_as_gpu::ioctl(u32 command, const std::vector<u8>& input, std::vector< } } // namespace Devices -} // namespace NVDRV +} // namespace Nvidia } // namespace Service diff --git a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h index 6f441b020..01f8861c8 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h +++ b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h @@ -9,7 +9,7 @@ #include "core/hle/service/nvdrv/devices/nvdevice.h" namespace Service { -namespace NVDRV { +namespace Nvidia { namespace Devices { class nvhost_as_gpu final : public nvdevice { @@ -21,5 +21,5 @@ public: }; } // namespace Devices -} // namespace NVDRV +} // namespace Nvidia } // namespace Service diff --git a/src/core/hle/service/nvdrv/devices/nvmap.cpp b/src/core/hle/service/nvdrv/devices/nvmap.cpp index 2d6f30e3e..d37b5b159 100644 --- a/src/core/hle/service/nvdrv/devices/nvmap.cpp +++ b/src/core/hle/service/nvdrv/devices/nvmap.cpp @@ -9,7 +9,7 @@ #include "core/hle/service/nvdrv/devices/nvmap.h" namespace Service { -namespace NVDRV { +namespace Nvidia { namespace Devices { VAddr nvmap::GetObjectAddress(u32 handle) const { @@ -151,5 +151,5 @@ u32 nvmap::IocParam(const std::vector<u8>& input, std::vector<u8>& output) { } } // namespace Devices -} // namespace NVDRV +} // namespace Nvidia } // namespace Service diff --git a/src/core/hle/service/nvdrv/devices/nvmap.h b/src/core/hle/service/nvdrv/devices/nvmap.h index e74f356e5..6954c0324 100644 --- a/src/core/hle/service/nvdrv/devices/nvmap.h +++ b/src/core/hle/service/nvdrv/devices/nvmap.h @@ -13,7 +13,7 @@ #include "core/hle/service/nvdrv/devices/nvdevice.h" namespace Service { -namespace NVDRV { +namespace Nvidia { namespace Devices { class nvmap final : public nvdevice { @@ -104,5 +104,5 @@ private: }; } // namespace Devices -} // namespace NVDRV +} // namespace Nvidia } // namespace Service diff --git a/src/core/hle/service/nvdrv/nvdrv_a.cpp b/src/core/hle/service/nvdrv/interface.cpp index 84d89cb49..0670ca155 100644 --- a/src/core/hle/service/nvdrv/nvdrv_a.cpp +++ b/src/core/hle/service/nvdrv/interface.cpp @@ -4,35 +4,27 @@ #include "common/logging/log.h" #include "core/hle/ipc_helpers.h" -#include "core/hle/service/nvdrv/devices/nvdevice.h" -#include "core/hle/service/nvdrv/devices/nvdisp_disp0.h" -#include "core/hle/service/nvdrv/devices/nvhost_as_gpu.h" -#include "core/hle/service/nvdrv/devices/nvmap.h" +#include "core/hle/service/nvdrv/interface.h" #include "core/hle/service/nvdrv/nvdrv.h" -#include "core/hle/service/nvdrv/nvdrv_a.h" namespace Service { -namespace NVDRV { +namespace Nvidia { -void NVDRV_A::Open(Kernel::HLERequestContext& ctx) { +void NVDRV::Open(Kernel::HLERequestContext& ctx) { LOG_WARNING(Service, "(STUBBED) called"); auto buffer = ctx.BufferDescriptorA()[0]; std::string device_name = Memory::ReadCString(buffer.Address(), buffer.Size()); - auto device = devices[device_name]; - u32 fd = next_fd++; - - open_files[fd] = device; - + u32 fd = nvdrv->Open(device_name); IPC::RequestBuilder rb{ctx, 4}; rb.Push(RESULT_SUCCESS); rb.Push<u32>(fd); rb.Push<u32>(0); } -void NVDRV_A::Ioctl(Kernel::HLERequestContext& ctx) { +void NVDRV::Ioctl(Kernel::HLERequestContext& ctx) { LOG_WARNING(Service, "(STUBBED) called"); IPC::RequestParser rp{ctx}; @@ -46,11 +38,8 @@ void NVDRV_A::Ioctl(Kernel::HLERequestContext& ctx) { std::vector<u8> output(output_buffer.Size()); Memory::ReadBlock(input_buffer.Address(), input.data(), input_buffer.Size()); - auto itr = open_files.find(fd); - ASSERT_MSG(itr != open_files.end(), "Tried to talk to an invalid device"); - auto device = itr->second; - u32 nv_result = device->ioctl(command, input, output); + u32 nv_result = nvdrv->Ioctl(fd, command, input, output); Memory::WriteBlock(output_buffer.Address(), output.data(), output_buffer.Size()); @@ -59,26 +48,22 @@ void NVDRV_A::Ioctl(Kernel::HLERequestContext& ctx) { rb.Push(nv_result); } -void NVDRV_A::Initialize(Kernel::HLERequestContext& ctx) { +void NVDRV::Initialize(Kernel::HLERequestContext& ctx) { LOG_WARNING(Service, "(STUBBED) called"); IPC::RequestBuilder rb{ctx, 3}; rb.Push(RESULT_SUCCESS); rb.Push<u32>(0); } -NVDRV_A::NVDRV_A() : ServiceFramework("nvdrv:a") { +NVDRV::NVDRV(std::shared_ptr<Module> nvdrv, const char* name) + : ServiceFramework(name), nvdrv(std::move(nvdrv)) { static const FunctionInfo functions[] = { - {0, &NVDRV_A::Open, "Open"}, - {1, &NVDRV_A::Ioctl, "Ioctl"}, - {3, &NVDRV_A::Initialize, "Initialize"}, + {0, &NVDRV::Open, "Open"}, + {1, &NVDRV::Ioctl, "Ioctl"}, + {3, &NVDRV::Initialize, "Initialize"}, }; RegisterHandlers(functions); - - auto nvmap_dev = std::make_shared<Devices::nvmap>(); - devices["/dev/nvhost-as-gpu"] = std::make_shared<Devices::nvhost_as_gpu>(); - devices["/dev/nvmap"] = nvmap_dev; - devices["/dev/nvdisp_disp0"] = std::make_shared<Devices::nvdisp_disp0>(nvmap_dev); } -} // namespace NVDRV +} // namespace Nvidia } // namespace Service diff --git a/src/core/hle/service/nvdrv/interface.h b/src/core/hle/service/nvdrv/interface.h new file mode 100644 index 000000000..8c95b7217 --- /dev/null +++ b/src/core/hle/service/nvdrv/interface.h @@ -0,0 +1,29 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include <memory> +#include <string> +#include "core/hle/service/nvdrv/nvdrv.h" +#include "core/hle/service/service.h" + +namespace Service { +namespace Nvidia { + +class NVDRV final : public ServiceFramework<NVDRV> { +public: + NVDRV(std::shared_ptr<Module> nvdrv, const char* name); + ~NVDRV() = default; + +private: + void Open(Kernel::HLERequestContext& ctx); + void Ioctl(Kernel::HLERequestContext& ctx); + void Initialize(Kernel::HLERequestContext& ctx); + + std::shared_ptr<Module> nvdrv; +}; + +} // namespace Nvidia +} // namespace Service diff --git a/src/core/hle/service/nvdrv/nvdrv.cpp b/src/core/hle/service/nvdrv/nvdrv.cpp index c874e6395..cf525a875 100644 --- a/src/core/hle/service/nvdrv/nvdrv.cpp +++ b/src/core/hle/service/nvdrv/nvdrv.cpp @@ -2,19 +2,52 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. +#include "core/hle/ipc_helpers.h" +#include "core/hle/service/nvdrv/devices/nvdevice.h" +#include "core/hle/service/nvdrv/devices/nvdisp_disp0.h" +#include "core/hle/service/nvdrv/devices/nvhost_as_gpu.h" +#include "core/hle/service/nvdrv/devices/nvmap.h" #include "core/hle/service/nvdrv/nvdrv.h" -#include "core/hle/service/nvdrv/nvdrv_a.h" +#include "core/hle/service/nvdrv/interface.h" namespace Service { -namespace NVDRV { +namespace Nvidia { -std::weak_ptr<NVDRV_A> nvdrv_a; +std::weak_ptr<Module> nvdrv; void InstallInterfaces(SM::ServiceManager& service_manager) { - auto nvdrv = std::make_shared<NVDRV_A>(); - nvdrv->InstallAsService(service_manager); - nvdrv_a = nvdrv; + auto module_ = std::make_shared<Module>(); + std::make_shared<NVDRV>(module_, "nvdrv")->InstallAsService(service_manager); + std::make_shared<NVDRV>(module_, "nvdrv:a")->InstallAsService(service_manager); + nvdrv = module_; } -} // namespace NVDRV +Module::Module() { + auto nvmap_dev = std::make_shared<Devices::nvmap>(); + devices["/dev/nvhost-as-gpu"] = std::make_shared<Devices::nvhost_as_gpu>(); + devices["/dev/nvmap"] = nvmap_dev; + devices["/dev/nvdisp_disp0"] = std::make_shared<Devices::nvdisp_disp0>(nvmap_dev); +} + +u32 Module::Open(std::string device_name) { + ASSERT_MSG(devices.find(device_name) != devices.end(), "Trying to open unknown device %s", + device_name.c_str()); + + auto device = devices[device_name]; + u32 fd = next_fd++; + + open_files[fd] = device; + + return fd; +} + +u32 Module::Ioctl(u32 fd, u32 command, const std::vector<u8>& input, std::vector<u8>& output) { + auto itr = open_files.find(fd); + ASSERT_MSG(itr != open_files.end(), "Tried to talk to an invalid device"); + + auto device = itr->second; + return device->ioctl(command, input, output); +} + +} // namespace Nvidia } // namespace Service diff --git a/src/core/hle/service/nvdrv/nvdrv.h b/src/core/hle/service/nvdrv/nvdrv.h index 7530d80ad..1940ced99 100644 --- a/src/core/hle/service/nvdrv/nvdrv.h +++ b/src/core/hle/service/nvdrv/nvdrv.h @@ -11,109 +11,46 @@ #include "core/hle/service/service.h" namespace Service { -namespace NVDRV { +namespace Nvidia { -class nvdevice { -public: - virtual ~nvdevice() = default; - - virtual u32 ioctl(u32 command, const std::vector<u8>& input, std::vector<u8>& output) = 0; -}; +namespace Devices { +class nvdevice; +} -class nvmap : public nvdevice { +class Module final { public: - /// Returns the allocated address of an nvmap object given its handle. - VAddr GetObjectAddress(u32 handle) const; + Module(); + ~Module() = default; + + /// Returns a pointer to one of the available devices, identified by its name. + template <typename T> + std::shared_ptr<T> GetDevice(std::string name) { + auto itr = devices.find(name); + if (itr == devices.end()) + return nullptr; + return std::static_pointer_cast<T>(itr->second); + } + + /// Opens a device node and returns a file descriptor to it. + u32 Open(std::string device_name); + /// Sends an ioctl command to the specified file descriptor. + u32 Ioctl(u32 fd, u32 command, const std::vector<u8>& input, std::vector<u8>& output); - u32 ioctl(u32 command, const std::vector<u8>& input, std::vector<u8>& output) override; private: - // Represents an nvmap object. - struct Object { - enum class Status { Created, Allocated }; - u32 id; - u32 size; - u32 flags; - u32 align; - u8 kind; - VAddr addr; - Status status; - }; - - u32 next_handle = 1; - u32 next_id = 1; - std::unordered_map<u32, std::shared_ptr<Object>> handles; - - enum IoctlCommands { - IocCreateCommand = 0xC0080101, - IocFromIdCommand = 0xC0080103, - IocAllocCommand = 0xC0200104, - IocParamCommand = 0xC00C0109, - IocGetIdCommand = 0xC008010E - }; - - struct IocCreateParams { - // Input - u32_le size; - // Output - u32_le handle; - }; - - struct IocAllocParams { - // Input - u32_le handle; - u32_le heap_mask; - u32_le flags; - u32_le align; - u8 kind; - INSERT_PADDING_BYTES(7); - u64_le addr; - }; - - struct IocGetIdParams { - // Output - u32_le id; - // Input - u32_le handle; - }; - - struct IocFromIdParams { - // Input - u32_le id; - // Output - u32_le handle; - }; + /// Id to use for the next open file descriptor. + u32 next_fd = 1; - struct IocParamParams { - // Input - u32_le handle; - u32_le type; - // Output - u32_le value; - }; + /// Mapping of file descriptors to the devices they reference. + std::unordered_map<u32, std::shared_ptr<Devices::nvdevice>> open_files; - u32 IocCreate(const std::vector<u8>& input, std::vector<u8>& output); - u32 IocAlloc(const std::vector<u8>& input, std::vector<u8>& output); - u32 IocGetId(const std::vector<u8>& input, std::vector<u8>& output); - u32 IocFromId(const std::vector<u8>& input, std::vector<u8>& output); - u32 IocParam(const std::vector<u8>& input, std::vector<u8>& output); -}; - -class nvdisp_disp0 : public nvdevice { -public: - nvdisp_disp0(std::shared_ptr<nvmap> nvmap_dev) : nvdevice(), nvmap_dev(std::move(nvmap_dev)) {} - ~nvdisp_disp0() = default; - - u32 ioctl(u32 command, const std::vector<u8>& input, std::vector<u8>& output) override; - - /// Performs a screen flip, drawing the buffer pointed to by the handle. - void flip(u32 buffer_handle, u32 offset, u32 format, u32 width, u32 height, u32 stride); - -private: - std::shared_ptr<nvmap> nvmap_dev; + /// Mapping of device node names to their implementation. + std::unordered_map<std::string, std::shared_ptr<Devices::nvdevice>> devices; }; /// Registers all NVDRV services with the specified service manager. void InstallInterfaces(SM::ServiceManager& service_manager); -} // namespace NVDRV +extern std::weak_ptr<Module> nvdrv; + +} // namespace Nvidia } // namespace Service diff --git a/src/core/hle/service/nvdrv/nvdrv_a.h b/src/core/hle/service/nvdrv/nvdrv_a.h deleted file mode 100644 index 62f10e9f6..000000000 --- a/src/core/hle/service/nvdrv/nvdrv_a.h +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright 2018 yuzu emulator team -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#pragma once - -#include <memory> -#include <string> -#include "core/hle/service/nvdrv/nvdrv.h" -#include "core/hle/service/service.h" - -namespace Service { -namespace NVDRV { - -namespace Devices { -class nvdevice; -} - -class NVDRV_A final : public ServiceFramework<NVDRV_A> { -public: - NVDRV_A(); - ~NVDRV_A() = default; - - /// Returns a pointer to one of the available devices, identified by its name. - template <typename T> - std::shared_ptr<T> GetDevice(std::string name) { - auto itr = devices.find(name); - if (itr == devices.end()) - return nullptr; - return std::static_pointer_cast<T>(itr->second); - } - -private: - void Open(Kernel::HLERequestContext& ctx); - void Ioctl(Kernel::HLERequestContext& ctx); - void Initialize(Kernel::HLERequestContext& ctx); - - /// Id to use for the next open file descriptor. - u32 next_fd = 1; - - /// Mapping of file descriptors to the devices they reference. - std::unordered_map<u32, std::shared_ptr<Devices::nvdevice>> open_files; - - /// Mapping of device node names to their implementation. - std::unordered_map<std::string, std::shared_ptr<Devices::nvdevice>> devices; -}; - -extern std::weak_ptr<NVDRV_A> nvdrv_a; - -} // namespace NVDRV -} // namespace Service diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp index 02d434660..fe76b381c 100644 --- a/src/core/hle/service/service.cpp +++ b/src/core/hle/service/service.cpp @@ -14,6 +14,7 @@ #include "core/hle/kernel/process.h" #include "core/hle/kernel/server_port.h" #include "core/hle/kernel/thread.h" +#include "core/hle/service/acc/acc.h" #include "core/hle/service/am/am.h" #include "core/hle/service/aoc/aoc_u.h" #include "core/hle/service/apm/apm.h" @@ -164,13 +165,14 @@ void Init() { SM::g_service_manager = std::make_shared<SM::ServiceManager>(); SM::ServiceManager::InstallInterfaces(SM::g_service_manager); + Account::InstallInterfaces(*SM::g_service_manager); AM::InstallInterfaces(*SM::g_service_manager); AOC::InstallInterfaces(*SM::g_service_manager); APM::InstallInterfaces(*SM::g_service_manager); Audio::InstallInterfaces(*SM::g_service_manager); HID::InstallInterfaces(*SM::g_service_manager); LM::InstallInterfaces(*SM::g_service_manager); - NVDRV::InstallInterfaces(*SM::g_service_manager); + Nvidia::InstallInterfaces(*SM::g_service_manager); PCTL::InstallInterfaces(*SM::g_service_manager); Time::InstallInterfaces(*SM::g_service_manager); VI::InstallInterfaces(*SM::g_service_manager); diff --git a/src/core/hle/service/vi/vi.cpp b/src/core/hle/service/vi/vi.cpp index 93ebbe75f..cae2c4466 100644 --- a/src/core/hle/service/vi/vi.cpp +++ b/src/core/hle/service/vi/vi.cpp @@ -9,7 +9,7 @@ #include "core/core_timing.h" #include "core/hle/ipc_helpers.h" #include "core/hle/service/nvdrv/devices/nvdisp_disp0.h" -#include "core/hle/service/nvdrv/nvdrv_a.h" +#include "core/hle/service/nvdrv/nvdrv.h" #include "core/hle/service/vi/vi.h" #include "core/hle/service/vi/vi_m.h" #include "video_core/renderer_base.h" @@ -361,7 +361,7 @@ public: static const FunctionInfo functions[] = { {0, &IHOSBinderDriver::TransactParcel, "TransactParcel"}, {1, &IHOSBinderDriver::AdjustRefcount, "AdjustRefcount"}, - {2, nullptr, "GetNativeHandle"}, + {2, &IHOSBinderDriver::GetNativeHandle, "GetNativeHandle"}, {3, nullptr, "TransactParcelAuto"}, }; RegisterHandlers(functions); @@ -463,6 +463,21 @@ private: rb.Push(RESULT_SUCCESS); } + void GetNativeHandle(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + u32 id = rp.Pop<u32>(); + u32 unknown = rp.Pop<u32>(); + + auto buffer_queue = nv_flinger->GetBufferQueue(id); + + // TODO(Subv): Find out what this actually is. + + LOG_WARNING(Service, "(STUBBED) called id=%u, unknown=%08X", id, unknown); + IPC::RequestBuilder rb{ctx, 2, 1}; + rb.Push(RESULT_SUCCESS); + rb.PushCopyObjects(buffer_queue->GetNativeHandle()); + } + std::shared_ptr<NVFlinger> nv_flinger; }; @@ -565,6 +580,15 @@ void IApplicationDisplayService::GetManagerDisplayService(Kernel::HLERequestCont rb.PushIpcInterface<IManagerDisplayService>(nv_flinger); } +void IApplicationDisplayService::GetIndirectDisplayTransactionService( + Kernel::HLERequestContext& ctx) { + LOG_WARNING(Service, "(STUBBED) called"); + + IPC::RequestBuilder rb{ctx, 2, 0, 0, 1}; + rb.Push(RESULT_SUCCESS); + rb.PushIpcInterface<IHOSBinderDriver>(nv_flinger); +} + void IApplicationDisplayService::OpenDisplay(Kernel::HLERequestContext& ctx) { LOG_WARNING(Service, "(STUBBED) called"); IPC::RequestParser rp{ctx}; @@ -580,6 +604,15 @@ void IApplicationDisplayService::OpenDisplay(Kernel::HLERequestContext& ctx) { rb.Push<u64>(nv_flinger->OpenDisplay(name)); } +void IApplicationDisplayService::CloseDisplay(Kernel::HLERequestContext& ctx) { + LOG_WARNING(Service, "(STUBBED) called"); + IPC::RequestParser rp{ctx}; + u64 display_id = rp.Pop<u64>(); + + IPC::RequestBuilder rb = rp.MakeBuilder(4, 0, 0, 0); + rb.Push(RESULT_SUCCESS); +} + void IApplicationDisplayService::OpenLayer(Kernel::HLERequestContext& ctx) { LOG_WARNING(Service, "(STUBBED) called"); IPC::RequestParser rp{ctx}; @@ -605,6 +638,40 @@ void IApplicationDisplayService::OpenLayer(Kernel::HLERequestContext& ctx) { rb.Push<u64>(data.size()); } +void IApplicationDisplayService::CreateStrayLayer(Kernel::HLERequestContext& ctx) { + LOG_WARNING(Service, "(STUBBED) called"); + + IPC::RequestParser rp{ctx}; + u32 flags = rp.Pop<u32>(); + u64 display_id = rp.Pop<u64>(); + + auto& buffer = ctx.BufferDescriptorB()[0]; + + // TODO(Subv): What's the difference between a Stray and a Managed layer? + + u64 layer_id = nv_flinger->CreateLayer(display_id); + u32 buffer_queue_id = nv_flinger->GetBufferQueueId(display_id, layer_id); + + NativeWindow native_window{buffer_queue_id}; + auto data = native_window.Serialize(); + Memory::WriteBlock(buffer.Address(), data.data(), data.size()); + + IPC::RequestBuilder rb = rp.MakeBuilder(6, 0, 0, 0); + rb.Push(RESULT_SUCCESS); + rb.Push(layer_id); + rb.Push<u64>(data.size()); +} + +void IApplicationDisplayService::DestroyStrayLayer(Kernel::HLERequestContext& ctx) { + LOG_WARNING(Service, "(STUBBED) called"); + + IPC::RequestParser rp{ctx}; + u64 layer_id = rp.Pop<u64>(); + + IPC::RequestBuilder rb = rp.MakeBuilder(2, 0, 0, 0); + rb.Push(RESULT_SUCCESS); +} + void IApplicationDisplayService::SetLayerScalingMode(Kernel::HLERequestContext& ctx) { LOG_WARNING(Service, "(STUBBED) called"); IPC::RequestParser rp{ctx}; @@ -633,11 +700,15 @@ IApplicationDisplayService::IApplicationDisplayService(std::shared_ptr<NVFlinger {100, &IApplicationDisplayService::GetRelayService, "GetRelayService"}, {101, &IApplicationDisplayService::GetSystemDisplayService, "GetSystemDisplayService"}, {102, &IApplicationDisplayService::GetManagerDisplayService, "GetManagerDisplayService"}, - {103, nullptr, "GetIndirectDisplayTransactionService"}, + {103, &IApplicationDisplayService::GetIndirectDisplayTransactionService, + "GetIndirectDisplayTransactionService"}, {1000, nullptr, "ListDisplays"}, {1010, &IApplicationDisplayService::OpenDisplay, "OpenDisplay"}, + {1020, &IApplicationDisplayService::CloseDisplay, "CloseDisplay"}, {2101, &IApplicationDisplayService::SetLayerScalingMode, "SetLayerScalingMode"}, {2020, &IApplicationDisplayService::OpenLayer, "OpenLayer"}, + {2030, &IApplicationDisplayService::CreateStrayLayer, "CreateStrayLayer"}, + {2031, &IApplicationDisplayService::DestroyStrayLayer, "DestroyStrayLayer"}, {5202, &IApplicationDisplayService::GetDisplayVsyncEvent, "GetDisplayVsyncEvent"}, }; RegisterHandlers(functions); @@ -763,12 +834,12 @@ void NVFlinger::Compose() { auto& igbp_buffer = buffer->igbp_buffer; // Now send the buffer to the GPU for drawing. - auto nvdrv = NVDRV::nvdrv_a.lock(); + auto nvdrv = Nvidia::nvdrv.lock(); ASSERT(nvdrv); // TODO(Subv): Support more than just disp0. The display device selection is probably based // on which display we're drawing (Default, Internal, External, etc) - auto nvdisp = nvdrv->GetDevice<NVDRV::Devices::nvdisp_disp0>("/dev/nvdisp_disp0"); + auto nvdisp = nvdrv->GetDevice<Nvidia::Devices::nvdisp_disp0>("/dev/nvdisp_disp0"); ASSERT(nvdisp); nvdisp->flip(igbp_buffer.gpu_buffer_id, igbp_buffer.offset, igbp_buffer.format, @@ -778,7 +849,9 @@ void NVFlinger::Compose() { } } -BufferQueue::BufferQueue(u32 id, u64 layer_id) : id(id), layer_id(layer_id) {} +BufferQueue::BufferQueue(u32 id, u64 layer_id) : id(id), layer_id(layer_id) { + native_handle = Kernel::Event::Create(Kernel::ResetType::OneShot, "BufferQueue NativeHandle"); +} void BufferQueue::SetPreallocatedBuffer(u32 slot, IGBPBuffer& igbp_buffer) { Buffer buffer{}; diff --git a/src/core/hle/service/vi/vi.h b/src/core/hle/service/vi/vi.h index 10e894f8c..81d4f3daa 100644 --- a/src/core/hle/service/vi/vi.h +++ b/src/core/hle/service/vi/vi.h @@ -59,11 +59,16 @@ public: return id; } + Kernel::SharedPtr<Kernel::Event> GetNativeHandle() const { + return native_handle; + } + private: u32 id; u64 layer_id; std::vector<Buffer> queue; + Kernel::SharedPtr<Kernel::Event> native_handle; }; struct Layer { @@ -138,9 +143,13 @@ private: void GetRelayService(Kernel::HLERequestContext& ctx); void GetSystemDisplayService(Kernel::HLERequestContext& ctx); void GetManagerDisplayService(Kernel::HLERequestContext& ctx); + void GetIndirectDisplayTransactionService(Kernel::HLERequestContext& ctx); void OpenDisplay(Kernel::HLERequestContext& ctx); + void CloseDisplay(Kernel::HLERequestContext& ctx); void SetLayerScalingMode(Kernel::HLERequestContext& ctx); void OpenLayer(Kernel::HLERequestContext& ctx); + void CreateStrayLayer(Kernel::HLERequestContext& ctx); + void DestroyStrayLayer(Kernel::HLERequestContext& ctx); void GetDisplayVsyncEvent(Kernel::HLERequestContext& ctx); std::shared_ptr<NVFlinger> nv_flinger; diff --git a/src/core/loader/linker.cpp b/src/core/loader/linker.cpp index f82c6f4b4..87cc65e91 100644 --- a/src/core/loader/linker.cpp +++ b/src/core/loader/linker.cpp @@ -48,9 +48,9 @@ struct Elf64_Sym { }; static_assert(sizeof(Elf64_Sym) == 0x18, "Elf64_Sym has incorrect size."); -void Linker::WriteRelocations(std::vector<u8>& program_image, - const std::vector<Symbol>& symbols, u64 relocation_offset, - u64 size, bool is_jump_relocation, VAddr load_base) { +void Linker::WriteRelocations(std::vector<u8>& program_image, const std::vector<Symbol>& symbols, + u64 relocation_offset, u64 size, bool is_jump_relocation, + VAddr load_base) { for (u64 i = 0; i < size; i += sizeof(Elf64_Rela)) { Elf64_Rela rela; std::memcpy(&rela, &program_image[relocation_offset + i], sizeof(Elf64_Rela)); @@ -90,8 +90,7 @@ void Linker::WriteRelocations(std::vector<u8>& program_image, } } -void Linker::Relocate(std::vector<u8>& program_image, u32 dynamic_section_offset, - VAddr load_base) { +void Linker::Relocate(std::vector<u8>& program_image, u32 dynamic_section_offset, VAddr load_base) { std::map<u64, u64> dynamic; while (dynamic_section_offset < program_image.size()) { Elf64_Dyn dyn; @@ -141,8 +140,7 @@ void Linker::ResolveImports() { const auto& search = exports.find(import.first); if (search != exports.end()) { Memory::Write64(import.second.ea, search->second + import.second.addend); - } - else { + } else { LOG_ERROR(Loader, "Unresolved import: %s", import.first.c_str()); } } diff --git a/src/core/loader/nso.cpp b/src/core/loader/nso.cpp index 7e1953701..ff96e129b 100644 --- a/src/core/loader/nso.cpp +++ b/src/core/loader/nso.cpp @@ -19,7 +19,10 @@ struct NsoSegmentHeader { u32_le offset; u32_le location; u32_le size; - u32_le alignment; + union { + u32_le alignment; + u32_le bss_size; + }; }; static_assert(sizeof(NsoSegmentHeader) == 0x10, "NsoSegmentHeader has incorrect size."); @@ -120,14 +123,15 @@ VAddr AppLoader_NSO::LoadNso(const std::string& path, VAddr load_base, bool relo // Read MOD header ModHeader mod_header{}; - u32 bss_size{Memory::PAGE_SIZE}; // Default .bss to page size if MOD0 section doesn't exist + // Default .bss to size in segment header if MOD0 section doesn't exist + u32 bss_size{PageAlignSize(nso_header.segments[2].bss_size)}; std::memcpy(&mod_header, program_image.data() + module_offset, sizeof(ModHeader)); const bool has_mod_header{mod_header.magic == Common::MakeMagic('M', 'O', 'D', '0')}; if (has_mod_header) { // Resize program image to include .bss section and page align each section bss_size = PageAlignSize(mod_header.bss_end_offset - mod_header.bss_start_offset); - codeset->data.size += bss_size; } + codeset->data.size += bss_size; const u32 image_size{PageAlignSize(static_cast<u32>(program_image.size()) + bss_size)}; program_image.resize(image_size); @@ -157,7 +161,8 @@ ResultStatus AppLoader_NSO::Load(Kernel::SharedPtr<Kernel::Process>& process) { // Load NSO modules VAddr next_load_addr{Memory::PROCESS_IMAGE_VADDR}; - for (const auto& module : {"rtld", "sdk", "subsdk0", "subsdk1", "subsdk2", "subsdk3", "subsdk4"}) { + for (const auto& module : + {"rtld", "sdk", "subsdk0", "subsdk1", "subsdk2", "subsdk3", "subsdk4"}) { const std::string path = filepath.substr(0, filepath.find_last_of("/\\")) + "/" + module; const VAddr load_addr = next_load_addr; next_load_addr = LoadNso(path, load_addr); diff --git a/src/core/loader/nso.h b/src/core/loader/nso.h index 28df00384..03424e70d 100644 --- a/src/core/loader/nso.h +++ b/src/core/loader/nso.h @@ -18,8 +18,7 @@ namespace Loader { class AppLoader_NSO final : public AppLoader, Linker { public: AppLoader_NSO(FileUtil::IOFile&& file, std::string filepath) - : AppLoader(std::move(file)), filepath(std::move(filepath)) { - } + : AppLoader(std::move(file)), filepath(std::move(filepath)) {} /** * Returns the type of the file diff --git a/src/core/memory.h b/src/core/memory.h index 91bd4d889..7e554f394 100644 --- a/src/core/memory.h +++ b/src/core/memory.h @@ -136,7 +136,7 @@ enum : VAddr { /// Application heap (includes stack). HEAP_VADDR = 0x108000000, - HEAP_SIZE = 0x18000000, + HEAP_SIZE = 0xF0000000, HEAP_VADDR_END = HEAP_VADDR + HEAP_SIZE, /// Area where shared memory buffers are mapped onto. @@ -177,7 +177,7 @@ enum : VAddr { SHARED_PAGE_VADDR_END = SHARED_PAGE_VADDR + SHARED_PAGE_SIZE, /// Area where TLS (Thread-Local Storage) buffers are allocated. - TLS_AREA_VADDR = 0x1FF82000, + TLS_AREA_VADDR = 0x228000000, TLS_ENTRY_SIZE = 0x200, /// Equivalent to LINEAR_HEAP_VADDR, but expanded to cover the extra memory in the New 3DS. diff --git a/src/input_common/main.cpp b/src/input_common/main.cpp index 557353740..95d40f09f 100644 --- a/src/input_common/main.cpp +++ b/src/input_common/main.cpp @@ -71,4 +71,15 @@ std::string GenerateAnalogParamFromKeys(int key_up, int key_down, int key_left, return circle_pad_param.Serialize(); } +namespace Polling { + +std::vector<std::unique_ptr<DevicePoller>> GetPollers(DeviceType type) { +#ifdef HAVE_SDL2 + return SDL::Polling::GetPollers(type); +#else + return {}; +#endif +} + +} // namespace Polling } // namespace InputCommon diff --git a/src/input_common/main.h b/src/input_common/main.h index 5604f0fa8..77a0ce90b 100644 --- a/src/input_common/main.h +++ b/src/input_common/main.h @@ -4,7 +4,13 @@ #pragma once +#include <memory> #include <string> +#include <vector> + +namespace Common { +class ParamPackage; +} namespace InputCommon { @@ -31,4 +37,30 @@ std::string GenerateKeyboardParam(int key_code); std::string GenerateAnalogParamFromKeys(int key_up, int key_down, int key_left, int key_right, int key_modifier, float modifier_scale); +namespace Polling { + +enum class DeviceType { Button, Analog }; + +/** + * A class that can be used to get inputs from an input device like controllers without having to + * poll the device's status yourself + */ +class DevicePoller { +public: + virtual ~DevicePoller() = default; + /// Setup and start polling for inputs, should be called before GetNextInput + virtual void Start() = 0; + /// Stop polling + virtual void Stop() = 0; + /** + * Every call to this function returns the next input recorded since calling Start + * @return A ParamPackage of the recorded input, which can be used to create an InputDevice. + * If there has been no input, the package is empty + */ + virtual Common::ParamPackage GetNextInput() = 0; +}; + +// Get all DevicePoller from all backends for a specific device type +std::vector<std::unique_ptr<DevicePoller>> GetPollers(DeviceType type); +} // namespace Polling } // namespace InputCommon diff --git a/src/input_common/sdl/sdl.cpp b/src/input_common/sdl/sdl.cpp index d404afa89..88b557c5d 100644 --- a/src/input_common/sdl/sdl.cpp +++ b/src/input_common/sdl/sdl.cpp @@ -3,13 +3,15 @@ // Refer to the license.txt file included. #include <cmath> -#include <memory> #include <string> #include <tuple> #include <unordered_map> +#include <utility> #include <SDL.h> #include "common/logging/log.h" #include "common/math_util.h" +#include "common/param_package.h" +#include "input_common/main.h" #include "input_common/sdl/sdl.h" namespace InputCommon { @@ -69,6 +71,10 @@ public: return (SDL_JoystickGetHat(joystick.get(), hat) & direction) != 0; } + SDL_JoystickID GetJoystickID() const { + return SDL_JoystickInstanceID(joystick.get()); + } + private: std::unique_ptr<SDL_Joystick, decltype(&SDL_JoystickClose)> joystick; }; @@ -247,5 +253,180 @@ void Shutdown() { } } +/** + * This function converts a joystick ID used in SDL events to the device index. This is necessary + * because Citra opens joysticks using their indices, not their IDs. + */ +static int JoystickIDToDeviceIndex(SDL_JoystickID id) { + int num_joysticks = SDL_NumJoysticks(); + for (int i = 0; i < num_joysticks; i++) { + auto joystick = GetJoystick(i); + if (joystick->GetJoystickID() == id) { + return i; + } + } + return -1; +} + +Common::ParamPackage SDLEventToButtonParamPackage(const SDL_Event& event) { + Common::ParamPackage params({{"engine", "sdl"}}); + switch (event.type) { + case SDL_JOYAXISMOTION: + params.Set("joystick", JoystickIDToDeviceIndex(event.jaxis.which)); + params.Set("axis", event.jaxis.axis); + if (event.jaxis.value > 0) { + params.Set("direction", "+"); + params.Set("threshold", "0.5"); + } else { + params.Set("direction", "-"); + params.Set("threshold", "-0.5"); + } + break; + case SDL_JOYBUTTONUP: + params.Set("joystick", JoystickIDToDeviceIndex(event.jbutton.which)); + params.Set("button", event.jbutton.button); + break; + case SDL_JOYHATMOTION: + params.Set("joystick", JoystickIDToDeviceIndex(event.jhat.which)); + params.Set("hat", event.jhat.hat); + switch (event.jhat.value) { + case SDL_HAT_UP: + params.Set("direction", "up"); + break; + case SDL_HAT_DOWN: + params.Set("direction", "down"); + break; + case SDL_HAT_LEFT: + params.Set("direction", "left"); + break; + case SDL_HAT_RIGHT: + params.Set("direction", "right"); + break; + default: + return {}; + } + break; + } + return params; +} + +namespace Polling { + +class SDLPoller : public InputCommon::Polling::DevicePoller { +public: + SDLPoller() = default; + + ~SDLPoller() = default; + + void Start() override { + // SDL joysticks must be opened, otherwise they don't generate events + SDL_JoystickUpdate(); + int num_joysticks = SDL_NumJoysticks(); + for (int i = 0; i < num_joysticks; i++) { + joysticks_opened.emplace_back(GetJoystick(i)); + } + // Empty event queue to get rid of old events. citra-qt doesn't use the queue + SDL_Event dummy; + while (SDL_PollEvent(&dummy)) { + } + } + + void Stop() override { + joysticks_opened.clear(); + } + +private: + std::vector<std::shared_ptr<SDLJoystick>> joysticks_opened; +}; + +class SDLButtonPoller final : public SDLPoller { +public: + SDLButtonPoller() = default; + + ~SDLButtonPoller() = default; + + Common::ParamPackage GetNextInput() override { + SDL_Event event; + while (SDL_PollEvent(&event)) { + switch (event.type) { + case SDL_JOYAXISMOTION: + if (std::abs(event.jaxis.value / 32767.0) < 0.5) { + break; + } + case SDL_JOYBUTTONUP: + case SDL_JOYHATMOTION: + return SDLEventToButtonParamPackage(event); + } + } + return {}; + } +}; + +class SDLAnalogPoller final : public SDLPoller { +public: + SDLAnalogPoller() = default; + + ~SDLAnalogPoller() = default; + + void Start() override { + SDLPoller::Start(); + + // Reset stored axes + analog_xaxis = -1; + analog_yaxis = -1; + analog_axes_joystick = -1; + } + + Common::ParamPackage GetNextInput() override { + SDL_Event event; + while (SDL_PollEvent(&event)) { + if (event.type != SDL_JOYAXISMOTION || std::abs(event.jaxis.value / 32767.0) < 0.5) { + continue; + } + // An analog device needs two axes, so we need to store the axis for later and wait for + // a second SDL event. The axes also must be from the same joystick. + int axis = event.jaxis.axis; + if (analog_xaxis == -1) { + analog_xaxis = axis; + analog_axes_joystick = event.jaxis.which; + } else if (analog_yaxis == -1 && analog_xaxis != axis && + analog_axes_joystick == event.jaxis.which) { + analog_yaxis = axis; + } + } + Common::ParamPackage params; + if (analog_xaxis != -1 && analog_yaxis != -1) { + params.Set("engine", "sdl"); + params.Set("joystick", JoystickIDToDeviceIndex(analog_axes_joystick)); + params.Set("axis_x", analog_xaxis); + params.Set("axis_y", analog_yaxis); + analog_xaxis = -1; + analog_yaxis = -1; + analog_axes_joystick = -1; + return params; + } + return params; + } + +private: + int analog_xaxis = -1; + int analog_yaxis = -1; + SDL_JoystickID analog_axes_joystick = -1; +}; + +std::vector<std::unique_ptr<InputCommon::Polling::DevicePoller>> GetPollers( + InputCommon::Polling::DeviceType type) { + std::vector<std::unique_ptr<InputCommon::Polling::DevicePoller>> pollers; + switch (type) { + case InputCommon::Polling::DeviceType::Analog: + pollers.push_back(std::make_unique<SDLAnalogPoller>()); + break; + case InputCommon::Polling::DeviceType::Button: + pollers.push_back(std::make_unique<SDLButtonPoller>()); + break; + } + return std::move(pollers); +} +} // namespace Polling } // namespace SDL } // namespace InputCommon diff --git a/src/input_common/sdl/sdl.h b/src/input_common/sdl/sdl.h index 3e72debcc..7934099d4 100644 --- a/src/input_common/sdl/sdl.h +++ b/src/input_common/sdl/sdl.h @@ -4,8 +4,21 @@ #pragma once +#include <memory> +#include <vector> #include "core/frontend/input.h" +union SDL_Event; +namespace Common { +class ParamPackage; +} +namespace InputCommon { +namespace Polling { +class DevicePoller; +enum class DeviceType; +} // namespace Polling +} // namespace InputCommon + namespace InputCommon { namespace SDL { @@ -15,5 +28,15 @@ void Init(); /// Unresisters SDL device factories and shut them down. void Shutdown(); +/// Creates a ParamPackage from an SDL_Event that can directly be used to create a ButtonDevice +Common::ParamPackage SDLEventToButtonParamPackage(const SDL_Event& event); + +namespace Polling { + +/// Get all DevicePoller that use the SDL backend for a specific device type +std::vector<std::unique_ptr<InputCommon::Polling::DevicePoller>> GetPollers( + InputCommon::Polling::DeviceType type); + +} // namespace Polling } // namespace SDL } // namespace InputCommon diff --git a/src/video_core/renderer_opengl/renderer_opengl.h b/src/video_core/renderer_opengl/renderer_opengl.h index dd01e1b1a..db6c355a5 100644 --- a/src/video_core/renderer_opengl/renderer_opengl.h +++ b/src/video_core/renderer_opengl/renderer_opengl.h @@ -61,7 +61,8 @@ private: // Loads framebuffer from emulated memory into the display information structure void LoadFBToScreenInfo(const FramebufferInfo& framebuffer_info, ScreenInfo& screen_info); // Fills active OpenGL texture with the given RGBA color. - void LoadColorToActiveGLTexture(u8 color_r, u8 color_g, u8 color_b, u8 color_a, const TextureInfo& texture); + void LoadColorToActiveGLTexture(u8 color_r, u8 color_g, u8 color_b, u8 color_a, + const TextureInfo& texture); EmuWindow* render_window; ///< Handle to render window diff --git a/src/yuzu/about_dialog.cpp b/src/yuzu/about_dialog.cpp index 0f1b6cdc6..da3429822 100644 --- a/src/yuzu/about_dialog.cpp +++ b/src/yuzu/about_dialog.cpp @@ -9,7 +9,7 @@ AboutDialog::AboutDialog(QWidget* parent) : QDialog(parent), ui(new Ui::AboutDialog) { ui->setupUi(this); ui->labelBuildInfo->setText(ui->labelBuildInfo->text().arg( -Common::g_build_name, Common::g_scm_branch, Common::g_scm_desc)); + Common::g_build_name, Common::g_scm_branch, Common::g_scm_desc)); } AboutDialog::~AboutDialog() {} diff --git a/src/yuzu/bootmanager.cpp b/src/yuzu/bootmanager.cpp index a1e0cf575..843ac6ad7 100644 --- a/src/yuzu/bootmanager.cpp +++ b/src/yuzu/bootmanager.cpp @@ -40,6 +40,7 @@ void EmuThread::run() { Core::System::ResultStatus result = Core::System::GetInstance().RunLoop(); if (result != Core::System::ResultStatus::Success) { + this->SetRunning(false); emit ErrorThrown(result, Core::System::GetInstance().GetStatusDetails()); } diff --git a/src/yuzu/configuration/config.cpp b/src/yuzu/configuration/config.cpp index ab6ba0ec9..6a40f035c 100644 --- a/src/yuzu/configuration/config.cpp +++ b/src/yuzu/configuration/config.cpp @@ -18,10 +18,10 @@ Config::Config() { } const std::array<int, Settings::NativeButton::NumButtons> Config::default_buttons = { - Qt::Key_A, Qt::Key_S, Qt::Key_Z, Qt::Key_X, Qt::Key_3, Qt::Key_4, Qt::Key_Q, Qt::Key_W, - Qt::Key_1, Qt::Key_2, Qt::Key_N, Qt::Key_M, Qt::Key_F, Qt::Key_T, Qt::Key_H, Qt::Key_G, - Qt::Key_Left, Qt::Key_Up, Qt::Key_Right, Qt::Key_Down, Qt::Key_J, Qt::Key_I, Qt::Key_L, - Qt::Key_K, Qt::Key_D, Qt::Key_C, Qt::Key_B, Qt::Key_V, + Qt::Key_A, Qt::Key_S, Qt::Key_Z, Qt::Key_X, Qt::Key_3, Qt::Key_4, Qt::Key_Q, + Qt::Key_W, Qt::Key_1, Qt::Key_2, Qt::Key_N, Qt::Key_M, Qt::Key_F, Qt::Key_T, + Qt::Key_H, Qt::Key_G, Qt::Key_Left, Qt::Key_Up, Qt::Key_Right, Qt::Key_Down, Qt::Key_J, + Qt::Key_I, Qt::Key_L, Qt::Key_K, Qt::Key_D, Qt::Key_C, Qt::Key_B, Qt::Key_V, }; const std::array<std::array<int, 5>, Settings::NativeAnalog::NumAnalogs> Config::default_analogs{{ @@ -137,6 +137,7 @@ void Config::ReadValues() { qt_config->endGroup(); UISettings::values.single_window_mode = qt_config->value("singleWindowMode", true).toBool(); + UISettings::values.fullscreen = qt_config->value("fullscreen", false).toBool(); UISettings::values.display_titlebar = qt_config->value("displayTitleBars", true).toBool(); UISettings::values.show_filter_bar = qt_config->value("showFilterBar", true).toBool(); UISettings::values.show_status_bar = qt_config->value("showStatusBar", true).toBool(); @@ -216,6 +217,7 @@ void Config::SaveValues() { qt_config->endGroup(); qt_config->setValue("singleWindowMode", UISettings::values.single_window_mode); + qt_config->setValue("fullscreen", UISettings::values.fullscreen); qt_config->setValue("displayTitleBars", UISettings::values.display_titlebar); qt_config->setValue("showFilterBar", UISettings::values.show_filter_bar); qt_config->setValue("showStatusBar", UISettings::values.show_status_bar); diff --git a/src/yuzu/configuration/configure_debug.cpp b/src/yuzu/configuration/configure_debug.cpp index 9eb71c593..a45edd510 100644 --- a/src/yuzu/configuration/configure_debug.cpp +++ b/src/yuzu/configuration/configure_debug.cpp @@ -6,7 +6,6 @@ #include "ui_configure_debug.h" #include "yuzu/configuration/configure_debug.h" - ConfigureDebug::ConfigureDebug(QWidget* parent) : QWidget(parent), ui(new Ui::ConfigureDebug) { ui->setupUi(this); this->setConfiguration(); diff --git a/src/yuzu/configuration/configure_debug.ui b/src/yuzu/configuration/configure_debug.ui index 96638ebdb..a10bea2f4 100644 --- a/src/yuzu/configuration/configure_debug.ui +++ b/src/yuzu/configuration/configure_debug.ui @@ -13,24 +13,24 @@ <property name="windowTitle"> <string>Form</string> </property> - <layout class="QVBoxLayout" name="verticalLayout"> + <layout class="QVBoxLayout" name="verticalLayout_1"> <item> - <layout class="QVBoxLayout" name="verticalLayout_3"> + <layout class="QVBoxLayout" name="verticalLayout_2"> <item> <widget class="QGroupBox" name="groupBox"> <property name="title"> <string>GDB</string> </property> - <layout class="QVBoxLayout" name="verticalLayout_2"> + <layout class="QVBoxLayout" name="verticalLayout_3"> <item> - <widget class="QLabel"> + <widget class="QLabel" name="label_1"> <property name="text"> <string>The GDB Stub only works correctly when the CPU JIT is off.</string> </property> </widget> </item> <item> - <layout class="QHBoxLayout" name="horizontalLayout_3"> + <layout class="QHBoxLayout" name="horizontalLayout_1"> <item> <widget class="QCheckBox" name="toggle_gdbstub"> <property name="text"> @@ -52,7 +52,7 @@ </spacer> </item> <item> - <widget class="QLabel" name="label"> + <widget class="QLabel" name="label_2"> <property name="text"> <string>Port:</string> </property> diff --git a/src/yuzu/configuration/configure_dialog.cpp b/src/yuzu/configuration/configure_dialog.cpp index 23e5687d0..358f33005 100644 --- a/src/yuzu/configuration/configure_dialog.cpp +++ b/src/yuzu/configuration/configure_dialog.cpp @@ -7,7 +7,6 @@ #include "yuzu/configuration/config.h" #include "yuzu/configuration/configure_dialog.h" - ConfigureDialog::ConfigureDialog(QWidget* parent) : QDialog(parent), ui(new Ui::ConfigureDialog) { ui->setupUi(this); this->setConfiguration(); diff --git a/src/yuzu/configuration/configure_input.cpp b/src/yuzu/configuration/configure_input.cpp index d92a1fed9..10043e6e8 100644 --- a/src/yuzu/configuration/configure_input.cpp +++ b/src/yuzu/configuration/configure_input.cpp @@ -5,13 +5,13 @@ #include <algorithm> #include <memory> #include <utility> +#include <QMessageBox> #include <QTimer> #include "common/param_package.h" #include "input_common/main.h" #include "yuzu/configuration/config.h" #include "yuzu/configuration/configure_input.h" - const std::array<std::string, ConfigureInput::ANALOG_SUB_BUTTONS_NUM> ConfigureInput::analog_sub_buttons{{ "up", "down", "left", "right", "modifier", @@ -32,38 +32,80 @@ static QString getKeyName(int key_code) { } } -static void SetButtonKey(int key, Common::ParamPackage& button_param) { - button_param = Common::ParamPackage{InputCommon::GenerateKeyboardParam(key)}; -} - -static void SetAnalogKey(int key, Common::ParamPackage& analog_param, - const std::string& button_name) { +static void SetAnalogButton(const Common::ParamPackage& input_param, + Common::ParamPackage& analog_param, const std::string& button_name) { if (analog_param.Get("engine", "") != "analog_from_button") { analog_param = { {"engine", "analog_from_button"}, {"modifier_scale", "0.5"}, }; } - analog_param.Set(button_name, InputCommon::GenerateKeyboardParam(key)); + analog_param.Set(button_name, input_param.Serialize()); } +static QString ButtonToText(const Common::ParamPackage& param) { + if (!param.Has("engine")) { + return QObject::tr("[not set]"); + } else if (param.Get("engine", "") == "keyboard") { + return getKeyName(param.Get("code", 0)); + } else if (param.Get("engine", "") == "sdl") { + QString text = QString(QObject::tr("Joystick %1")).arg(param.Get("joystick", "").c_str()); + if (param.Has("hat")) { + text += QString(QObject::tr(" Hat %1 %2")) + .arg(param.Get("hat", "").c_str(), param.Get("direction", "").c_str()); + } + if (param.Has("axis")) { + text += QString(QObject::tr(" Axis %1%2")) + .arg(param.Get("axis", "").c_str(), param.Get("direction", "").c_str()); + } + if (param.Has("button")) { + text += QString(QObject::tr(" Button %1")).arg(param.Get("button", "").c_str()); + } + return text; + } else { + return QObject::tr("[unknown]"); + } +}; + +static QString AnalogToText(const Common::ParamPackage& param, const std::string& dir) { + if (!param.Has("engine")) { + return QObject::tr("[not set]"); + } else if (param.Get("engine", "") == "analog_from_button") { + return ButtonToText(Common::ParamPackage{param.Get(dir, "")}); + } else if (param.Get("engine", "") == "sdl") { + if (dir == "modifier") { + return QString(QObject::tr("[unused]")); + } + + QString text = QString(QObject::tr("Joystick %1")).arg(param.Get("joystick", "").c_str()); + if (dir == "left" || dir == "right") { + text += QString(QObject::tr(" Axis %1")).arg(param.Get("axis_x", "").c_str()); + } else if (dir == "up" || dir == "down") { + text += QString(QObject::tr(" Axis %1")).arg(param.Get("axis_y", "").c_str()); + } + return text; + } else { + return QObject::tr("[unknown]"); + } +}; + ConfigureInput::ConfigureInput(QWidget* parent) : QWidget(parent), ui(std::make_unique<Ui::ConfigureInput>()), - timer(std::make_unique<QTimer>()) { + timeout_timer(std::make_unique<QTimer>()), poll_timer(std::make_unique<QTimer>()) { ui->setupUi(this); setFocusPolicy(Qt::ClickFocus); button_map = { - ui->buttonA, ui->buttonB, ui->buttonX, ui->buttonY, - ui->buttonLStick, ui->buttonRStick, ui->buttonL, ui->buttonR, - ui->buttonZL, ui->buttonZR, ui->buttonPlus, ui->buttonMinus, - ui->buttonDpadLeft, ui->buttonDpadUp, ui->buttonDpadRight, ui->buttonDpadDown, - ui->buttonLStickLeft, ui->buttonLStickUp, ui->buttonLStickRight, ui->buttonLStickDown, - ui->buttonRStickLeft, ui->buttonRStickUp, ui->buttonRStickRight, ui->buttonRStickDown, - ui->buttonSL, ui->buttonSR, ui->buttonHome, ui->buttonScreenshot, + ui->buttonA, ui->buttonB, ui->buttonX, ui->buttonY, + ui->buttonLStick, ui->buttonRStick, ui->buttonL, ui->buttonR, + ui->buttonZL, ui->buttonZR, ui->buttonPlus, ui->buttonMinus, + ui->buttonDpadLeft, ui->buttonDpadUp, ui->buttonDpadRight, ui->buttonDpadDown, + ui->buttonLStickLeft, ui->buttonLStickUp, ui->buttonLStickRight, ui->buttonLStickDown, + ui->buttonRStickLeft, ui->buttonRStickUp, ui->buttonRStickRight, ui->buttonRStickDown, + ui->buttonSL, ui->buttonSR, ui->buttonHome, ui->buttonScreenshot, }; - analog_map = {{ + analog_map_buttons = {{ { ui->buttonLStickUp, ui->buttonLStickDown, ui->buttonLStickLeft, ui->buttonLStickRight, ui->buttonLStickMod, @@ -74,35 +116,57 @@ ConfigureInput::ConfigureInput(QWidget* parent) }, }}; + analog_map_stick = {ui->buttonLStickAnalog, ui->buttonRStickAnalog}; + for (int button_id = 0; button_id < Settings::NativeButton::NumButtons; button_id++) { if (button_map[button_id]) connect(button_map[button_id], &QPushButton::released, [=]() { - handleClick(button_map[button_id], - [=](int key) { SetButtonKey(key, buttons_param[button_id]); }); + handleClick( + button_map[button_id], + [=](const Common::ParamPackage& params) { buttons_param[button_id] = params; }, + InputCommon::Polling::DeviceType::Button); }); } for (int analog_id = 0; analog_id < Settings::NativeAnalog::NumAnalogs; analog_id++) { for (int sub_button_id = 0; sub_button_id < ANALOG_SUB_BUTTONS_NUM; sub_button_id++) { - if (analog_map[analog_id][sub_button_id] != nullptr) { - connect(analog_map[analog_id][sub_button_id], &QPushButton::released, [=]() { - handleClick(analog_map[analog_id][sub_button_id], [=](int key) { - SetAnalogKey(key, analogs_param[analog_id], - analog_sub_buttons[sub_button_id]); - }); - }); + if (analog_map_buttons[analog_id][sub_button_id] != nullptr) { + connect(analog_map_buttons[analog_id][sub_button_id], &QPushButton::released, + [=]() { + handleClick(analog_map_buttons[analog_id][sub_button_id], + [=](const Common::ParamPackage& params) { + SetAnalogButton(params, analogs_param[analog_id], + analog_sub_buttons[sub_button_id]); + }, + InputCommon::Polling::DeviceType::Button); + }); } } + connect(analog_map_stick[analog_id], &QPushButton::released, [=]() { + QMessageBox::information( + this, "Information", + "After pressing OK, first move your joystick horizontally, and then vertically."); + handleClick( + analog_map_stick[analog_id], + [=](const Common::ParamPackage& params) { analogs_param[analog_id] = params; }, + InputCommon::Polling::DeviceType::Analog); + }); } connect(ui->buttonRestoreDefaults, &QPushButton::released, [this]() { restoreDefaults(); }); - timer->setSingleShot(true); - connect(timer.get(), &QTimer::timeout, [this]() { - releaseKeyboard(); - releaseMouse(); - key_setter = boost::none; - updateButtonLabels(); + timeout_timer->setSingleShot(true); + connect(timeout_timer.get(), &QTimer::timeout, [this]() { setPollingResult({}, true); }); + + connect(poll_timer.get(), &QTimer::timeout, [this]() { + Common::ParamPackage params; + for (auto& poller : device_pollers) { + params = poller->GetNextInput(); + if (params.Has("engine")) { + setPollingResult(params, false); + return; + } + } }); this->loadConfiguration(); @@ -132,13 +196,15 @@ void ConfigureInput::loadConfiguration() { void ConfigureInput::restoreDefaults() { for (int button_id = 0; button_id < Settings::NativeButton::NumButtons; button_id++) { - SetButtonKey(Config::default_buttons[button_id], buttons_param[button_id]); + buttons_param[button_id] = Common::ParamPackage{ + InputCommon::GenerateKeyboardParam(Config::default_buttons[button_id])}; } for (int analog_id = 0; analog_id < Settings::NativeAnalog::NumAnalogs; analog_id++) { for (int sub_button_id = 0; sub_button_id < ANALOG_SUB_BUTTONS_NUM; sub_button_id++) { - SetAnalogKey(Config::default_analogs[analog_id][sub_button_id], - analogs_param[analog_id], analog_sub_buttons[sub_button_id]); + Common::ParamPackage params{InputCommon::GenerateKeyboardParam( + Config::default_analogs[analog_id][sub_button_id])}; + SetAnalogButton(params, analogs_param[analog_id], analog_sub_buttons[sub_button_id]); } } updateButtonLabels(); @@ -146,59 +212,73 @@ void ConfigureInput::restoreDefaults() { } void ConfigureInput::updateButtonLabels() { - QString non_keyboard(tr("[non-keyboard]")); - - auto KeyToText = [&non_keyboard](const Common::ParamPackage& param) { - if (param.Get("engine", "") != "keyboard") { - return non_keyboard; - } else { - return getKeyName(param.Get("code", 0)); - } - }; - for (int button = 0; button < Settings::NativeButton::NumButtons; button++) { - button_map[button]->setText(KeyToText(buttons_param[button])); + button_map[button]->setText(ButtonToText(buttons_param[button])); } for (int analog_id = 0; analog_id < Settings::NativeAnalog::NumAnalogs; analog_id++) { - if (analogs_param[analog_id].Get("engine", "") != "analog_from_button") { - for (QPushButton* button : analog_map[analog_id]) { - if (button) - button->setText(non_keyboard); - } - } else { - for (int sub_button_id = 0; sub_button_id < ANALOG_SUB_BUTTONS_NUM; sub_button_id++) { - Common::ParamPackage param( - analogs_param[analog_id].Get(analog_sub_buttons[sub_button_id], "")); - if (analog_map[analog_id][sub_button_id]) - analog_map[analog_id][sub_button_id]->setText(KeyToText(param)); + for (int sub_button_id = 0; sub_button_id < ANALOG_SUB_BUTTONS_NUM; sub_button_id++) { + if (analog_map_buttons[analog_id][sub_button_id]) { + analog_map_buttons[analog_id][sub_button_id]->setText( + AnalogToText(analogs_param[analog_id], analog_sub_buttons[sub_button_id])); } } + analog_map_stick[analog_id]->setText(tr("Set Analog Stick")); } } -void ConfigureInput::handleClick(QPushButton* button, std::function<void(int)> new_key_setter) { +void ConfigureInput::handleClick(QPushButton* button, + std::function<void(const Common::ParamPackage&)> new_input_setter, + InputCommon::Polling::DeviceType type) { button->setText(tr("[press key]")); button->setFocus(); - key_setter = new_key_setter; + input_setter = new_input_setter; + + device_pollers = InputCommon::Polling::GetPollers(type); + + // Keyboard keys can only be used as button devices + want_keyboard_keys = type == InputCommon::Polling::DeviceType::Button; + + for (auto& poller : device_pollers) { + poller->Start(); + } grabKeyboard(); grabMouse(); - timer->start(5000); // Cancel after 5 seconds + timeout_timer->start(5000); // Cancel after 5 seconds + poll_timer->start(200); // Check for new inputs every 200ms } -void ConfigureInput::keyPressEvent(QKeyEvent* event) { +void ConfigureInput::setPollingResult(const Common::ParamPackage& params, bool abort) { releaseKeyboard(); releaseMouse(); + timeout_timer->stop(); + poll_timer->stop(); + for (auto& poller : device_pollers) { + poller->Stop(); + } - if (!key_setter || !event) - return; - - if (event->key() != Qt::Key_Escape) - (*key_setter)(event->key()); + if (!abort) { + (*input_setter)(params); + } updateButtonLabels(); - key_setter = boost::none; - timer->stop(); + input_setter = boost::none; +} + +void ConfigureInput::keyPressEvent(QKeyEvent* event) { + if (!input_setter || !event) + return; + + if (event->key() != Qt::Key_Escape) { + if (want_keyboard_keys) { + setPollingResult(Common::ParamPackage{InputCommon::GenerateKeyboardParam(event->key())}, + false); + } else { + // Escape key wasn't pressed and we don't want any keyboard keys, so don't stop polling + return; + } + } + setPollingResult({}, true); } diff --git a/src/yuzu/configuration/configure_input.h b/src/yuzu/configuration/configure_input.h index c950fbcb4..a0bef86d5 100644 --- a/src/yuzu/configuration/configure_input.h +++ b/src/yuzu/configuration/configure_input.h @@ -8,11 +8,13 @@ #include <functional> #include <memory> #include <string> +#include <unordered_map> #include <QKeyEvent> #include <QWidget> #include <boost/optional.hpp> #include "common/param_package.h" #include "core/settings.h" +#include "input_common/main.h" #include "ui_configure_input.h" class QPushButton; @@ -35,10 +37,11 @@ public: private: std::unique_ptr<Ui::ConfigureInput> ui; - std::unique_ptr<QTimer> timer; + std::unique_ptr<QTimer> timeout_timer; + std::unique_ptr<QTimer> poll_timer; /// This will be the the setting function when an input is awaiting configuration. - boost::optional<std::function<void(int)>> key_setter; + boost::optional<std::function<void(const Common::ParamPackage&)>> input_setter; std::array<Common::ParamPackage, Settings::NativeButton::NumButtons> buttons_param; std::array<Common::ParamPackage, Settings::NativeAnalog::NumAnalogs> analogs_param; @@ -48,13 +51,23 @@ private: /// Each button input is represented by a QPushButton. std::array<QPushButton*, Settings::NativeButton::NumButtons> button_map; - /// Each analog input is represented by five QPushButtons which represents up, down, left, right - /// and modifier + /// A group of five QPushButtons represent one analog input. The buttons each represent up, + /// down, left, right, and modifier, respectively. std::array<std::array<QPushButton*, ANALOG_SUB_BUTTONS_NUM>, Settings::NativeAnalog::NumAnalogs> - analog_map; + analog_map_buttons; + + /// Analog inputs are also represented each with a single button, used to configure with an + /// actual analog stick + std::array<QPushButton*, Settings::NativeAnalog::NumAnalogs> analog_map_stick; static const std::array<std::string, ANALOG_SUB_BUTTONS_NUM> analog_sub_buttons; + std::vector<std::unique_ptr<InputCommon::Polling::DevicePoller>> device_pollers; + + /// A flag to indicate if keyboard keys are okay when configuring an input. If this is false, + /// keyboard events are ignored. + bool want_keyboard_keys = false; + /// Load configuration settings. void loadConfiguration(); /// Restore all buttons to their default values. @@ -63,7 +76,13 @@ private: void updateButtonLabels(); /// Called when the button was pressed. - void handleClick(QPushButton* button, std::function<void(int)> new_key_setter); + void handleClick(QPushButton* button, + std::function<void(const Common::ParamPackage&)> new_input_setter, + InputCommon::Polling::DeviceType type); + + /// Finish polling and configure input using the input_setter + void setPollingResult(const Common::ParamPackage& params, bool abort); + /// Handle key press events. void keyPressEvent(QKeyEvent* event) override; }; diff --git a/src/yuzu/configuration/configure_input.ui b/src/yuzu/configuration/configure_input.ui index 5143c9d72..c162ca02c 100644 --- a/src/yuzu/configuration/configure_input.ui +++ b/src/yuzu/configuration/configure_input.ui @@ -7,7 +7,7 @@ <x>0</x> <y>0</y> <width>343</width> - <height>665</height> + <height>677</height> </rect> </property> <property name="windowTitle"> @@ -16,10 +16,10 @@ <layout class="QVBoxLayout" name="verticalLayout_5"> <item> <layout class="QGridLayout" name="gridLayout_7"> - <item row="0" column="0"> - <widget class="QGroupBox" name="faceButtons"> + <item row="3" column="1"> + <widget class="QGroupBox" name="faceButtons_6"> <property name="title"> - <string>Face Buttons</string> + <string>Misc.</string> </property> <property name="flat"> <bool>false</bool> @@ -27,18 +27,18 @@ <property name="checkable"> <bool>false</bool> </property> - <layout class="QGridLayout" name="gridLayout"> + <layout class="QGridLayout" name="gridLayout_6"> <item row="0" column="0"> - <layout class="QVBoxLayout" name="verticalLayout"> + <layout class="QVBoxLayout" name="verticalLayout_25"> <item> - <widget class="QLabel" name="label"> + <widget class="QLabel" name="label_29"> <property name="text"> - <string>A:</string> + <string>Plus:</string> </property> </widget> </item> <item> - <widget class="QPushButton" name="buttonA"> + <widget class="QPushButton" name="buttonPlus"> <property name="text"> <string/> </property> @@ -47,16 +47,16 @@ </layout> </item> <item row="0" column="1"> - <layout class="QVBoxLayout" name="verticalLayout_2"> + <layout class="QVBoxLayout" name="verticalLayout_26"> <item> - <widget class="QLabel" name="label_2"> + <widget class="QLabel" name="label_30"> <property name="text"> - <string>B:</string> + <string>Minus:</string> </property> </widget> </item> <item> - <widget class="QPushButton" name="buttonB"> + <widget class="QPushButton" name="buttonMinus"> <property name="text"> <string/> </property> @@ -65,16 +65,16 @@ </layout> </item> <item row="1" column="0"> - <layout class="QVBoxLayout" name="verticalLayout_3"> + <layout class="QVBoxLayout" name="verticalLayout_27"> <item> - <widget class="QLabel" name="label_3"> + <widget class="QLabel" name="label_31"> <property name="text"> - <string>X:</string> + <string>Home:</string> </property> </widget> </item> <item> - <widget class="QPushButton" name="buttonX"> + <widget class="QPushButton" name="buttonHome"> <property name="text"> <string/> </property> @@ -83,16 +83,17 @@ </layout> </item> <item row="1" column="1"> - <layout class="QVBoxLayout" name="verticalLayout_4"> + <layout class="QVBoxLayout" name="verticalLayout_28"> <item> - <widget class="QLabel" name="label_4"> + <widget class="QLabel" name="label_11"> <property name="text"> - <string>Y:</string> + <string>Screen +Capture:</string> </property> </widget> </item> <item> - <widget class="QPushButton" name="buttonY"> + <widget class="QPushButton" name="buttonScreenshot"> <property name="text"> <string/> </property> @@ -100,13 +101,26 @@ </item> </layout> </item> + <item row="2" column="1"> + <spacer name="verticalSpacer"> + <property name="orientation"> + <enum>Qt::Vertical</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>20</width> + <height>40</height> + </size> + </property> + </spacer> + </item> </layout> </widget> </item> - <item row="0" column="1"> - <widget class="QGroupBox" name="faceButtons_2"> + <item row="0" column="0"> + <widget class="QGroupBox" name="faceButtons"> <property name="title"> - <string>Directional Pad</string> + <string>Face Buttons</string> </property> <property name="flat"> <bool>false</bool> @@ -114,18 +128,18 @@ <property name="checkable"> <bool>false</bool> </property> - <layout class="QGridLayout" name="gridLayout_2"> - <item row="1" column="0"> - <layout class="QVBoxLayout" name="verticalLayout_12"> + <layout class="QGridLayout" name="gridLayout"> + <item row="0" column="0"> + <layout class="QVBoxLayout" name="verticalLayout"> <item> - <widget class="QLabel" name="label_34"> + <widget class="QLabel" name="label"> <property name="text"> - <string>Up:</string> + <string>A:</string> </property> </widget> </item> <item> - <widget class="QPushButton" name="buttonDpadUp"> + <widget class="QPushButton" name="buttonA"> <property name="text"> <string/> </property> @@ -133,17 +147,17 @@ </item> </layout> </item> - <item row="1" column="1"> - <layout class="QVBoxLayout" name="verticalLayout_9"> + <item row="0" column="1"> + <layout class="QVBoxLayout" name="verticalLayout_2"> <item> - <widget class="QLabel" name="label_35"> + <widget class="QLabel" name="label_2"> <property name="text"> - <string>Down:</string> + <string>B:</string> </property> </widget> </item> <item> - <widget class="QPushButton" name="buttonDpadDown"> + <widget class="QPushButton" name="buttonB"> <property name="text"> <string/> </property> @@ -151,17 +165,17 @@ </item> </layout> </item> - <item row="0" column="0"> - <layout class="QVBoxLayout" name="verticalLayout_10"> + <item row="1" column="0"> + <layout class="QVBoxLayout" name="verticalLayout_3"> <item> - <widget class="QLabel" name="label_32"> + <widget class="QLabel" name="label_3"> <property name="text"> - <string>Left:</string> + <string>X:</string> </property> </widget> </item> <item> - <widget class="QPushButton" name="buttonDpadLeft"> + <widget class="QPushButton" name="buttonX"> <property name="text"> <string/> </property> @@ -169,17 +183,17 @@ </item> </layout> </item> - <item row="0" column="1"> - <layout class="QVBoxLayout" name="verticalLayout_11"> + <item row="1" column="1"> + <layout class="QVBoxLayout" name="verticalLayout_4"> <item> - <widget class="QLabel" name="label_33"> + <widget class="QLabel" name="label_4"> <property name="text"> - <string>Right:</string> + <string>Y:</string> </property> </widget> </item> <item> - <widget class="QPushButton" name="buttonDpadRight"> + <widget class="QPushButton" name="buttonY"> <property name="text"> <string/> </property> @@ -190,10 +204,10 @@ </layout> </widget> </item> - <item row="3" column="1"> - <widget class="QGroupBox" name="faceButtons_6"> + <item row="0" column="1"> + <widget class="QGroupBox" name="faceButtons_2"> <property name="title"> - <string>Misc.</string> + <string>Directional Pad</string> </property> <property name="flat"> <bool>false</bool> @@ -201,18 +215,18 @@ <property name="checkable"> <bool>false</bool> </property> - <layout class="QGridLayout" name="gridLayout_6"> - <item row="0" column="0"> - <layout class="QVBoxLayout" name="verticalLayout_25"> + <layout class="QGridLayout" name="gridLayout_2"> + <item row="1" column="0"> + <layout class="QVBoxLayout" name="verticalLayout_12"> <item> - <widget class="QLabel" name="label_29"> + <widget class="QLabel" name="label_34"> <property name="text"> - <string>Plus:</string> + <string>Up:</string> </property> </widget> </item> <item> - <widget class="QPushButton" name="buttonPlus"> + <widget class="QPushButton" name="buttonDpadUp"> <property name="text"> <string/> </property> @@ -220,17 +234,17 @@ </item> </layout> </item> - <item row="0" column="1"> - <layout class="QVBoxLayout" name="verticalLayout_26"> + <item row="1" column="1"> + <layout class="QVBoxLayout" name="verticalLayout_9"> <item> - <widget class="QLabel" name="label_30"> + <widget class="QLabel" name="label_35"> <property name="text"> - <string>Minus:</string> + <string>Down:</string> </property> </widget> </item> <item> - <widget class="QPushButton" name="buttonMinus"> + <widget class="QPushButton" name="buttonDpadDown"> <property name="text"> <string/> </property> @@ -238,17 +252,17 @@ </item> </layout> </item> - <item row="1" column="0"> - <layout class="QVBoxLayout" name="verticalLayout_27"> + <item row="0" column="0"> + <layout class="QVBoxLayout" name="verticalLayout_10"> <item> - <widget class="QLabel" name="label_31"> + <widget class="QLabel" name="label_32"> <property name="text"> - <string>Home:</string> + <string>Left:</string> </property> </widget> </item> <item> - <widget class="QPushButton" name="buttonHome"> + <widget class="QPushButton" name="buttonDpadLeft"> <property name="text"> <string/> </property> @@ -256,18 +270,17 @@ </item> </layout> </item> - <item row="1" column="1"> - <layout class="QVBoxLayout" name="verticalLayout_28"> + <item row="0" column="1"> + <layout class="QVBoxLayout" name="verticalLayout_11"> <item> - <widget class="QLabel" name="label_11"> + <widget class="QLabel" name="label_33"> <property name="text"> - <string>Screen -Capture:</string> + <string>Right:</string> </property> </widget> </item> <item> - <widget class="QPushButton" name="buttonScreenshot"> + <widget class="QPushButton" name="buttonDpadRight"> <property name="text"> <string/> </property> @@ -275,19 +288,6 @@ Capture:</string> </item> </layout> </item> - <item row="2" column="1"> - <spacer name="verticalSpacer"> - <property name="orientation"> - <enum>Qt::Vertical</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>20</width> - <height>40</height> - </size> - </property> - </spacer> - </item> </layout> </widget> </item> @@ -414,10 +414,13 @@ Capture:</string> </layout> </widget> </item> - <item row="1" column="0"> - <widget class="QGroupBox" name="faceButtons_4"> + <item row="1" column="1"> + <widget class="QGroupBox" name="faceButtons_5"> <property name="title"> - <string>Left Stick</string> + <string>Right Stick</string> + </property> + <property name="alignment"> + <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set> </property> <property name="flat"> <bool>false</bool> @@ -425,18 +428,18 @@ Capture:</string> <property name="checkable"> <bool>false</bool> </property> - <layout class="QGridLayout" name="gridLayout_4"> - <item row="0" column="0"> - <layout class="QVBoxLayout" name="verticalLayout_17"> + <layout class="QGridLayout" name="gridLayout_5"> + <item row="1" column="1"> + <layout class="QVBoxLayout" name="verticalLayout_24"> <item> - <widget class="QLabel" name="label_21"> + <widget class="QLabel" name="label_26"> <property name="text"> - <string>Left:</string> + <string>Down:</string> </property> </widget> </item> <item> - <widget class="QPushButton" name="buttonLStickLeft"> + <widget class="QPushButton" name="buttonRStickDown"> <property name="text"> <string/> </property> @@ -445,16 +448,16 @@ Capture:</string> </layout> </item> <item row="0" column="1"> - <layout class="QVBoxLayout" name="verticalLayout_18"> + <layout class="QVBoxLayout" name="verticalLayout_22"> <item> - <widget class="QLabel" name="label_23"> + <widget class="QLabel" name="label_27"> <property name="text"> <string>Right:</string> </property> </widget> </item> <item> - <widget class="QPushButton" name="buttonLStickRight"> + <widget class="QPushButton" name="buttonRStickRight"> <property name="text"> <string/> </property> @@ -462,17 +465,24 @@ Capture:</string> </item> </layout> </item> + <item row="3" column="0" colspan="2"> + <widget class="QPushButton" name="buttonRStickAnalog"> + <property name="text"> + <string>Set Analog Stick</string> + </property> + </widget> + </item> <item row="1" column="0"> - <layout class="QVBoxLayout" name="verticalLayout_19"> + <layout class="QVBoxLayout" name="verticalLayout_21"> <item> - <widget class="QLabel" name="label_24"> + <widget class="QLabel" name="label_25"> <property name="text"> - <string>Up:</string> + <string>Left:</string> </property> </widget> </item> <item> - <widget class="QPushButton" name="buttonLStickUp"> + <widget class="QPushButton" name="buttonRStickLeft"> <property name="text"> <string/> </property> @@ -480,17 +490,17 @@ Capture:</string> </item> </layout> </item> - <item row="1" column="1"> - <layout class="QVBoxLayout" name="verticalLayout_20"> + <item row="0" column="0"> + <layout class="QVBoxLayout" name="verticalLayout_25"> <item> - <widget class="QLabel" name="label_22"> + <widget class="QLabel" name="label_28"> <property name="text"> - <string>Down:</string> + <string>Up:</string> </property> </widget> </item> <item> - <widget class="QPushButton" name="buttonLStickDown"> + <widget class="QPushButton" name="buttonRStickUp"> <property name="text"> <string/> </property> @@ -499,16 +509,16 @@ Capture:</string> </layout> </item> <item row="2" column="0"> - <layout class="QVBoxLayout" name="verticalLayout_7" stretch="0,0"> + <layout class="QVBoxLayout" name="verticalLayout_6"> <item> - <widget class="QLabel" name="label_6"> + <widget class="QLabel" name="label_5"> <property name="text"> <string>Pressed:</string> </property> </widget> </item> <item> - <widget class="QPushButton" name="buttonLStick"> + <widget class="QPushButton" name="buttonRStick"> <property name="text"> <string/> </property> @@ -517,16 +527,16 @@ Capture:</string> </layout> </item> <item row="2" column="1"> - <layout class="QVBoxLayout" name="verticalLayout_31"> + <layout class="QVBoxLayout" name="verticalLayout_32"> <item> - <widget class="QLabel" name="label_9"> + <widget class="QLabel" name="label_10"> <property name="text"> <string>Modifier:</string> </property> </widget> </item> <item> - <widget class="QPushButton" name="buttonLStickMod"> + <widget class="QPushButton" name="buttonRStickMod"> <property name="text"> <string/> </property> @@ -537,13 +547,10 @@ Capture:</string> </layout> </widget> </item> - <item row="1" column="1"> - <widget class="QGroupBox" name="faceButtons_5"> + <item row="1" column="0"> + <widget class="QGroupBox" name="faceButtons_4"> <property name="title"> - <string>Right Stick</string> - </property> - <property name="alignment"> - <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set> + <string>Left Stick</string> </property> <property name="flat"> <bool>false</bool> @@ -551,18 +558,18 @@ Capture:</string> <property name="checkable"> <bool>false</bool> </property> - <layout class="QGridLayout" name="gridLayout_5"> + <layout class="QGridLayout" name="gridLayout_4"> <item row="1" column="1"> - <layout class="QVBoxLayout" name="verticalLayout_24"> + <layout class="QVBoxLayout" name="verticalLayout_20"> <item> - <widget class="QLabel" name="label_26"> + <widget class="QLabel" name="label_22"> <property name="text"> <string>Down:</string> </property> </widget> </item> <item> - <widget class="QPushButton" name="buttonRStickDown"> + <widget class="QPushButton" name="buttonLStickDown"> <property name="text"> <string/> </property> @@ -570,17 +577,24 @@ Capture:</string> </item> </layout> </item> + <item row="4" column="0" colspan="2"> + <widget class="QPushButton" name="buttonLStickAnalog"> + <property name="text"> + <string>Set Analog Stick</string> + </property> + </widget> + </item> <item row="0" column="1"> - <layout class="QVBoxLayout" name="verticalLayout_22"> + <layout class="QVBoxLayout" name="verticalLayout_18"> <item> - <widget class="QLabel" name="label_27"> + <widget class="QLabel" name="label_23"> <property name="text"> <string>Right:</string> </property> </widget> </item> <item> - <widget class="QPushButton" name="buttonRStickRight"> + <widget class="QPushButton" name="buttonLStickRight"> <property name="text"> <string/> </property> @@ -588,17 +602,17 @@ Capture:</string> </item> </layout> </item> - <item row="1" column="0"> - <layout class="QVBoxLayout" name="verticalLayout_23"> + <item row="0" column="0"> + <layout class="QVBoxLayout" name="verticalLayout_17"> <item> - <widget class="QLabel" name="label_28"> + <widget class="QLabel" name="label_21"> <property name="text"> - <string>Up:</string> + <string>Left:</string> </property> </widget> </item> <item> - <widget class="QPushButton" name="buttonRStickUp"> + <widget class="QPushButton" name="buttonLStickLeft"> <property name="text"> <string/> </property> @@ -606,17 +620,17 @@ Capture:</string> </item> </layout> </item> - <item row="0" column="0"> - <layout class="QVBoxLayout" name="verticalLayout_21"> + <item row="1" column="0"> + <layout class="QVBoxLayout" name="verticalLayout_19"> <item> - <widget class="QLabel" name="label_25"> + <widget class="QLabel" name="label_24"> <property name="text"> - <string>Left:</string> + <string>Up:</string> </property> </widget> </item> <item> - <widget class="QPushButton" name="buttonRStickLeft"> + <widget class="QPushButton" name="buttonLStickUp"> <property name="text"> <string/> </property> @@ -624,17 +638,17 @@ Capture:</string> </item> </layout> </item> - <item row="2" column="1"> - <layout class="QVBoxLayout" name="verticalLayout_32"> + <item row="3" column="0"> + <layout class="QVBoxLayout" name="verticalLayout_31"> <item> - <widget class="QLabel" name="label_10"> + <widget class="QLabel" name="label_9"> <property name="text"> <string>Modifier:</string> </property> </widget> </item> <item> - <widget class="QPushButton" name="buttonRStickMod"> + <widget class="QPushButton" name="buttonLStickMod"> <property name="text"> <string/> </property> @@ -642,17 +656,17 @@ Capture:</string> </item> </layout> </item> - <item row="2" column="0"> - <layout class="QVBoxLayout" name="verticalLayout_6"> + <item row="3" column="1"> + <layout class="QVBoxLayout" name="verticalLayout_7" stretch="0,0"> <item> - <widget class="QLabel" name="label_5"> + <widget class="QLabel" name="label_6"> <property name="text"> <string>Pressed:</string> </property> </widget> </item> <item> - <widget class="QPushButton" name="buttonRStick"> + <widget class="QPushButton" name="buttonLStick"> <property name="text"> <string/> </property> diff --git a/src/yuzu/configuration/configure_system.cpp b/src/yuzu/configuration/configure_system.cpp index 417afef87..d198e38ae 100644 --- a/src/yuzu/configuration/configure_system.cpp +++ b/src/yuzu/configuration/configure_system.cpp @@ -8,7 +8,6 @@ #include "yuzu/configuration/configure_system.h" #include "yuzu/ui_settings.h" - static const std::array<int, 12> days_in_month = {{ 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, }}; diff --git a/src/yuzu/debugger/registers.cpp b/src/yuzu/debugger/registers.cpp index a52725075..06e2d1647 100644 --- a/src/yuzu/debugger/registers.cpp +++ b/src/yuzu/debugger/registers.cpp @@ -8,7 +8,6 @@ #include "yuzu/debugger/registers.h" #include "yuzu/util/util.h" - RegistersWidget::RegistersWidget(QWidget* parent) : QDockWidget(parent) { cpu_regs_ui.setupUi(this); diff --git a/src/yuzu/game_list.cpp b/src/yuzu/game_list.cpp index 532c4ae63..679c89828 100644 --- a/src/yuzu/game_list.cpp +++ b/src/yuzu/game_list.cpp @@ -174,7 +174,7 @@ void GameList::onTextChanged(const QString& newText) { child_file->data(GameListItemPath::ProgramIdRole).toString().toLower(); // Only items which filename in combination with its title contains all words - // that are in the searchfiel will be visible in the gamelist + // that are in the searchfield will be visible in the gamelist // The search is case insensitive because of toLower() // I decided not to use Qt::CaseInsensitive in containsAllWords to prevent // multiple conversions of edit_filter_text for each game in the gamelist diff --git a/src/yuzu/game_list_p.h b/src/yuzu/game_list_p.h index e40cd38b3..a758b77aa 100644 --- a/src/yuzu/game_list_p.h +++ b/src/yuzu/game_list_p.h @@ -9,8 +9,8 @@ #include <QRunnable> #include <QStandardItem> #include <QString> -#include "yuzu/util/util.h" #include "common/string_util.h" +#include "yuzu/util/util.h" /** * Gets the default icon (for games without valid SMDH) diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index f64e68268..31f2825ee 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -122,8 +122,9 @@ void GMainWindow::InitializeWidgets() { statusBar()->addPermanentWidget(message_label, 1); emu_speed_label = new QLabel(); - emu_speed_label->setToolTip(tr("Current emulation speed. Values higher or lower than 100% " - "indicate emulation is running faster or slower than a Switch.")); + emu_speed_label->setToolTip( + tr("Current emulation speed. Values higher or lower than 100% " + "indicate emulation is running faster or slower than a Switch.")); game_fps_label = new QLabel(); game_fps_label->setToolTip(tr("How many frames per second the game is currently displaying. " "This will vary from game to game and scene to scene.")); @@ -185,12 +186,24 @@ void GMainWindow::InitializeRecentFileMenuActions() { void GMainWindow::InitializeHotkeys() { RegisterHotkey("Main Window", "Load File", QKeySequence::Open); RegisterHotkey("Main Window", "Start Emulation"); + RegisterHotkey("Main Window", "Fullscreen", QKeySequence::FullScreen); + RegisterHotkey("Main Window", "Exit Fullscreen", QKeySequence::Cancel, Qt::ApplicationShortcut); LoadHotkeys(); connect(GetHotkey("Main Window", "Load File", this), SIGNAL(activated()), this, SLOT(OnMenuLoadFile())); connect(GetHotkey("Main Window", "Start Emulation", this), SIGNAL(activated()), this, SLOT(OnStartGame())); + connect(GetHotkey("Main Window", "Fullscreen", render_window), &QShortcut::activated, + ui.action_Fullscreen, &QAction::trigger); + connect(GetHotkey("Main Window", "Fullscreen", render_window), &QShortcut::activatedAmbiguously, + ui.action_Fullscreen, &QAction::trigger); + connect(GetHotkey("Main Window", "Exit Fullscreen", this), &QShortcut::activated, this, [&] { + if (emulation_running) { + ui.action_Fullscreen->setChecked(false); + ToggleFullscreen(); + } + }); } void GMainWindow::SetDefaultUIGeometry() { @@ -219,6 +232,8 @@ void GMainWindow::RestoreUIState() { ui.action_Single_Window_Mode->setChecked(UISettings::values.single_window_mode); ToggleWindowMode(); + ui.action_Fullscreen->setChecked(UISettings::values.fullscreen); + ui.action_Display_Dock_Widget_Headers->setChecked(UISettings::values.display_titlebar); OnDisplayTitleBars(ui.action_Display_Dock_Widget_Headers->isChecked()); @@ -263,6 +278,10 @@ void GMainWindow::ConnectMenuEvents() { connect(ui.action_Show_Filter_Bar, &QAction::triggered, this, &GMainWindow::OnToggleFilterBar); connect(ui.action_Show_Status_Bar, &QAction::triggered, statusBar(), &QStatusBar::setVisible); + // Fullscreen + ui.action_Fullscreen->setShortcut(GetHotkey("Main Window", "Fullscreen", this)->key()); + connect(ui.action_Fullscreen, &QAction::triggered, this, &GMainWindow::ToggleFullscreen); + // Help connect(ui.action_About, &QAction::triggered, this, &GMainWindow::OnAbout); } @@ -402,6 +421,9 @@ void GMainWindow::BootGame(const QString& filename) { render_window->setFocus(); emulation_running = true; + if (ui.action_Fullscreen->isChecked()) { + ShowFullscreen(); + } OnStartGame(); } @@ -548,6 +570,41 @@ void GMainWindow::OnStopGame() { ShutdownGame(); } +void GMainWindow::ToggleFullscreen() { + if (!emulation_running) { + return; + } + if (ui.action_Fullscreen->isChecked()) { + ShowFullscreen(); + } else { + HideFullscreen(); + } +} + +void GMainWindow::ShowFullscreen() { + if (ui.action_Single_Window_Mode->isChecked()) { + UISettings::values.geometry = saveGeometry(); + ui.menubar->hide(); + statusBar()->hide(); + showFullScreen(); + } else { + UISettings::values.renderwindow_geometry = render_window->saveGeometry(); + render_window->showFullScreen(); + } +} + +void GMainWindow::HideFullscreen() { + if (ui.action_Single_Window_Mode->isChecked()) { + statusBar()->setVisible(ui.action_Show_Status_Bar->isChecked()); + ui.menubar->show(); + showNormal(); + restoreGeometry(UISettings::values.geometry); + } else { + render_window->showNormal(); + render_window->restoreGeometry(UISettings::values.renderwindow_geometry); + } +} + void GMainWindow::ToggleWindowMode() { if (ui.action_Single_Window_Mode->isChecked()) { // Render in the main window... @@ -670,6 +727,7 @@ void GMainWindow::OnCoreError(Core::System::ResultStatus result, std::string det } else { // Only show the message if the game is still running. if (emu_thread) { + emu_thread->SetRunning(true); message_label->setText(status_message); message_label->setVisible(true); } @@ -700,6 +758,7 @@ void GMainWindow::closeEvent(QCloseEvent* event) { UISettings::values.microprofile_visible = microProfileDialog->isVisible(); #endif UISettings::values.single_window_mode = ui.action_Single_Window_Mode->isChecked(); + UISettings::values.fullscreen = ui.action_Fullscreen->isChecked(); UISettings::values.display_titlebar = ui.action_Display_Dock_Widget_Headers->isChecked(); UISettings::values.show_filter_bar = ui.action_Show_Filter_Bar->isChecked(); UISettings::values.show_status_bar = ui.action_Show_Status_Bar->isChecked(); diff --git a/src/yuzu/main.h b/src/yuzu/main.h index 3add882dd..4a0d912bb 100644 --- a/src/yuzu/main.h +++ b/src/yuzu/main.h @@ -127,6 +127,9 @@ private slots: void OnAbout(); void OnToggleFilterBar(); void OnDisplayTitleBars(bool); + void ToggleFullscreen(); + void ShowFullscreen(); + void HideFullscreen(); void ToggleWindowMode(); void OnCoreError(Core::System::ResultStatus, std::string); diff --git a/src/yuzu/main.ui b/src/yuzu/main.ui index 721e769e8..0fcd93cc2 100644 --- a/src/yuzu/main.ui +++ b/src/yuzu/main.ui @@ -83,6 +83,7 @@ <string>Debugging</string> </property> </widget> + <addaction name="action_Fullscreen"/> <addaction name="action_Single_Window_Mode"/> <addaction name="action_Display_Dock_Widget_Headers"/> <addaction name="action_Show_Filter_Bar"/> @@ -189,6 +190,14 @@ <string>Selects a folder to display in the game list</string> </property> </action> - </widget> + <action name="action_Fullscreen"> + <property name="checkable"> + <bool>true</bool> + </property> + <property name="text"> + <string>Fullscreen</string> + </property> + </action> + </widget> <resources/> </ui> diff --git a/src/yuzu/ui_settings.h b/src/yuzu/ui_settings.h index e965f0ba9..d093da641 100644 --- a/src/yuzu/ui_settings.h +++ b/src/yuzu/ui_settings.h @@ -27,6 +27,7 @@ struct Values { bool microprofile_visible; bool single_window_mode; + bool fullscreen; bool display_titlebar; bool show_filter_bar; bool show_status_bar; diff --git a/src/yuzu/util/spinbox.cpp b/src/yuzu/util/spinbox.cpp index ede6fe0a8..92753ec1c 100644 --- a/src/yuzu/util/spinbox.cpp +++ b/src/yuzu/util/spinbox.cpp @@ -31,8 +31,8 @@ #include <cstdlib> #include <QLineEdit> #include <QRegExpValidator> -#include "yuzu/util/spinbox.h" #include "common/assert.h" +#include "yuzu/util/spinbox.h" CSpinBox::CSpinBox(QWidget* parent) : QAbstractSpinBox(parent), min_value(-100), max_value(100), value(0), base(10), num_digits(0) { diff --git a/src/yuzu_cmd/yuzu.cpp b/src/yuzu_cmd/yuzu.cpp index 785d96672..8f7c75796 100644 --- a/src/yuzu_cmd/yuzu.cpp +++ b/src/yuzu_cmd/yuzu.cpp @@ -37,7 +37,6 @@ #include "yuzu_cmd/config.h" #include "yuzu_cmd/emu_window/emu_window_sdl2.h" - static void PrintHelp(const char* argv0) { std::cout << "Usage: " << argv0 << " [options] <filename>\n" |