diff options
Diffstat (limited to 'src')
210 files changed, 2076 insertions, 957 deletions
diff --git a/src/audio_core/audio_renderer.cpp b/src/audio_core/audio_renderer.cpp index 397b107f5..a75cd3be5 100644 --- a/src/audio_core/audio_renderer.cpp +++ b/src/audio_core/audio_renderer.cpp @@ -17,10 +17,10 @@ AudioRenderer::AudioRenderer(AudioRendererParameter params, Kernel::SharedPtr<Kernel::Event> buffer_event) : worker_params{params}, buffer_event{buffer_event}, voices(params.voice_count) { - audio_core = std::make_unique<AudioCore::AudioOut>(); - stream = audio_core->OpenStream(STREAM_SAMPLE_RATE, STREAM_NUM_CHANNELS, "AudioRenderer", - [=]() { buffer_event->Signal(); }); - audio_core->StartStream(stream); + audio_out = std::make_unique<AudioCore::AudioOut>(); + stream = audio_out->OpenStream(STREAM_SAMPLE_RATE, STREAM_NUM_CHANNELS, "AudioRenderer", + [=]() { buffer_event->Signal(); }); + audio_out->StartStream(stream); QueueMixedBuffer(0); QueueMixedBuffer(1); @@ -236,11 +236,11 @@ void AudioRenderer::QueueMixedBuffer(Buffer::Tag tag) { } } } - audio_core->QueueBuffer(stream, tag, std::move(buffer)); + audio_out->QueueBuffer(stream, tag, std::move(buffer)); } void AudioRenderer::ReleaseAndQueueBuffers() { - const auto released_buffers{audio_core->GetTagsAndReleaseBuffers(stream, 2)}; + const auto released_buffers{audio_out->GetTagsAndReleaseBuffers(stream, 2)}; for (const auto& tag : released_buffers) { QueueMixedBuffer(tag); } diff --git a/src/audio_core/audio_renderer.h b/src/audio_core/audio_renderer.h index eba67f28e..6d069d693 100644 --- a/src/audio_core/audio_renderer.h +++ b/src/audio_core/audio_renderer.h @@ -204,7 +204,7 @@ private: AudioRendererParameter worker_params; Kernel::SharedPtr<Kernel::Event> buffer_event; std::vector<VoiceState> voices; - std::unique_ptr<AudioCore::AudioOut> audio_core; + std::unique_ptr<AudioCore::AudioOut> audio_out; AudioCore::StreamPtr stream; }; diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 7ddc87539..26f727d96 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -388,7 +388,7 @@ add_library(core STATIC create_target_directory_groups(core) target_link_libraries(core PUBLIC common PRIVATE audio_core video_core) -target_link_libraries(core PUBLIC Boost::boost PRIVATE fmt lz4_static mbedtls opus unicorn) +target_link_libraries(core PUBLIC Boost::boost PRIVATE fmt lz4_static mbedtls opus unicorn open_source_archives) if (ARCHITECTURE_x86_64) target_sources(core PRIVATE diff --git a/src/core/hle/kernel/errors.h b/src/core/hle/kernel/errors.h index 4054d5db6..ad39c8271 100644 --- a/src/core/hle/kernel/errors.h +++ b/src/core/hle/kernel/errors.h @@ -21,6 +21,7 @@ enum { HandleTableFull = 105, InvalidMemoryState = 106, InvalidMemoryPermissions = 108, + InvalidThreadPriority = 112, InvalidProcessorId = 113, InvalidHandle = 114, InvalidCombination = 116, @@ -36,7 +37,7 @@ enum { // WARNING: The kernel is quite inconsistent in it's usage of errors code. Make sure to always // double check that the code matches before re-using the constant. -// TODO(bunnei): Replace these with correct errors for Switch OS +// TODO(bunnei): Replace -1 with correct errors for Switch OS constexpr ResultCode ERR_HANDLE_TABLE_FULL(ErrorModule::Kernel, ErrCodes::HandleTableFull); constexpr ResultCode ERR_SESSION_CLOSED_BY_REMOTE(-1); constexpr ResultCode ERR_PORT_NAME_TOO_LONG(ErrorModule::Kernel, ErrCodes::TooLarge); @@ -53,15 +54,16 @@ constexpr ResultCode ERR_INVALID_ADDRESS_STATE(ErrorModule::Kernel, ErrCodes::In constexpr ResultCode ERR_INVALID_MEMORY_PERMISSIONS(ErrorModule::Kernel, ErrCodes::InvalidMemoryPermissions); constexpr ResultCode ERR_INVALID_HANDLE(ErrorModule::Kernel, ErrCodes::InvalidHandle); +constexpr ResultCode ERR_INVALID_PROCESSOR_ID(ErrorModule::Kernel, ErrCodes::InvalidProcessorId); constexpr ResultCode ERR_INVALID_STATE(ErrorModule::Kernel, ErrCodes::InvalidState); +constexpr ResultCode ERR_INVALID_THREAD_PRIORITY(ErrorModule::Kernel, + ErrCodes::InvalidThreadPriority); constexpr ResultCode ERR_INVALID_POINTER(-1); constexpr ResultCode ERR_INVALID_OBJECT_ADDR(-1); constexpr ResultCode ERR_NOT_AUTHORIZED(-1); /// Alternate code returned instead of ERR_INVALID_HANDLE in some code paths. constexpr ResultCode ERR_INVALID_HANDLE_OS(-1); constexpr ResultCode ERR_NOT_FOUND(-1); -constexpr ResultCode ERR_OUT_OF_RANGE(-1); -constexpr ResultCode ERR_OUT_OF_RANGE_KERNEL(-1); constexpr ResultCode RESULT_TIMEOUT(ErrorModule::Kernel, ErrCodes::Timeout); /// Returned when Accept() is called on a port with no sessions to be accepted. constexpr ResultCode ERR_NO_PENDING_SESSIONS(-1); diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index 1c9373ed8..f500fd2e7 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -273,7 +273,11 @@ static void Break(u64 reason, u64 info1, u64 info2) { } /// Used to output a message on a debug hardware unit - does nothing on a retail unit -static void OutputDebugString(VAddr address, s32 len) { +static void OutputDebugString(VAddr address, u64 len) { + if (len == 0) { + return; + } + std::string str(len, '\0'); Memory::ReadBlock(address, str.data(), str.size()); LOG_DEBUG(Debug_Emulated, "{}", str); @@ -378,7 +382,7 @@ static ResultCode GetThreadPriority(u32* priority, Handle handle) { /// Sets the priority for the specified thread static ResultCode SetThreadPriority(Handle handle, u32 priority) { if (priority > THREADPRIO_LOWEST) { - return ERR_OUT_OF_RANGE; + return ERR_INVALID_THREAD_PRIORITY; } auto& kernel = Core::System::GetInstance().Kernel(); @@ -523,7 +527,7 @@ static ResultCode CreateThread(Handle* out_handle, VAddr entry_point, u64 arg, V std::string name = fmt::format("unknown-{:X}", entry_point); if (priority > THREADPRIO_LOWEST) { - return ERR_OUT_OF_RANGE; + return ERR_INVALID_THREAD_PRIORITY; } SharedPtr<ResourceLimit>& resource_limit = Core::CurrentProcess()->resource_limit; @@ -544,8 +548,8 @@ static ResultCode CreateThread(Handle* out_handle, VAddr entry_point, u64 arg, V case THREADPROCESSORID_3: break; default: - ASSERT_MSG(false, "Unsupported thread processor ID: {}", processor_id); - break; + LOG_ERROR(Kernel_SVC, "Invalid thread processor ID: {}", processor_id); + return ERR_INVALID_PROCESSOR_ID; } auto& kernel = Core::System::GetInstance().Kernel(); diff --git a/src/core/hle/kernel/svc_wrap.h b/src/core/hle/kernel/svc_wrap.h index 79c3fe31b..1eda5f879 100644 --- a/src/core/hle/kernel/svc_wrap.h +++ b/src/core/hle/kernel/svc_wrap.h @@ -222,9 +222,9 @@ void SvcWrap() { func((s64)PARAM(0)); } -template <void func(u64, s32 len)> +template <void func(u64, u64 len)> void SvcWrap() { - func(PARAM(0), (s32)(PARAM(1) & 0xFFFFFFFF)); + func(PARAM(0), PARAM(1)); } template <void func(u64, u64, u64)> diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index 3d10d9af2..3f12a84dc 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp @@ -227,12 +227,12 @@ ResultVal<SharedPtr<Thread>> Thread::Create(KernelCore& kernel, std::string name // Check if priority is in ranged. Lowest priority -> highest priority id. if (priority > THREADPRIO_LOWEST) { LOG_ERROR(Kernel_SVC, "Invalid thread priority: {}", priority); - return ERR_OUT_OF_RANGE; + return ERR_INVALID_THREAD_PRIORITY; } if (processor_id > THREADPROCESSORID_MAX) { LOG_ERROR(Kernel_SVC, "Invalid processor id: {}", processor_id); - return ERR_OUT_OF_RANGE_KERNEL; + return ERR_INVALID_PROCESSOR_ID; } // TODO(yuriks): Other checks, returning 0xD9001BEA diff --git a/src/core/hle/service/acc/acc_aa.cpp b/src/core/hle/service/acc/acc_aa.cpp index 9bd595a37..e84d9f7cf 100644 --- a/src/core/hle/service/acc/acc_aa.cpp +++ b/src/core/hle/service/acc/acc_aa.cpp @@ -18,4 +18,6 @@ ACC_AA::ACC_AA(std::shared_ptr<Module> module, std::shared_ptr<ProfileManager> p RegisterHandlers(functions); } +ACC_AA::~ACC_AA() = default; + } // namespace Service::Account diff --git a/src/core/hle/service/acc/acc_aa.h b/src/core/hle/service/acc/acc_aa.h index 2e08c781a..9edb0421b 100644 --- a/src/core/hle/service/acc/acc_aa.h +++ b/src/core/hle/service/acc/acc_aa.h @@ -12,6 +12,7 @@ class ACC_AA final : public Module::Interface { public: explicit ACC_AA(std::shared_ptr<Module> module, std::shared_ptr<ProfileManager> profile_manager); + ~ACC_AA() override; }; } // namespace Service::Account diff --git a/src/core/hle/service/acc/acc_su.cpp b/src/core/hle/service/acc/acc_su.cpp index 0218ee859..ad455c3a7 100644 --- a/src/core/hle/service/acc/acc_su.cpp +++ b/src/core/hle/service/acc/acc_su.cpp @@ -51,4 +51,6 @@ ACC_SU::ACC_SU(std::shared_ptr<Module> module, std::shared_ptr<ProfileManager> p RegisterHandlers(functions); } +ACC_SU::~ACC_SU() = default; + } // namespace Service::Account diff --git a/src/core/hle/service/acc/acc_su.h b/src/core/hle/service/acc/acc_su.h index 79a47d88d..a3eb885bf 100644 --- a/src/core/hle/service/acc/acc_su.h +++ b/src/core/hle/service/acc/acc_su.h @@ -13,6 +13,7 @@ class ACC_SU final : public Module::Interface { public: explicit ACC_SU(std::shared_ptr<Module> module, std::shared_ptr<ProfileManager> profile_manager); + ~ACC_SU() override; }; } // namespace Account diff --git a/src/core/hle/service/acc/acc_u0.cpp b/src/core/hle/service/acc/acc_u0.cpp index 84a4d05b8..72d4adf35 100644 --- a/src/core/hle/service/acc/acc_u0.cpp +++ b/src/core/hle/service/acc/acc_u0.cpp @@ -31,4 +31,6 @@ ACC_U0::ACC_U0(std::shared_ptr<Module> module, std::shared_ptr<ProfileManager> p RegisterHandlers(functions); } +ACC_U0::~ACC_U0() = default; + } // namespace Service::Account diff --git a/src/core/hle/service/acc/acc_u0.h b/src/core/hle/service/acc/acc_u0.h index e8a114f99..a1290e0bd 100644 --- a/src/core/hle/service/acc/acc_u0.h +++ b/src/core/hle/service/acc/acc_u0.h @@ -12,6 +12,7 @@ class ACC_U0 final : public Module::Interface { public: explicit ACC_U0(std::shared_ptr<Module> module, std::shared_ptr<ProfileManager> profile_manager); + ~ACC_U0() override; }; } // namespace Service::Account diff --git a/src/core/hle/service/acc/acc_u1.cpp b/src/core/hle/service/acc/acc_u1.cpp index 495693949..d480f08e5 100644 --- a/src/core/hle/service/acc/acc_u1.cpp +++ b/src/core/hle/service/acc/acc_u1.cpp @@ -38,4 +38,6 @@ ACC_U1::ACC_U1(std::shared_ptr<Module> module, std::shared_ptr<ProfileManager> p RegisterHandlers(functions); } +ACC_U1::~ACC_U1() = default; + } // namespace Service::Account diff --git a/src/core/hle/service/acc/acc_u1.h b/src/core/hle/service/acc/acc_u1.h index a77520e6f..9e79daee3 100644 --- a/src/core/hle/service/acc/acc_u1.h +++ b/src/core/hle/service/acc/acc_u1.h @@ -12,6 +12,7 @@ class ACC_U1 final : public Module::Interface { public: explicit ACC_U1(std::shared_ptr<Module> module, std::shared_ptr<ProfileManager> profile_manager); + ~ACC_U1() override; }; } // namespace Service::Account diff --git a/src/core/hle/service/acc/profile_manager.cpp b/src/core/hle/service/acc/profile_manager.cpp index e0b03d763..4ccebef23 100644 --- a/src/core/hle/service/acc/profile_manager.cpp +++ b/src/core/hle/service/acc/profile_manager.cpp @@ -29,6 +29,8 @@ ProfileManager::ProfileManager() { OpenUser(user_uuid); } +ProfileManager::~ProfileManager() = default; + /// After a users creation it needs to be "registered" to the system. AddToProfiles handles the /// internal management of the users profiles boost::optional<size_t> ProfileManager::AddToProfiles(const ProfileInfo& user) { diff --git a/src/core/hle/service/acc/profile_manager.h b/src/core/hle/service/acc/profile_manager.h index 52967844d..cd8df93a5 100644 --- a/src/core/hle/service/acc/profile_manager.h +++ b/src/core/hle/service/acc/profile_manager.h @@ -82,6 +82,8 @@ static_assert(sizeof(ProfileBase) == 0x38, "ProfileBase is an invalid size"); class ProfileManager { public: ProfileManager(); // TODO(ogniK): Load from system save + ~ProfileManager(); + ResultCode AddUser(const ProfileInfo& user); ResultCode CreateNewUser(UUID uuid, const ProfileUsername& username); ResultCode CreateNewUser(UUID uuid, const std::string& username); diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp index 818c03e0f..a57ed3042 100644 --- a/src/core/hle/service/am/am.cpp +++ b/src/core/hle/service/am/am.cpp @@ -35,6 +35,8 @@ IWindowController::IWindowController() : ServiceFramework("IWindowController") { RegisterHandlers(functions); } +IWindowController::~IWindowController() = default; + void IWindowController::GetAppletResourceUserId(Kernel::HLERequestContext& ctx) { LOG_WARNING(Service_AM, "(STUBBED) called"); IPC::ResponseBuilder rb{ctx, 4}; @@ -61,6 +63,8 @@ IAudioController::IAudioController() : ServiceFramework("IAudioController") { RegisterHandlers(functions); } +IAudioController::~IAudioController() = default; + void IAudioController::SetExpectedMasterVolume(Kernel::HLERequestContext& ctx) { LOG_WARNING(Service_AM, "(STUBBED) called"); IPC::ResponseBuilder rb{ctx, 2}; @@ -116,7 +120,10 @@ IDisplayController::IDisplayController() : ServiceFramework("IDisplayController" RegisterHandlers(functions); } +IDisplayController::~IDisplayController() = default; + IDebugFunctions::IDebugFunctions() : ServiceFramework("IDebugFunctions") {} +IDebugFunctions::~IDebugFunctions() = default; ISelfController::ISelfController(std::shared_ptr<NVFlinger::NVFlinger> nvflinger) : ServiceFramework("ISelfController"), nvflinger(std::move(nvflinger)) { @@ -165,6 +172,8 @@ ISelfController::ISelfController(std::shared_ptr<NVFlinger::NVFlinger> nvflinger Kernel::Event::Create(kernel, Kernel::ResetType::Sticky, "ISelfController:LaunchableEvent"); } +ISelfController::~ISelfController() = default; + void ISelfController::SetFocusHandlingMode(Kernel::HLERequestContext& ctx) { // Takes 3 input u8s with each field located immediately after the previous u8, these are // bool flags. No output. @@ -337,6 +346,8 @@ ICommonStateGetter::ICommonStateGetter() : ServiceFramework("ICommonStateGetter" event = Kernel::Event::Create(kernel, Kernel::ResetType::OneShot, "ICommonStateGetter:Event"); } +ICommonStateGetter::~ICommonStateGetter() = default; + void ICommonStateGetter::GetBootMode(Kernel::HLERequestContext& ctx) { IPC::ResponseBuilder rb{ctx, 3}; rb.Push(RESULT_SUCCESS); @@ -573,6 +584,8 @@ ILibraryAppletCreator::ILibraryAppletCreator() : ServiceFramework("ILibraryApple RegisterHandlers(functions); } +ILibraryAppletCreator::~ILibraryAppletCreator() = default; + void ILibraryAppletCreator::CreateLibraryApplet(Kernel::HLERequestContext& ctx) { IPC::ResponseBuilder rb{ctx, 2, 0, 1}; @@ -638,6 +651,8 @@ IApplicationFunctions::IApplicationFunctions() : ServiceFramework("IApplicationF RegisterHandlers(functions); } +IApplicationFunctions::~IApplicationFunctions() = default; + void IApplicationFunctions::PopLaunchParameter(Kernel::HLERequestContext& ctx) { constexpr std::array<u8, 0x88> data{{ 0xca, 0x97, 0x94, 0xc7, // Magic @@ -760,6 +775,8 @@ IHomeMenuFunctions::IHomeMenuFunctions() : ServiceFramework("IHomeMenuFunctions" RegisterHandlers(functions); } +IHomeMenuFunctions::~IHomeMenuFunctions() = default; + void IHomeMenuFunctions::RequestToGetForeground(Kernel::HLERequestContext& ctx) { IPC::ResponseBuilder rb{ctx, 2}; rb.Push(RESULT_SUCCESS); @@ -783,6 +800,8 @@ IGlobalStateController::IGlobalStateController() : ServiceFramework("IGlobalStat RegisterHandlers(functions); } +IGlobalStateController::~IGlobalStateController() = default; + IApplicationCreator::IApplicationCreator() : ServiceFramework("IApplicationCreator") { static const FunctionInfo functions[] = { {0, nullptr, "CreateApplication"}, @@ -793,6 +812,8 @@ IApplicationCreator::IApplicationCreator() : ServiceFramework("IApplicationCreat RegisterHandlers(functions); } +IApplicationCreator::~IApplicationCreator() = default; + IProcessWindingController::IProcessWindingController() : ServiceFramework("IProcessWindingController") { static const FunctionInfo functions[] = { @@ -807,4 +828,6 @@ IProcessWindingController::IProcessWindingController() }; RegisterHandlers(functions); } + +IProcessWindingController::~IProcessWindingController() = default; } // namespace Service::AM diff --git a/src/core/hle/service/am/am.h b/src/core/hle/service/am/am.h index 9e8bb4e43..fd9ae296b 100644 --- a/src/core/hle/service/am/am.h +++ b/src/core/hle/service/am/am.h @@ -42,6 +42,7 @@ enum SystemLanguage { class IWindowController final : public ServiceFramework<IWindowController> { public: IWindowController(); + ~IWindowController() override; private: void GetAppletResourceUserId(Kernel::HLERequestContext& ctx); @@ -51,6 +52,7 @@ private: class IAudioController final : public ServiceFramework<IAudioController> { public: IAudioController(); + ~IAudioController() override; private: void SetExpectedMasterVolume(Kernel::HLERequestContext& ctx); @@ -63,16 +65,19 @@ private: class IDisplayController final : public ServiceFramework<IDisplayController> { public: IDisplayController(); + ~IDisplayController() override; }; class IDebugFunctions final : public ServiceFramework<IDebugFunctions> { public: IDebugFunctions(); + ~IDebugFunctions() override; }; class ISelfController final : public ServiceFramework<ISelfController> { public: explicit ISelfController(std::shared_ptr<NVFlinger::NVFlinger> nvflinger); + ~ISelfController() override; private: void SetFocusHandlingMode(Kernel::HLERequestContext& ctx); @@ -98,6 +103,7 @@ private: class ICommonStateGetter final : public ServiceFramework<ICommonStateGetter> { public: ICommonStateGetter(); + ~ICommonStateGetter() override; private: enum class FocusState : u8 { @@ -124,6 +130,7 @@ private: class ILibraryAppletCreator final : public ServiceFramework<ILibraryAppletCreator> { public: ILibraryAppletCreator(); + ~ILibraryAppletCreator() override; private: void CreateLibraryApplet(Kernel::HLERequestContext& ctx); @@ -133,6 +140,7 @@ private: class IApplicationFunctions final : public ServiceFramework<IApplicationFunctions> { public: IApplicationFunctions(); + ~IApplicationFunctions() override; private: void PopLaunchParameter(Kernel::HLERequestContext& ctx); @@ -150,6 +158,7 @@ private: class IHomeMenuFunctions final : public ServiceFramework<IHomeMenuFunctions> { public: IHomeMenuFunctions(); + ~IHomeMenuFunctions() override; private: void RequestToGetForeground(Kernel::HLERequestContext& ctx); @@ -158,16 +167,19 @@ private: class IGlobalStateController final : public ServiceFramework<IGlobalStateController> { public: IGlobalStateController(); + ~IGlobalStateController() override; }; class IApplicationCreator final : public ServiceFramework<IApplicationCreator> { public: IApplicationCreator(); + ~IApplicationCreator() override; }; class IProcessWindingController final : public ServiceFramework<IProcessWindingController> { public: IProcessWindingController(); + ~IProcessWindingController() override; }; /// Registers all AM services with the specified service manager. diff --git a/src/core/hle/service/am/applet_ae.cpp b/src/core/hle/service/am/applet_ae.cpp index 7cebc918a..4296c255e 100644 --- a/src/core/hle/service/am/applet_ae.cpp +++ b/src/core/hle/service/am/applet_ae.cpp @@ -222,4 +222,6 @@ AppletAE::AppletAE(std::shared_ptr<NVFlinger::NVFlinger> nvflinger) RegisterHandlers(functions); } +AppletAE::~AppletAE() = default; + } // namespace Service::AM diff --git a/src/core/hle/service/am/applet_ae.h b/src/core/hle/service/am/applet_ae.h index bdc57b9bc..1ed77baa4 100644 --- a/src/core/hle/service/am/applet_ae.h +++ b/src/core/hle/service/am/applet_ae.h @@ -18,7 +18,7 @@ namespace AM { class AppletAE final : public ServiceFramework<AppletAE> { public: explicit AppletAE(std::shared_ptr<NVFlinger::NVFlinger> nvflinger); - ~AppletAE() = default; + ~AppletAE() override; private: void OpenSystemAppletProxy(Kernel::HLERequestContext& ctx); diff --git a/src/core/hle/service/am/applet_oe.cpp b/src/core/hle/service/am/applet_oe.cpp index beea7d19b..e45cf6e20 100644 --- a/src/core/hle/service/am/applet_oe.cpp +++ b/src/core/hle/service/am/applet_oe.cpp @@ -103,4 +103,6 @@ AppletOE::AppletOE(std::shared_ptr<NVFlinger::NVFlinger> nvflinger) RegisterHandlers(functions); } +AppletOE::~AppletOE() = default; + } // namespace Service::AM diff --git a/src/core/hle/service/am/applet_oe.h b/src/core/hle/service/am/applet_oe.h index c52e2a322..60cfdfd9d 100644 --- a/src/core/hle/service/am/applet_oe.h +++ b/src/core/hle/service/am/applet_oe.h @@ -18,7 +18,7 @@ namespace AM { class AppletOE final : public ServiceFramework<AppletOE> { public: explicit AppletOE(std::shared_ptr<NVFlinger::NVFlinger> nvflinger); - ~AppletOE() = default; + ~AppletOE() override; private: void OpenApplicationProxy(Kernel::HLERequestContext& ctx); diff --git a/src/core/hle/service/am/idle.cpp b/src/core/hle/service/am/idle.cpp index af46e9494..0e3088bc8 100644 --- a/src/core/hle/service/am/idle.cpp +++ b/src/core/hle/service/am/idle.cpp @@ -21,4 +21,6 @@ IdleSys::IdleSys() : ServiceFramework{"idle:sys"} { RegisterHandlers(functions); } +IdleSys::~IdleSys() = default; + } // namespace Service::AM diff --git a/src/core/hle/service/am/idle.h b/src/core/hle/service/am/idle.h index 1eb68d2c9..c44e856b1 100644 --- a/src/core/hle/service/am/idle.h +++ b/src/core/hle/service/am/idle.h @@ -11,6 +11,7 @@ namespace Service::AM { class IdleSys final : public ServiceFramework<IdleSys> { public: explicit IdleSys(); + ~IdleSys() override; }; } // namespace Service::AM diff --git a/src/core/hle/service/am/omm.cpp b/src/core/hle/service/am/omm.cpp index 447fe8669..1c37f849f 100644 --- a/src/core/hle/service/am/omm.cpp +++ b/src/core/hle/service/am/omm.cpp @@ -39,4 +39,6 @@ OMM::OMM() : ServiceFramework{"omm"} { RegisterHandlers(functions); } +OMM::~OMM() = default; + } // namespace Service::AM diff --git a/src/core/hle/service/am/omm.h b/src/core/hle/service/am/omm.h index 49e5d331c..59dc91b72 100644 --- a/src/core/hle/service/am/omm.h +++ b/src/core/hle/service/am/omm.h @@ -11,6 +11,7 @@ namespace Service::AM { class OMM final : public ServiceFramework<OMM> { public: explicit OMM(); + ~OMM() override; }; } // namespace Service::AM diff --git a/src/core/hle/service/am/spsm.cpp b/src/core/hle/service/am/spsm.cpp index a05d433d0..003ee8667 100644 --- a/src/core/hle/service/am/spsm.cpp +++ b/src/core/hle/service/am/spsm.cpp @@ -27,4 +27,6 @@ SPSM::SPSM() : ServiceFramework{"spsm"} { RegisterHandlers(functions); } +SPSM::~SPSM() = default; + } // namespace Service::AM diff --git a/src/core/hle/service/am/spsm.h b/src/core/hle/service/am/spsm.h index 57dde62e1..3a0b979fa 100644 --- a/src/core/hle/service/am/spsm.h +++ b/src/core/hle/service/am/spsm.h @@ -11,6 +11,7 @@ namespace Service::AM { class SPSM final : public ServiceFramework<SPSM> { public: explicit SPSM(); + ~SPSM() override; }; } // namespace Service::AM diff --git a/src/core/hle/service/aoc/aoc_u.cpp b/src/core/hle/service/aoc/aoc_u.cpp index 6e7438580..d9eeac9ec 100644 --- a/src/core/hle/service/aoc/aoc_u.cpp +++ b/src/core/hle/service/aoc/aoc_u.cpp @@ -23,6 +23,8 @@ AOC_U::AOC_U() : ServiceFramework("aoc:u") { RegisterHandlers(functions); } +AOC_U::~AOC_U() = default; + void AOC_U::CountAddOnContent(Kernel::HLERequestContext& ctx) { IPC::ResponseBuilder rb{ctx, 4}; rb.Push(RESULT_SUCCESS); diff --git a/src/core/hle/service/aoc/aoc_u.h b/src/core/hle/service/aoc/aoc_u.h index 17d48ef30..29ce8f488 100644 --- a/src/core/hle/service/aoc/aoc_u.h +++ b/src/core/hle/service/aoc/aoc_u.h @@ -11,7 +11,7 @@ namespace Service::AOC { class AOC_U final : public ServiceFramework<AOC_U> { public: AOC_U(); - ~AOC_U() = default; + ~AOC_U() override; private: void CountAddOnContent(Kernel::HLERequestContext& ctx); diff --git a/src/core/hle/service/apm/apm.cpp b/src/core/hle/service/apm/apm.cpp index 4109cb7f7..f3c09bbb1 100644 --- a/src/core/hle/service/apm/apm.cpp +++ b/src/core/hle/service/apm/apm.cpp @@ -9,6 +9,9 @@ namespace Service::APM { +Module::Module() = default; +Module::~Module() = default; + void InstallInterfaces(SM::ServiceManager& service_manager) { auto module_ = std::make_shared<Module>(); std::make_shared<APM>(module_, "apm")->InstallAsService(service_manager); diff --git a/src/core/hle/service/apm/apm.h b/src/core/hle/service/apm/apm.h index 90a80d51b..4d7d5bb7c 100644 --- a/src/core/hle/service/apm/apm.h +++ b/src/core/hle/service/apm/apm.h @@ -15,8 +15,8 @@ enum class PerformanceMode : u8 { class Module final { public: - Module() = default; - ~Module() = default; + Module(); + ~Module(); }; /// Registers all AM services with the specified service manager. diff --git a/src/core/hle/service/apm/interface.cpp b/src/core/hle/service/apm/interface.cpp index 4cd8132f5..c22bd3859 100644 --- a/src/core/hle/service/apm/interface.cpp +++ b/src/core/hle/service/apm/interface.cpp @@ -70,6 +70,8 @@ APM::APM(std::shared_ptr<Module> apm, const char* name) RegisterHandlers(functions); } +APM::~APM() = default; + void APM::OpenSession(Kernel::HLERequestContext& ctx) { IPC::ResponseBuilder rb{ctx, 2, 0, 1}; rb.Push(RESULT_SUCCESS); @@ -93,6 +95,8 @@ APM_Sys::APM_Sys() : ServiceFramework{"apm:sys"} { RegisterHandlers(functions); } +APM_Sys::~APM_Sys() = default; + void APM_Sys::GetPerformanceEvent(Kernel::HLERequestContext& ctx) { IPC::ResponseBuilder rb{ctx, 2, 0, 1}; rb.Push(RESULT_SUCCESS); diff --git a/src/core/hle/service/apm/interface.h b/src/core/hle/service/apm/interface.h index d14264ad7..773541aa4 100644 --- a/src/core/hle/service/apm/interface.h +++ b/src/core/hle/service/apm/interface.h @@ -11,7 +11,7 @@ namespace Service::APM { class APM final : public ServiceFramework<APM> { public: explicit APM(std::shared_ptr<Module> apm, const char* name); - ~APM() = default; + ~APM() override; private: void OpenSession(Kernel::HLERequestContext& ctx); @@ -22,6 +22,7 @@ private: class APM_Sys final : public ServiceFramework<APM_Sys> { public: explicit APM_Sys(); + ~APM_Sys() override; private: void GetPerformanceEvent(Kernel::HLERequestContext& ctx); diff --git a/src/core/hle/service/audio/audctl.cpp b/src/core/hle/service/audio/audctl.cpp index 37c3fdcac..b6b71f966 100644 --- a/src/core/hle/service/audio/audctl.cpp +++ b/src/core/hle/service/audio/audctl.cpp @@ -42,4 +42,6 @@ AudCtl::AudCtl() : ServiceFramework{"audctl"} { RegisterHandlers(functions); } +AudCtl::~AudCtl() = default; + } // namespace Service::Audio diff --git a/src/core/hle/service/audio/audctl.h b/src/core/hle/service/audio/audctl.h index ed837bdf2..9d2d9e83b 100644 --- a/src/core/hle/service/audio/audctl.h +++ b/src/core/hle/service/audio/audctl.h @@ -11,6 +11,7 @@ namespace Service::Audio { class AudCtl final : public ServiceFramework<AudCtl> { public: explicit AudCtl(); + ~AudCtl() override; }; } // namespace Service::Audio diff --git a/src/core/hle/service/audio/auddbg.cpp b/src/core/hle/service/audio/auddbg.cpp index b08c21a20..8fff3e4b4 100644 --- a/src/core/hle/service/audio/auddbg.cpp +++ b/src/core/hle/service/audio/auddbg.cpp @@ -17,4 +17,6 @@ AudDbg::AudDbg(const char* name) : ServiceFramework{name} { RegisterHandlers(functions); } +AudDbg::~AudDbg() = default; + } // namespace Service::Audio diff --git a/src/core/hle/service/audio/auddbg.h b/src/core/hle/service/audio/auddbg.h index a2f540b75..6689f4759 100644 --- a/src/core/hle/service/audio/auddbg.h +++ b/src/core/hle/service/audio/auddbg.h @@ -11,6 +11,7 @@ namespace Service::Audio { class AudDbg final : public ServiceFramework<AudDbg> { public: explicit AudDbg(const char* name); + ~AudDbg() override; }; } // namespace Service::Audio diff --git a/src/core/hle/service/audio/audin_a.cpp b/src/core/hle/service/audio/audin_a.cpp index a70d5bca4..ddd12f35e 100644 --- a/src/core/hle/service/audio/audin_a.cpp +++ b/src/core/hle/service/audio/audin_a.cpp @@ -19,4 +19,6 @@ AudInA::AudInA() : ServiceFramework{"audin:a"} { RegisterHandlers(functions); } +AudInA::~AudInA() = default; + } // namespace Service::Audio diff --git a/src/core/hle/service/audio/audin_a.h b/src/core/hle/service/audio/audin_a.h index e4c75510f..e7623bc29 100644 --- a/src/core/hle/service/audio/audin_a.h +++ b/src/core/hle/service/audio/audin_a.h @@ -11,6 +11,7 @@ namespace Service::Audio { class AudInA final : public ServiceFramework<AudInA> { public: explicit AudInA(); + ~AudInA() override; }; } // namespace Service::Audio diff --git a/src/core/hle/service/audio/audin_u.cpp b/src/core/hle/service/audio/audin_u.cpp index cbc49e55e..657010312 100644 --- a/src/core/hle/service/audio/audin_u.cpp +++ b/src/core/hle/service/audio/audin_u.cpp @@ -41,4 +41,6 @@ AudInU::AudInU() : ServiceFramework("audin:u") { RegisterHandlers(functions); } +AudInU::~AudInU() = default; + } // namespace Service::Audio diff --git a/src/core/hle/service/audio/audin_u.h b/src/core/hle/service/audio/audin_u.h index 2e65efb5b..0538b9560 100644 --- a/src/core/hle/service/audio/audin_u.h +++ b/src/core/hle/service/audio/audin_u.h @@ -15,7 +15,7 @@ namespace Service::Audio { class AudInU final : public ServiceFramework<AudInU> { public: explicit AudInU(); - ~AudInU() = default; + ~AudInU() override; }; } // namespace Service::Audio diff --git a/src/core/hle/service/audio/audio.cpp b/src/core/hle/service/audio/audio.cpp index 6b5e15633..128df7db5 100644 --- a/src/core/hle/service/audio/audio.cpp +++ b/src/core/hle/service/audio/audio.cpp @@ -15,6 +15,7 @@ #include "core/hle/service/audio/audren_u.h" #include "core/hle/service/audio/codecctl.h" #include "core/hle/service/audio/hwopus.h" +#include "core/hle/service/service.h" namespace Service::Audio { diff --git a/src/core/hle/service/audio/audio.h b/src/core/hle/service/audio/audio.h index 95e5691f7..f5bd3bf5f 100644 --- a/src/core/hle/service/audio/audio.h +++ b/src/core/hle/service/audio/audio.h @@ -4,7 +4,9 @@ #pragma once -#include "core/hle/service/service.h" +namespace Service::SM { +class ServiceManager; +} namespace Service::Audio { diff --git a/src/core/hle/service/audio/audout_a.cpp b/src/core/hle/service/audio/audout_a.cpp index bf8d40157..85febbca3 100644 --- a/src/core/hle/service/audio/audout_a.cpp +++ b/src/core/hle/service/audio/audout_a.cpp @@ -21,4 +21,6 @@ AudOutA::AudOutA() : ServiceFramework{"audout:a"} { RegisterHandlers(functions); } +AudOutA::~AudOutA() = default; + } // namespace Service::Audio diff --git a/src/core/hle/service/audio/audout_a.h b/src/core/hle/service/audio/audout_a.h index 91a069152..d65b66e8e 100644 --- a/src/core/hle/service/audio/audout_a.h +++ b/src/core/hle/service/audio/audout_a.h @@ -11,6 +11,7 @@ namespace Service::Audio { class AudOutA final : public ServiceFramework<AudOutA> { public: explicit AudOutA(); + ~AudOutA() override; }; } // namespace Service::Audio diff --git a/src/core/hle/service/audio/audout_u.cpp b/src/core/hle/service/audio/audout_u.cpp index 5f370bbdf..80a002322 100644 --- a/src/core/hle/service/audio/audout_u.cpp +++ b/src/core/hle/service/audio/audout_u.cpp @@ -3,15 +3,20 @@ // Refer to the license.txt file included. #include <array> +#include <cstring> #include <vector> +#include "audio_core/audio_out.h" #include "audio_core/codec.h" +#include "common/common_funcs.h" #include "common/logging/log.h" +#include "common/swap.h" #include "core/core.h" #include "core/hle/ipc_helpers.h" #include "core/hle/kernel/event.h" #include "core/hle/kernel/hle_ipc.h" #include "core/hle/service/audio/audout_u.h" +#include "core/memory.h" namespace Service::Audio { @@ -25,6 +30,18 @@ enum { constexpr std::array<char, 10> DefaultDevice{{"DeviceOut"}}; constexpr int DefaultSampleRate{48000}; +struct AudoutParams { + s32_le sample_rate; + u16_le channel_count; + INSERT_PADDING_BYTES(2); +}; +static_assert(sizeof(AudoutParams) == 0x8, "AudoutParams is an invalid size"); + +enum class AudioState : u32 { + Started, + Stopped, +}; + class IAudioOut final : public ServiceFramework<IAudioOut> { public: IAudioOut(AudoutParams audio_params, AudioCore::AudioOut& audio_core) @@ -218,4 +235,6 @@ AudOutU::AudOutU() : ServiceFramework("audout:u") { audio_core = std::make_unique<AudioCore::AudioOut>(); } +AudOutU::~AudOutU() = default; + } // namespace Service::Audio diff --git a/src/core/hle/service/audio/audout_u.h b/src/core/hle/service/audio/audout_u.h index fd491f65d..dcaf64708 100644 --- a/src/core/hle/service/audio/audout_u.h +++ b/src/core/hle/service/audio/audout_u.h @@ -4,33 +4,24 @@ #pragma once -#include "audio_core/audio_out.h" #include "core/hle/service/service.h" +namespace AudioCore { +class AudioOut; +} + namespace Kernel { class HLERequestContext; } namespace Service::Audio { -struct AudoutParams { - s32_le sample_rate; - u16_le channel_count; - INSERT_PADDING_BYTES(2); -}; -static_assert(sizeof(AudoutParams) == 0x8, "AudoutParams is an invalid size"); - -enum class AudioState : u32 { - Started, - Stopped, -}; - class IAudioOut; class AudOutU final : public ServiceFramework<AudOutU> { public: AudOutU(); - ~AudOutU() = default; + ~AudOutU() override; private: std::shared_ptr<IAudioOut> audio_out_interface; diff --git a/src/core/hle/service/audio/audrec_a.cpp b/src/core/hle/service/audio/audrec_a.cpp index 016eabf53..ce1bfb48d 100644 --- a/src/core/hle/service/audio/audrec_a.cpp +++ b/src/core/hle/service/audio/audrec_a.cpp @@ -17,4 +17,6 @@ AudRecA::AudRecA() : ServiceFramework{"audrec:a"} { RegisterHandlers(functions); } +AudRecA::~AudRecA() = default; + } // namespace Service::Audio diff --git a/src/core/hle/service/audio/audrec_a.h b/src/core/hle/service/audio/audrec_a.h index 9685047f2..384d24c69 100644 --- a/src/core/hle/service/audio/audrec_a.h +++ b/src/core/hle/service/audio/audrec_a.h @@ -11,6 +11,7 @@ namespace Service::Audio { class AudRecA final : public ServiceFramework<AudRecA> { public: explicit AudRecA(); + ~AudRecA() override; }; } // namespace Service::Audio diff --git a/src/core/hle/service/audio/audrec_u.cpp b/src/core/hle/service/audio/audrec_u.cpp index 74909415c..34974afa9 100644 --- a/src/core/hle/service/audio/audrec_u.cpp +++ b/src/core/hle/service/audio/audrec_u.cpp @@ -36,4 +36,6 @@ AudRecU::AudRecU() : ServiceFramework("audrec:u") { RegisterHandlers(functions); } +AudRecU::~AudRecU() = default; + } // namespace Service::Audio diff --git a/src/core/hle/service/audio/audrec_u.h b/src/core/hle/service/audio/audrec_u.h index 46daa33a4..ca3d638e8 100644 --- a/src/core/hle/service/audio/audrec_u.h +++ b/src/core/hle/service/audio/audrec_u.h @@ -15,7 +15,7 @@ namespace Service::Audio { class AudRecU final : public ServiceFramework<AudRecU> { public: explicit AudRecU(); - ~AudRecU() = default; + ~AudRecU() override; }; } // namespace Service::Audio diff --git a/src/core/hle/service/audio/audren_a.cpp b/src/core/hle/service/audio/audren_a.cpp index 616ff3dc4..edb66d985 100644 --- a/src/core/hle/service/audio/audren_a.cpp +++ b/src/core/hle/service/audio/audren_a.cpp @@ -23,4 +23,6 @@ AudRenA::AudRenA() : ServiceFramework{"audren:a"} { RegisterHandlers(functions); } +AudRenA::~AudRenA() = default; + } // namespace Service::Audio diff --git a/src/core/hle/service/audio/audren_a.h b/src/core/hle/service/audio/audren_a.h index 5ecf2e184..81fef0ffe 100644 --- a/src/core/hle/service/audio/audren_a.h +++ b/src/core/hle/service/audio/audren_a.h @@ -11,6 +11,7 @@ namespace Service::Audio { class AudRenA final : public ServiceFramework<AudRenA> { public: explicit AudRenA(); + ~AudRenA() override; }; } // namespace Service::Audio diff --git a/src/core/hle/service/audio/audren_u.cpp b/src/core/hle/service/audio/audren_u.cpp index 016db7c82..e84c4fa2b 100644 --- a/src/core/hle/service/audio/audren_u.cpp +++ b/src/core/hle/service/audio/audren_u.cpp @@ -2,12 +2,14 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. +#include <algorithm> #include <array> +#include <memory> +#include "audio_core/audio_renderer.h" #include "common/alignment.h" +#include "common/common_funcs.h" #include "common/logging/log.h" -#include "core/core_timing.h" -#include "core/core_timing_util.h" #include "core/hle/ipc_helpers.h" #include "core/hle/kernel/event.h" #include "core/hle/kernel/hle_ipc.h" @@ -198,6 +200,8 @@ AudRenU::AudRenU() : ServiceFramework("audren:u") { RegisterHandlers(functions); } +AudRenU::~AudRenU() = default; + void AudRenU::OpenAudioRenderer(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; auto params = rp.PopRaw<AudioCore::AudioRendererParameter>(); diff --git a/src/core/hle/service/audio/audren_u.h b/src/core/hle/service/audio/audren_u.h index 8600ac6e4..c6bc3a90a 100644 --- a/src/core/hle/service/audio/audren_u.h +++ b/src/core/hle/service/audio/audren_u.h @@ -4,7 +4,6 @@ #pragma once -#include "audio_core/audio_renderer.h" #include "core/hle/service/service.h" namespace Kernel { @@ -16,7 +15,7 @@ namespace Service::Audio { class AudRenU final : public ServiceFramework<AudRenU> { public: explicit AudRenU(); - ~AudRenU() = default; + ~AudRenU() override; private: void OpenAudioRenderer(Kernel::HLERequestContext& ctx); diff --git a/src/core/hle/service/audio/codecctl.cpp b/src/core/hle/service/audio/codecctl.cpp index 212c8d448..c6864146d 100644 --- a/src/core/hle/service/audio/codecctl.cpp +++ b/src/core/hle/service/audio/codecctl.cpp @@ -28,4 +28,6 @@ CodecCtl::CodecCtl() : ServiceFramework("codecctl") { RegisterHandlers(functions); } +CodecCtl::~CodecCtl() = default; + } // namespace Service::Audio diff --git a/src/core/hle/service/audio/codecctl.h b/src/core/hle/service/audio/codecctl.h index d9ac29b67..2fe75b6e2 100644 --- a/src/core/hle/service/audio/codecctl.h +++ b/src/core/hle/service/audio/codecctl.h @@ -15,7 +15,7 @@ namespace Service::Audio { class CodecCtl final : public ServiceFramework<CodecCtl> { public: explicit CodecCtl(); - ~CodecCtl() = default; + ~CodecCtl() override; }; } // namespace Service::Audio diff --git a/src/core/hle/service/audio/hwopus.cpp b/src/core/hle/service/audio/hwopus.cpp index 371cd4997..668fef145 100644 --- a/src/core/hle/service/audio/hwopus.cpp +++ b/src/core/hle/service/audio/hwopus.cpp @@ -3,7 +3,12 @@ // Refer to the license.txt file included. #include <cstring> +#include <memory> +#include <vector> + #include <opus.h> + +#include "common/common_funcs.h" #include "common/logging/log.h" #include "core/hle/ipc_helpers.h" #include "core/hle/kernel/hle_ipc.h" @@ -151,4 +156,6 @@ HwOpus::HwOpus() : ServiceFramework("hwopus") { RegisterHandlers(functions); } +HwOpus::~HwOpus() = default; + } // namespace Service::Audio diff --git a/src/core/hle/service/audio/hwopus.h b/src/core/hle/service/audio/hwopus.h index 5258d59f3..602ede8ba 100644 --- a/src/core/hle/service/audio/hwopus.h +++ b/src/core/hle/service/audio/hwopus.h @@ -11,7 +11,7 @@ namespace Service::Audio { class HwOpus final : public ServiceFramework<HwOpus> { public: explicit HwOpus(); - ~HwOpus() = default; + ~HwOpus() override; private: void OpenOpusDecoder(Kernel::HLERequestContext& ctx); diff --git a/src/core/hle/service/bcat/bcat.cpp b/src/core/hle/service/bcat/bcat.cpp index 20ce692dc..179aa4949 100644 --- a/src/core/hle/service/bcat/bcat.cpp +++ b/src/core/hle/service/bcat/bcat.cpp @@ -13,4 +13,6 @@ BCAT::BCAT(std::shared_ptr<Module> module, const char* name) }; RegisterHandlers(functions); } + +BCAT::~BCAT() = default; } // namespace Service::BCAT diff --git a/src/core/hle/service/bcat/bcat.h b/src/core/hle/service/bcat/bcat.h index 6632996a0..802bd689a 100644 --- a/src/core/hle/service/bcat/bcat.h +++ b/src/core/hle/service/bcat/bcat.h @@ -11,6 +11,7 @@ namespace Service::BCAT { class BCAT final : public Module::Interface { public: explicit BCAT(std::shared_ptr<Module> module, const char* name); + ~BCAT() override; }; } // namespace Service::BCAT diff --git a/src/core/hle/service/bcat/module.cpp b/src/core/hle/service/bcat/module.cpp index 35e024c3d..6e7b795fb 100644 --- a/src/core/hle/service/bcat/module.cpp +++ b/src/core/hle/service/bcat/module.cpp @@ -42,6 +42,8 @@ void Module::Interface::CreateBcatService(Kernel::HLERequestContext& ctx) { Module::Interface::Interface(std::shared_ptr<Module> module, const char* name) : ServiceFramework(name), module(std::move(module)) {} +Module::Interface::~Interface() = default; + void InstallInterfaces(SM::ServiceManager& service_manager) { auto module = std::make_shared<Module>(); std::make_shared<BCAT>(module, "bcat:a")->InstallAsService(service_manager); diff --git a/src/core/hle/service/bcat/module.h b/src/core/hle/service/bcat/module.h index 62f6f5f9d..f0d63cab0 100644 --- a/src/core/hle/service/bcat/module.h +++ b/src/core/hle/service/bcat/module.h @@ -13,6 +13,7 @@ public: class Interface : public ServiceFramework<Interface> { public: explicit Interface(std::shared_ptr<Module> module, const char* name); + ~Interface() override; void CreateBcatService(Kernel::HLERequestContext& ctx); diff --git a/src/core/hle/service/fatal/fatal.cpp b/src/core/hle/service/fatal/fatal.cpp index 299b9474f..b436ce4e6 100644 --- a/src/core/hle/service/fatal/fatal.cpp +++ b/src/core/hle/service/fatal/fatal.cpp @@ -13,6 +13,8 @@ namespace Service::Fatal { Module::Interface::Interface(std::shared_ptr<Module> module, const char* name) : ServiceFramework(name), module(std::move(module)) {} +Module::Interface::~Interface() = default; + void Module::Interface::ThrowFatalWithPolicy(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp(ctx); u32 error_code = rp.Pop<u32>(); diff --git a/src/core/hle/service/fatal/fatal.h b/src/core/hle/service/fatal/fatal.h index ca607e236..4d9a5be52 100644 --- a/src/core/hle/service/fatal/fatal.h +++ b/src/core/hle/service/fatal/fatal.h @@ -13,6 +13,7 @@ public: class Interface : public ServiceFramework<Interface> { public: explicit Interface(std::shared_ptr<Module> module, const char* name); + ~Interface() override; void ThrowFatalWithPolicy(Kernel::HLERequestContext& ctx); void ThrowFatalWithCpuContext(Kernel::HLERequestContext& ctx); diff --git a/src/core/hle/service/fatal/fatal_p.cpp b/src/core/hle/service/fatal/fatal_p.cpp index a5254ac2f..9e5f872ff 100644 --- a/src/core/hle/service/fatal/fatal_p.cpp +++ b/src/core/hle/service/fatal/fatal_p.cpp @@ -9,4 +9,6 @@ namespace Service::Fatal { Fatal_P::Fatal_P(std::shared_ptr<Module> module) : Module::Interface(std::move(module), "fatal:p") {} +Fatal_P::~Fatal_P() = default; + } // namespace Service::Fatal diff --git a/src/core/hle/service/fatal/fatal_p.h b/src/core/hle/service/fatal/fatal_p.h index bfd8c8b74..6e9c5979f 100644 --- a/src/core/hle/service/fatal/fatal_p.h +++ b/src/core/hle/service/fatal/fatal_p.h @@ -11,6 +11,7 @@ namespace Service::Fatal { class Fatal_P final : public Module::Interface { public: explicit Fatal_P(std::shared_ptr<Module> module); + ~Fatal_P() override; }; } // namespace Service::Fatal diff --git a/src/core/hle/service/fatal/fatal_u.cpp b/src/core/hle/service/fatal/fatal_u.cpp index f0631329e..befc307cf 100644 --- a/src/core/hle/service/fatal/fatal_u.cpp +++ b/src/core/hle/service/fatal/fatal_u.cpp @@ -15,4 +15,6 @@ Fatal_U::Fatal_U(std::shared_ptr<Module> module) : Module::Interface(std::move(m RegisterHandlers(functions); } +Fatal_U::~Fatal_U() = default; + } // namespace Service::Fatal diff --git a/src/core/hle/service/fatal/fatal_u.h b/src/core/hle/service/fatal/fatal_u.h index 9b1a9e97a..72cb6d076 100644 --- a/src/core/hle/service/fatal/fatal_u.h +++ b/src/core/hle/service/fatal/fatal_u.h @@ -11,6 +11,7 @@ namespace Service::Fatal { class Fatal_U final : public Module::Interface { public: explicit Fatal_U(std::shared_ptr<Module> module); + ~Fatal_U() override; }; } // namespace Service::Fatal diff --git a/src/core/hle/service/filesystem/filesystem.cpp b/src/core/hle/service/filesystem/filesystem.cpp index 04c9d750f..5c4971724 100644 --- a/src/core/hle/service/filesystem/filesystem.cpp +++ b/src/core/hle/service/filesystem/filesystem.cpp @@ -40,6 +40,8 @@ static FileSys::VirtualDir GetDirectoryRelativeWrapped(FileSys::VirtualDir base, VfsDirectoryServiceWrapper::VfsDirectoryServiceWrapper(FileSys::VirtualDir backing_) : backing(std::move(backing_)) {} +VfsDirectoryServiceWrapper::~VfsDirectoryServiceWrapper() = default; + std::string VfsDirectoryServiceWrapper::GetName() const { return backing->GetName(); } diff --git a/src/core/hle/service/filesystem/filesystem.h b/src/core/hle/service/filesystem/filesystem.h index 793a7b06f..aab65a2b8 100644 --- a/src/core/hle/service/filesystem/filesystem.h +++ b/src/core/hle/service/filesystem/filesystem.h @@ -64,6 +64,7 @@ void InstallInterfaces(SM::ServiceManager& service_manager, const FileSys::Virtu class VfsDirectoryServiceWrapper { public: explicit VfsDirectoryServiceWrapper(FileSys::VirtualDir backing); + ~VfsDirectoryServiceWrapper(); /** * Get a descriptive name for the archive (e.g. "RomFS", "SaveData", etc.) diff --git a/src/core/hle/service/filesystem/fsp_ldr.cpp b/src/core/hle/service/filesystem/fsp_ldr.cpp index 0ab9c2606..fb487d5bc 100644 --- a/src/core/hle/service/filesystem/fsp_ldr.cpp +++ b/src/core/hle/service/filesystem/fsp_ldr.cpp @@ -19,4 +19,6 @@ FSP_LDR::FSP_LDR() : ServiceFramework{"fsp:ldr"} { RegisterHandlers(functions); } +FSP_LDR::~FSP_LDR() = default; + } // namespace Service::FileSystem diff --git a/src/core/hle/service/filesystem/fsp_ldr.h b/src/core/hle/service/filesystem/fsp_ldr.h index fa8e11b4c..8210b7729 100644 --- a/src/core/hle/service/filesystem/fsp_ldr.h +++ b/src/core/hle/service/filesystem/fsp_ldr.h @@ -11,6 +11,7 @@ namespace Service::FileSystem { class FSP_LDR final : public ServiceFramework<FSP_LDR> { public: explicit FSP_LDR(); + ~FSP_LDR() override; }; } // namespace Service::FileSystem diff --git a/src/core/hle/service/filesystem/fsp_pr.cpp b/src/core/hle/service/filesystem/fsp_pr.cpp index 32b0ae454..378201610 100644 --- a/src/core/hle/service/filesystem/fsp_pr.cpp +++ b/src/core/hle/service/filesystem/fsp_pr.cpp @@ -20,4 +20,6 @@ FSP_PR::FSP_PR() : ServiceFramework{"fsp:pr"} { RegisterHandlers(functions); } +FSP_PR::~FSP_PR() = default; + } // namespace Service::FileSystem diff --git a/src/core/hle/service/filesystem/fsp_pr.h b/src/core/hle/service/filesystem/fsp_pr.h index 62edcd08a..556ae5ce9 100644 --- a/src/core/hle/service/filesystem/fsp_pr.h +++ b/src/core/hle/service/filesystem/fsp_pr.h @@ -11,6 +11,7 @@ namespace Service::FileSystem { class FSP_PR final : public ServiceFramework<FSP_PR> { public: explicit FSP_PR(); + ~FSP_PR() override; }; } // namespace Service::FileSystem diff --git a/src/core/hle/service/filesystem/fsp_srv.cpp b/src/core/hle/service/filesystem/fsp_srv.cpp index 3f8ff67e8..cabaf5a55 100644 --- a/src/core/hle/service/filesystem/fsp_srv.cpp +++ b/src/core/hle/service/filesystem/fsp_srv.cpp @@ -520,6 +520,8 @@ FSP_SRV::FSP_SRV() : ServiceFramework("fsp-srv") { RegisterHandlers(functions); } +FSP_SRV::~FSP_SRV() = default; + void FSP_SRV::Initialize(Kernel::HLERequestContext& ctx) { LOG_WARNING(Service_FS, "(STUBBED) called"); diff --git a/src/core/hle/service/filesystem/fsp_srv.h b/src/core/hle/service/filesystem/fsp_srv.h index 2b5c21abb..4aa0358cb 100644 --- a/src/core/hle/service/filesystem/fsp_srv.h +++ b/src/core/hle/service/filesystem/fsp_srv.h @@ -16,7 +16,7 @@ namespace Service::FileSystem { class FSP_SRV final : public ServiceFramework<FSP_SRV> { public: explicit FSP_SRV(); - ~FSP_SRV() = default; + ~FSP_SRV() override; private: void Initialize(Kernel::HLERequestContext& ctx); diff --git a/src/core/hle/service/friend/friend.cpp b/src/core/hle/service/friend/friend.cpp index f2b0e509a..d9225d624 100644 --- a/src/core/hle/service/friend/friend.cpp +++ b/src/core/hle/service/friend/friend.cpp @@ -118,6 +118,8 @@ void Module::Interface::CreateFriendService(Kernel::HLERequestContext& ctx) { Module::Interface::Interface(std::shared_ptr<Module> module, const char* name) : ServiceFramework(name), module(std::move(module)) {} +Module::Interface::~Interface() = default; + void InstallInterfaces(SM::ServiceManager& service_manager) { auto module = std::make_shared<Module>(); std::make_shared<Friend>(module, "friend:a")->InstallAsService(service_manager); diff --git a/src/core/hle/service/friend/friend.h b/src/core/hle/service/friend/friend.h index c1b36518a..e762840cb 100644 --- a/src/core/hle/service/friend/friend.h +++ b/src/core/hle/service/friend/friend.h @@ -13,6 +13,7 @@ public: class Interface : public ServiceFramework<Interface> { public: explicit Interface(std::shared_ptr<Module> module, const char* name); + ~Interface() override; void CreateFriendService(Kernel::HLERequestContext& ctx); diff --git a/src/core/hle/service/friend/interface.cpp b/src/core/hle/service/friend/interface.cpp index 27c6a09e2..5a6840af5 100644 --- a/src/core/hle/service/friend/interface.cpp +++ b/src/core/hle/service/friend/interface.cpp @@ -16,4 +16,6 @@ Friend::Friend(std::shared_ptr<Module> module, const char* name) RegisterHandlers(functions); } +Friend::~Friend() = default; + } // namespace Service::Friend diff --git a/src/core/hle/service/friend/interface.h b/src/core/hle/service/friend/interface.h index 89dae8471..1963def39 100644 --- a/src/core/hle/service/friend/interface.h +++ b/src/core/hle/service/friend/interface.h @@ -11,6 +11,7 @@ namespace Service::Friend { class Friend final : public Module::Interface { public: explicit Friend(std::shared_ptr<Module> module, const char* name); + ~Friend() override; }; } // namespace Service::Friend diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp index 0d31abe8b..a8e0c869f 100644 --- a/src/core/hle/service/hid/hid.cpp +++ b/src/core/hle/service/hid/hid.cpp @@ -2,7 +2,6 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. -#include <atomic> #include "common/logging/log.h" #include "core/core.h" #include "core/core_timing.h" @@ -78,7 +77,7 @@ private: SharedMemory mem{}; std::memcpy(&mem, shared_mem->GetPointer(), sizeof(SharedMemory)); - if (is_device_reload_pending.exchange(false)) + if (Settings::values.is_device_reload_pending.exchange(false)) LoadInputDevices(); // Set up controllers as neon red+blue Joy-Con attached to console @@ -267,7 +266,6 @@ private: CoreTiming::EventType* pad_update_event; // Stored input state info - std::atomic<bool> is_device_reload_pending{true}; std::array<std::unique_ptr<Input::ButtonDevice>, Settings::NativeButton::NUM_BUTTONS_HID> buttons; std::array<std::unique_ptr<Input::AnalogDevice>, Settings::NativeAnalog::NUM_STICKS_HID> sticks; @@ -797,7 +795,9 @@ public: } }; -void ReloadInputDevices() {} +void ReloadInputDevices() { + Settings::values.is_device_reload_pending.store(true); +} void InstallInterfaces(SM::ServiceManager& service_manager) { std::make_shared<Hid>()->InstallAsService(service_manager); diff --git a/src/core/hle/service/hid/irs.cpp b/src/core/hle/service/hid/irs.cpp index aaf311912..e587ad0d8 100644 --- a/src/core/hle/service/hid/irs.cpp +++ b/src/core/hle/service/hid/irs.cpp @@ -33,6 +33,8 @@ IRS::IRS() : ServiceFramework{"irs"} { RegisterHandlers(functions); } +IRS::~IRS() = default; + IRS_SYS::IRS_SYS() : ServiceFramework{"irs:sys"} { // clang-format off static const FunctionInfo functions[] = { @@ -46,4 +48,6 @@ IRS_SYS::IRS_SYS() : ServiceFramework{"irs:sys"} { RegisterHandlers(functions); } +IRS_SYS::~IRS_SYS() = default; + } // namespace Service::HID diff --git a/src/core/hle/service/hid/irs.h b/src/core/hle/service/hid/irs.h index a8be701c7..6fb16b45d 100644 --- a/src/core/hle/service/hid/irs.h +++ b/src/core/hle/service/hid/irs.h @@ -11,11 +11,13 @@ namespace Service::HID { class IRS final : public ServiceFramework<IRS> { public: explicit IRS(); + ~IRS() override; }; class IRS_SYS final : public ServiceFramework<IRS_SYS> { public: explicit IRS_SYS(); + ~IRS_SYS() override; }; } // namespace Service::HID diff --git a/src/core/hle/service/hid/xcd.cpp b/src/core/hle/service/hid/xcd.cpp index 49f733f60..c8e9125f6 100644 --- a/src/core/hle/service/hid/xcd.cpp +++ b/src/core/hle/service/hid/xcd.cpp @@ -34,4 +34,6 @@ XCD_SYS::XCD_SYS() : ServiceFramework{"xcd:sys"} { RegisterHandlers(functions); } +XCD_SYS::~XCD_SYS() = default; + } // namespace Service::HID diff --git a/src/core/hle/service/hid/xcd.h b/src/core/hle/service/hid/xcd.h index 232a044df..fd506d303 100644 --- a/src/core/hle/service/hid/xcd.h +++ b/src/core/hle/service/hid/xcd.h @@ -11,6 +11,7 @@ namespace Service::HID { class XCD_SYS final : public ServiceFramework<XCD_SYS> { public: explicit XCD_SYS(); + ~XCD_SYS() override; }; } // namespace Service::HID diff --git a/src/core/hle/service/nfp/nfp.cpp b/src/core/hle/service/nfp/nfp.cpp index 4f7543af5..f8d2127d9 100644 --- a/src/core/hle/service/nfp/nfp.cpp +++ b/src/core/hle/service/nfp/nfp.cpp @@ -14,6 +14,8 @@ namespace Service::NFP { Module::Interface::Interface(std::shared_ptr<Module> module, const char* name) : ServiceFramework(name), module(std::move(module)) {} +Module::Interface::~Interface() = default; + class IUser final : public ServiceFramework<IUser> { public: IUser() : ServiceFramework("IUser") { diff --git a/src/core/hle/service/nfp/nfp.h b/src/core/hle/service/nfp/nfp.h index 0cd7be3d5..77df343c4 100644 --- a/src/core/hle/service/nfp/nfp.h +++ b/src/core/hle/service/nfp/nfp.h @@ -13,6 +13,7 @@ public: class Interface : public ServiceFramework<Interface> { public: explicit Interface(std::shared_ptr<Module> module, const char* name); + ~Interface() override; void CreateUserInterface(Kernel::HLERequestContext& ctx); diff --git a/src/core/hle/service/nfp/nfp_user.cpp b/src/core/hle/service/nfp/nfp_user.cpp index b608fe693..784a87c1b 100644 --- a/src/core/hle/service/nfp/nfp_user.cpp +++ b/src/core/hle/service/nfp/nfp_user.cpp @@ -14,4 +14,6 @@ NFP_User::NFP_User(std::shared_ptr<Module> module) RegisterHandlers(functions); } +NFP_User::~NFP_User() = default; + } // namespace Service::NFP diff --git a/src/core/hle/service/nfp/nfp_user.h b/src/core/hle/service/nfp/nfp_user.h index 700043114..65d9aaf48 100644 --- a/src/core/hle/service/nfp/nfp_user.h +++ b/src/core/hle/service/nfp/nfp_user.h @@ -11,6 +11,7 @@ namespace Service::NFP { class NFP_User final : public Module::Interface { public: explicit NFP_User(std::shared_ptr<Module> module); + ~NFP_User() override; }; } // namespace Service::NFP diff --git a/src/core/hle/service/ns/pl_u.cpp b/src/core/hle/service/ns/pl_u.cpp index 878bbe439..ac0eaaa8f 100644 --- a/src/core/hle/service/ns/pl_u.cpp +++ b/src/core/hle/service/ns/pl_u.cpp @@ -2,14 +2,30 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. +#include <algorithm> +#include <cstring> +#include <vector> + +#include <FontChineseSimplified.h> +#include <FontChineseTraditional.h> +#include <FontExtendedChineseSimplified.h> +#include <FontKorean.h> +#include <FontNintendoExtended.h> +#include <FontStandard.h> + +#include "common/assert.h" #include "common/common_paths.h" +#include "common/common_types.h" #include "common/file_util.h" +#include "common/logging/log.h" +#include "common/swap.h" #include "core/core.h" #include "core/file_sys/content_archive.h" #include "core/file_sys/nca_metadata.h" #include "core/file_sys/registered_cache.h" #include "core/file_sys/romfs.h" #include "core/hle/ipc_helpers.h" +#include "core/hle/kernel/shared_memory.h" #include "core/hle/service/filesystem/filesystem.h" #include "core/hle/service/ns/pl_u.h" @@ -28,49 +44,41 @@ struct FontRegion { u32 size; }; -static constexpr std::array<std::pair<FontArchives, const char*>, 7> SHARED_FONTS{ +constexpr std::array<std::pair<FontArchives, const char*>, 7> SHARED_FONTS{ std::make_pair(FontArchives::Standard, "nintendo_udsg-r_std_003.bfttf"), std::make_pair(FontArchives::ChineseSimple, "nintendo_udsg-r_org_zh-cn_003.bfttf"), std::make_pair(FontArchives::ChineseSimple, "nintendo_udsg-r_ext_zh-cn_003.bfttf"), std::make_pair(FontArchives::ChineseTraditional, "nintendo_udjxh-db_zh-tw_003.bfttf"), std::make_pair(FontArchives::Korean, "nintendo_udsg-r_ko_003.bfttf"), std::make_pair(FontArchives::Extension, "nintendo_ext_003.bfttf"), - std::make_pair(FontArchives::Extension, "nintendo_ext2_003.bfttf")}; + std::make_pair(FontArchives::Extension, "nintendo_ext2_003.bfttf"), +}; -static constexpr std::array<const char*, 7> SHARED_FONTS_TTF{"FontStandard.ttf", - "FontChineseSimplified.ttf", - "FontExtendedChineseSimplified.ttf", - "FontChineseTraditional.ttf", - "FontKorean.ttf", - "FontNintendoExtended.ttf", - "FontNintendoExtended2.ttf"}; +constexpr std::array<const char*, 7> SHARED_FONTS_TTF{ + "FontStandard.ttf", + "FontChineseSimplified.ttf", + "FontExtendedChineseSimplified.ttf", + "FontChineseTraditional.ttf", + "FontKorean.ttf", + "FontNintendoExtended.ttf", + "FontNintendoExtended2.ttf", +}; // The below data is specific to shared font data dumped from Switch on f/w 2.2 // Virtual address and offsets/sizes likely will vary by dump -static constexpr VAddr SHARED_FONT_MEM_VADDR{0x00000009d3016000ULL}; -static constexpr u32 EXPECTED_RESULT{ - 0x7f9a0218}; // What we expect the decrypted bfttf first 4 bytes to be -static constexpr u32 EXPECTED_MAGIC{ - 0x36f81a1e}; // What we expect the encrypted bfttf first 4 bytes to be -static constexpr u64 SHARED_FONT_MEM_SIZE{0x1100000}; -static constexpr FontRegion EMPTY_REGION{0, 0}; -std::vector<FontRegion> - SHARED_FONT_REGIONS{}; // Automatically populated based on shared_fonts dump or system archives - -const FontRegion& GetSharedFontRegion(size_t index) { - if (index >= SHARED_FONT_REGIONS.size() || SHARED_FONT_REGIONS.empty()) { - // No font fallback - return EMPTY_REGION; - } - return SHARED_FONT_REGIONS.at(index); -} +constexpr VAddr SHARED_FONT_MEM_VADDR{0x00000009d3016000ULL}; +constexpr u32 EXPECTED_RESULT{0x7f9a0218}; // What we expect the decrypted bfttf first 4 bytes to be +constexpr u32 EXPECTED_MAGIC{0x36f81a1e}; // What we expect the encrypted bfttf first 4 bytes to be +constexpr u64 SHARED_FONT_MEM_SIZE{0x1100000}; +constexpr FontRegion EMPTY_REGION{0, 0}; enum class LoadState : u32 { Loading = 0, Done = 1, }; -void DecryptSharedFont(const std::vector<u32>& input, std::vector<u8>& output, size_t& offset) { +static void DecryptSharedFont(const std::vector<u32>& input, std::vector<u8>& output, + size_t& offset) { ASSERT_MSG(offset + (input.size() * sizeof(u32)) < SHARED_FONT_MEM_SIZE, "Shared fonts exceeds 17mb!"); ASSERT_MSG(input[0] == EXPECTED_MAGIC, "Failed to derive key, unexpected magic number"); @@ -97,28 +105,52 @@ static void EncryptSharedFont(const std::vector<u8>& input, std::vector<u8>& out offset += input.size() + (sizeof(u32) * 2); } +// Helper function to make BuildSharedFontsRawRegions a bit nicer static u32 GetU32Swapped(const u8* data) { u32 value; std::memcpy(&value, data, sizeof(value)); - return Common::swap32(value); // Helper function to make BuildSharedFontsRawRegions a bit nicer + return Common::swap32(value); } -void BuildSharedFontsRawRegions(const std::vector<u8>& input) { - unsigned cur_offset = 0; // As we can derive the xor key we can just populate the offsets based - // on the shared memory dump - for (size_t i = 0; i < SHARED_FONTS.size(); i++) { - // Out of shared fonts/Invalid font - if (GetU32Swapped(input.data() + cur_offset) != EXPECTED_RESULT) - break; - const u32 KEY = GetU32Swapped(input.data() + cur_offset) ^ - EXPECTED_MAGIC; // Derive key withing inverse xor - const u32 SIZE = GetU32Swapped(input.data() + cur_offset + 4) ^ KEY; - SHARED_FONT_REGIONS.push_back(FontRegion{cur_offset + 8, SIZE}); - cur_offset += SIZE + 8; +struct PL_U::Impl { + const FontRegion& GetSharedFontRegion(size_t index) const { + if (index >= shared_font_regions.size() || shared_font_regions.empty()) { + // No font fallback + return EMPTY_REGION; + } + return shared_font_regions.at(index); } -} -PL_U::PL_U() : ServiceFramework("pl:u") { + void BuildSharedFontsRawRegions(const std::vector<u8>& input) { + // As we can derive the xor key we can just populate the offsets + // based on the shared memory dump + unsigned cur_offset = 0; + + for (size_t i = 0; i < SHARED_FONTS.size(); i++) { + // Out of shared fonts/invalid font + if (GetU32Swapped(input.data() + cur_offset) != EXPECTED_RESULT) { + break; + } + + // Derive key withing inverse xor + const u32 KEY = GetU32Swapped(input.data() + cur_offset) ^ EXPECTED_MAGIC; + const u32 SIZE = GetU32Swapped(input.data() + cur_offset + 4) ^ KEY; + shared_font_regions.push_back(FontRegion{cur_offset + 8, SIZE}); + cur_offset += SIZE + 8; + } + } + + /// Handle to shared memory region designated for a shared font + Kernel::SharedPtr<Kernel::SharedMemory> shared_font_mem; + + /// Backing memory for the shared font data + std::shared_ptr<std::vector<u8>> shared_font; + + // Automatically populated based on shared_fonts dump or system archives. + std::vector<FontRegion> shared_font_regions; +}; + +PL_U::PL_U() : ServiceFramework("pl:u"), impl{std::make_unique<Impl>()} { static const FunctionInfo functions[] = { {0, &PL_U::RequestLoad, "RequestLoad"}, {1, &PL_U::GetLoadState, "GetLoadState"}, @@ -134,7 +166,7 @@ PL_U::PL_U() : ServiceFramework("pl:u") { // Rebuild shared fonts from data ncas if (nand->HasEntry(static_cast<u64>(FontArchives::Standard), FileSys::ContentRecordType::Data)) { - shared_font = std::make_shared<std::vector<u8>>(SHARED_FONT_MEM_SIZE); + impl->shared_font = std::make_shared<std::vector<u8>>(SHARED_FONT_MEM_SIZE); for (auto font : SHARED_FONTS) { const auto nca = nand->GetEntry(static_cast<u64>(font.first), FileSys::ContentRecordType::Data); @@ -170,12 +202,12 @@ PL_U::PL_U() : ServiceFramework("pl:u") { static_cast<u32>(offset + 8), static_cast<u32>((font_data_u32.size() * sizeof(u32)) - 8)}; // Font offset and size do not account for the header - DecryptSharedFont(font_data_u32, *shared_font, offset); - SHARED_FONT_REGIONS.push_back(region); + DecryptSharedFont(font_data_u32, *impl->shared_font, offset); + impl->shared_font_regions.push_back(region); } } else { - shared_font = std::make_shared<std::vector<u8>>( + impl->shared_font = std::make_shared<std::vector<u8>>( SHARED_FONT_MEM_SIZE); // Shared memory needs to always be allocated and a fixed size const std::string user_path = FileUtil::GetUserPath(FileUtil::UserPath::SysDataDir); @@ -199,8 +231,8 @@ PL_U::PL_U() : ServiceFramework("pl:u") { static_cast<u32>(offset + 8), static_cast<u32>(ttf_bytes.size())}; // Font offset and size do not account // for the header - EncryptSharedFont(ttf_bytes, *shared_font, offset); - SHARED_FONT_REGIONS.push_back(region); + EncryptSharedFont(ttf_bytes, *impl->shared_font, offset); + impl->shared_font_regions.push_back(region); } else { LOG_WARNING(Service_NS, "Unable to load font: {}", font_ttf); } @@ -215,14 +247,33 @@ PL_U::PL_U() : ServiceFramework("pl:u") { if (file.IsOpen()) { // Read shared font data ASSERT(file.GetSize() == SHARED_FONT_MEM_SIZE); - file.ReadBytes(shared_font->data(), shared_font->size()); - BuildSharedFontsRawRegions(*shared_font); + file.ReadBytes(impl->shared_font->data(), impl->shared_font->size()); + impl->BuildSharedFontsRawRegions(*impl->shared_font); } else { - LOG_WARNING(Service_NS, "Unable to load shared font: {}", filepath); + LOG_WARNING(Service_NS, + "Shared Font file missing. Loading open source replacement from memory"); + + const std::vector<std::vector<u8>> open_source_shared_fonts_ttf = { + {std::begin(FontChineseSimplified), std::end(FontChineseSimplified)}, + {std::begin(FontChineseTraditional), std::end(FontChineseTraditional)}, + {std::begin(FontExtendedChineseSimplified), + std::end(FontExtendedChineseSimplified)}, + {std::begin(FontNintendoExtended), std::end(FontNintendoExtended)}, + {std::begin(FontStandard), std::end(FontStandard)}, + }; + + for (const std::vector<u8>& font_ttf : open_source_shared_fonts_ttf) { + const FontRegion region{static_cast<u32>(offset + 8), + static_cast<u32>(font_ttf.size())}; + EncryptSharedFont(font_ttf, *impl->shared_font, offset); + impl->shared_font_regions.push_back(region); + } } } } +PL_U::~PL_U() = default; + void PL_U::RequestLoad(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; const u32 shared_font_type{rp.Pop<u32>()}; @@ -249,7 +300,7 @@ void PL_U::GetSize(Kernel::HLERequestContext& ctx) { LOG_DEBUG(Service_NS, "called, font_id={}", font_id); IPC::ResponseBuilder rb{ctx, 3}; rb.Push(RESULT_SUCCESS); - rb.Push<u32>(GetSharedFontRegion(font_id).size); + rb.Push<u32>(impl->GetSharedFontRegion(font_id).size); } void PL_U::GetSharedMemoryAddressOffset(Kernel::HLERequestContext& ctx) { @@ -259,17 +310,18 @@ void PL_U::GetSharedMemoryAddressOffset(Kernel::HLERequestContext& ctx) { LOG_DEBUG(Service_NS, "called, font_id={}", font_id); IPC::ResponseBuilder rb{ctx, 3}; rb.Push(RESULT_SUCCESS); - rb.Push<u32>(GetSharedFontRegion(font_id).offset); + rb.Push<u32>(impl->GetSharedFontRegion(font_id).offset); } void PL_U::GetSharedMemoryNativeHandle(Kernel::HLERequestContext& ctx) { // Map backing memory for the font data - Core::CurrentProcess()->vm_manager.MapMemoryBlock( - SHARED_FONT_MEM_VADDR, shared_font, 0, SHARED_FONT_MEM_SIZE, Kernel::MemoryState::Shared); + Core::CurrentProcess()->vm_manager.MapMemoryBlock(SHARED_FONT_MEM_VADDR, impl->shared_font, 0, + SHARED_FONT_MEM_SIZE, + Kernel::MemoryState::Shared); // Create shared font memory object auto& kernel = Core::System::GetInstance().Kernel(); - shared_font_mem = Kernel::SharedMemory::Create( + impl->shared_font_mem = Kernel::SharedMemory::Create( kernel, Core::CurrentProcess(), SHARED_FONT_MEM_SIZE, Kernel::MemoryPermission::ReadWrite, Kernel::MemoryPermission::Read, SHARED_FONT_MEM_VADDR, Kernel::MemoryRegion::BASE, "PL_U:shared_font_mem"); @@ -277,7 +329,7 @@ void PL_U::GetSharedMemoryNativeHandle(Kernel::HLERequestContext& ctx) { LOG_DEBUG(Service_NS, "called"); IPC::ResponseBuilder rb{ctx, 2, 1}; rb.Push(RESULT_SUCCESS); - rb.PushCopyObjects(shared_font_mem); + rb.PushCopyObjects(impl->shared_font_mem); } void PL_U::GetSharedFontInOrderOfPriority(Kernel::HLERequestContext& ctx) { @@ -290,9 +342,9 @@ void PL_U::GetSharedFontInOrderOfPriority(Kernel::HLERequestContext& ctx) { std::vector<u32> font_sizes; // TODO(ogniK): Have actual priority order - for (size_t i = 0; i < SHARED_FONT_REGIONS.size(); i++) { + for (size_t i = 0; i < impl->shared_font_regions.size(); i++) { font_codes.push_back(static_cast<u32>(i)); - auto region = GetSharedFontRegion(i); + auto region = impl->GetSharedFontRegion(i); font_offsets.push_back(region.offset); font_sizes.push_back(region.size); } diff --git a/src/core/hle/service/ns/pl_u.h b/src/core/hle/service/ns/pl_u.h index fcc2acab7..253f26a2a 100644 --- a/src/core/hle/service/ns/pl_u.h +++ b/src/core/hle/service/ns/pl_u.h @@ -5,7 +5,6 @@ #pragma once #include <memory> -#include "core/hle/kernel/shared_memory.h" #include "core/hle/service/service.h" namespace Service::NS { @@ -13,7 +12,7 @@ namespace Service::NS { class PL_U final : public ServiceFramework<PL_U> { public: PL_U(); - ~PL_U() = default; + ~PL_U() override; private: void RequestLoad(Kernel::HLERequestContext& ctx); @@ -23,11 +22,8 @@ private: void GetSharedMemoryNativeHandle(Kernel::HLERequestContext& ctx); void GetSharedFontInOrderOfPriority(Kernel::HLERequestContext& ctx); - /// Handle to shared memory region designated for a shared font - Kernel::SharedPtr<Kernel::SharedMemory> shared_font_mem; - - /// Backing memory for the shared font data - std::shared_ptr<std::vector<u8>> shared_font; + struct Impl; + std::unique_ptr<Impl> impl; }; } // namespace Service::NS diff --git a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp index 0b37098e1..92acc57b1 100644 --- a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp +++ b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp @@ -13,6 +13,9 @@ namespace Service::Nvidia::Devices { +nvdisp_disp0::nvdisp_disp0(std::shared_ptr<nvmap> nvmap_dev) : nvmap_dev(std::move(nvmap_dev)) {} +nvdisp_disp0 ::~nvdisp_disp0() = default; + u32 nvdisp_disp0::ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) { UNIMPLEMENTED_MSG("Unimplemented ioctl"); return 0; diff --git a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.h b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.h index 6f0697b58..a45086e45 100644 --- a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.h +++ b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.h @@ -17,8 +17,8 @@ class nvmap; class nvdisp_disp0 final : public nvdevice { public: - explicit nvdisp_disp0(std::shared_ptr<nvmap> nvmap_dev) : nvmap_dev(std::move(nvmap_dev)) {} - ~nvdisp_disp0() = default; + explicit nvdisp_disp0(std::shared_ptr<nvmap> nvmap_dev); + ~nvdisp_disp0(); u32 ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) override; 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 75487c4e8..25d5a93fa 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp @@ -3,6 +3,8 @@ // Refer to the license.txt file included. #include <cstring> +#include <utility> + #include "common/assert.h" #include "common/logging/log.h" #include "core/core.h" @@ -14,6 +16,9 @@ namespace Service::Nvidia::Devices { +nvhost_as_gpu::nvhost_as_gpu(std::shared_ptr<nvmap> nvmap_dev) : nvmap_dev(std::move(nvmap_dev)) {} +nvhost_as_gpu::~nvhost_as_gpu() = default; + u32 nvhost_as_gpu::ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) { LOG_DEBUG(Service_NVDRV, "called, command=0x{:08X}, input_size=0x{:X}, output_size=0x{:X}", command.raw, input.size(), output.size()); 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 9f8999d9c..eb14b1da8 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h +++ b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h @@ -6,7 +6,6 @@ #include <memory> #include <unordered_map> -#include <utility> #include <vector> #include "common/common_types.h" #include "common/swap.h" @@ -18,8 +17,8 @@ class nvmap; class nvhost_as_gpu final : public nvdevice { public: - explicit nvhost_as_gpu(std::shared_ptr<nvmap> nvmap_dev) : nvmap_dev(std::move(nvmap_dev)) {} - ~nvhost_as_gpu() override = default; + explicit nvhost_as_gpu(std::shared_ptr<nvmap> nvmap_dev); + ~nvhost_as_gpu() override; u32 ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) override; diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp index 5685eb2be..b39fb9ef9 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp @@ -11,6 +11,9 @@ namespace Service::Nvidia::Devices { +nvhost_ctrl::nvhost_ctrl() = default; +nvhost_ctrl::~nvhost_ctrl() = default; + u32 nvhost_ctrl::ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) { LOG_DEBUG(Service_NVDRV, "called, command=0x{:08X}, input_size=0x{:X}, output_size=0x{:X}", command.raw, input.size(), output.size()); diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.h b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.h index 6b496e9fe..6d0de2212 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.h +++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.h @@ -13,8 +13,8 @@ namespace Service::Nvidia::Devices { class nvhost_ctrl final : public nvdevice { public: - nvhost_ctrl() = default; - ~nvhost_ctrl() override = default; + nvhost_ctrl(); + ~nvhost_ctrl() override; u32 ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) override; diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp b/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp index ae421247d..7a88ae029 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp @@ -9,6 +9,9 @@ namespace Service::Nvidia::Devices { +nvhost_ctrl_gpu::nvhost_ctrl_gpu() = default; +nvhost_ctrl_gpu::~nvhost_ctrl_gpu() = default; + u32 nvhost_ctrl_gpu::ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) { LOG_DEBUG(Service_NVDRV, "called, command=0x{:08X}, input_size=0x{:X}, output_size=0x{:X}", command.raw, input.size(), output.size()); diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.h b/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.h index f09113e67..3bbf028ad 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.h +++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.h @@ -13,8 +13,8 @@ namespace Service::Nvidia::Devices { class nvhost_ctrl_gpu final : public nvdevice { public: - nvhost_ctrl_gpu() = default; - ~nvhost_ctrl_gpu() override = default; + nvhost_ctrl_gpu(); + ~nvhost_ctrl_gpu() override; u32 ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) override; diff --git a/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp b/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp index 4cdf7f613..874d5e1c3 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp @@ -8,11 +8,15 @@ #include "core/core.h" #include "core/hle/service/nvdrv/devices/nvhost_gpu.h" #include "core/memory.h" +#include "video_core/command_processor.h" #include "video_core/gpu.h" #include "video_core/memory_manager.h" namespace Service::Nvidia::Devices { +nvhost_gpu::nvhost_gpu(std::shared_ptr<nvmap> nvmap_dev) : nvmap_dev(std::move(nvmap_dev)) {} +nvhost_gpu::~nvhost_gpu() = default; + u32 nvhost_gpu::ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) { LOG_DEBUG(Service_NVDRV, "called, command=0x{:08X}, input_size=0x{:X}, output_size=0x{:X}", command.raw, input.size(), output.size()); @@ -134,17 +138,16 @@ u32 nvhost_gpu::SubmitGPFIFO(const std::vector<u8>& input, std::vector<u8>& outp LOG_WARNING(Service_NVDRV, "(STUBBED) called, gpfifo={:X}, num_entries={:X}, flags={:X}", params.address, params.num_entries, params.flags); - ASSERT_MSG(input.size() == - sizeof(IoctlSubmitGpfifo) + params.num_entries * sizeof(IoctlGpfifoEntry), + ASSERT_MSG(input.size() == sizeof(IoctlSubmitGpfifo) + + params.num_entries * sizeof(Tegra::CommandListHeader), "Incorrect input size"); - std::vector<IoctlGpfifoEntry> entries(params.num_entries); + std::vector<Tegra::CommandListHeader> entries(params.num_entries); std::memcpy(entries.data(), &input[sizeof(IoctlSubmitGpfifo)], - params.num_entries * sizeof(IoctlGpfifoEntry)); - for (auto entry : entries) { - Tegra::GPUVAddr va_addr = entry.Address(); - Core::System::GetInstance().GPU().ProcessCommandList(va_addr, entry.sz); - } + params.num_entries * sizeof(Tegra::CommandListHeader)); + + Core::System::GetInstance().GPU().ProcessCommandLists(entries); + params.fence_out.id = 0; params.fence_out.value = 0; std::memcpy(output.data(), ¶ms, sizeof(IoctlSubmitGpfifo)); @@ -160,14 +163,12 @@ u32 nvhost_gpu::KickoffPB(const std::vector<u8>& input, std::vector<u8>& output) LOG_WARNING(Service_NVDRV, "(STUBBED) called, gpfifo={:X}, num_entries={:X}, flags={:X}", params.address, params.num_entries, params.flags); - std::vector<IoctlGpfifoEntry> entries(params.num_entries); + std::vector<Tegra::CommandListHeader> entries(params.num_entries); Memory::ReadBlock(params.address, entries.data(), - params.num_entries * sizeof(IoctlGpfifoEntry)); + params.num_entries * sizeof(Tegra::CommandListHeader)); + + Core::System::GetInstance().GPU().ProcessCommandLists(entries); - for (auto entry : entries) { - Tegra::GPUVAddr va_addr = entry.Address(); - Core::System::GetInstance().GPU().ProcessCommandList(va_addr, entry.sz); - } params.fence_out.id = 0; params.fence_out.value = 0; std::memcpy(output.data(), ¶ms, output.size()); diff --git a/src/core/hle/service/nvdrv/devices/nvhost_gpu.h b/src/core/hle/service/nvdrv/devices/nvhost_gpu.h index 03b7356d0..62beb5c0c 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_gpu.h +++ b/src/core/hle/service/nvdrv/devices/nvhost_gpu.h @@ -10,7 +10,6 @@ #include "common/common_types.h" #include "common/swap.h" #include "core/hle/service/nvdrv/devices/nvdevice.h" -#include "video_core/memory_manager.h" namespace Service::Nvidia::Devices { @@ -21,8 +20,8 @@ constexpr u32 NVGPU_IOCTL_CHANNEL_KICKOFF_PB(0x1b); class nvhost_gpu final : public nvdevice { public: - explicit nvhost_gpu(std::shared_ptr<nvmap> nvmap_dev) : nvmap_dev(std::move(nvmap_dev)) {} - ~nvhost_gpu() override = default; + explicit nvhost_gpu(std::shared_ptr<nvmap> nvmap_dev); + ~nvhost_gpu() override; u32 ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) override; @@ -151,22 +150,6 @@ private: }; static_assert(sizeof(IoctlAllocObjCtx) == 16, "IoctlAllocObjCtx is incorrect size"); - struct IoctlGpfifoEntry { - u32_le entry0; // gpu_va_lo - union { - u32_le entry1; // gpu_va_hi | (unk_0x02 << 0x08) | (size << 0x0A) | (unk_0x01 << 0x1F) - BitField<0, 8, u32_le> gpu_va_hi; - BitField<8, 2, u32_le> unk1; - BitField<10, 21, u32_le> sz; - BitField<31, 1, u32_le> unk2; - }; - - Tegra::GPUVAddr Address() const { - return (static_cast<Tegra::GPUVAddr>(gpu_va_hi) << 32) | entry0; - } - }; - static_assert(sizeof(IoctlGpfifoEntry) == 8, "IoctlGpfifoEntry is incorrect size"); - struct IoctlSubmitGpfifo { u64_le address; // pointer to gpfifo entry structs u32_le num_entries; // number of fence objects being submitted diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp b/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp index 364619e67..46dbbc37c 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp @@ -10,6 +10,9 @@ namespace Service::Nvidia::Devices { +nvhost_nvdec::nvhost_nvdec() = default; +nvhost_nvdec::~nvhost_nvdec() = default; + u32 nvhost_nvdec::ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) { LOG_DEBUG(Service_NVDRV, "called, command=0x{:08X}, input_size=0x{:X}, output_size=0x{:X}", command.raw, input.size(), output.size()); diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvdec.h b/src/core/hle/service/nvdrv/devices/nvhost_nvdec.h index 6ad74421b..0e7b284f8 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_nvdec.h +++ b/src/core/hle/service/nvdrv/devices/nvhost_nvdec.h @@ -13,8 +13,8 @@ namespace Service::Nvidia::Devices { class nvhost_nvdec final : public nvdevice { public: - nvhost_nvdec() = default; - ~nvhost_nvdec() override = default; + nvhost_nvdec(); + ~nvhost_nvdec() override; u32 ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) override; diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.cpp b/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.cpp index 51f01077b..c67f934f6 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.cpp @@ -10,6 +10,9 @@ namespace Service::Nvidia::Devices { +nvhost_nvjpg::nvhost_nvjpg() = default; +nvhost_nvjpg::~nvhost_nvjpg() = default; + u32 nvhost_nvjpg::ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) { LOG_DEBUG(Service_NVDRV, "called, command=0x{:08X}, input_size=0x{:X}, output_size=0x{:X}", command.raw, input.size(), output.size()); diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.h b/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.h index 2b0eb43ee..89fd5e95e 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.h +++ b/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.h @@ -13,8 +13,8 @@ namespace Service::Nvidia::Devices { class nvhost_nvjpg final : public nvdevice { public: - nvhost_nvjpg() = default; - ~nvhost_nvjpg() override = default; + nvhost_nvjpg(); + ~nvhost_nvjpg() override; u32 ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) override; diff --git a/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp b/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp index fcb488d50..727b9fee4 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp @@ -10,6 +10,9 @@ namespace Service::Nvidia::Devices { +nvhost_vic::nvhost_vic() = default; +nvhost_vic::~nvhost_vic() = default; + u32 nvhost_vic::ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) { LOG_DEBUG(Service_NVDRV, "called, command=0x{:08X}, input_size=0x{:X}, output_size=0x{:X}", command.raw, input.size(), output.size()); diff --git a/src/core/hle/service/nvdrv/devices/nvhost_vic.h b/src/core/hle/service/nvdrv/devices/nvhost_vic.h index c7d681e52..fc24c3f9c 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_vic.h +++ b/src/core/hle/service/nvdrv/devices/nvhost_vic.h @@ -13,8 +13,8 @@ namespace Service::Nvidia::Devices { class nvhost_vic final : public nvdevice { public: - nvhost_vic() = default; - ~nvhost_vic() override = default; + nvhost_vic(); + ~nvhost_vic() override; u32 ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) override; diff --git a/src/core/hle/service/nvdrv/devices/nvmap.cpp b/src/core/hle/service/nvdrv/devices/nvmap.cpp index e9305bfb3..a2287cc1b 100644 --- a/src/core/hle/service/nvdrv/devices/nvmap.cpp +++ b/src/core/hle/service/nvdrv/devices/nvmap.cpp @@ -11,6 +11,9 @@ namespace Service::Nvidia::Devices { +nvmap::nvmap() = default; +nvmap::~nvmap() = default; + VAddr nvmap::GetObjectAddress(u32 handle) const { auto object = GetObject(handle); ASSERT(object); diff --git a/src/core/hle/service/nvdrv/devices/nvmap.h b/src/core/hle/service/nvdrv/devices/nvmap.h index f2eec6409..396230c19 100644 --- a/src/core/hle/service/nvdrv/devices/nvmap.h +++ b/src/core/hle/service/nvdrv/devices/nvmap.h @@ -16,8 +16,8 @@ namespace Service::Nvidia::Devices { class nvmap final : public nvdevice { public: - nvmap() = default; - ~nvmap() override = default; + nvmap(); + ~nvmap() override; /// Returns the allocated address of an nvmap object given its handle. VAddr GetObjectAddress(u32 handle) const; diff --git a/src/core/hle/service/nvdrv/interface.cpp b/src/core/hle/service/nvdrv/interface.cpp index 634ab9196..ac3859353 100644 --- a/src/core/hle/service/nvdrv/interface.cpp +++ b/src/core/hle/service/nvdrv/interface.cpp @@ -112,4 +112,6 @@ NVDRV::NVDRV(std::shared_ptr<Module> nvdrv, const char* name) query_event = Kernel::Event::Create(kernel, Kernel::ResetType::OneShot, "NVDRV::query_event"); } +NVDRV::~NVDRV() = default; + } // namespace Service::Nvidia diff --git a/src/core/hle/service/nvdrv/interface.h b/src/core/hle/service/nvdrv/interface.h index 1c3529bb6..d340893c2 100644 --- a/src/core/hle/service/nvdrv/interface.h +++ b/src/core/hle/service/nvdrv/interface.h @@ -14,7 +14,7 @@ namespace Service::Nvidia { class NVDRV final : public ServiceFramework<NVDRV> { public: NVDRV(std::shared_ptr<Module> nvdrv, const char* name); - ~NVDRV() = default; + ~NVDRV(); private: void Open(Kernel::HLERequestContext& ctx); diff --git a/src/core/hle/service/nvdrv/nvdrv.cpp b/src/core/hle/service/nvdrv/nvdrv.cpp index 2de39822f..6e4b8f2c6 100644 --- a/src/core/hle/service/nvdrv/nvdrv.cpp +++ b/src/core/hle/service/nvdrv/nvdrv.cpp @@ -45,6 +45,8 @@ Module::Module() { devices["/dev/nvhost-vic"] = std::make_shared<Devices::nvhost_vic>(); } +Module::~Module() = default; + u32 Module::Open(const std::string& device_name) { ASSERT_MSG(devices.find(device_name) != devices.end(), "Trying to open unknown device {}", device_name); diff --git a/src/core/hle/service/nvdrv/nvdrv.h b/src/core/hle/service/nvdrv/nvdrv.h index 99eb1128a..53564f696 100644 --- a/src/core/hle/service/nvdrv/nvdrv.h +++ b/src/core/hle/service/nvdrv/nvdrv.h @@ -30,7 +30,7 @@ static_assert(sizeof(IoctlFence) == 8, "IoctlFence has wrong size"); class Module final { public: Module(); - ~Module() = default; + ~Module(); /// Returns a pointer to one of the available devices, identified by its name. template <typename T> diff --git a/src/core/hle/service/nvdrv/nvmemp.cpp b/src/core/hle/service/nvdrv/nvmemp.cpp index 0e8e21bad..b7b8b7a1b 100644 --- a/src/core/hle/service/nvdrv/nvmemp.cpp +++ b/src/core/hle/service/nvdrv/nvmemp.cpp @@ -16,6 +16,8 @@ NVMEMP::NVMEMP() : ServiceFramework("nvmemp") { RegisterHandlers(functions); } +NVMEMP::~NVMEMP() = default; + void NVMEMP::Cmd0(Kernel::HLERequestContext& ctx) { UNIMPLEMENTED(); } diff --git a/src/core/hle/service/nvdrv/nvmemp.h b/src/core/hle/service/nvdrv/nvmemp.h index dfdcabf4a..5a4dfc1f9 100644 --- a/src/core/hle/service/nvdrv/nvmemp.h +++ b/src/core/hle/service/nvdrv/nvmemp.h @@ -11,7 +11,7 @@ namespace Service::Nvidia { class NVMEMP final : public ServiceFramework<NVMEMP> { public: NVMEMP(); - ~NVMEMP() = default; + ~NVMEMP(); private: void Cmd0(Kernel::HLERequestContext& ctx); diff --git a/src/core/hle/service/nvflinger/buffer_queue.cpp b/src/core/hle/service/nvflinger/buffer_queue.cpp index 8d8962276..34f98fe5a 100644 --- a/src/core/hle/service/nvflinger/buffer_queue.cpp +++ b/src/core/hle/service/nvflinger/buffer_queue.cpp @@ -18,6 +18,8 @@ BufferQueue::BufferQueue(u32 id, u64 layer_id) : id(id), layer_id(layer_id) { Kernel::Event::Create(kernel, Kernel::ResetType::Sticky, "BufferQueue NativeHandle"); } +BufferQueue::~BufferQueue() = default; + void BufferQueue::SetPreallocatedBuffer(u32 slot, const IGBPBuffer& igbp_buffer) { Buffer buffer{}; buffer.slot = slot; diff --git a/src/core/hle/service/nvflinger/buffer_queue.h b/src/core/hle/service/nvflinger/buffer_queue.h index db2e17c0c..17c81928a 100644 --- a/src/core/hle/service/nvflinger/buffer_queue.h +++ b/src/core/hle/service/nvflinger/buffer_queue.h @@ -46,7 +46,7 @@ public: }; BufferQueue(u32 id, u64 layer_id); - ~BufferQueue() = default; + ~BufferQueue(); enum class BufferTransformFlags : u32 { /// No transform flags are set diff --git a/src/core/hle/service/nvflinger/nvflinger.cpp b/src/core/hle/service/nvflinger/nvflinger.cpp index 06040da6f..7455ddd19 100644 --- a/src/core/hle/service/nvflinger/nvflinger.cpp +++ b/src/core/hle/service/nvflinger/nvflinger.cpp @@ -160,10 +160,13 @@ void NVFlinger::Compose() { } Layer::Layer(u64 id, std::shared_ptr<BufferQueue> queue) : id(id), buffer_queue(std::move(queue)) {} +Layer::~Layer() = default; Display::Display(u64 id, std::string name) : id(id), name(std::move(name)) { auto& kernel = Core::System::GetInstance().Kernel(); vsync_event = Kernel::Event::Create(kernel, Kernel::ResetType::Pulse, "Display VSync Event"); } +Display::~Display() = default; + } // namespace Service::NVFlinger diff --git a/src/core/hle/service/nvflinger/nvflinger.h b/src/core/hle/service/nvflinger/nvflinger.h index f7112949f..3dc69e69b 100644 --- a/src/core/hle/service/nvflinger/nvflinger.h +++ b/src/core/hle/service/nvflinger/nvflinger.h @@ -26,7 +26,7 @@ class BufferQueue; struct Layer { Layer(u64 id, std::shared_ptr<BufferQueue> queue); - ~Layer() = default; + ~Layer(); u64 id; std::shared_ptr<BufferQueue> buffer_queue; @@ -34,7 +34,7 @@ struct Layer { struct Display { Display(u64 id, std::string name); - ~Display() = default; + ~Display(); u64 id; std::string name; diff --git a/src/core/hle/service/pctl/module.cpp b/src/core/hle/service/pctl/module.cpp index 6cc3b1992..4fd185f69 100644 --- a/src/core/hle/service/pctl/module.cpp +++ b/src/core/hle/service/pctl/module.cpp @@ -142,6 +142,8 @@ void Module::Interface::CreateServiceWithoutInitialize(Kernel::HLERequestContext Module::Interface::Interface(std::shared_ptr<Module> module, const char* name) : ServiceFramework(name), module(std::move(module)) {} +Module::Interface::~Interface() = default; + void InstallInterfaces(SM::ServiceManager& service_manager) { auto module = std::make_shared<Module>(); std::make_shared<PCTL>(module, "pctl")->InstallAsService(service_manager); diff --git a/src/core/hle/service/pctl/module.h b/src/core/hle/service/pctl/module.h index e7d492760..3e449110d 100644 --- a/src/core/hle/service/pctl/module.h +++ b/src/core/hle/service/pctl/module.h @@ -13,6 +13,7 @@ public: class Interface : public ServiceFramework<Interface> { public: explicit Interface(std::shared_ptr<Module> module, const char* name); + ~Interface() override; void CreateService(Kernel::HLERequestContext& ctx); void CreateServiceWithoutInitialize(Kernel::HLERequestContext& ctx); diff --git a/src/core/hle/service/pctl/pctl.cpp b/src/core/hle/service/pctl/pctl.cpp index de2741d66..af9d1433a 100644 --- a/src/core/hle/service/pctl/pctl.cpp +++ b/src/core/hle/service/pctl/pctl.cpp @@ -14,4 +14,6 @@ PCTL::PCTL(std::shared_ptr<Module> module, const char* name) }; RegisterHandlers(functions); } + +PCTL::~PCTL() = default; } // namespace Service::PCTL diff --git a/src/core/hle/service/pctl/pctl.h b/src/core/hle/service/pctl/pctl.h index 8ddf69128..c33ea80b6 100644 --- a/src/core/hle/service/pctl/pctl.h +++ b/src/core/hle/service/pctl/pctl.h @@ -11,6 +11,7 @@ namespace Service::PCTL { class PCTL final : public Module::Interface { public: explicit PCTL(std::shared_ptr<Module> module, const char* name); + ~PCTL() override; }; } // namespace Service::PCTL diff --git a/src/core/hle/service/prepo/prepo.cpp b/src/core/hle/service/prepo/prepo.cpp index 3c43b8d8c..6a9eccfb5 100644 --- a/src/core/hle/service/prepo/prepo.cpp +++ b/src/core/hle/service/prepo/prepo.cpp @@ -1,36 +1,47 @@ -#include <cinttypes> +// 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/kernel/event.h" #include "core/hle/service/prepo/prepo.h" +#include "core/hle/service/service.h" namespace Service::PlayReport { -PlayReport::PlayReport(const char* name) : ServiceFramework(name) { - static const FunctionInfo functions[] = { - {10100, nullptr, "SaveReport"}, - {10101, &PlayReport::SaveReportWithUser, "SaveReportWithUser"}, - {10200, nullptr, "RequestImmediateTransmission"}, - {10300, nullptr, "GetTransmissionStatus"}, - {20100, nullptr, "SaveSystemReport"}, - {20200, nullptr, "SetOperationMode"}, - {20101, nullptr, "SaveSystemReportWithUser"}, - {30100, nullptr, "ClearStorage"}, - {40100, nullptr, "IsUserAgreementCheckEnabled"}, - {40101, nullptr, "SetUserAgreementCheckEnabled"}, - {90100, nullptr, "GetStorageUsage"}, - {90200, nullptr, "GetStatistics"}, - {90201, nullptr, "GetThroughputHistory"}, - {90300, nullptr, "GetLastUploadError"}, - }; - RegisterHandlers(functions); -}; -void PlayReport::SaveReportWithUser(Kernel::HLERequestContext& ctx) { - // TODO(ogniK): Do we want to add play report? - LOG_WARNING(Service_PREPO, "(STUBBED) called"); +class PlayReport final : public ServiceFramework<PlayReport> { +public: + explicit PlayReport(const char* name) : ServiceFramework{name} { + // clang-format off + static const FunctionInfo functions[] = { + {10100, nullptr, "SaveReport"}, + {10101, &PlayReport::SaveReportWithUser, "SaveReportWithUser"}, + {10200, nullptr, "RequestImmediateTransmission"}, + {10300, nullptr, "GetTransmissionStatus"}, + {20100, nullptr, "SaveSystemReport"}, + {20200, nullptr, "SetOperationMode"}, + {20101, nullptr, "SaveSystemReportWithUser"}, + {30100, nullptr, "ClearStorage"}, + {40100, nullptr, "IsUserAgreementCheckEnabled"}, + {40101, nullptr, "SetUserAgreementCheckEnabled"}, + {90100, nullptr, "GetStorageUsage"}, + {90200, nullptr, "GetStatistics"}, + {90201, nullptr, "GetThroughputHistory"}, + {90300, nullptr, "GetLastUploadError"}, + }; + // clang-format on + + RegisterHandlers(functions); + } + +private: + void SaveReportWithUser(Kernel::HLERequestContext& ctx) { + // TODO(ogniK): Do we want to add play report? + LOG_WARNING(Service_PREPO, "(STUBBED) called"); - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(RESULT_SUCCESS); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(RESULT_SUCCESS); + } }; void InstallInterfaces(SM::ServiceManager& service_manager) { diff --git a/src/core/hle/service/prepo/prepo.h b/src/core/hle/service/prepo/prepo.h index f5a6aba6d..0e7b01331 100644 --- a/src/core/hle/service/prepo/prepo.h +++ b/src/core/hle/service/prepo/prepo.h @@ -4,22 +4,12 @@ #pragma once -#include <memory> -#include <string> -#include "core/hle/kernel/event.h" -#include "core/hle/service/service.h" +namespace Service::SM { +class ServiceManager; +} namespace Service::PlayReport { -class PlayReport final : public ServiceFramework<PlayReport> { -public: - explicit PlayReport(const char* name); - ~PlayReport() = default; - -private: - void SaveReportWithUser(Kernel::HLERequestContext& ctx); -}; - void InstallInterfaces(SM::ServiceManager& service_manager); } // namespace Service::PlayReport diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp index 9d804652e..9bb7c7b26 100644 --- a/src/core/hle/service/service.cpp +++ b/src/core/hle/service/service.cpp @@ -74,8 +74,6 @@ using Kernel::SharedPtr; namespace Service { -std::unordered_map<std::string, SharedPtr<ClientPort>> g_kernel_named_ports; - /** * Creates a function string for logging, complete with the name (or header code, depending * on what's passed in) the port name, and all the cmd_buff arguments. diff --git a/src/core/hle/service/set/set.cpp b/src/core/hle/service/set/set.cpp index 92b0640e8..59eb20155 100644 --- a/src/core/hle/service/set/set.cpp +++ b/src/core/hle/service/set/set.cpp @@ -112,4 +112,6 @@ SET::SET() : ServiceFramework("set") { RegisterHandlers(functions); } +SET::~SET() = default; + } // namespace Service::Set diff --git a/src/core/hle/service/set/set.h b/src/core/hle/service/set/set.h index 669e740b7..5f0214359 100644 --- a/src/core/hle/service/set/set.h +++ b/src/core/hle/service/set/set.h @@ -33,7 +33,7 @@ LanguageCode GetLanguageCodeFromIndex(size_t idx); class SET final : public ServiceFramework<SET> { public: explicit SET(); - ~SET() = default; + ~SET() override; private: void GetLanguageCode(Kernel::HLERequestContext& ctx); diff --git a/src/core/hle/service/set/set_cal.cpp b/src/core/hle/service/set/set_cal.cpp index 7066ef725..5af356d10 100644 --- a/src/core/hle/service/set/set_cal.cpp +++ b/src/core/hle/service/set/set_cal.cpp @@ -44,4 +44,6 @@ SET_CAL::SET_CAL() : ServiceFramework("set:cal") { RegisterHandlers(functions); } +SET_CAL::~SET_CAL() = default; + } // namespace Service::Set diff --git a/src/core/hle/service/set/set_cal.h b/src/core/hle/service/set/set_cal.h index bb50336aa..583036eac 100644 --- a/src/core/hle/service/set/set_cal.h +++ b/src/core/hle/service/set/set_cal.h @@ -11,7 +11,7 @@ namespace Service::Set { class SET_CAL final : public ServiceFramework<SET_CAL> { public: explicit SET_CAL(); - ~SET_CAL() = default; + ~SET_CAL(); }; } // namespace Service::Set diff --git a/src/core/hle/service/set/set_fd.cpp b/src/core/hle/service/set/set_fd.cpp index c9f938716..cac6af86d 100644 --- a/src/core/hle/service/set/set_fd.cpp +++ b/src/core/hle/service/set/set_fd.cpp @@ -20,4 +20,6 @@ SET_FD::SET_FD() : ServiceFramework("set:fd") { RegisterHandlers(functions); } +SET_FD::~SET_FD() = default; + } // namespace Service::Set diff --git a/src/core/hle/service/set/set_fd.h b/src/core/hle/service/set/set_fd.h index dbd850bc7..216e65f1f 100644 --- a/src/core/hle/service/set/set_fd.h +++ b/src/core/hle/service/set/set_fd.h @@ -11,7 +11,7 @@ namespace Service::Set { class SET_FD final : public ServiceFramework<SET_FD> { public: explicit SET_FD(); - ~SET_FD() = default; + ~SET_FD() override; }; } // namespace Service::Set diff --git a/src/core/hle/service/sockets/bsd.cpp b/src/core/hle/service/sockets/bsd.cpp index 3211a8346..4342f3b2d 100644 --- a/src/core/hle/service/sockets/bsd.cpp +++ b/src/core/hle/service/sockets/bsd.cpp @@ -109,6 +109,8 @@ BSD::BSD(const char* name) : ServiceFramework(name) { RegisterHandlers(functions); } +BSD::~BSD() = default; + BSDCFG::BSDCFG() : ServiceFramework{"bsdcfg"} { // clang-format off static const FunctionInfo functions[] = { @@ -131,4 +133,6 @@ BSDCFG::BSDCFG() : ServiceFramework{"bsdcfg"} { RegisterHandlers(functions); } +BSDCFG::~BSDCFG() = default; + } // namespace Service::Sockets diff --git a/src/core/hle/service/sockets/bsd.h b/src/core/hle/service/sockets/bsd.h index c1da59b24..0fe0e65c6 100644 --- a/src/core/hle/service/sockets/bsd.h +++ b/src/core/hle/service/sockets/bsd.h @@ -12,7 +12,7 @@ namespace Service::Sockets { class BSD final : public ServiceFramework<BSD> { public: explicit BSD(const char* name); - ~BSD() = default; + ~BSD() override; private: void RegisterClient(Kernel::HLERequestContext& ctx); @@ -29,6 +29,7 @@ private: class BSDCFG final : public ServiceFramework<BSDCFG> { public: explicit BSDCFG(); + ~BSDCFG() override; }; } // namespace Service::Sockets diff --git a/src/core/hle/service/sockets/ethc.cpp b/src/core/hle/service/sockets/ethc.cpp index d53c25eec..abbeb4c50 100644 --- a/src/core/hle/service/sockets/ethc.cpp +++ b/src/core/hle/service/sockets/ethc.cpp @@ -21,6 +21,8 @@ ETHC_C::ETHC_C() : ServiceFramework{"ethc:c"} { RegisterHandlers(functions); } +ETHC_C::~ETHC_C() = default; + ETHC_I::ETHC_I() : ServiceFramework{"ethc:i"} { // clang-format off static const FunctionInfo functions[] = { @@ -35,4 +37,6 @@ ETHC_I::ETHC_I() : ServiceFramework{"ethc:i"} { RegisterHandlers(functions); } +ETHC_I::~ETHC_I() = default; + } // namespace Service::Sockets diff --git a/src/core/hle/service/sockets/ethc.h b/src/core/hle/service/sockets/ethc.h index 9a3c88100..da2c7f741 100644 --- a/src/core/hle/service/sockets/ethc.h +++ b/src/core/hle/service/sockets/ethc.h @@ -11,11 +11,13 @@ namespace Service::Sockets { class ETHC_C final : public ServiceFramework<ETHC_C> { public: explicit ETHC_C(); + ~ETHC_C() override; }; class ETHC_I final : public ServiceFramework<ETHC_I> { public: explicit ETHC_I(); + ~ETHC_I() override; }; } // namespace Service::Sockets diff --git a/src/core/hle/service/sockets/nsd.cpp b/src/core/hle/service/sockets/nsd.cpp index 8682dc2e0..e6d73065e 100644 --- a/src/core/hle/service/sockets/nsd.cpp +++ b/src/core/hle/service/sockets/nsd.cpp @@ -29,4 +29,6 @@ NSD::NSD(const char* name) : ServiceFramework(name) { RegisterHandlers(functions); } +NSD::~NSD() = default; + } // namespace Service::Sockets diff --git a/src/core/hle/service/sockets/nsd.h b/src/core/hle/service/sockets/nsd.h index 3b7edfc43..d842e3232 100644 --- a/src/core/hle/service/sockets/nsd.h +++ b/src/core/hle/service/sockets/nsd.h @@ -12,7 +12,7 @@ namespace Service::Sockets { class NSD final : public ServiceFramework<NSD> { public: explicit NSD(const char* name); - ~NSD() = default; + ~NSD() override; }; } // namespace Service::Sockets diff --git a/src/core/hle/service/sockets/sfdnsres.cpp b/src/core/hle/service/sockets/sfdnsres.cpp index d235c4cfd..13ab1d31e 100644 --- a/src/core/hle/service/sockets/sfdnsres.cpp +++ b/src/core/hle/service/sockets/sfdnsres.cpp @@ -34,4 +34,6 @@ SFDNSRES::SFDNSRES() : ServiceFramework("sfdnsres") { RegisterHandlers(functions); } +SFDNSRES::~SFDNSRES() = default; + } // namespace Service::Sockets diff --git a/src/core/hle/service/sockets/sfdnsres.h b/src/core/hle/service/sockets/sfdnsres.h index 62c7e35bf..eda432903 100644 --- a/src/core/hle/service/sockets/sfdnsres.h +++ b/src/core/hle/service/sockets/sfdnsres.h @@ -12,7 +12,7 @@ namespace Service::Sockets { class SFDNSRES final : public ServiceFramework<SFDNSRES> { public: explicit SFDNSRES(); - ~SFDNSRES() = default; + ~SFDNSRES() override; private: void GetAddrInfo(Kernel::HLERequestContext& ctx); diff --git a/src/core/hle/service/spl/csrng.cpp b/src/core/hle/service/spl/csrng.cpp index b9e6b799d..674928798 100644 --- a/src/core/hle/service/spl/csrng.cpp +++ b/src/core/hle/service/spl/csrng.cpp @@ -13,4 +13,6 @@ CSRNG::CSRNG(std::shared_ptr<Module> module) : Module::Interface(std::move(modul RegisterHandlers(functions); } +CSRNG::~CSRNG() = default; + } // namespace Service::SPL diff --git a/src/core/hle/service/spl/csrng.h b/src/core/hle/service/spl/csrng.h index 3f849b5a7..764d5ceb0 100644 --- a/src/core/hle/service/spl/csrng.h +++ b/src/core/hle/service/spl/csrng.h @@ -11,6 +11,7 @@ namespace Service::SPL { class CSRNG final : public Module::Interface { public: explicit CSRNG(std::shared_ptr<Module> module); + ~CSRNG() override; }; } // namespace Service::SPL diff --git a/src/core/hle/service/spl/module.cpp b/src/core/hle/service/spl/module.cpp index 3f5a342a7..0d8441fb1 100644 --- a/src/core/hle/service/spl/module.cpp +++ b/src/core/hle/service/spl/module.cpp @@ -16,6 +16,8 @@ namespace Service::SPL { Module::Interface::Interface(std::shared_ptr<Module> module, const char* name) : ServiceFramework(name), module(std::move(module)) {} +Module::Interface::~Interface() = default; + void Module::Interface::GetRandomBytes(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; diff --git a/src/core/hle/service/spl/module.h b/src/core/hle/service/spl/module.h index f24d998e8..48fda6099 100644 --- a/src/core/hle/service/spl/module.h +++ b/src/core/hle/service/spl/module.h @@ -13,6 +13,7 @@ public: class Interface : public ServiceFramework<Interface> { public: explicit Interface(std::shared_ptr<Module> module, const char* name); + ~Interface() override; void GetRandomBytes(Kernel::HLERequestContext& ctx); diff --git a/src/core/hle/service/spl/spl.cpp b/src/core/hle/service/spl/spl.cpp index bb1e03342..70cb41905 100644 --- a/src/core/hle/service/spl/spl.cpp +++ b/src/core/hle/service/spl/spl.cpp @@ -42,4 +42,6 @@ SPL::SPL(std::shared_ptr<Module> module) : Module::Interface(std::move(module), RegisterHandlers(functions); } +SPL::~SPL() = default; + } // namespace Service::SPL diff --git a/src/core/hle/service/spl/spl.h b/src/core/hle/service/spl/spl.h index 69c4c1747..3637d1623 100644 --- a/src/core/hle/service/spl/spl.h +++ b/src/core/hle/service/spl/spl.h @@ -11,6 +11,7 @@ namespace Service::SPL { class SPL final : public Module::Interface { public: explicit SPL(std::shared_ptr<Module> module); + ~SPL() override; }; } // namespace Service::SPL diff --git a/src/core/hle/service/time/interface.cpp b/src/core/hle/service/time/interface.cpp index 048d5b077..18a5d71d5 100644 --- a/src/core/hle/service/time/interface.cpp +++ b/src/core/hle/service/time/interface.cpp @@ -29,4 +29,6 @@ Time::Time(std::shared_ptr<Module> time, const char* name) RegisterHandlers(functions); } +Time::~Time() = default; + } // namespace Service::Time diff --git a/src/core/hle/service/time/interface.h b/src/core/hle/service/time/interface.h index 183a53db1..cd6b44dec 100644 --- a/src/core/hle/service/time/interface.h +++ b/src/core/hle/service/time/interface.h @@ -11,6 +11,7 @@ namespace Service::Time { class Time final : public Module::Interface { public: explicit Time(std::shared_ptr<Module> time, const char* name); + ~Time() override; }; } // namespace Service::Time diff --git a/src/core/hle/service/time/time.cpp b/src/core/hle/service/time/time.cpp index 2172c681b..28fd8debc 100644 --- a/src/core/hle/service/time/time.cpp +++ b/src/core/hle/service/time/time.cpp @@ -210,6 +210,8 @@ void Module::Interface::GetStandardLocalSystemClock(Kernel::HLERequestContext& c Module::Interface::Interface(std::shared_ptr<Module> time, const char* name) : ServiceFramework(name), time(std::move(time)) {} +Module::Interface::~Interface() = default; + void InstallInterfaces(SM::ServiceManager& service_manager) { auto time = std::make_shared<Module>(); std::make_shared<Time>(time, "time:a")->InstallAsService(service_manager); diff --git a/src/core/hle/service/time/time.h b/src/core/hle/service/time/time.h index 8dde28a94..5659ecad3 100644 --- a/src/core/hle/service/time/time.h +++ b/src/core/hle/service/time/time.h @@ -58,6 +58,7 @@ public: class Interface : public ServiceFramework<Interface> { public: explicit Interface(std::shared_ptr<Module> time, const char* name); + ~Interface() override; void GetStandardUserSystemClock(Kernel::HLERequestContext& ctx); void GetStandardNetworkSystemClock(Kernel::HLERequestContext& ctx); diff --git a/src/core/hle/service/vi/vi.cpp b/src/core/hle/service/vi/vi.cpp index 993f1e65a..85244ac3b 100644 --- a/src/core/hle/service/vi/vi.cpp +++ b/src/core/hle/service/vi/vi.cpp @@ -984,6 +984,8 @@ Module::Interface::Interface(std::shared_ptr<Module> module, const char* name, std::shared_ptr<NVFlinger::NVFlinger> nv_flinger) : ServiceFramework(name), module(std::move(module)), nv_flinger(std::move(nv_flinger)) {} +Module::Interface::~Interface() = default; + void Module::Interface::GetDisplayService(Kernel::HLERequestContext& ctx) { LOG_WARNING(Service_VI, "(STUBBED) called"); diff --git a/src/core/hle/service/vi/vi.h b/src/core/hle/service/vi/vi.h index 92f5b6059..c2dc83605 100644 --- a/src/core/hle/service/vi/vi.h +++ b/src/core/hle/service/vi/vi.h @@ -26,6 +26,7 @@ public: public: explicit Interface(std::shared_ptr<Module> module, const char* name, std::shared_ptr<NVFlinger::NVFlinger> nv_flinger); + ~Interface() override; void GetDisplayService(Kernel::HLERequestContext& ctx); diff --git a/src/core/hle/service/vi/vi_m.cpp b/src/core/hle/service/vi/vi_m.cpp index d47da565b..207c06b16 100644 --- a/src/core/hle/service/vi/vi_m.cpp +++ b/src/core/hle/service/vi/vi_m.cpp @@ -15,4 +15,6 @@ VI_M::VI_M(std::shared_ptr<Module> module, std::shared_ptr<NVFlinger::NVFlinger> RegisterHandlers(functions); } +VI_M::~VI_M() = default; + } // namespace Service::VI diff --git a/src/core/hle/service/vi/vi_m.h b/src/core/hle/service/vi/vi_m.h index 6abb9b3a3..487d58d50 100644 --- a/src/core/hle/service/vi/vi_m.h +++ b/src/core/hle/service/vi/vi_m.h @@ -11,6 +11,7 @@ namespace Service::VI { class VI_M final : public Module::Interface { public: explicit VI_M(std::shared_ptr<Module> module, std::shared_ptr<NVFlinger::NVFlinger> nv_flinger); + ~VI_M() override; }; } // namespace Service::VI diff --git a/src/core/hle/service/vi/vi_s.cpp b/src/core/hle/service/vi/vi_s.cpp index 8f82e797f..920e6a1f6 100644 --- a/src/core/hle/service/vi/vi_s.cpp +++ b/src/core/hle/service/vi/vi_s.cpp @@ -15,4 +15,6 @@ VI_S::VI_S(std::shared_ptr<Module> module, std::shared_ptr<NVFlinger::NVFlinger> RegisterHandlers(functions); } +VI_S::~VI_S() = default; + } // namespace Service::VI diff --git a/src/core/hle/service/vi/vi_s.h b/src/core/hle/service/vi/vi_s.h index 8f16f804f..bbc31148f 100644 --- a/src/core/hle/service/vi/vi_s.h +++ b/src/core/hle/service/vi/vi_s.h @@ -11,6 +11,7 @@ namespace Service::VI { class VI_S final : public Module::Interface { public: explicit VI_S(std::shared_ptr<Module> module, std::shared_ptr<NVFlinger::NVFlinger> nv_flinger); + ~VI_S() override; }; } // namespace Service::VI diff --git a/src/core/hle/service/vi/vi_u.cpp b/src/core/hle/service/vi/vi_u.cpp index b84aed1d5..d81e410d6 100644 --- a/src/core/hle/service/vi/vi_u.cpp +++ b/src/core/hle/service/vi/vi_u.cpp @@ -14,4 +14,6 @@ VI_U::VI_U(std::shared_ptr<Module> module, std::shared_ptr<NVFlinger::NVFlinger> RegisterHandlers(functions); } +VI_U::~VI_U() = default; + } // namespace Service::VI diff --git a/src/core/hle/service/vi/vi_u.h b/src/core/hle/service/vi/vi_u.h index e9b4f76b2..b92f28c92 100644 --- a/src/core/hle/service/vi/vi_u.h +++ b/src/core/hle/service/vi/vi_u.h @@ -11,6 +11,7 @@ namespace Service::VI { class VI_U final : public Module::Interface { public: explicit VI_U(std::shared_ptr<Module> module, std::shared_ptr<NVFlinger::NVFlinger> nv_flinger); + ~VI_U() override; }; } // namespace Service::VI diff --git a/src/core/settings.h b/src/core/settings.h index c25f8ba70..0318d019c 100644 --- a/src/core/settings.h +++ b/src/core/settings.h @@ -5,6 +5,7 @@ #pragma once #include <array> +#include <atomic> #include <string> #include "common/common_types.h" @@ -120,6 +121,7 @@ struct Values { std::array<std::string, NativeAnalog::NumAnalogs> analogs; std::string motion_device; std::string touch_device; + std::atomic_bool is_device_reload_pending{true}; // Core bool use_cpu_jit; diff --git a/src/input_common/main.cpp b/src/input_common/main.cpp index b12623d55..37f572853 100644 --- a/src/input_common/main.cpp +++ b/src/input_common/main.cpp @@ -3,6 +3,7 @@ // Refer to the license.txt file included. #include <memory> +#include <thread> #include "common/param_package.h" #include "input_common/analog_from_button.h" #include "input_common/keyboard.h" @@ -17,6 +18,10 @@ namespace InputCommon { static std::shared_ptr<Keyboard> keyboard; static std::shared_ptr<MotionEmu> motion_emu; +#ifdef HAVE_SDL2 +static std::thread poll_thread; +#endif + void Init() { keyboard = std::make_shared<Keyboard>(); Input::RegisterFactory<Input::ButtonDevice>("keyboard", keyboard); @@ -30,6 +35,12 @@ void Init() { #endif } +void StartJoystickEventHandler() { +#ifdef HAVE_SDL2 + poll_thread = std::thread(SDL::PollLoop); +#endif +} + void Shutdown() { Input::UnregisterFactory<Input::ButtonDevice>("keyboard"); keyboard.reset(); @@ -39,6 +50,7 @@ void Shutdown() { #ifdef HAVE_SDL2 SDL::Shutdown(); + poll_thread.join(); #endif } diff --git a/src/input_common/main.h b/src/input_common/main.h index 77a0ce90b..9eb13106e 100644 --- a/src/input_common/main.h +++ b/src/input_common/main.h @@ -20,6 +20,8 @@ void Init(); /// Deregisters all built-in input device factories and shuts them down. void Shutdown(); +void StartJoystickEventHandler(); + class Keyboard; /// Gets the keyboard button device factory. diff --git a/src/input_common/sdl/sdl.cpp b/src/input_common/sdl/sdl.cpp index d1b960fd7..faf3c1fa3 100644 --- a/src/input_common/sdl/sdl.cpp +++ b/src/input_common/sdl/sdl.cpp @@ -2,15 +2,24 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. +#include <algorithm> +#include <atomic> #include <cmath> +#include <functional> +#include <iterator> +#include <mutex> #include <string> +#include <thread> #include <tuple> #include <unordered_map> #include <utility> +#include <vector> #include <SDL.h> +#include "common/assert.h" #include "common/logging/log.h" #include "common/math_util.h" #include "common/param_package.h" +#include "common/threadsafe_queue.h" #include "input_common/main.h" #include "input_common/sdl/sdl.h" @@ -21,33 +30,51 @@ namespace SDL { class SDLJoystick; class SDLButtonFactory; class SDLAnalogFactory; -static std::unordered_map<int, std::weak_ptr<SDLJoystick>> joystick_list; + +/// Map of GUID of a list of corresponding virtual Joysticks +static std::unordered_map<std::string, std::vector<std::shared_ptr<SDLJoystick>>> joystick_map; +static std::mutex joystick_map_mutex; + static std::shared_ptr<SDLButtonFactory> button_factory; static std::shared_ptr<SDLAnalogFactory> analog_factory; -static bool initialized = false; +/// Used by the Pollers during config +static std::atomic<bool> polling; +static Common::SPSCQueue<SDL_Event> event_queue; + +static std::atomic<bool> initialized = false; + +static std::string GetGUID(SDL_Joystick* joystick) { + SDL_JoystickGUID guid = SDL_JoystickGetGUID(joystick); + char guid_str[33]; + SDL_JoystickGetGUIDString(guid, guid_str, sizeof(guid_str)); + return guid_str; +} class SDLJoystick { public: - explicit SDLJoystick(int joystick_index) - : joystick{SDL_JoystickOpen(joystick_index), SDL_JoystickClose} { - if (!joystick) { - LOG_ERROR(Input, "failed to open joystick {}", joystick_index); - } + SDLJoystick(std::string guid_, int port_, SDL_Joystick* joystick, + decltype(&SDL_JoystickClose) deleter = &SDL_JoystickClose) + : guid{std::move(guid_)}, port{port_}, sdl_joystick{joystick, deleter} {} + + void SetButton(int button, bool value) { + std::lock_guard<std::mutex> lock(mutex); + state.buttons[button] = value; } bool GetButton(int button) const { - if (!joystick) - return {}; - SDL_JoystickUpdate(); - return SDL_JoystickGetButton(joystick.get(), button) == 1; + std::lock_guard<std::mutex> lock(mutex); + return state.buttons.at(button); + } + + void SetAxis(int axis, Sint16 value) { + std::lock_guard<std::mutex> lock(mutex); + state.axes[axis] = value; } float GetAxis(int axis) const { - if (!joystick) - return {}; - SDL_JoystickUpdate(); - return SDL_JoystickGetAxis(joystick.get(), axis) / 32767.0f; + std::lock_guard<std::mutex> lock(mutex); + return state.axes.at(axis) / 32767.0f; } std::tuple<float, float> GetAnalog(int axis_x, int axis_y) const { @@ -67,18 +94,213 @@ public: return std::make_tuple(x, y); } + void SetHat(int hat, Uint8 direction) { + std::lock_guard<std::mutex> lock(mutex); + state.hats[hat] = direction; + } + bool GetHatDirection(int hat, Uint8 direction) const { - return (SDL_JoystickGetHat(joystick.get(), hat) & direction) != 0; + std::lock_guard<std::mutex> lock(mutex); + return (state.hats.at(hat) & direction) != 0; + } + /** + * The guid of the joystick + */ + const std::string& GetGUID() const { + return guid; + } + + /** + * The number of joystick from the same type that were connected before this joystick + */ + int GetPort() const { + return port; + } + + SDL_Joystick* GetSDLJoystick() const { + return sdl_joystick.get(); } - SDL_JoystickID GetJoystickID() const { - return SDL_JoystickInstanceID(joystick.get()); + void SetSDLJoystick(SDL_Joystick* joystick, + decltype(&SDL_JoystickClose) deleter = &SDL_JoystickClose) { + sdl_joystick = + std::unique_ptr<SDL_Joystick, decltype(&SDL_JoystickClose)>(joystick, deleter); } private: - std::unique_ptr<SDL_Joystick, decltype(&SDL_JoystickClose)> joystick; + struct State { + std::unordered_map<int, bool> buttons; + std::unordered_map<int, Sint16> axes; + std::unordered_map<int, Uint8> hats; + } state; + std::string guid; + int port; + std::unique_ptr<SDL_Joystick, decltype(&SDL_JoystickClose)> sdl_joystick; + mutable std::mutex mutex; }; +/** + * Get the nth joystick with the corresponding GUID + */ +static std::shared_ptr<SDLJoystick> GetSDLJoystickByGUID(const std::string& guid, int port) { + std::lock_guard<std::mutex> lock(joystick_map_mutex); + const auto it = joystick_map.find(guid); + if (it != joystick_map.end()) { + while (it->second.size() <= port) { + auto joystick = std::make_shared<SDLJoystick>(guid, it->second.size(), nullptr, + [](SDL_Joystick*) {}); + it->second.emplace_back(std::move(joystick)); + } + return it->second[port]; + } + auto joystick = std::make_shared<SDLJoystick>(guid, 0, nullptr, [](SDL_Joystick*) {}); + return joystick_map[guid].emplace_back(std::move(joystick)); +} + +/** + * Check how many identical joysticks (by guid) were connected before the one with sdl_id and so tie + * it to a SDLJoystick with the same guid and that port + */ +static std::shared_ptr<SDLJoystick> GetSDLJoystickBySDLID(SDL_JoystickID sdl_id) { + std::lock_guard<std::mutex> lock(joystick_map_mutex); + auto sdl_joystick = SDL_JoystickFromInstanceID(sdl_id); + const std::string guid = GetGUID(sdl_joystick); + auto map_it = joystick_map.find(guid); + if (map_it != joystick_map.end()) { + auto vec_it = std::find_if(map_it->second.begin(), map_it->second.end(), + [&sdl_joystick](const std::shared_ptr<SDLJoystick>& joystick) { + return sdl_joystick == joystick->GetSDLJoystick(); + }); + if (vec_it != map_it->second.end()) { + // This is the common case: There is already an existing SDL_Joystick maped to a + // SDLJoystick. return the SDLJoystick + return *vec_it; + } + // Search for a SDLJoystick without a mapped SDL_Joystick... + auto nullptr_it = std::find_if(map_it->second.begin(), map_it->second.end(), + [](const std::shared_ptr<SDLJoystick>& joystick) { + return !joystick->GetSDLJoystick(); + }); + if (nullptr_it != map_it->second.end()) { + // ... and map it + (*nullptr_it)->SetSDLJoystick(sdl_joystick); + return *nullptr_it; + } + // There is no SDLJoystick without a mapped SDL_Joystick + // Create a new SDLJoystick + auto joystick = std::make_shared<SDLJoystick>(guid, map_it->second.size(), sdl_joystick); + return map_it->second.emplace_back(std::move(joystick)); + } + auto joystick = std::make_shared<SDLJoystick>(guid, 0, sdl_joystick); + return joystick_map[guid].emplace_back(std::move(joystick)); +} + +void InitJoystick(int joystick_index) { + std::lock_guard<std::mutex> lock(joystick_map_mutex); + SDL_Joystick* sdl_joystick = SDL_JoystickOpen(joystick_index); + if (!sdl_joystick) { + LOG_ERROR(Input, "failed to open joystick {}", joystick_index); + return; + } + std::string guid = GetGUID(sdl_joystick); + if (joystick_map.find(guid) == joystick_map.end()) { + auto joystick = std::make_shared<SDLJoystick>(guid, 0, sdl_joystick); + joystick_map[guid].emplace_back(std::move(joystick)); + return; + } + auto& joystick_guid_list = joystick_map[guid]; + const auto it = std::find_if( + joystick_guid_list.begin(), joystick_guid_list.end(), + [](const std::shared_ptr<SDLJoystick>& joystick) { return !joystick->GetSDLJoystick(); }); + if (it != joystick_guid_list.end()) { + (*it)->SetSDLJoystick(sdl_joystick); + return; + } + auto joystick = std::make_shared<SDLJoystick>(guid, joystick_guid_list.size(), sdl_joystick); + joystick_guid_list.emplace_back(std::move(joystick)); +} + +void CloseJoystick(SDL_Joystick* sdl_joystick) { + std::lock_guard<std::mutex> lock(joystick_map_mutex); + std::string guid = GetGUID(sdl_joystick); + // This call to guid is save since the joystick is guranteed to be in that map + auto& joystick_guid_list = joystick_map[guid]; + const auto joystick_it = + std::find_if(joystick_guid_list.begin(), joystick_guid_list.end(), + [&sdl_joystick](const std::shared_ptr<SDLJoystick>& joystick) { + return joystick->GetSDLJoystick() == sdl_joystick; + }); + (*joystick_it)->SetSDLJoystick(nullptr, [](SDL_Joystick*) {}); +} + +void HandleGameControllerEvent(const SDL_Event& event) { + switch (event.type) { + case SDL_JOYBUTTONUP: { + auto joystick = GetSDLJoystickBySDLID(event.jbutton.which); + if (joystick) { + joystick->SetButton(event.jbutton.button, false); + } + break; + } + case SDL_JOYBUTTONDOWN: { + auto joystick = GetSDLJoystickBySDLID(event.jbutton.which); + if (joystick) { + joystick->SetButton(event.jbutton.button, true); + } + break; + } + case SDL_JOYHATMOTION: { + auto joystick = GetSDLJoystickBySDLID(event.jhat.which); + if (joystick) { + joystick->SetHat(event.jhat.hat, event.jhat.value); + } + break; + } + case SDL_JOYAXISMOTION: { + auto joystick = GetSDLJoystickBySDLID(event.jaxis.which); + if (joystick) { + joystick->SetAxis(event.jaxis.axis, event.jaxis.value); + } + break; + } + case SDL_JOYDEVICEREMOVED: + LOG_DEBUG(Input, "Controller removed with Instance_ID {}", event.jdevice.which); + CloseJoystick(SDL_JoystickFromInstanceID(event.jdevice.which)); + break; + case SDL_JOYDEVICEADDED: + LOG_DEBUG(Input, "Controller connected with device index {}", event.jdevice.which); + InitJoystick(event.jdevice.which); + break; + } +} + +void CloseSDLJoysticks() { + std::lock_guard<std::mutex> lock(joystick_map_mutex); + joystick_map.clear(); +} + +void PollLoop() { + if (SDL_Init(SDL_INIT_JOYSTICK) < 0) { + LOG_CRITICAL(Input, "SDL_Init(SDL_INIT_JOYSTICK) failed with: {}", SDL_GetError()); + return; + } + + SDL_Event event; + while (initialized) { + // Wait for 10 ms or until an event happens + if (SDL_WaitEventTimeout(&event, 10)) { + // Don't handle the event if we are configuring + if (polling) { + event_queue.Push(event); + } else { + HandleGameControllerEvent(event); + } + } + } + CloseSDLJoysticks(); + SDL_QuitSubSystem(SDL_INIT_JOYSTICK); +} + class SDLButton final : public Input::ButtonDevice { public: explicit SDLButton(std::shared_ptr<SDLJoystick> joystick_, int button_) @@ -144,22 +366,14 @@ private: int axis_y; }; -static std::shared_ptr<SDLJoystick> GetJoystick(int joystick_index) { - std::shared_ptr<SDLJoystick> joystick = joystick_list[joystick_index].lock(); - if (!joystick) { - joystick = std::make_shared<SDLJoystick>(joystick_index); - joystick_list[joystick_index] = joystick; - } - return joystick; -} - /// A button device factory that creates button devices from SDL joystick class SDLButtonFactory final : public Input::Factory<Input::ButtonDevice> { public: /** * Creates a button device from a joystick button * @param params contains parameters for creating the device: - * - "joystick": the index of the joystick to bind + * - "guid": the guid of the joystick to bind + * - "port": the nth joystick of the same type to bind * - "button"(optional): the index of the button to bind * - "hat"(optional): the index of the hat to bind as direction buttons * - "axis"(optional): the index of the axis to bind @@ -167,12 +381,15 @@ public: * "down", "left" or "right" * - "threshold"(only used for axis): a float value in (-1.0, 1.0) which the button is * triggered if the axis value crosses - * - "direction"(only used for axis): "+" means the button is triggered when the axis value - * is greater than the threshold; "-" means the button is triggered when the axis value - * is smaller than the threshold + * - "direction"(only used for axis): "+" means the button is triggered when the axis + * value is greater than the threshold; "-" means the button is triggered when the axis + * value is smaller than the threshold */ std::unique_ptr<Input::ButtonDevice> Create(const Common::ParamPackage& params) override { - const int joystick_index = params.Get("joystick", 0); + const std::string guid = params.Get("guid", "0"); + const int port = params.Get("port", 0); + + auto joystick = GetSDLJoystickByGUID(guid, port); if (params.Has("hat")) { const int hat = params.Get("hat", 0); @@ -189,8 +406,9 @@ public: } else { direction = 0; } - return std::make_unique<SDLDirectionButton>(GetJoystick(joystick_index), hat, - direction); + // This is necessary so accessing GetHat with hat won't crash + joystick->SetHat(hat, SDL_HAT_CENTERED); + return std::make_unique<SDLDirectionButton>(joystick, hat, direction); } if (params.Has("axis")) { @@ -206,12 +424,15 @@ public: trigger_if_greater = true; LOG_ERROR(Input, "Unknown direction '{}'", direction_name); } - return std::make_unique<SDLAxisButton>(GetJoystick(joystick_index), axis, threshold, - trigger_if_greater); + // This is necessary so accessing GetAxis with axis won't crash + joystick->SetAxis(axis, 0); + return std::make_unique<SDLAxisButton>(joystick, axis, threshold, trigger_if_greater); } const int button = params.Get("button", 0); - return std::make_unique<SDLButton>(GetJoystick(joystick_index), button); + // This is necessary so accessing GetButton with button won't crash + joystick->SetButton(button, false); + return std::make_unique<SDLButton>(joystick, button); } }; @@ -221,27 +442,32 @@ public: /** * Creates analog device from joystick axes * @param params contains parameters for creating the device: - * - "joystick": the index of the joystick to bind + * - "guid": the guid of the joystick to bind + * - "port": the nth joystick of the same type * - "axis_x": the index of the axis to be bind as x-axis * - "axis_y": the index of the axis to be bind as y-axis */ std::unique_ptr<Input::AnalogDevice> Create(const Common::ParamPackage& params) override { - const int joystick_index = params.Get("joystick", 0); + const std::string guid = params.Get("guid", "0"); + const int port = params.Get("port", 0); const int axis_x = params.Get("axis_x", 0); const int axis_y = params.Get("axis_y", 1); - return std::make_unique<SDLAnalog>(GetJoystick(joystick_index), axis_x, axis_y); + + auto joystick = GetSDLJoystickByGUID(guid, port); + + // This is necessary so accessing GetAxis with axis_x and axis_y won't crash + joystick->SetAxis(axis_x, 0); + joystick->SetAxis(axis_y, 0); + return std::make_unique<SDLAnalog>(joystick, axis_x, axis_y); } }; void Init() { - if (SDL_Init(SDL_INIT_JOYSTICK) < 0) { - LOG_CRITICAL(Input, "SDL_Init(SDL_INIT_JOYSTICK) failed with: {}", SDL_GetError()); - } else { - using namespace Input; - RegisterFactory<ButtonDevice>("sdl", std::make_shared<SDLButtonFactory>()); - RegisterFactory<AnalogDevice>("sdl", std::make_shared<SDLAnalogFactory>()); - initialized = true; - } + using namespace Input; + RegisterFactory<ButtonDevice>("sdl", std::make_shared<SDLButtonFactory>()); + RegisterFactory<AnalogDevice>("sdl", std::make_shared<SDLAnalogFactory>()); + polling = false; + initialized = true; } void Shutdown() { @@ -249,30 +475,17 @@ void Shutdown() { using namespace Input; UnregisterFactory<ButtonDevice>("sdl"); UnregisterFactory<AnalogDevice>("sdl"); - SDL_QuitSubSystem(SDL_INIT_JOYSTICK); + initialized = false; } } -/** - * 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)); + case SDL_JOYAXISMOTION: { + auto joystick = GetSDLJoystickBySDLID(event.jaxis.which); + params.Set("port", joystick->GetPort()); + params.Set("guid", joystick->GetGUID()); params.Set("axis", event.jaxis.axis); if (event.jaxis.value > 0) { params.Set("direction", "+"); @@ -282,12 +495,18 @@ Common::ParamPackage SDLEventToButtonParamPackage(const SDL_Event& event) { params.Set("threshold", "-0.5"); } break; - case SDL_JOYBUTTONUP: - params.Set("joystick", JoystickIDToDeviceIndex(event.jbutton.which)); + } + case SDL_JOYBUTTONUP: { + auto joystick = GetSDLJoystickBySDLID(event.jbutton.which); + params.Set("port", joystick->GetPort()); + params.Set("guid", joystick->GetGUID()); params.Set("button", event.jbutton.button); break; - case SDL_JOYHATMOTION: - params.Set("joystick", JoystickIDToDeviceIndex(event.jhat.which)); + } + case SDL_JOYHATMOTION: { + auto joystick = GetSDLJoystickBySDLID(event.jhat.which); + params.Set("port", joystick->GetPort()); + params.Set("guid", joystick->GetGUID()); params.Set("hat", event.jhat.hat); switch (event.jhat.value) { case SDL_HAT_UP: @@ -307,6 +526,7 @@ Common::ParamPackage SDLEventToButtonParamPackage(const SDL_Event& event) { } break; } + } return params; } @@ -315,31 +535,20 @@ namespace Polling { class SDLPoller : public InputCommon::Polling::DevicePoller { public: 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)) { - } + event_queue.Clear(); + polling = true; } void Stop() override { - joysticks_opened.clear(); + polling = false; } - -private: - std::vector<std::shared_ptr<SDLJoystick>> joysticks_opened; }; class SDLButtonPoller final : public SDLPoller { public: Common::ParamPackage GetNextInput() override { SDL_Event event; - while (SDL_PollEvent(&event)) { + while (event_queue.Pop(event)) { switch (event.type) { case SDL_JOYAXISMOTION: if (std::abs(event.jaxis.value / 32767.0) < 0.5) { @@ -367,7 +576,7 @@ public: Common::ParamPackage GetNextInput() override { SDL_Event event; - while (SDL_PollEvent(&event)) { + while (event_queue.Pop(event)) { if (event.type != SDL_JOYAXISMOTION || std::abs(event.jaxis.value / 32767.0) < 0.5) { continue; } @@ -384,8 +593,10 @@ public: } Common::ParamPackage params; if (analog_xaxis != -1 && analog_yaxis != -1) { + auto joystick = GetSDLJoystickBySDLID(event.jaxis.which); params.Set("engine", "sdl"); - params.Set("joystick", JoystickIDToDeviceIndex(analog_axes_joystick)); + params.Set("port", joystick->GetPort()); + params.Set("guid", joystick->GetGUID()); params.Set("axis_x", analog_xaxis); params.Set("axis_y", analog_yaxis); analog_xaxis = -1; diff --git a/src/input_common/sdl/sdl.h b/src/input_common/sdl/sdl.h index 7934099d4..0206860d3 100644 --- a/src/input_common/sdl/sdl.h +++ b/src/input_common/sdl/sdl.h @@ -28,6 +28,15 @@ void Init(); /// Unresisters SDL device factories and shut them down. void Shutdown(); +/// Needs to be called before SDL_QuitSubSystem. +void CloseSDLJoysticks(); + +/// Handle SDL_Events for joysticks from SDL_PollEvent +void HandleGameControllerEvent(const SDL_Event& event); + +/// A Loop that calls HandleGameControllerEvent until Shutdown is called +void PollLoop(); + /// Creates a ParamPackage from an SDL_Event that can directly be used to create a ButtonDevice Common::ParamPackage SDLEventToButtonParamPackage(const SDL_Event& event); diff --git a/src/video_core/command_processor.cpp b/src/video_core/command_processor.cpp index d5831e752..2625ddfdc 100644 --- a/src/video_core/command_processor.cpp +++ b/src/video_core/command_processor.cpp @@ -28,98 +28,106 @@ enum class BufferMethods { CountBufferMethods = 0x40, }; -void GPU::WriteReg(u32 method, u32 subchannel, u32 value, u32 remaining_params) { - LOG_TRACE(HW_GPU, - "Processing method {:08X} on subchannel {} value " - "{:08X} remaining params {}", - method, subchannel, value, remaining_params); - - ASSERT(subchannel < bound_engines.size()); - - if (method == static_cast<u32>(BufferMethods::BindObject)) { - // Bind the current subchannel to the desired engine id. - LOG_DEBUG(HW_GPU, "Binding subchannel {} to engine {}", subchannel, value); - bound_engines[subchannel] = static_cast<EngineID>(value); - return; - } +MICROPROFILE_DEFINE(ProcessCommandLists, "GPU", "Execute command buffer", MP_RGB(128, 128, 192)); - if (method < static_cast<u32>(BufferMethods::CountBufferMethods)) { - // TODO(Subv): Research and implement these methods. - LOG_ERROR(HW_GPU, "Special buffer methods other than Bind are not implemented"); - return; - } +void GPU::ProcessCommandLists(const std::vector<CommandListHeader>& commands) { + MICROPROFILE_SCOPE(ProcessCommandLists); - const EngineID engine = bound_engines[subchannel]; - - switch (engine) { - case EngineID::FERMI_TWOD_A: - fermi_2d->WriteReg(method, value); - break; - case EngineID::MAXWELL_B: - maxwell_3d->WriteReg(method, value, remaining_params); - break; - case EngineID::MAXWELL_COMPUTE_B: - maxwell_compute->WriteReg(method, value); - break; - case EngineID::MAXWELL_DMA_COPY_A: - maxwell_dma->WriteReg(method, value); - break; - default: - UNIMPLEMENTED_MSG("Unimplemented engine"); - } -} + auto WriteReg = [this](u32 method, u32 subchannel, u32 value, u32 remaining_params) { + LOG_TRACE(HW_GPU, + "Processing method {:08X} on subchannel {} value " + "{:08X} remaining params {}", + method, subchannel, value, remaining_params); -void GPU::ProcessCommandList(GPUVAddr address, u32 size) { - const boost::optional<VAddr> head_address = memory_manager->GpuToCpuAddress(address); - VAddr current_addr = *head_address; - while (current_addr < *head_address + size * sizeof(CommandHeader)) { - const CommandHeader header = {Memory::Read32(current_addr)}; - current_addr += sizeof(u32); - - switch (header.mode.Value()) { - case SubmissionMode::IncreasingOld: - case SubmissionMode::Increasing: { - // Increase the method value with each argument. - for (unsigned i = 0; i < header.arg_count; ++i) { - WriteReg(header.method + i, header.subchannel, Memory::Read32(current_addr), - header.arg_count - i - 1); - current_addr += sizeof(u32); - } - break; + ASSERT(subchannel < bound_engines.size()); + + if (method == static_cast<u32>(BufferMethods::BindObject)) { + // Bind the current subchannel to the desired engine id. + LOG_DEBUG(HW_GPU, "Binding subchannel {} to engine {}", subchannel, value); + bound_engines[subchannel] = static_cast<EngineID>(value); + return; } - case SubmissionMode::NonIncreasingOld: - case SubmissionMode::NonIncreasing: { - // Use the same method value for all arguments. - for (unsigned i = 0; i < header.arg_count; ++i) { - WriteReg(header.method, header.subchannel, Memory::Read32(current_addr), - header.arg_count - i - 1); - current_addr += sizeof(u32); - } + + if (method < static_cast<u32>(BufferMethods::CountBufferMethods)) { + // TODO(Subv): Research and implement these methods. + LOG_ERROR(HW_GPU, "Special buffer methods other than Bind are not implemented"); + return; + } + + const EngineID engine = bound_engines[subchannel]; + + switch (engine) { + case EngineID::FERMI_TWOD_A: + fermi_2d->WriteReg(method, value); + break; + case EngineID::MAXWELL_B: + maxwell_3d->WriteReg(method, value, remaining_params); break; + case EngineID::MAXWELL_COMPUTE_B: + maxwell_compute->WriteReg(method, value); + break; + case EngineID::MAXWELL_DMA_COPY_A: + maxwell_dma->WriteReg(method, value); + break; + default: + UNIMPLEMENTED_MSG("Unimplemented engine"); } - case SubmissionMode::IncreaseOnce: { - ASSERT(header.arg_count.Value() >= 1); + }; - // Use the original method for the first argument and then the next method for all other - // arguments. - WriteReg(header.method, header.subchannel, Memory::Read32(current_addr), - header.arg_count - 1); + for (auto entry : commands) { + Tegra::GPUVAddr address = entry.Address(); + u32 size = entry.sz; + const boost::optional<VAddr> head_address = memory_manager->GpuToCpuAddress(address); + VAddr current_addr = *head_address; + while (current_addr < *head_address + size * sizeof(CommandHeader)) { + const CommandHeader header = {Memory::Read32(current_addr)}; current_addr += sizeof(u32); - for (unsigned i = 1; i < header.arg_count; ++i) { - WriteReg(header.method + 1, header.subchannel, Memory::Read32(current_addr), - header.arg_count - i - 1); + switch (header.mode.Value()) { + case SubmissionMode::IncreasingOld: + case SubmissionMode::Increasing: { + // Increase the method value with each argument. + for (unsigned i = 0; i < header.arg_count; ++i) { + WriteReg(header.method + i, header.subchannel, Memory::Read32(current_addr), + header.arg_count - i - 1); + current_addr += sizeof(u32); + } + break; + } + case SubmissionMode::NonIncreasingOld: + case SubmissionMode::NonIncreasing: { + // Use the same method value for all arguments. + for (unsigned i = 0; i < header.arg_count; ++i) { + WriteReg(header.method, header.subchannel, Memory::Read32(current_addr), + header.arg_count - i - 1); + current_addr += sizeof(u32); + } + break; + } + case SubmissionMode::IncreaseOnce: { + ASSERT(header.arg_count.Value() >= 1); + + // Use the original method for the first argument and then the next method for all + // other arguments. + WriteReg(header.method, header.subchannel, Memory::Read32(current_addr), + header.arg_count - 1); current_addr += sizeof(u32); + + for (unsigned i = 1; i < header.arg_count; ++i) { + WriteReg(header.method + 1, header.subchannel, Memory::Read32(current_addr), + header.arg_count - i - 1); + current_addr += sizeof(u32); + } + break; + } + case SubmissionMode::Inline: { + // The register value is stored in the bits 16-28 as an immediate + WriteReg(header.method, header.subchannel, header.inline_data, 0); + break; + } + default: + UNIMPLEMENTED(); } - break; - } - case SubmissionMode::Inline: { - // The register value is stored in the bits 16-28 as an immediate - WriteReg(header.method, header.subchannel, header.inline_data, 0); - break; - } - default: - UNIMPLEMENTED(); } } } diff --git a/src/video_core/command_processor.h b/src/video_core/command_processor.h index a01153e0b..bd766e77a 100644 --- a/src/video_core/command_processor.h +++ b/src/video_core/command_processor.h @@ -7,6 +7,7 @@ #include <type_traits> #include "common/bit_field.h" #include "common/common_types.h" +#include "video_core/memory_manager.h" namespace Tegra { @@ -19,6 +20,22 @@ enum class SubmissionMode : u32 { IncreaseOnce = 5 }; +struct CommandListHeader { + u32 entry0; // gpu_va_lo + union { + u32 entry1; // gpu_va_hi | (unk_0x02 << 0x08) | (size << 0x0A) | (unk_0x01 << 0x1F) + BitField<0, 8, u32> gpu_va_hi; + BitField<8, 2, u32> unk1; + BitField<10, 21, u32> sz; + BitField<31, 1, u32> unk2; + }; + + GPUVAddr Address() const { + return (static_cast<GPUVAddr>(gpu_va_hi) << 32) | entry0; + } +}; +static_assert(sizeof(CommandListHeader) == 8, "CommandListHeader is incorrect size"); + union CommandHeader { u32 hex; diff --git a/src/video_core/engines/maxwell_3d.cpp b/src/video_core/engines/maxwell_3d.cpp index e63ad4d46..329079ddd 100644 --- a/src/video_core/engines/maxwell_3d.cpp +++ b/src/video_core/engines/maxwell_3d.cpp @@ -135,8 +135,6 @@ void Maxwell3D::WriteReg(u32 method, u32 value, u32 remaining_params) { break; } - rasterizer.NotifyMaxwellRegisterChanged(method); - if (debug_context) { debug_context->OnEvent(Tegra::DebugContext::Event::MaxwellCommandProcessed, nullptr); } @@ -293,10 +291,6 @@ Texture::TICEntry Maxwell3D::GetTICEntry(u32 tic_index) const { tic_entry.header_version == Texture::TICHeaderVersion::Pitch, "TIC versions other than BlockLinear or Pitch are unimplemented"); - ASSERT_MSG((tic_entry.texture_type == Texture::TextureType::Texture2D) || - (tic_entry.texture_type == Texture::TextureType::Texture2DNoMipmap), - "Texture types other than Texture2D are unimplemented"); - auto r_type = tic_entry.r_type.Value(); auto g_type = tic_entry.g_type.Value(); auto b_type = tic_entry.b_type.Value(); diff --git a/src/video_core/engines/maxwell_3d.h b/src/video_core/engines/maxwell_3d.h index f59d01738..d3be900a4 100644 --- a/src/video_core/engines/maxwell_3d.h +++ b/src/video_core/engines/maxwell_3d.h @@ -533,7 +533,11 @@ public: u32 stencil_back_mask; u32 stencil_back_func_mask; - INSERT_PADDING_WORDS(0x20); + INSERT_PADDING_WORDS(0x13); + + u32 rt_separate_frag_data; + + INSERT_PADDING_WORDS(0xC); struct { u32 address_high; @@ -557,7 +561,22 @@ public: struct { union { BitField<0, 4, u32> count; + BitField<4, 3, u32> map_0; + BitField<7, 3, u32> map_1; + BitField<10, 3, u32> map_2; + BitField<13, 3, u32> map_3; + BitField<16, 3, u32> map_4; + BitField<19, 3, u32> map_5; + BitField<22, 3, u32> map_6; + BitField<25, 3, u32> map_7; }; + + u32 GetMap(size_t index) const { + const std::array<u32, NumRenderTargets> maps{map_0, map_1, map_2, map_3, + map_4, map_5, map_6, map_7}; + ASSERT(index < maps.size()); + return maps[index]; + } } rt_control; INSERT_PADDING_WORDS(0x2); @@ -968,6 +987,7 @@ ASSERT_REG_POSITION(clear_stencil, 0x368); ASSERT_REG_POSITION(stencil_back_func_ref, 0x3D5); ASSERT_REG_POSITION(stencil_back_mask, 0x3D6); ASSERT_REG_POSITION(stencil_back_func_mask, 0x3D7); +ASSERT_REG_POSITION(rt_separate_frag_data, 0x3EB); ASSERT_REG_POSITION(zeta, 0x3F8); ASSERT_REG_POSITION(vertex_attrib_format, 0x458); ASSERT_REG_POSITION(rt_control, 0x487); diff --git a/src/video_core/engines/maxwell_dma.cpp b/src/video_core/engines/maxwell_dma.cpp index 6e740713f..c24d33d5c 100644 --- a/src/video_core/engines/maxwell_dma.cpp +++ b/src/video_core/engines/maxwell_dma.cpp @@ -41,7 +41,6 @@ void MaxwellDMA::HandleCopy() { // TODO(Subv): Perform more research and implement all features of this engine. ASSERT(regs.exec.enable_swizzle == 0); - ASSERT(regs.exec.enable_2d == 1); ASSERT(regs.exec.query_mode == Regs::QueryMode::None); ASSERT(regs.exec.query_intr == Regs::QueryIntr::None); ASSERT(regs.exec.copy_mode == Regs::CopyMode::Unk2); @@ -51,10 +50,19 @@ void MaxwellDMA::HandleCopy() { ASSERT(regs.dst_params.pos_y == 0); if (regs.exec.is_dst_linear == regs.exec.is_src_linear) { - Memory::CopyBlock(dest_cpu, source_cpu, regs.x_count * regs.y_count); + size_t copy_size = regs.x_count; + + // When the enable_2d bit is disabled, the copy is performed as if we were copying a 1D + // buffer of length `x_count`, otherwise we copy a 2D buffer of size (x_count, y_count). + if (regs.exec.enable_2d) { + copy_size = copy_size * regs.y_count; + } + + Memory::CopyBlock(dest_cpu, source_cpu, copy_size); return; } + ASSERT(regs.exec.enable_2d == 1); u8* src_buffer = Memory::GetPointer(source_cpu); u8* dst_buffer = Memory::GetPointer(dest_cpu); diff --git a/src/video_core/engines/shader_bytecode.h b/src/video_core/engines/shader_bytecode.h index d2388673e..58f2904ce 100644 --- a/src/video_core/engines/shader_bytecode.h +++ b/src/video_core/engines/shader_bytecode.h @@ -244,6 +244,25 @@ enum class TextureType : u64 { TextureCube = 3, }; +enum class TextureQueryType : u64 { + Dimension = 1, + TextureType = 2, + SamplePosition = 5, + Filter = 16, + LevelOfDetail = 18, + Wrap = 20, + BorderColor = 22, +}; + +enum class TextureProcessMode : u64 { + None = 0, + LZ = 1, // Unknown, appears to be the same as none. + LB = 2, // Load Bias. + LL = 3, // Load LOD (LevelOfDetail) + LBA = 6, // Load Bias. The A is unknown, does not appear to differ with LB + LLA = 7 // Load LOD. The A is unknown, does not appear to differ with LL +}; + enum class IpaInterpMode : u64 { Linear = 0, Perspective = 1, Flat = 2, Sc = 3 }; enum class IpaSampleMode : u64 { Default = 0, Centroid = 1, Offset = 2 }; @@ -414,6 +433,45 @@ union Instruction { } bfe; union { + BitField<48, 3, u64> pred48; + + union { + BitField<20, 20, u64> entry_a; + BitField<39, 5, u64> entry_b; + BitField<45, 1, u64> neg; + BitField<46, 1, u64> uses_cc; + } imm; + + union { + BitField<20, 14, u64> cb_index; + BitField<34, 5, u64> cb_offset; + BitField<56, 1, u64> neg; + BitField<57, 1, u64> uses_cc; + } hi; + + union { + BitField<20, 14, u64> cb_index; + BitField<34, 5, u64> cb_offset; + BitField<39, 5, u64> entry_a; + BitField<45, 1, u64> neg; + BitField<46, 1, u64> uses_cc; + } rz; + + union { + BitField<39, 5, u64> entry_a; + BitField<45, 1, u64> neg; + BitField<46, 1, u64> uses_cc; + } r1; + + union { + BitField<28, 8, u64> entry_a; + BitField<37, 1, u64> neg; + BitField<38, 1, u64> uses_cc; + } r2; + + } lea; + + union { BitField<0, 5, FlowCondition> cond; } flow; @@ -468,6 +526,18 @@ union Instruction { } psetp; union { + BitField<12, 3, u64> pred12; + BitField<15, 1, u64> neg_pred12; + BitField<24, 2, PredOperation> cond; + BitField<29, 3, u64> pred29; + BitField<32, 1, u64> neg_pred29; + BitField<39, 3, u64> pred39; + BitField<42, 1, u64> neg_pred39; + BitField<44, 1, u64> bf; + BitField<45, 2, PredOperation> op; + } pset; + + union { BitField<39, 3, u64> pred39; BitField<42, 1, u64> neg_pred; BitField<43, 1, u64> neg_a; @@ -512,6 +582,7 @@ union Instruction { BitField<28, 1, u64> array; BitField<29, 2, TextureType> texture_type; BitField<31, 4, u64> component_mask; + BitField<55, 3, TextureProcessMode> process_mode; bool IsComponentEnabled(size_t component) const { return ((1ull << component) & component_mask) != 0; @@ -519,6 +590,21 @@ union Instruction { } tex; union { + BitField<22, 6, TextureQueryType> query_type; + BitField<31, 4, u64> component_mask; + } txq; + + union { + BitField<28, 1, u64> array; + BitField<29, 2, TextureType> texture_type; + BitField<31, 4, u64> component_mask; + + bool IsComponentEnabled(size_t component) const { + return ((1ull << component) & component_mask) != 0; + } + } tmml; + + union { BitField<28, 1, u64> array; BitField<29, 2, TextureType> texture_type; BitField<56, 2, u64> component; @@ -670,11 +756,13 @@ public: LDG, // Load from global memory STG, // Store in global memory TEX, - TEXQ, // Texture Query - TEXS, // Texture Fetch with scalar/non-vec4 source/destinations - TLDS, // Texture Load with scalar/non-vec4 source/destinations - TLD4, // Texture Load 4 - TLD4S, // Texture Load 4 with scalar / non - vec4 source / destinations + TXQ, // Texture Query + TEXS, // Texture Fetch with scalar/non-vec4 source/destinations + TLDS, // Texture Load with scalar/non-vec4 source/destinations + TLD4, // Texture Load 4 + TLD4S, // Texture Load 4 with scalar / non - vec4 source / destinations + TMML_B, // Texture Mip Map Level + TMML, // Texture Mip Map Level EXIT, IPA, FFMA_IMM, // Fused Multiply and Add @@ -699,6 +787,11 @@ public: ISCADD_C, // Scale and Add ISCADD_R, ISCADD_IMM, + LEA_R1, + LEA_R2, + LEA_RZ, + LEA_IMM, + LEA_HI, POPC_C, POPC_R, POPC_IMM, @@ -757,6 +850,7 @@ public: ISET_C, ISET_IMM, PSETP, + PSET, XMAD_IMM, XMAD_CR, XMAD_RC, @@ -780,6 +874,7 @@ public: IntegerSet, IntegerSetPredicate, PredicateSetPredicate, + PredicateSetRegister, Conversion, Xmad, Unknown, @@ -894,11 +989,13 @@ private: INST("1110111011010---", Id::LDG, Type::Memory, "LDG"), INST("1110111011011---", Id::STG, Type::Memory, "STG"), INST("110000----111---", Id::TEX, Type::Memory, "TEX"), - INST("1101111101001---", Id::TEXQ, Type::Memory, "TEXQ"), + INST("1101111101001---", Id::TXQ, Type::Memory, "TXQ"), INST("1101100---------", Id::TEXS, Type::Memory, "TEXS"), INST("1101101---------", Id::TLDS, Type::Memory, "TLDS"), INST("110010----111---", Id::TLD4, Type::Memory, "TLD4"), INST("1101111100------", Id::TLD4S, Type::Memory, "TLD4S"), + INST("110111110110----", Id::TMML_B, Type::Memory, "TMML_B"), + INST("1101111101011---", Id::TMML, Type::Memory, "TMML"), INST("111000110000----", Id::EXIT, Type::Trivial, "EXIT"), INST("11100000--------", Id::IPA, Type::Trivial, "IPA"), INST("0011001-1-------", Id::FFMA_IMM, Type::Ffma, "FFMA_IMM"), @@ -929,6 +1026,11 @@ private: INST("0100110010100---", Id::SEL_C, Type::ArithmeticInteger, "SEL_C"), INST("0101110010100---", Id::SEL_R, Type::ArithmeticInteger, "SEL_R"), INST("0011100-10100---", Id::SEL_IMM, Type::ArithmeticInteger, "SEL_IMM"), + INST("0101101111011---", Id::LEA_R2, Type::ArithmeticInteger, "LEA_R2"), + INST("0101101111010---", Id::LEA_R1, Type::ArithmeticInteger, "LEA_R1"), + INST("001101101101----", Id::LEA_IMM, Type::ArithmeticInteger, "LEA_IMM"), + INST("010010111101----", Id::LEA_RZ, Type::ArithmeticInteger, "LEA_RZ"), + INST("00011000--------", Id::LEA_HI, Type::ArithmeticInteger, "LEA_HI"), INST("0101000010000---", Id::MUFU, Type::Arithmetic, "MUFU"), INST("0100110010010---", Id::RRO_C, Type::Arithmetic, "RRO_C"), INST("0101110010010---", Id::RRO_R, Type::Arithmetic, "RRO_R"), @@ -983,6 +1085,7 @@ private: INST("010110110101----", Id::ISET_R, Type::IntegerSet, "ISET_R"), INST("010010110101----", Id::ISET_C, Type::IntegerSet, "ISET_C"), INST("0011011-0101----", Id::ISET_IMM, Type::IntegerSet, "ISET_IMM"), + INST("0101000010001---", Id::PSET, Type::PredicateSetRegister, "PSET"), INST("0101000010010---", Id::PSETP, Type::PredicateSetPredicate, "PSETP"), INST("0011011-00------", Id::XMAD_IMM, Type::Xmad, "XMAD_IMM"), INST("0100111---------", Id::XMAD_CR, Type::Xmad, "XMAD_CR"), diff --git a/src/video_core/gpu.cpp b/src/video_core/gpu.cpp index e6d8e65c6..86a809f86 100644 --- a/src/video_core/gpu.cpp +++ b/src/video_core/gpu.cpp @@ -66,6 +66,7 @@ u32 RenderTargetBytesPerPixel(RenderTargetFormat format) { case RenderTargetFormat::RGBA8_UINT: case RenderTargetFormat::RGB10_A2_UNORM: case RenderTargetFormat::BGRA8_UNORM: + case RenderTargetFormat::BGRA8_SRGB: case RenderTargetFormat::RG16_UNORM: case RenderTargetFormat::RG16_SNORM: case RenderTargetFormat::RG16_UINT: diff --git a/src/video_core/gpu.h b/src/video_core/gpu.h index d29f31f52..589a59b4f 100644 --- a/src/video_core/gpu.h +++ b/src/video_core/gpu.h @@ -6,6 +6,7 @@ #include <array> #include <memory> +#include <vector> #include "common/common_types.h" #include "core/hle/service/nvflinger/buffer_queue.h" #include "video_core/memory_manager.h" @@ -26,6 +27,7 @@ enum class RenderTargetFormat : u32 { RG32_FLOAT = 0xCB, RG32_UINT = 0xCD, BGRA8_UNORM = 0xCF, + BGRA8_SRGB = 0xD0, RGB10_A2_UNORM = 0xD1, RGBA8_UNORM = 0xD5, RGBA8_SRGB = 0xD6, @@ -67,6 +69,7 @@ u32 RenderTargetBytesPerPixel(RenderTargetFormat format); /// Returns the number of bytes per pixel of each depth format. u32 DepthFormatBytesPerPixel(DepthFormat format); +struct CommandListHeader; class DebugContext; /** @@ -115,7 +118,7 @@ public: ~GPU(); /// Processes a command list stored at the specified address in GPU memory. - void ProcessCommandList(GPUVAddr address, u32 size); + void ProcessCommandLists(const std::vector<CommandListHeader>& commands); /// Returns a reference to the Maxwell3D GPU engine. Engines::Maxwell3D& Maxwell3D(); @@ -130,9 +133,6 @@ public: const Tegra::MemoryManager& MemoryManager() const; private: - /// Writes a single register in the engine bound to the specified subchannel - void WriteReg(u32 method, u32 subchannel, u32 value, u32 remaining_params); - std::unique_ptr<Tegra::MemoryManager> memory_manager; /// Mapping of command subchannels to their bound engine ids. diff --git a/src/video_core/rasterizer_interface.h b/src/video_core/rasterizer_interface.h index 9d78e8b6b..cd819d69f 100644 --- a/src/video_core/rasterizer_interface.h +++ b/src/video_core/rasterizer_interface.h @@ -20,9 +20,6 @@ public: /// Clear the current framebuffer virtual void Clear() = 0; - /// Notify rasterizer that the specified Maxwell register has been changed - virtual void NotifyMaxwellRegisterChanged(u32 method) = 0; - /// Notify rasterizer that all caches should be flushed to Switch memory virtual void FlushAll() = 0; diff --git a/src/video_core/renderer_base.cpp b/src/video_core/renderer_base.cpp index be17a2b9c..0df3725c2 100644 --- a/src/video_core/renderer_base.cpp +++ b/src/video_core/renderer_base.cpp @@ -19,6 +19,7 @@ void RendererBase::RefreshBaseSettings() { UpdateCurrentFramebufferLayout(); renderer_settings.use_framelimiter = Settings::values.use_frame_limit; + renderer_settings.set_background_color = true; } void RendererBase::UpdateCurrentFramebufferLayout() { diff --git a/src/video_core/renderer_base.h b/src/video_core/renderer_base.h index 2a357f9d0..2cd0738ff 100644 --- a/src/video_core/renderer_base.h +++ b/src/video_core/renderer_base.h @@ -19,6 +19,7 @@ namespace VideoCore { struct RendererSettings { std::atomic_bool use_framelimiter{false}; + std::atomic_bool set_background_color{false}; }; class RendererBase : NonCopyable { diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp index 0c3bbc475..c59f3af1b 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp @@ -294,61 +294,80 @@ void RasterizerOpenGL::UpdatePagesCachedCount(VAddr addr, u64 size, int delta) { cached_pages.add({pages_interval, delta}); } -std::pair<Surface, Surface> RasterizerOpenGL::ConfigureFramebuffers(bool using_color_fb, - bool using_depth_fb, - bool preserve_contents) { +void RasterizerOpenGL::ConfigureFramebuffers(bool using_color_fb, bool using_depth_fb, + bool preserve_contents, + boost::optional<size_t> single_color_target) { MICROPROFILE_SCOPE(OpenGL_Framebuffer); const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs; - if (regs.rt[0].format == Tegra::RenderTargetFormat::NONE) { - LOG_ERROR(HW_GPU, "RenderTargetFormat is not configured"); - using_color_fb = false; + Surface depth_surface; + if (using_depth_fb) { + depth_surface = res_cache.GetDepthBufferSurface(preserve_contents); } - const bool has_stencil = regs.stencil_enable; - const bool write_color_fb = - state.color_mask.red_enabled == GL_TRUE || state.color_mask.green_enabled == GL_TRUE || - state.color_mask.blue_enabled == GL_TRUE || state.color_mask.alpha_enabled == GL_TRUE; - - const bool write_depth_fb = - (state.depth.test_enabled && state.depth.write_mask == GL_TRUE) || - (has_stencil && (state.stencil.front.write_mask || state.stencil.back.write_mask)); + // TODO(bunnei): Figure out how the below register works. According to envytools, this should be + // used to enable multiple render targets. However, it is left unset on all games that I have + // tested. + ASSERT_MSG(regs.rt_separate_frag_data == 0, "Unimplemented"); - Surface color_surface; - Surface depth_surface; - MathUtil::Rectangle<u32> surfaces_rect; - std::tie(color_surface, depth_surface, surfaces_rect) = - res_cache.GetFramebufferSurfaces(using_color_fb, using_depth_fb, preserve_contents); + // Bind the framebuffer surfaces + state.draw.draw_framebuffer = framebuffer.handle; + state.Apply(); - const MathUtil::Rectangle<s32> viewport_rect{regs.viewport_transform[0].GetRect()}; - const MathUtil::Rectangle<u32> draw_rect{ - static_cast<u32>(std::clamp<s32>(static_cast<s32>(surfaces_rect.left) + viewport_rect.left, - surfaces_rect.left, surfaces_rect.right)), // Left - static_cast<u32>(std::clamp<s32>(static_cast<s32>(surfaces_rect.bottom) + viewport_rect.top, - surfaces_rect.bottom, surfaces_rect.top)), // Top - static_cast<u32>(std::clamp<s32>(static_cast<s32>(surfaces_rect.left) + viewport_rect.right, - surfaces_rect.left, surfaces_rect.right)), // Right - static_cast<u32>( - std::clamp<s32>(static_cast<s32>(surfaces_rect.bottom) + viewport_rect.bottom, - surfaces_rect.bottom, surfaces_rect.top))}; // Bottom + if (using_color_fb) { + if (single_color_target) { + // Used when just a single color attachment is enabled, e.g. for clearing a color buffer + Surface color_surface = + res_cache.GetColorBufferSurface(*single_color_target, preserve_contents); + glFramebufferTexture2D( + GL_DRAW_FRAMEBUFFER, + GL_COLOR_ATTACHMENT0 + static_cast<GLenum>(*single_color_target), GL_TEXTURE_2D, + color_surface != nullptr ? color_surface->Texture().handle : 0, 0); + glDrawBuffer(GL_COLOR_ATTACHMENT0 + static_cast<GLenum>(*single_color_target)); + } else { + // Multiple color attachments are enabled + std::array<GLenum, Maxwell::NumRenderTargets> buffers; + for (size_t index = 0; index < Maxwell::NumRenderTargets; ++index) { + Surface color_surface = res_cache.GetColorBufferSurface(index, preserve_contents); + buffers[index] = GL_COLOR_ATTACHMENT0 + regs.rt_control.GetMap(index); + glFramebufferTexture2D( + GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + static_cast<GLenum>(index), + GL_TEXTURE_2D, color_surface != nullptr ? color_surface->Texture().handle : 0, + 0); + } + glDrawBuffers(regs.rt_control.count, buffers.data()); + } + } else { + // No color attachments are enabled - zero out all of them + for (size_t index = 0; index < Maxwell::NumRenderTargets; ++index) { + glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, + GL_COLOR_ATTACHMENT0 + static_cast<GLenum>(index), GL_TEXTURE_2D, + 0, 0); + } + glDrawBuffer(GL_NONE); + } - // Bind the framebuffer surfaces - BindFramebufferSurfaces(color_surface, depth_surface, has_stencil); + if (depth_surface) { + if (regs.stencil_enable) { + // Attach both depth and stencil + glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, + depth_surface->Texture().handle, 0); + } else { + // Attach depth + glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, + depth_surface->Texture().handle, 0); + // Clear stencil attachment + glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_TEXTURE_2D, 0, 0); + } + } else { + // Clear both depth and stencil attachment + glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, 0, + 0); + } - SyncViewport(surfaces_rect); + SyncViewport(); - // Viewport can have negative offsets or larger dimensions than our framebuffer sub-rect. Enable - // scissor test to prevent drawing outside of the framebuffer region - state.scissor.enabled = true; - state.scissor.x = draw_rect.left; - state.scissor.y = draw_rect.bottom; - state.scissor.width = draw_rect.GetWidth(); - state.scissor.height = draw_rect.GetHeight(); state.Apply(); - - // Only return the surface to be marked as dirty if writing to it is enabled. - return std::make_pair(write_color_fb ? color_surface : nullptr, - write_depth_fb ? depth_surface : nullptr); } void RasterizerOpenGL::Clear() { @@ -356,8 +375,9 @@ void RasterizerOpenGL::Clear() { SCOPE_EXIT({ prev_state.Apply(); }); const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs; - bool use_color_fb = false; - bool use_depth_fb = false; + bool use_color{}; + bool use_depth{}; + bool use_stencil{}; OpenGLState clear_state; clear_state.draw.draw_framebuffer = state.draw.draw_framebuffer; @@ -366,22 +386,13 @@ void RasterizerOpenGL::Clear() { clear_state.color_mask.blue_enabled = regs.clear_buffers.B ? GL_TRUE : GL_FALSE; clear_state.color_mask.alpha_enabled = regs.clear_buffers.A ? GL_TRUE : GL_FALSE; - GLbitfield clear_mask{}; if (regs.clear_buffers.R || regs.clear_buffers.G || regs.clear_buffers.B || regs.clear_buffers.A) { - if (regs.clear_buffers.RT == 0) { - // We only support clearing the first color attachment for now - clear_mask |= GL_COLOR_BUFFER_BIT; - use_color_fb = true; - } else { - // TODO(subv): Add support for the other color attachments - LOG_CRITICAL(HW_GPU, "Clear unimplemented for RT {}", regs.clear_buffers.RT); - } + use_color = true; } if (regs.clear_buffers.Z) { ASSERT_MSG(regs.zeta_enable != 0, "Tried to clear Z but buffer is not enabled!"); - use_depth_fb = true; - clear_mask |= GL_DEPTH_BUFFER_BIT; + use_depth = true; // Always enable the depth write when clearing the depth buffer. The depth write mask is // ignored when clearing the buffer in the Switch, but OpenGL obeys it so we set it to true. @@ -390,34 +401,33 @@ void RasterizerOpenGL::Clear() { } if (regs.clear_buffers.S) { ASSERT_MSG(regs.zeta_enable != 0, "Tried to clear stencil but buffer is not enabled!"); - use_depth_fb = true; - clear_mask |= GL_STENCIL_BUFFER_BIT; + use_stencil = true; clear_state.stencil.test_enabled = true; } - if (!use_color_fb && !use_depth_fb) { + if (!use_color && !use_depth && !use_stencil) { // No color surface nor depth/stencil surface are enabled return; } - if (clear_mask == 0) { - // No clear mask is enabled - return; - } - ScopeAcquireGLContext acquire_context{emu_window}; - auto [dirty_color_surface, dirty_depth_surface] = - ConfigureFramebuffers(use_color_fb, use_depth_fb, false); + ConfigureFramebuffers(use_color, use_depth || use_stencil, false, + regs.clear_buffers.RT.Value()); clear_state.Apply(); - glClearColor(regs.clear_color[0], regs.clear_color[1], regs.clear_color[2], - regs.clear_color[3]); - glClearDepth(regs.clear_depth); - glClearStencil(regs.clear_stencil); + if (use_color) { + glClearBufferfv(GL_COLOR, regs.clear_buffers.RT, regs.clear_color); + } - glClear(clear_mask); + if (use_depth && use_stencil) { + glClearBufferfi(GL_DEPTH_STENCIL, 0, regs.clear_depth, regs.clear_stencil); + } else if (use_depth) { + glClearBufferfv(GL_DEPTH, 0, ®s.clear_depth); + } else if (use_stencil) { + glClearBufferiv(GL_STENCIL, 0, ®s.clear_stencil); + } } void RasterizerOpenGL::DrawArrays() { @@ -430,8 +440,7 @@ void RasterizerOpenGL::DrawArrays() { ScopeAcquireGLContext acquire_context{emu_window}; - const auto [dirty_color_surface, dirty_depth_surface] = - ConfigureFramebuffers(true, regs.zeta.Address() != 0 && regs.zeta_enable != 0, true); + ConfigureFramebuffers(); SyncDepthTestState(); SyncStencilTestState(); @@ -525,8 +534,6 @@ void RasterizerOpenGL::DrawArrays() { state.Apply(); } -void RasterizerOpenGL::NotifyMaxwellRegisterChanged(u32 method) {} - void RasterizerOpenGL::FlushAll() {} void RasterizerOpenGL::FlushRegion(VAddr addr, u64 size) {} @@ -586,7 +593,7 @@ bool RasterizerOpenGL::AccelerateDisplay(const Tegra::FramebufferConfig& config, void RasterizerOpenGL::SamplerInfo::Create() { sampler.Create(); mag_filter = min_filter = Tegra::Texture::TextureFilter::Linear; - wrap_u = wrap_v = Tegra::Texture::WrapMode::Wrap; + wrap_u = wrap_v = wrap_p = Tegra::Texture::WrapMode::Wrap; // default is GL_LINEAR_MIPMAP_LINEAR glSamplerParameteri(sampler.handle, GL_TEXTURE_MIN_FILTER, GL_LINEAR); @@ -613,8 +620,13 @@ void RasterizerOpenGL::SamplerInfo::SyncWithConfig(const Tegra::Texture::TSCEntr wrap_v = config.wrap_v; glSamplerParameteri(s, GL_TEXTURE_WRAP_T, MaxwellToGL::WrapMode(wrap_v)); } + if (wrap_p != config.wrap_p) { + wrap_p = config.wrap_p; + glSamplerParameteri(s, GL_TEXTURE_WRAP_R, MaxwellToGL::WrapMode(wrap_p)); + } - if (wrap_u == Tegra::Texture::WrapMode::Border || wrap_v == Tegra::Texture::WrapMode::Border) { + if (wrap_u == Tegra::Texture::WrapMode::Border || wrap_v == Tegra::Texture::WrapMode::Border || + wrap_p == Tegra::Texture::WrapMode::Border) { const GLvec4 new_border_color = {{config.border_color_r, config.border_color_g, config.border_color_b, config.border_color_a}}; if (border_color != new_border_color) { @@ -698,14 +710,15 @@ u32 RasterizerOpenGL::SetupTextures(Maxwell::ShaderStage stage, Shader& shader, const auto texture = maxwell3d.GetStageTexture(entry.GetStage(), entry.GetOffset()); if (!texture.enabled) { - state.texture_units[current_bindpoint].texture_2d = 0; + state.texture_units[current_bindpoint].texture = 0; continue; } texture_samplers[current_bindpoint].SyncWithConfig(texture.tsc); Surface surface = res_cache.GetTextureSurface(texture); if (surface != nullptr) { - state.texture_units[current_bindpoint].texture_2d = surface->Texture().handle; + state.texture_units[current_bindpoint].texture = surface->Texture().handle; + state.texture_units[current_bindpoint].target = surface->Target(); state.texture_units[current_bindpoint].swizzle.r = MaxwellToGL::SwizzleSource(texture.tic.x_source); state.texture_units[current_bindpoint].swizzle.g = @@ -716,45 +729,19 @@ u32 RasterizerOpenGL::SetupTextures(Maxwell::ShaderStage stage, Shader& shader, MaxwellToGL::SwizzleSource(texture.tic.w_source); } else { // Can occur when texture addr is null or its memory is unmapped/invalid - state.texture_units[current_bindpoint].texture_2d = 0; + state.texture_units[current_bindpoint].texture = 0; } } return current_unit + static_cast<u32>(entries.size()); } -void RasterizerOpenGL::BindFramebufferSurfaces(const Surface& color_surface, - const Surface& depth_surface, bool has_stencil) { - state.draw.draw_framebuffer = framebuffer.handle; - state.Apply(); - - glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, - color_surface != nullptr ? color_surface->Texture().handle : 0, 0); - if (depth_surface != nullptr) { - if (has_stencil) { - // attach both depth and stencil - glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, - depth_surface->Texture().handle, 0); - } else { - // attach depth - glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, - depth_surface->Texture().handle, 0); - // clear stencil attachment - glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_TEXTURE_2D, 0, 0); - } - } else { - // clear both depth and stencil attachment - glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, 0, - 0); - } -} - -void RasterizerOpenGL::SyncViewport(const MathUtil::Rectangle<u32>& surfaces_rect) { +void RasterizerOpenGL::SyncViewport() { const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs; const MathUtil::Rectangle<s32> viewport_rect{regs.viewport_transform[0].GetRect()}; - state.viewport.x = static_cast<GLint>(surfaces_rect.left) + viewport_rect.left; - state.viewport.y = static_cast<GLint>(surfaces_rect.bottom) + viewport_rect.bottom; + state.viewport.x = viewport_rect.left; + state.viewport.y = viewport_rect.bottom; state.viewport.width = static_cast<GLsizei>(viewport_rect.GetWidth()); state.viewport.height = static_cast<GLsizei>(viewport_rect.GetHeight()); } diff --git a/src/video_core/renderer_opengl/gl_rasterizer.h b/src/video_core/renderer_opengl/gl_rasterizer.h index 9c30dc0e8..745c3dc0c 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.h +++ b/src/video_core/renderer_opengl/gl_rasterizer.h @@ -13,6 +13,7 @@ #include <vector> #include <boost/icl/interval_map.hpp> +#include <boost/optional.hpp> #include <boost/range/iterator_range.hpp> #include <glad/glad.h> @@ -45,7 +46,6 @@ public: void DrawArrays() override; void Clear() override; - void NotifyMaxwellRegisterChanged(u32 method) override; void FlushAll() override; void FlushRegion(VAddr addr, u64 size) override; void InvalidateRegion(VAddr addr, u64 size) override; @@ -93,17 +93,20 @@ private: Tegra::Texture::TextureFilter min_filter; Tegra::Texture::WrapMode wrap_u; Tegra::Texture::WrapMode wrap_v; + Tegra::Texture::WrapMode wrap_p; GLvec4 border_color; }; - /// Configures the color and depth framebuffer states and returns the dirty <Color, Depth> - /// surfaces if writing was enabled. - std::pair<Surface, Surface> ConfigureFramebuffers(bool using_color_fb, bool using_depth_fb, - bool preserve_contents); - - /// Binds the framebuffer color and depth surface - void BindFramebufferSurfaces(const Surface& color_surface, const Surface& depth_surface, - bool has_stencil); + /** + * Configures the color and depth framebuffer states. + * @param use_color_fb If true, configure color framebuffers. + * @param using_depth_fb If true, configure the depth/stencil framebuffer. + * @param preserve_contents If true, tries to preserve data from a previously used framebuffer. + * @param single_color_target Specifies if a single color buffer target should be used. + */ + void ConfigureFramebuffers(bool use_color_fb = true, bool using_depth_fb = true, + bool preserve_contents = true, + boost::optional<size_t> single_color_target = {}); /* * Configures the current constbuffers to use for the draw command. @@ -126,7 +129,7 @@ private: u32 current_unit); /// Syncs the viewport to match the guest state - void SyncViewport(const MathUtil::Rectangle<u32>& surfaces_rect); + void SyncViewport(); /// Syncs the clip enabled status to match the guest state void SyncClipEnabled(); diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp index f6b2c5a86..32001e44b 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp @@ -7,6 +7,7 @@ #include "common/alignment.h" #include "common/assert.h" +#include "common/logging/log.h" #include "common/microprofile.h" #include "common/scope_exit.h" #include "core/core.h" @@ -52,14 +53,30 @@ static VAddr TryGetCpuAddr(Tegra::GPUVAddr gpu_addr) { params.width = Common::AlignUp(config.tic.Width(), GetCompressionFactor(params.pixel_format)); params.height = Common::AlignUp(config.tic.Height(), GetCompressionFactor(params.pixel_format)); params.unaligned_height = config.tic.Height(); + params.target = SurfaceTargetFromTextureType(config.tic.texture_type); + + switch (params.target) { + case SurfaceTarget::Texture1D: + case SurfaceTarget::Texture2D: + params.depth = 1; + break; + case SurfaceTarget::Texture3D: + case SurfaceTarget::Texture2DArray: + params.depth = config.tic.Depth(); + break; + default: + LOG_CRITICAL(HW_GPU, "Unknown depth for target={}", static_cast<u32>(params.target)); + UNREACHABLE(); + params.depth = 1; + break; + } + params.size_in_bytes = params.SizeInBytes(); - params.cache_width = Common::AlignUp(params.width, 16); - params.cache_height = Common::AlignUp(params.height, 16); return params; } -/*static*/ SurfaceParams SurfaceParams::CreateForFramebuffer( - const Tegra::Engines::Maxwell3D::Regs::RenderTargetConfig& config) { +/*static*/ SurfaceParams SurfaceParams::CreateForFramebuffer(size_t index) { + const auto& config{Core::System::GetInstance().GPU().Maxwell3D().regs.rt[index]}; SurfaceParams params{}; params.addr = TryGetCpuAddr(config.Address()); params.is_tiled = true; @@ -70,9 +87,9 @@ static VAddr TryGetCpuAddr(Tegra::GPUVAddr gpu_addr) { params.width = config.width; params.height = config.height; params.unaligned_height = config.height; + params.target = SurfaceTarget::Texture2D; + params.depth = 1; params.size_in_bytes = params.SizeInBytes(); - params.cache_width = Common::AlignUp(params.width, 16); - params.cache_height = Common::AlignUp(params.height, 16); return params; } @@ -86,13 +103,12 @@ static VAddr TryGetCpuAddr(Tegra::GPUVAddr gpu_addr) { params.pixel_format = PixelFormatFromDepthFormat(format); params.component_type = ComponentTypeFromDepthFormat(format); params.type = GetFormatType(params.pixel_format); - params.size_in_bytes = params.SizeInBytes(); params.width = zeta_width; params.height = zeta_height; params.unaligned_height = zeta_height; + params.target = SurfaceTarget::Texture2D; + params.depth = 1; params.size_in_bytes = params.SizeInBytes(); - params.cache_width = Common::AlignUp(params.width, 16); - params.cache_height = Common::AlignUp(params.height, 16); return params; } @@ -100,7 +116,7 @@ static constexpr std::array<FormatTuple, SurfaceParams::MaxPixelFormat> tex_form {GL_RGBA8, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, ComponentType::UNorm, false}, // ABGR8U {GL_RGBA8, GL_RGBA, GL_BYTE, ComponentType::SNorm, false}, // ABGR8S {GL_RGBA8UI, GL_RGBA_INTEGER, GL_UNSIGNED_BYTE, ComponentType::UInt, false}, // ABGR8UI - {GL_RGB, GL_RGB, GL_UNSIGNED_SHORT_5_6_5_REV, ComponentType::UNorm, false}, // B5G6R5U + {GL_RGB8, GL_RGB, GL_UNSIGNED_SHORT_5_6_5_REV, ComponentType::UNorm, false}, // B5G6R5U {GL_RGB10_A2, GL_RGBA, GL_UNSIGNED_INT_2_10_10_10_REV, ComponentType::UNorm, false}, // A2B10G10R10U {GL_RGB5_A1, GL_RGBA, GL_UNSIGNED_SHORT_1_5_5_5_REV, ComponentType::UNorm, false}, // A1B5G5R5U @@ -166,6 +182,26 @@ static constexpr std::array<FormatTuple, SurfaceParams::MaxPixelFormat> tex_form ComponentType::Float, false}, // Z32FS8 }}; +static GLenum SurfaceTargetToGL(SurfaceParams::SurfaceTarget target) { + switch (target) { + case SurfaceParams::SurfaceTarget::Texture1D: + return GL_TEXTURE_1D; + case SurfaceParams::SurfaceTarget::Texture2D: + return GL_TEXTURE_2D; + case SurfaceParams::SurfaceTarget::Texture3D: + return GL_TEXTURE_3D; + case SurfaceParams::SurfaceTarget::Texture1DArray: + return GL_TEXTURE_1D_ARRAY; + case SurfaceParams::SurfaceTarget::Texture2DArray: + return GL_TEXTURE_2D_ARRAY; + case SurfaceParams::SurfaceTarget::TextureCubemap: + return GL_TEXTURE_CUBE_MAP; + } + LOG_CRITICAL(Render_OpenGL, "Unimplemented texture target={}", static_cast<u32>(target)); + UNREACHABLE(); + return {}; +} + static const FormatTuple& GetFormatTuple(PixelFormat pixel_format, ComponentType component_type) { ASSERT(static_cast<size_t>(pixel_format) < tex_format_tuples.size()); auto& format = tex_format_tuples[static_cast<unsigned int>(pixel_format)]; @@ -220,7 +256,8 @@ static bool IsFormatBCn(PixelFormat format) { } template <bool morton_to_gl, PixelFormat format> -void MortonCopy(u32 stride, u32 block_height, u32 height, std::vector<u8>& gl_buffer, VAddr addr) { +void MortonCopy(u32 stride, u32 block_height, u32 height, u8* gl_buffer, size_t gl_buffer_size, + VAddr addr) { constexpr u32 bytes_per_pixel = SurfaceParams::GetFormatBpp(format) / CHAR_BIT; constexpr u32 gl_bytes_per_pixel = CachedSurface::GetGLBytesPerPixel(format); @@ -230,18 +267,18 @@ void MortonCopy(u32 stride, u32 block_height, u32 height, std::vector<u8>& gl_bu const u32 tile_size{IsFormatBCn(format) ? 4U : 1U}; const std::vector<u8> data = Tegra::Texture::UnswizzleTexture( addr, tile_size, bytes_per_pixel, stride, height, block_height); - const size_t size_to_copy{std::min(gl_buffer.size(), data.size())}; - gl_buffer.assign(data.begin(), data.begin() + size_to_copy); + const size_t size_to_copy{std::min(gl_buffer_size, data.size())}; + memcpy(gl_buffer, data.data(), size_to_copy); } else { // TODO(bunnei): Assumes the default rendering GOB size of 16 (128 lines). We should // check the configuration for this and perform more generic un/swizzle LOG_WARNING(Render_OpenGL, "need to use correct swizzle/GOB parameters!"); VideoCore::MortonCopyPixels128(stride, height, bytes_per_pixel, gl_bytes_per_pixel, - Memory::GetPointer(addr), gl_buffer.data(), morton_to_gl); + Memory::GetPointer(addr), gl_buffer, morton_to_gl); } } -static constexpr std::array<void (*)(u32, u32, u32, std::vector<u8>&, VAddr), +static constexpr std::array<void (*)(u32, u32, u32, u8*, size_t, VAddr), SurfaceParams::MaxPixelFormat> morton_to_gl_fns = { // clang-format off @@ -298,7 +335,7 @@ static constexpr std::array<void (*)(u32, u32, u32, std::vector<u8>&, VAddr), // clang-format on }; -static constexpr std::array<void (*)(u32, u32, u32, std::vector<u8>&, VAddr), +static constexpr std::array<void (*)(u32, u32, u32, u8*, size_t, VAddr), SurfaceParams::MaxPixelFormat> gl_to_morton_fns = { // clang-format off @@ -357,33 +394,6 @@ static constexpr std::array<void (*)(u32, u32, u32, std::vector<u8>&, VAddr), // clang-format on }; -// Allocate an uninitialized texture of appropriate size and format for the surface -static void AllocateSurfaceTexture(GLuint texture, const FormatTuple& format_tuple, u32 width, - u32 height) { - OpenGLState cur_state = OpenGLState::GetCurState(); - - // Keep track of previous texture bindings - GLuint old_tex = cur_state.texture_units[0].texture_2d; - cur_state.texture_units[0].texture_2d = texture; - cur_state.Apply(); - glActiveTexture(GL_TEXTURE0); - - if (!format_tuple.compressed) { - // Only pre-create the texture for non-compressed textures. - glTexImage2D(GL_TEXTURE_2D, 0, format_tuple.internal_format, width, height, 0, - format_tuple.format, format_tuple.type, nullptr); - } - - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - - // Restore previous texture bindings - cur_state.texture_units[0].texture_2d = old_tex; - cur_state.Apply(); -} - static bool BlitTextures(GLuint src_tex, const MathUtil::Rectangle<u32>& src_rect, GLuint dst_tex, const MathUtil::Rectangle<u32>& dst_rect, SurfaceType type, GLuint read_fb_handle, GLuint draw_fb_handle) { @@ -438,12 +448,53 @@ static bool BlitTextures(GLuint src_tex, const MathUtil::Rectangle<u32>& src_rec return true; } -CachedSurface::CachedSurface(const SurfaceParams& params) : params(params) { +CachedSurface::CachedSurface(const SurfaceParams& params) + : params(params), gl_target(SurfaceTargetToGL(params.target)) { texture.Create(); const auto& rect{params.GetRect()}; - AllocateSurfaceTexture(texture.handle, - GetFormatTuple(params.pixel_format, params.component_type), + + // Keep track of previous texture bindings + OpenGLState cur_state = OpenGLState::GetCurState(); + const auto& old_tex = cur_state.texture_units[0]; + SCOPE_EXIT({ + cur_state.texture_units[0] = old_tex; + cur_state.Apply(); + }); + + cur_state.texture_units[0].texture = texture.handle; + cur_state.texture_units[0].target = SurfaceTargetToGL(params.target); + cur_state.Apply(); + glActiveTexture(GL_TEXTURE0); + + const auto& format_tuple = GetFormatTuple(params.pixel_format, params.component_type); + if (!format_tuple.compressed) { + // Only pre-create the texture for non-compressed textures. + switch (params.target) { + case SurfaceParams::SurfaceTarget::Texture1D: + glTexStorage1D(SurfaceTargetToGL(params.target), 1, format_tuple.internal_format, + rect.GetWidth()); + break; + case SurfaceParams::SurfaceTarget::Texture2D: + glTexStorage2D(SurfaceTargetToGL(params.target), 1, format_tuple.internal_format, rect.GetWidth(), rect.GetHeight()); + break; + case SurfaceParams::SurfaceTarget::Texture3D: + case SurfaceParams::SurfaceTarget::Texture2DArray: + glTexStorage3D(SurfaceTargetToGL(params.target), 1, format_tuple.internal_format, + rect.GetWidth(), rect.GetHeight(), params.depth); + break; + default: + LOG_CRITICAL(Render_OpenGL, "Unimplemented surface target={}", + static_cast<u32>(params.target)); + UNREACHABLE(); + glTexStorage2D(GL_TEXTURE_2D, 1, format_tuple.internal_format, rect.GetWidth(), + rect.GetHeight()); + } + } + + glTexParameteri(SurfaceTargetToGL(params.target), GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(SurfaceTargetToGL(params.target), GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(SurfaceTargetToGL(params.target), GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); } static void ConvertS8Z24ToZ24S8(std::vector<u8>& data, u32 width, u32 height) { @@ -461,7 +512,7 @@ static void ConvertS8Z24ToZ24S8(std::vector<u8>& data, u32 width, u32 height) { S8Z24 input_pixel{}; Z24S8 output_pixel{}; - const auto bpp{CachedSurface::GetGLBytesPerPixel(PixelFormat::S8Z24)}; + constexpr auto bpp{CachedSurface::GetGLBytesPerPixel(PixelFormat::S8Z24)}; for (size_t y = 0; y < height; ++y) { for (size_t x = 0; x < width; ++x) { const size_t offset{bpp * (y * width + x)}; @@ -474,7 +525,7 @@ static void ConvertS8Z24ToZ24S8(std::vector<u8>& data, u32 width, u32 height) { } static void ConvertG8R8ToR8G8(std::vector<u8>& data, u32 width, u32 height) { - const auto bpp{CachedSurface::GetGLBytesPerPixel(PixelFormat::G8R8U)}; + constexpr auto bpp{CachedSurface::GetGLBytesPerPixel(PixelFormat::G8R8U)}; for (size_t y = 0; y < height; ++y) { for (size_t x = 0; x < width; ++x) { const size_t offset{bpp * (y * width + x)}; @@ -514,23 +565,6 @@ static void ConvertFormatAsNeeded_LoadGLBuffer(std::vector<u8>& data, PixelForma } } -/** - * Helper function to perform software conversion (as needed) when flushing a buffer to Switch - * memory. This is for Maxwell pixel formats that cannot be represented as-is in OpenGL or with - * typical desktop GPUs. - */ -static void ConvertFormatAsNeeded_FlushGLBuffer(std::vector<u8>& /*data*/, PixelFormat pixel_format, - u32 /*width*/, u32 /*height*/) { - switch (pixel_format) { - case PixelFormat::ASTC_2D_4X4: - case PixelFormat::S8Z24: - LOG_CRITICAL(Render_OpenGL, "Unimplemented pixel_format={}", - static_cast<u32>(pixel_format)); - UNREACHABLE(); - break; - } -} - MICROPROFILE_DEFINE(OpenGL_SurfaceLoad, "OpenGL", "Surface Load", MP_RGB(128, 64, 192)); void CachedSurface::LoadGLBuffer() { ASSERT(params.type != SurfaceType::Fill); @@ -545,13 +579,25 @@ void CachedSurface::LoadGLBuffer() { MICROPROFILE_SCOPE(OpenGL_SurfaceLoad); if (params.is_tiled) { - gl_buffer.resize(copy_size); + // TODO(bunnei): This only unswizzles and copies a 2D texture - we do not yet know how to do + // this for 3D textures, etc. + switch (params.target) { + case SurfaceParams::SurfaceTarget::Texture2D: + // Pass impl. to the fallback code below + break; + default: + LOG_CRITICAL(HW_GPU, "Unimplemented tiled load for target={}", + static_cast<u32>(params.target)); + UNREACHABLE(); + } + gl_buffer.resize(static_cast<size_t>(params.depth) * copy_size); morton_to_gl_fns[static_cast<size_t>(params.pixel_format)]( - params.width, params.block_height, params.height, gl_buffer, params.addr); + params.width, params.block_height, params.height, gl_buffer.data(), copy_size, + params.addr); } else { - const u8* const texture_src_data_end = texture_src_data + copy_size; - + const u8* const texture_src_data_end{texture_src_data + + (static_cast<size_t>(params.depth) * copy_size)}; gl_buffer.assign(texture_src_data, texture_src_data_end); } @@ -560,23 +606,7 @@ void CachedSurface::LoadGLBuffer() { MICROPROFILE_DEFINE(OpenGL_SurfaceFlush, "OpenGL", "Surface Flush", MP_RGB(128, 192, 64)); void CachedSurface::FlushGLBuffer() { - u8* const dst_buffer = Memory::GetPointer(params.addr); - - ASSERT(dst_buffer); - ASSERT(gl_buffer.size() == - params.width * params.height * GetGLBytesPerPixel(params.pixel_format)); - - MICROPROFILE_SCOPE(OpenGL_SurfaceFlush); - - ConvertFormatAsNeeded_FlushGLBuffer(gl_buffer, params.pixel_format, params.width, - params.height); - - if (!params.is_tiled) { - std::memcpy(dst_buffer, gl_buffer.data(), params.size_in_bytes); - } else { - gl_to_morton_fns[static_cast<size_t>(params.pixel_format)]( - params.width, params.block_height, params.height, gl_buffer, params.addr); - } + ASSERT_MSG(false, "Unimplemented"); } MICROPROFILE_DEFINE(OpenGL_TextureUL, "OpenGL", "Texture Upload", MP_RGB(128, 64, 192)); @@ -586,22 +616,29 @@ void CachedSurface::UploadGLTexture(GLuint read_fb_handle, GLuint draw_fb_handle MICROPROFILE_SCOPE(OpenGL_TextureUL); - ASSERT(gl_buffer.size() == - params.width * params.height * GetGLBytesPerPixel(params.pixel_format)); + ASSERT(gl_buffer.size() == static_cast<size_t>(params.width) * params.height * + GetGLBytesPerPixel(params.pixel_format) * params.depth); const auto& rect{params.GetRect()}; // Load data from memory to the surface - GLint x0 = static_cast<GLint>(rect.left); - GLint y0 = static_cast<GLint>(rect.bottom); - size_t buffer_offset = (y0 * params.width + x0) * GetGLBytesPerPixel(params.pixel_format); + const GLint x0 = static_cast<GLint>(rect.left); + const GLint y0 = static_cast<GLint>(rect.bottom); + const size_t buffer_offset = + static_cast<size_t>(static_cast<size_t>(y0) * params.width + static_cast<size_t>(x0)) * + GetGLBytesPerPixel(params.pixel_format); const FormatTuple& tuple = GetFormatTuple(params.pixel_format, params.component_type); - GLuint target_tex = texture.handle; + const GLuint target_tex = texture.handle; OpenGLState cur_state = OpenGLState::GetCurState(); - GLuint old_tex = cur_state.texture_units[0].texture_2d; - cur_state.texture_units[0].texture_2d = target_tex; + const auto& old_tex = cur_state.texture_units[0]; + SCOPE_EXIT({ + cur_state.texture_units[0] = old_tex; + cur_state.Apply(); + }); + cur_state.texture_units[0].texture = target_tex; + cur_state.texture_units[0].target = SurfaceTargetToGL(params.target); cur_state.Apply(); // Ensure no bad interactions with GL_UNPACK_ALIGNMENT @@ -610,136 +647,102 @@ void CachedSurface::UploadGLTexture(GLuint read_fb_handle, GLuint draw_fb_handle glActiveTexture(GL_TEXTURE0); if (tuple.compressed) { - glCompressedTexImage2D( - GL_TEXTURE_2D, 0, tuple.internal_format, static_cast<GLsizei>(params.width), - static_cast<GLsizei>(params.height), 0, static_cast<GLsizei>(params.size_in_bytes), - &gl_buffer[buffer_offset]); + switch (params.target) { + case SurfaceParams::SurfaceTarget::Texture2D: + glCompressedTexImage2D( + SurfaceTargetToGL(params.target), 0, tuple.internal_format, + static_cast<GLsizei>(params.width), static_cast<GLsizei>(params.height), 0, + static_cast<GLsizei>(params.size_in_bytes), &gl_buffer[buffer_offset]); + break; + case SurfaceParams::SurfaceTarget::Texture3D: + case SurfaceParams::SurfaceTarget::Texture2DArray: + glCompressedTexImage3D( + SurfaceTargetToGL(params.target), 0, tuple.internal_format, + static_cast<GLsizei>(params.width), static_cast<GLsizei>(params.height), + static_cast<GLsizei>(params.depth), 0, static_cast<GLsizei>(params.size_in_bytes), + &gl_buffer[buffer_offset]); + break; + default: + LOG_CRITICAL(Render_OpenGL, "Unimplemented surface target={}", + static_cast<u32>(params.target)); + UNREACHABLE(); + glCompressedTexImage2D( + GL_TEXTURE_2D, 0, tuple.internal_format, static_cast<GLsizei>(params.width), + static_cast<GLsizei>(params.height), 0, static_cast<GLsizei>(params.size_in_bytes), + &gl_buffer[buffer_offset]); + } } else { - glTexSubImage2D(GL_TEXTURE_2D, 0, x0, y0, static_cast<GLsizei>(rect.GetWidth()), - static_cast<GLsizei>(rect.GetHeight()), tuple.format, tuple.type, - &gl_buffer[buffer_offset]); - } - - glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); - - cur_state.texture_units[0].texture_2d = old_tex; - cur_state.Apply(); -} - -MICROPROFILE_DEFINE(OpenGL_TextureDL, "OpenGL", "Texture Download", MP_RGB(128, 192, 64)); -void CachedSurface::DownloadGLTexture(GLuint read_fb_handle, GLuint draw_fb_handle) { - if (params.type == SurfaceType::Fill) - return; - - MICROPROFILE_SCOPE(OpenGL_TextureDL); - - gl_buffer.resize(params.width * params.height * GetGLBytesPerPixel(params.pixel_format)); - - OpenGLState state = OpenGLState::GetCurState(); - OpenGLState prev_state = state; - SCOPE_EXIT({ prev_state.Apply(); }); - - const FormatTuple& tuple = GetFormatTuple(params.pixel_format, params.component_type); - - // Ensure no bad interactions with GL_PACK_ALIGNMENT - ASSERT(params.width * GetGLBytesPerPixel(params.pixel_format) % 4 == 0); - glPixelStorei(GL_PACK_ROW_LENGTH, static_cast<GLint>(params.width)); - - const auto& rect{params.GetRect()}; - size_t buffer_offset = - (rect.bottom * params.width + rect.left) * GetGLBytesPerPixel(params.pixel_format); - - state.UnbindTexture(texture.handle); - state.draw.read_framebuffer = read_fb_handle; - state.Apply(); - if (params.type == SurfaceType::ColorTexture) { - glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, - texture.handle, 0); - glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, 0, - 0); - } else if (params.type == SurfaceType::Depth) { - glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0); - glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, - texture.handle, 0); - glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_TEXTURE_2D, 0, 0); - } else { - glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0); - glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, - texture.handle, 0); + switch (params.target) { + case SurfaceParams::SurfaceTarget::Texture1D: + glTexSubImage1D(SurfaceTargetToGL(params.target), 0, x0, + static_cast<GLsizei>(rect.GetWidth()), tuple.format, tuple.type, + &gl_buffer[buffer_offset]); + break; + case SurfaceParams::SurfaceTarget::Texture2D: + glTexSubImage2D(SurfaceTargetToGL(params.target), 0, x0, y0, + static_cast<GLsizei>(rect.GetWidth()), + static_cast<GLsizei>(rect.GetHeight()), tuple.format, tuple.type, + &gl_buffer[buffer_offset]); + break; + case SurfaceParams::SurfaceTarget::Texture3D: + case SurfaceParams::SurfaceTarget::Texture2DArray: + glTexSubImage3D(SurfaceTargetToGL(params.target), 0, x0, y0, 0, + static_cast<GLsizei>(rect.GetWidth()), + static_cast<GLsizei>(rect.GetHeight()), params.depth, tuple.format, + tuple.type, &gl_buffer[buffer_offset]); + break; + default: + LOG_CRITICAL(Render_OpenGL, "Unimplemented surface target={}", + static_cast<u32>(params.target)); + UNREACHABLE(); + glTexSubImage2D(GL_TEXTURE_2D, 0, x0, y0, static_cast<GLsizei>(rect.GetWidth()), + static_cast<GLsizei>(rect.GetHeight()), tuple.format, tuple.type, + &gl_buffer[buffer_offset]); + } } - glReadPixels(static_cast<GLint>(rect.left), static_cast<GLint>(rect.bottom), - static_cast<GLsizei>(rect.GetWidth()), static_cast<GLsizei>(rect.GetHeight()), - tuple.format, tuple.type, &gl_buffer[buffer_offset]); - glPixelStorei(GL_PACK_ROW_LENGTH, 0); + glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); } RasterizerCacheOpenGL::RasterizerCacheOpenGL() { read_framebuffer.Create(); draw_framebuffer.Create(); + copy_pbo.Create(); } Surface RasterizerCacheOpenGL::GetTextureSurface(const Tegra::Texture::FullTextureInfo& config) { return GetSurface(SurfaceParams::CreateForTexture(config)); } -SurfaceSurfaceRect_Tuple RasterizerCacheOpenGL::GetFramebufferSurfaces(bool using_color_fb, - bool using_depth_fb, - bool preserve_contents) { - const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs; +Surface RasterizerCacheOpenGL::GetDepthBufferSurface(bool preserve_contents) { + const auto& regs{Core::System::GetInstance().GPU().Maxwell3D().regs}; + if (!regs.zeta.Address() || !regs.zeta_enable) { + return {}; + } - // TODO(bunnei): This is hard corded to use just the first render buffer - LOG_TRACE(Render_OpenGL, "hard-coded for render target 0!"); + SurfaceParams depth_params{SurfaceParams::CreateForDepthBuffer( + regs.zeta_width, regs.zeta_height, regs.zeta.Address(), regs.zeta.format)}; - // get color and depth surfaces - SurfaceParams color_params{}; - SurfaceParams depth_params{}; + return GetSurface(depth_params, preserve_contents); +} - if (using_color_fb) { - color_params = SurfaceParams::CreateForFramebuffer(regs.rt[0]); - } +Surface RasterizerCacheOpenGL::GetColorBufferSurface(size_t index, bool preserve_contents) { + const auto& regs{Core::System::GetInstance().GPU().Maxwell3D().regs}; - if (using_depth_fb) { - depth_params = SurfaceParams::CreateForDepthBuffer(regs.zeta_width, regs.zeta_height, - regs.zeta.Address(), regs.zeta.format); - } + ASSERT(index < Tegra::Engines::Maxwell3D::Regs::NumRenderTargets); - MathUtil::Rectangle<u32> color_rect{}; - Surface color_surface; - if (using_color_fb) { - color_surface = GetSurface(color_params, preserve_contents); - if (color_surface) { - color_rect = color_surface->GetSurfaceParams().GetRect(); - } + if (index >= regs.rt_control.count) { + return {}; } - MathUtil::Rectangle<u32> depth_rect{}; - Surface depth_surface; - if (using_depth_fb) { - depth_surface = GetSurface(depth_params, preserve_contents); - if (depth_surface) { - depth_rect = depth_surface->GetSurfaceParams().GetRect(); - } + if (regs.rt[index].Address() == 0 || regs.rt[index].format == Tegra::RenderTargetFormat::NONE) { + return {}; } - MathUtil::Rectangle<u32> fb_rect{}; - if (color_surface && depth_surface) { - fb_rect = color_rect; - // Color and Depth surfaces must have the same dimensions and offsets - if (color_rect.bottom != depth_rect.bottom || color_rect.top != depth_rect.top || - color_rect.left != depth_rect.left || color_rect.right != depth_rect.right) { - color_surface = GetSurface(color_params); - depth_surface = GetSurface(depth_params); - fb_rect = color_surface->GetSurfaceParams().GetRect(); - } - } else if (color_surface) { - fb_rect = color_rect; - } else if (depth_surface) { - fb_rect = depth_rect; - } + const SurfaceParams color_params{SurfaceParams::CreateForFramebuffer(index)}; - return std::make_tuple(color_surface, depth_surface, fb_rect); + return GetSurface(color_params, preserve_contents); } void RasterizerCacheOpenGL::LoadSurface(const Surface& surface) { @@ -748,7 +751,6 @@ void RasterizerCacheOpenGL::LoadSurface(const Surface& surface) { } void RasterizerCacheOpenGL::FlushSurface(const Surface& surface) { - surface->DownloadGLTexture(read_framebuffer.handle, draw_framebuffer.handle); surface->FlushGLBuffer(); } @@ -806,27 +808,26 @@ Surface RasterizerCacheOpenGL::RecreateSurface(const Surface& surface, // Get a new surface with the new parameters, and blit the previous surface to it Surface new_surface{GetUncachedSurface(new_params)}; - // If format is unchanged, we can do a faster blit without reinterpreting pixel data - if (params.pixel_format == new_params.pixel_format) { + if (params.pixel_format == new_params.pixel_format || + !Settings::values.use_accurate_framebuffers) { + // If the format is the same, just do a framebuffer blit. This is significantly faster than + // using PBOs. The is also likely less accurate, as textures will be converted rather than + // reinterpreted. + BlitTextures(surface->Texture().handle, params.GetRect(), new_surface->Texture().handle, - new_surface->GetSurfaceParams().GetRect(), params.type, - read_framebuffer.handle, draw_framebuffer.handle); - return new_surface; - } + params.GetRect(), params.type, read_framebuffer.handle, + draw_framebuffer.handle); + } else { + // When use_accurate_framebuffers setting is enabled, perform a more accurate surface copy, + // where pixels are reinterpreted as a new format (without conversion). This code path uses + // OpenGL PBOs and is quite slow. - // When using accurate framebuffers, always copy old data to new surface, regardless of format - if (Settings::values.use_accurate_framebuffers) { auto source_format = GetFormatTuple(params.pixel_format, params.component_type); auto dest_format = GetFormatTuple(new_params.pixel_format, new_params.component_type); size_t buffer_size = std::max(params.SizeInBytes(), new_params.SizeInBytes()); - // Use a Pixel Buffer Object to download the previous texture and then upload it to the new - // one using the new format. - OGLBuffer pbo; - pbo.Create(); - - glBindBuffer(GL_PIXEL_PACK_BUFFER, pbo.handle); + glBindBuffer(GL_PIXEL_PACK_BUFFER, copy_pbo.handle); glBufferData(GL_PIXEL_PACK_BUFFER, buffer_size, nullptr, GL_STREAM_DRAW_ARB); if (source_format.compressed) { glGetCompressedTextureImage(surface->Texture().handle, 0, @@ -845,8 +846,8 @@ Surface RasterizerCacheOpenGL::RecreateSurface(const Surface& surface, // of the data in this case. Games like Super Mario Odyssey seem to hit this case // when drawing, it re-uses the memory of a previous texture as a bigger framebuffer // but it doesn't clear it beforehand, the texture is already full of zeros. - LOG_CRITICAL(HW_GPU, "Trying to upload extra texture data from the CPU during " - "reinterpretation but the texture is tiled."); + LOG_DEBUG(HW_GPU, "Trying to upload extra texture data from the CPU during " + "reinterpretation but the texture is tiled."); } size_t remaining_size = new_params.SizeInBytes() - params.SizeInBytes(); std::vector<u8> data(remaining_size); @@ -859,21 +860,38 @@ Surface RasterizerCacheOpenGL::RecreateSurface(const Surface& surface, const auto& dest_rect{new_params.GetRect()}; - glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pbo.handle); + glBindBuffer(GL_PIXEL_UNPACK_BUFFER, copy_pbo.handle); if (dest_format.compressed) { - glCompressedTexSubImage2D( - GL_TEXTURE_2D, 0, 0, 0, static_cast<GLsizei>(dest_rect.GetWidth()), - static_cast<GLsizei>(dest_rect.GetHeight()), dest_format.format, - static_cast<GLsizei>(new_params.SizeInBytes()), nullptr); + LOG_CRITICAL(HW_GPU, "Compressed copy is unimplemented!"); + UNREACHABLE(); } else { - glTextureSubImage2D(new_surface->Texture().handle, 0, 0, 0, - static_cast<GLsizei>(dest_rect.GetWidth()), - static_cast<GLsizei>(dest_rect.GetHeight()), dest_format.format, - dest_format.type, nullptr); + switch (new_params.target) { + case SurfaceParams::SurfaceTarget::Texture1D: + glTextureSubImage1D(new_surface->Texture().handle, 0, 0, + static_cast<GLsizei>(dest_rect.GetWidth()), dest_format.format, + dest_format.type, nullptr); + break; + case SurfaceParams::SurfaceTarget::Texture2D: + glTextureSubImage2D(new_surface->Texture().handle, 0, 0, 0, + static_cast<GLsizei>(dest_rect.GetWidth()), + static_cast<GLsizei>(dest_rect.GetHeight()), dest_format.format, + dest_format.type, nullptr); + break; + case SurfaceParams::SurfaceTarget::Texture3D: + case SurfaceParams::SurfaceTarget::Texture2DArray: + glTextureSubImage3D(new_surface->Texture().handle, 0, 0, 0, 0, + static_cast<GLsizei>(dest_rect.GetWidth()), + static_cast<GLsizei>(dest_rect.GetHeight()), + static_cast<GLsizei>(new_params.depth), dest_format.format, + dest_format.type, nullptr); + break; + default: + LOG_CRITICAL(Render_OpenGL, "Unimplemented surface target={}", + static_cast<u32>(params.target)); + UNREACHABLE(); + } } glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0); - - pbo.Release(); } return new_surface; diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.h b/src/video_core/renderer_opengl/gl_rasterizer_cache.h index aad75f200..57ea8593b 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer_cache.h +++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.h @@ -109,6 +109,33 @@ struct SurfaceParams { Invalid = 4, }; + enum class SurfaceTarget { + Texture1D, + Texture2D, + Texture3D, + Texture1DArray, + Texture2DArray, + TextureCubemap, + }; + + static SurfaceTarget SurfaceTargetFromTextureType(Tegra::Texture::TextureType texture_type) { + switch (texture_type) { + case Tegra::Texture::TextureType::Texture1D: + return SurfaceTarget::Texture1D; + case Tegra::Texture::TextureType::Texture2D: + case Tegra::Texture::TextureType::Texture2DNoMipmap: + return SurfaceTarget::Texture2D; + case Tegra::Texture::TextureType::Texture1DArray: + return SurfaceTarget::Texture1DArray; + case Tegra::Texture::TextureType::Texture2DArray: + return SurfaceTarget::Texture2DArray; + default: + LOG_CRITICAL(HW_GPU, "Unimplemented texture_type={}", static_cast<u32>(texture_type)); + UNREACHABLE(); + return SurfaceTarget::Texture2D; + } + } + /** * Gets the compression factor for the specified PixelFormat. This applies to just the * "compressed width" and "compressed height", not the overall compression factor of a @@ -270,6 +297,7 @@ struct SurfaceParams { return PixelFormat::ABGR8S; case Tegra::RenderTargetFormat::RGBA8_UINT: return PixelFormat::ABGR8UI; + case Tegra::RenderTargetFormat::BGRA8_SRGB: case Tegra::RenderTargetFormat::BGRA8_UNORM: return PixelFormat::BGRA8; case Tegra::RenderTargetFormat::RGB10_A2_UNORM: @@ -542,6 +570,7 @@ struct SurfaceParams { case Tegra::RenderTargetFormat::RGBA8_UNORM: case Tegra::RenderTargetFormat::RGBA8_SRGB: case Tegra::RenderTargetFormat::BGRA8_UNORM: + case Tegra::RenderTargetFormat::BGRA8_SRGB: case Tegra::RenderTargetFormat::RGB10_A2_UNORM: case Tegra::RenderTargetFormat::R8_UNORM: case Tegra::RenderTargetFormat::RG16_UNORM: @@ -635,15 +664,14 @@ struct SurfaceParams { ASSERT(width % compression_factor == 0); ASSERT(height % compression_factor == 0); return (width / compression_factor) * (height / compression_factor) * - GetFormatBpp(pixel_format) / CHAR_BIT; + GetFormatBpp(pixel_format) * depth / CHAR_BIT; } /// Creates SurfaceParams from a texture configuration static SurfaceParams CreateForTexture(const Tegra::Texture::FullTextureInfo& config); /// Creates SurfaceParams from a framebuffer configuration - static SurfaceParams CreateForFramebuffer( - const Tegra::Engines::Maxwell3D::Regs::RenderTargetConfig& config); + static SurfaceParams CreateForFramebuffer(size_t index); /// Creates SurfaceParams for a depth buffer configuration static SurfaceParams CreateForDepthBuffer(u32 zeta_width, u32 zeta_height, @@ -652,8 +680,8 @@ struct SurfaceParams { /// Checks if surfaces are compatible for caching bool IsCompatibleSurface(const SurfaceParams& other) const { - return std::tie(pixel_format, type, cache_width, cache_height) == - std::tie(other.pixel_format, other.type, other.cache_width, other.cache_height); + return std::tie(pixel_format, type, width, height) == + std::tie(other.pixel_format, other.type, other.width, other.height); } VAddr addr; @@ -664,12 +692,10 @@ struct SurfaceParams { SurfaceType type; u32 width; u32 height; + u32 depth; u32 unaligned_height; size_t size_in_bytes; - - // Parameters used for caching only - u32 cache_width; - u32 cache_height; + SurfaceTarget target; }; }; // namespace OpenGL @@ -709,6 +735,10 @@ public: return texture; } + GLenum Target() const { + return gl_target; + } + static constexpr unsigned int GetGLBytesPerPixel(SurfaceParams::PixelFormat format) { if (format == SurfaceParams::PixelFormat::Invalid) return 0; @@ -724,14 +754,14 @@ public: void LoadGLBuffer(); void FlushGLBuffer(); - // Upload/Download data in gl_buffer in/to this surface's texture + // Upload data in gl_buffer to this surface's texture void UploadGLTexture(GLuint read_fb_handle, GLuint draw_fb_handle); - void DownloadGLTexture(GLuint read_fb_handle, GLuint draw_fb_handle); private: OGLTexture texture; std::vector<u8> gl_buffer; SurfaceParams params; + GLenum gl_target; }; class RasterizerCacheOpenGL final : public RasterizerCache<Surface> { @@ -741,9 +771,11 @@ public: /// Get a surface based on the texture configuration Surface GetTextureSurface(const Tegra::Texture::FullTextureInfo& config); - /// Get the color and depth surfaces based on the framebuffer configuration - SurfaceSurfaceRect_Tuple GetFramebufferSurfaces(bool using_color_fb, bool using_depth_fb, - bool preserve_contents); + /// Get the depth surface based on the framebuffer configuration + Surface GetDepthBufferSurface(bool preserve_contents); + + /// Get the color surface based on the framebuffer configuration and the specified render target + Surface GetColorBufferSurface(size_t index, bool preserve_contents); /// Flushes the surface to Switch memory void FlushSurface(const Surface& surface); @@ -774,6 +806,10 @@ private: OGLFramebuffer read_framebuffer; OGLFramebuffer draw_framebuffer; + + /// Use a Pixel Buffer Object to download the previous texture and then upload it to the new one + /// using the new format. + OGLBuffer copy_pbo; }; } // namespace OpenGL diff --git a/src/video_core/renderer_opengl/gl_shader_cache.cpp b/src/video_core/renderer_opengl/gl_shader_cache.cpp index 7e4b85ac3..61080f5cc 100644 --- a/src/video_core/renderer_opengl/gl_shader_cache.cpp +++ b/src/video_core/renderer_opengl/gl_shader_cache.cpp @@ -13,8 +13,8 @@ namespace OpenGL { /// Gets the address for the specified shader stage program static VAddr GetShaderAddress(Maxwell::ShaderProgram program) { - auto& gpu = Core::System::GetInstance().GPU().Maxwell3D(); - auto& shader_config = gpu.regs.shader_config[static_cast<size_t>(program)]; + const auto& gpu = Core::System::GetInstance().GPU().Maxwell3D(); + const auto& shader_config = gpu.regs.shader_config[static_cast<size_t>(program)]; return *gpu.memory_manager.GpuToCpuAddress(gpu.regs.code_address.CodeAddress() + shader_config.offset); } @@ -86,7 +86,7 @@ CachedShader::CachedShader(VAddr addr, Maxwell::ShaderProgram program_type) } GLuint CachedShader::GetProgramResourceIndex(const GLShader::ConstBufferEntry& buffer) { - auto search{resource_cache.find(buffer.GetHash())}; + const auto search{resource_cache.find(buffer.GetHash())}; if (search == resource_cache.end()) { const GLuint index{ glGetProgramResourceIndex(program.handle, GL_UNIFORM_BLOCK, buffer.GetName().c_str())}; @@ -98,7 +98,7 @@ GLuint CachedShader::GetProgramResourceIndex(const GLShader::ConstBufferEntry& b } GLint CachedShader::GetUniformLocation(const GLShader::SamplerEntry& sampler) { - auto search{uniform_cache.find(sampler.GetHash())}; + const auto search{uniform_cache.find(sampler.GetHash())}; if (search == uniform_cache.end()) { const GLint index{glGetUniformLocation(program.handle, sampler.GetName().c_str())}; uniform_cache[sampler.GetHash()] = index; diff --git a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp index 841647ebe..2d56370c7 100644 --- a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp +++ b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp @@ -113,7 +113,7 @@ private: /// Scans a range of code for labels and determines the exit method. ExitMethod Scan(u32 begin, u32 end, std::set<u32>& labels) { - auto [iter, inserted] = + const auto [iter, inserted] = exit_method_map.emplace(std::make_pair(begin, end), ExitMethod::Undetermined); ExitMethod& exit_method = iter->second; if (!inserted) @@ -131,22 +131,22 @@ private: if (instr.pred.pred_index == static_cast<u64>(Pred::UnusedIndex)) { return exit_method = ExitMethod::AlwaysEnd; } else { - ExitMethod not_met = Scan(offset + 1, end, labels); + const ExitMethod not_met = Scan(offset + 1, end, labels); return exit_method = ParallelExit(ExitMethod::AlwaysEnd, not_met); } } case OpCode::Id::BRA: { - u32 target = offset + instr.bra.GetBranchTarget(); + const u32 target = offset + instr.bra.GetBranchTarget(); labels.insert(target); - ExitMethod no_jmp = Scan(offset + 1, end, labels); - ExitMethod jmp = Scan(target, end, labels); + const ExitMethod no_jmp = Scan(offset + 1, end, labels); + const ExitMethod jmp = Scan(target, end, labels); return exit_method = ParallelExit(no_jmp, jmp); } case OpCode::Id::SSY: { // The SSY instruction uses a similar encoding as the BRA instruction. ASSERT_MSG(instr.bra.constant_buffer == 0, "Constant buffer SSY is not supported"); - u32 target = offset + instr.bra.GetBranchTarget(); + const u32 target = offset + instr.bra.GetBranchTarget(); labels.insert(target); // Continue scanning for an exit method. break; @@ -346,8 +346,8 @@ public: */ void SetRegisterToInputAttibute(const Register& reg, u64 elem, Attribute::Index attribute, const Tegra::Shader::IpaMode& input_mode) { - std::string dest = GetRegisterAsFloat(reg); - std::string src = GetInputAttribute(attribute, input_mode) + GetSwizzle(elem); + const std::string dest = GetRegisterAsFloat(reg); + const std::string src = GetInputAttribute(attribute, input_mode) + GetSwizzle(elem); shader.AddLine(dest + " = " + src + ';'); } @@ -359,8 +359,8 @@ public: * @param reg The register to use as the source value. */ void SetOutputAttributeToRegister(Attribute::Index attribute, u64 elem, const Register& reg) { - std::string dest = GetOutputAttribute(attribute); - std::string src = GetRegisterAsFloat(reg); + const std::string dest = GetOutputAttribute(attribute); + const std::string src = GetRegisterAsFloat(reg); if (!dest.empty()) { // Can happen with unknown/unimplemented output attributes, in which case we ignore the @@ -393,9 +393,9 @@ public: GLSLRegister::Type type) { declr_const_buffers[cbuf_index].MarkAsUsedIndirect(cbuf_index, stage); - std::string final_offset = fmt::format("({} + {})", index_str, offset / 4); - std::string value = 'c' + std::to_string(cbuf_index) + '[' + final_offset + " / 4][" + - final_offset + " % 4]"; + const std::string final_offset = fmt::format("({} + {})", index_str, offset / 4); + const std::string value = 'c' + std::to_string(cbuf_index) + '[' + final_offset + " / 4][" + + final_offset + " % 4]"; if (type == GLSLRegister::Type::Float) { return value; @@ -443,13 +443,12 @@ public: } declarations.AddNewLine(); - // Append the sampler2D array for the used textures. - const size_t num_samplers = used_samplers.size(); - if (num_samplers > 0) { - declarations.AddLine("uniform sampler2D " + SamplerEntry::GetArrayName(stage) + '[' + - std::to_string(num_samplers) + "];"); - declarations.AddNewLine(); + const auto& samplers = GetSamplers(); + for (const auto& sampler : samplers) { + declarations.AddLine("uniform " + sampler.GetTypeString() + ' ' + sampler.GetName() + + ';'); } + declarations.AddNewLine(); } /// Returns a list of constant buffer declarations @@ -461,27 +460,29 @@ public: } /// Returns a list of samplers used in the shader - std::vector<SamplerEntry> GetSamplers() const { + const std::vector<SamplerEntry>& GetSamplers() const { return used_samplers; } /// Returns the GLSL sampler used for the input shader sampler, and creates a new one if /// necessary. - std::string AccessSampler(const Sampler& sampler) { - size_t offset = static_cast<size_t>(sampler.index.Value()); + std::string AccessSampler(const Sampler& sampler, Tegra::Shader::TextureType type, + bool is_array) { + const size_t offset = static_cast<size_t>(sampler.index.Value()); // If this sampler has already been used, return the existing mapping. - auto itr = + const auto itr = std::find_if(used_samplers.begin(), used_samplers.end(), [&](const SamplerEntry& entry) { return entry.GetOffset() == offset; }); if (itr != used_samplers.end()) { + ASSERT(itr->GetType() == type && itr->IsArray() == is_array); return itr->GetName(); } // Otherwise create a new mapping for this sampler - size_t next_index = used_samplers.size(); - SamplerEntry entry{stage, offset, next_index}; + const size_t next_index = used_samplers.size(); + const SamplerEntry entry{stage, offset, next_index, type, is_array}; used_samplers.emplace_back(entry); return entry.GetName(); } @@ -698,7 +699,7 @@ private: }; bool IsColorComponentOutputEnabled(u32 render_target, u32 component) const { - u32 bit = render_target * 4 + component; + const u32 bit = render_target * 4 + component; return enabled_color_outputs & (1 << bit); } }; @@ -706,7 +707,7 @@ private: /// Gets the Subroutine object corresponding to the specified address. const Subroutine& GetSubroutine(u32 begin, u32 end) const { - auto iter = subroutines.find(Subroutine{begin, end, suffix}); + const auto iter = subroutines.find(Subroutine{begin, end, suffix}); ASSERT(iter != subroutines.end()); return *iter; } @@ -722,8 +723,8 @@ private: } /// Generates code representing a texture sampler. - std::string GetSampler(const Sampler& sampler) { - return regs.AccessSampler(sampler); + std::string GetSampler(const Sampler& sampler, Tegra::Shader::TextureType type, bool is_array) { + return regs.AccessSampler(sampler, type, is_array); } /** @@ -751,7 +752,7 @@ private: // Can't assign to the constant predicate. ASSERT(pred != static_cast<u64>(Pred::UnusedIndex)); - std::string variable = 'p' + std::to_string(pred) + '_' + suffix; + const std::string variable = 'p' + std::to_string(pred) + '_' + suffix; shader.AddLine(variable + " = " + value + ';'); declr_predicates.insert(std::move(variable)); } @@ -1022,7 +1023,7 @@ private: // TODO(Subv): Figure out how dual-source blending is configured in the Switch. for (u32 component = 0; component < 4; ++component) { if (header.IsColorComponentOutputEnabled(render_target, component)) { - shader.AddLine(fmt::format("color[{}][{}] = {};", render_target, component, + shader.AddLine(fmt::format("FragColor{}[{}] = {};", render_target, component, regs.GetRegisterAsFloat(current_reg))); ++current_reg; } @@ -1032,7 +1033,11 @@ private: if (header.writes_depth) { // The depth output is always 2 registers after the last color output, and current_reg // already contains one past the last color register. - shader.AddLine("gl_FragDepth = " + regs.GetRegisterAsFloat(current_reg + 1) + ';'); + + shader.AddLine( + "gl_FragDepth = " + + regs.GetRegisterAsFloat(static_cast<Tegra::Shader::Register>(current_reg) + 1) + + ';'); } } @@ -1434,7 +1439,7 @@ private: if (instr.alu_integer.negate_b) op_b = "-(" + op_b + ')'; - std::string shift = std::to_string(instr.alu_integer.shift_amount.Value()); + const std::string shift = std::to_string(instr.alu_integer.shift_amount.Value()); regs.SetRegisterToInteger(instr.gpr0, true, 0, "((" + op_a + " << " + shift + ") + " + op_b + ')', 1, 1); @@ -1452,7 +1457,7 @@ private: case OpCode::Id::SEL_C: case OpCode::Id::SEL_R: case OpCode::Id::SEL_IMM: { - std::string condition = + const std::string condition = GetPredicateCondition(instr.sel.pred, instr.sel.neg_pred != 0); regs.SetRegisterToInteger(instr.gpr0, true, 0, '(' + condition + ") ? " + op_a + " : " + op_b, 1, 1); @@ -1474,8 +1479,9 @@ private: case OpCode::Id::LOP3_C: case OpCode::Id::LOP3_R: case OpCode::Id::LOP3_IMM: { - std::string op_c = regs.GetRegisterAsInteger(instr.gpr39); + const std::string op_c = regs.GetRegisterAsInteger(instr.gpr39); std::string lut; + if (opcode->GetId() == OpCode::Id::LOP3_R) { lut = '(' + std::to_string(instr.alu.lop3.GetImmLut28()) + ')'; } else { @@ -1490,15 +1496,82 @@ private: case OpCode::Id::IMNMX_IMM: { ASSERT_MSG(instr.imnmx.exchange == Tegra::Shader::IMinMaxExchange::None, "Unimplemented"); - std::string condition = + const std::string condition = GetPredicateCondition(instr.imnmx.pred, instr.imnmx.negate_pred != 0); - std::string parameters = op_a + ',' + op_b; + const std::string parameters = op_a + ',' + op_b; regs.SetRegisterToInteger(instr.gpr0, instr.imnmx.is_signed, 0, '(' + condition + ") ? min(" + parameters + ") : max(" + parameters + ')', 1, 1); break; } + case OpCode::Id::LEA_R2: + case OpCode::Id::LEA_R1: + case OpCode::Id::LEA_IMM: + case OpCode::Id::LEA_RZ: + case OpCode::Id::LEA_HI: { + std::string op_a; + std::string op_b; + std::string op_c; + + switch (opcode->GetId()) { + case OpCode::Id::LEA_R2: { + op_a = regs.GetRegisterAsInteger(instr.gpr20); + op_b = regs.GetRegisterAsInteger(instr.gpr39); + op_c = std::to_string(instr.lea.r2.entry_a); + break; + } + + case OpCode::Id::LEA_R1: { + const bool neg = instr.lea.r1.neg != 0; + op_a = regs.GetRegisterAsInteger(instr.gpr8); + if (neg) + op_a = "-(" + op_a + ')'; + op_b = regs.GetRegisterAsInteger(instr.gpr20); + op_c = std::to_string(instr.lea.r1.entry_a); + break; + } + + case OpCode::Id::LEA_IMM: { + const bool neg = instr.lea.imm.neg != 0; + op_b = regs.GetRegisterAsInteger(instr.gpr8); + if (neg) + op_b = "-(" + op_b + ')'; + op_a = std::to_string(instr.lea.imm.entry_a); + op_c = std::to_string(instr.lea.imm.entry_b); + break; + } + + case OpCode::Id::LEA_RZ: { + const bool neg = instr.lea.rz.neg != 0; + op_b = regs.GetRegisterAsInteger(instr.gpr8); + if (neg) + op_b = "-(" + op_b + ')'; + op_a = regs.GetUniform(instr.lea.rz.cb_index, instr.lea.rz.cb_offset, + GLSLRegister::Type::Integer); + op_c = std::to_string(instr.lea.rz.entry_a); + + break; + } + + case OpCode::Id::LEA_HI: + default: { + op_b = regs.GetRegisterAsInteger(instr.gpr8); + op_a = std::to_string(instr.lea.imm.entry_a); + op_c = std::to_string(instr.lea.imm.entry_b); + LOG_CRITICAL(HW_GPU, "Unhandled LEA subinstruction: {}", opcode->GetName()); + UNREACHABLE(); + } + } + if (instr.lea.pred48 != static_cast<u64>(Pred::UnusedIndex)) { + LOG_ERROR(HW_GPU, "Unhandled LEA Predicate"); + UNREACHABLE(); + } + const std::string value = '(' + op_a + " + (" + op_b + "*(1 << " + op_c + ")))"; + regs.SetRegisterToInteger(instr.gpr0, true, 0, value, 1, 1); + + break; + } default: { LOG_CRITICAL(HW_GPU, "Unhandled ArithmeticInteger instruction: {}", opcode->GetName()); @@ -1509,7 +1582,7 @@ private: break; } case OpCode::Type::Ffma: { - std::string op_a = regs.GetRegisterAsFloat(instr.gpr8); + const std::string op_a = regs.GetRegisterAsFloat(instr.gpr8); std::string op_b = instr.ffma.negate_b ? "-" : ""; std::string op_c = instr.ffma.negate_c ? "-" : ""; @@ -1719,7 +1792,7 @@ private: shader.AddLine("uint index = (" + regs.GetRegisterAsInteger(instr.gpr8, 0, false) + " / 4) & (MAX_CONSTBUFFER_ELEMENTS - 1);"); - std::string op_a = + const std::string op_a = regs.GetUniformIndirect(instr.cbuf36.index, instr.cbuf36.offset + 0, "index", GLSLRegister::Type::Float); @@ -1729,7 +1802,7 @@ private: break; case Tegra::Shader::UniformType::Double: { - std::string op_b = + const std::string op_b = regs.GetUniformIndirect(instr.cbuf36.index, instr.cbuf36.offset + 4, "index", GLSLRegister::Type::Float); regs.SetRegisterToFloat(instr.gpr0, 0, op_a, 1, 1); @@ -1753,17 +1826,74 @@ private: break; } case OpCode::Id::TEX: { - const std::string op_a = regs.GetRegisterAsFloat(instr.gpr8); - const std::string op_b = regs.GetRegisterAsFloat(instr.gpr8.Value() + 1); - const std::string sampler = GetSampler(instr.sampler); - const std::string coord = "vec2 coords = vec2(" + op_a + ", " + op_b + ");"; + ASSERT_MSG(instr.tex.array == 0, "TEX arrays unimplemented"); + Tegra::Shader::TextureType texture_type{instr.tex.texture_type}; + std::string coord; + + switch (texture_type) { + case Tegra::Shader::TextureType::Texture1D: { + const std::string x = regs.GetRegisterAsFloat(instr.gpr8); + coord = "float coords = " + x + ';'; + break; + } + case Tegra::Shader::TextureType::Texture2D: { + const std::string x = regs.GetRegisterAsFloat(instr.gpr8); + const std::string y = regs.GetRegisterAsFloat(instr.gpr8.Value() + 1); + coord = "vec2 coords = vec2(" + x + ", " + y + ");"; + break; + } + default: + LOG_CRITICAL(HW_GPU, "Unhandled texture type {}", + static_cast<u32>(texture_type)); + UNREACHABLE(); + + // Fallback to interpreting as a 2D texture for now + const std::string x = regs.GetRegisterAsFloat(instr.gpr8); + const std::string y = regs.GetRegisterAsFloat(instr.gpr8.Value() + 1); + coord = "vec2 coords = vec2(" + x + ", " + y + ");"; + texture_type = Tegra::Shader::TextureType::Texture2D; + } + // TODO: make sure coordinates are always indexed to gpr8 and gpr20 is always bias + // or lod. + const std::string op_c = regs.GetRegisterAsFloat(instr.gpr20); + + const std::string sampler = GetSampler(instr.sampler, texture_type, false); // Add an extra scope and declare the texture coords inside to prevent // overwriting them in case they are used as outputs of the texs instruction. + shader.AddLine("{"); ++shader.scope; shader.AddLine(coord); - const std::string texture = "texture(" + sampler + ", coords)"; + std::string texture; + switch (instr.tex.process_mode) { + case Tegra::Shader::TextureProcessMode::None: { + texture = "texture(" + sampler + ", coords)"; + break; + } + case Tegra::Shader::TextureProcessMode::LZ: { + texture = "textureLod(" + sampler + ", coords, 0.0)"; + break; + } + case Tegra::Shader::TextureProcessMode::LB: + case Tegra::Shader::TextureProcessMode::LBA: { + // TODO: Figure if A suffix changes the equation at all. + texture = "texture(" + sampler + ", coords, " + op_c + ')'; + break; + } + case Tegra::Shader::TextureProcessMode::LL: + case Tegra::Shader::TextureProcessMode::LLA: { + // TODO: Figure if A suffix changes the equation at all. + texture = "textureLod(" + sampler + ", coords, " + op_c + ')'; + break; + } + default: { + texture = "texture(" + sampler + ", coords)"; + LOG_CRITICAL(HW_GPU, "Unhandled texture process mode {}", + static_cast<u32>(instr.tex.process_mode.Value())); + UNREACHABLE(); + } + } size_t dest_elem{}; for (size_t elem = 0; elem < 4; ++elem) { if (!instr.tex.IsComponentEnabled(elem)) { @@ -1778,20 +1908,65 @@ private: break; } case OpCode::Id::TEXS: { - const std::string op_a = regs.GetRegisterAsFloat(instr.gpr8); - const std::string op_b = regs.GetRegisterAsFloat(instr.gpr20); - const std::string sampler = GetSampler(instr.sampler); - const std::string coord = "vec2 coords = vec2(" + op_a + ", " + op_b + ");"; + std::string coord; + Tegra::Shader::TextureType texture_type{instr.texs.GetTextureType()}; + bool is_array{instr.texs.IsArrayTexture()}; + + switch (texture_type) { + case Tegra::Shader::TextureType::Texture2D: { + if (is_array) { + const std::string index = regs.GetRegisterAsInteger(instr.gpr8); + const std::string x = regs.GetRegisterAsFloat(instr.gpr8.Value() + 1); + const std::string y = regs.GetRegisterAsFloat(instr.gpr20); + coord = "vec3 coords = vec3(" + x + ", " + y + ", " + index + ");"; + } else { + const std::string x = regs.GetRegisterAsFloat(instr.gpr8); + const std::string y = regs.GetRegisterAsFloat(instr.gpr20); + coord = "vec2 coords = vec2(" + x + ", " + y + ");"; + } + break; + } + default: + LOG_CRITICAL(HW_GPU, "Unhandled texture type {}", + static_cast<u32>(texture_type)); + UNREACHABLE(); + // Fallback to interpreting as a 2D texture for now + const std::string x = regs.GetRegisterAsFloat(instr.gpr8); + const std::string y = regs.GetRegisterAsFloat(instr.gpr20); + coord = "vec2 coords = vec2(" + x + ", " + y + ");"; + texture_type = Tegra::Shader::TextureType::Texture2D; + is_array = false; + } + const std::string sampler = GetSampler(instr.sampler, texture_type, is_array); const std::string texture = "texture(" + sampler + ", coords)"; WriteTexsInstruction(instr, coord, texture); break; } case OpCode::Id::TLDS: { - const std::string op_a = regs.GetRegisterAsInteger(instr.gpr8); - const std::string op_b = regs.GetRegisterAsInteger(instr.gpr20); - const std::string sampler = GetSampler(instr.sampler); - const std::string coord = "ivec2 coords = ivec2(" + op_a + ", " + op_b + ");"; + ASSERT(instr.tlds.GetTextureType() == Tegra::Shader::TextureType::Texture2D); + ASSERT(instr.tlds.IsArrayTexture() == false); + std::string coord; + + switch (instr.tlds.GetTextureType()) { + case Tegra::Shader::TextureType::Texture2D: { + if (instr.tlds.IsArrayTexture()) { + LOG_CRITICAL(HW_GPU, "Unhandled 2d array texture"); + UNREACHABLE(); + } else { + const std::string x = regs.GetRegisterAsInteger(instr.gpr8); + const std::string y = regs.GetRegisterAsInteger(instr.gpr20); + coord = "ivec2 coords = ivec2(" + x + ", " + y + ");"; + } + break; + } + default: + LOG_CRITICAL(HW_GPU, "Unhandled texture type {}", + static_cast<u32>(instr.tlds.GetTextureType())); + UNREACHABLE(); + } + const std::string sampler = GetSampler(instr.sampler, instr.tlds.GetTextureType(), + instr.tlds.IsArrayTexture()); const std::string texture = "texelFetch(" + sampler + ", coords, 0)"; WriteTexsInstruction(instr, coord, texture); break; @@ -1799,12 +1974,12 @@ private: case OpCode::Id::TLD4: { ASSERT(instr.tld4.texture_type == Tegra::Shader::TextureType::Texture2D); ASSERT(instr.tld4.array == 0); - std::string coord{}; + std::string coord; switch (instr.tld4.texture_type) { case Tegra::Shader::TextureType::Texture2D: { - std::string x = regs.GetRegisterAsFloat(instr.gpr8); - std::string y = regs.GetRegisterAsFloat(instr.gpr8.Value() + 1); + const std::string x = regs.GetRegisterAsFloat(instr.gpr8); + const std::string y = regs.GetRegisterAsFloat(instr.gpr8.Value() + 1); coord = "vec2 coords = vec2(" + x + ", " + y + ");"; break; } @@ -1814,7 +1989,8 @@ private: UNREACHABLE(); } - const std::string sampler = GetSampler(instr.sampler); + const std::string sampler = + GetSampler(instr.sampler, instr.tld4.texture_type, false); // Add an extra scope and declare the texture coords inside to prevent // overwriting them in case they are used as outputs of the texs instruction. shader.AddLine("{"); @@ -1840,13 +2016,82 @@ private: const std::string op_a = regs.GetRegisterAsFloat(instr.gpr8); const std::string op_b = regs.GetRegisterAsFloat(instr.gpr20); // TODO(Subv): Figure out how the sampler type is encoded in the TLD4S instruction. - const std::string sampler = GetSampler(instr.sampler); + const std::string sampler = + GetSampler(instr.sampler, Tegra::Shader::TextureType::Texture2D, false); const std::string coord = "vec2 coords = vec2(" + op_a + ", " + op_b + ");"; const std::string texture = "textureGather(" + sampler + ", coords, " + std::to_string(instr.tld4s.component) + ')'; WriteTexsInstruction(instr, coord, texture); break; } + case OpCode::Id::TXQ: { + // TODO: the new commits on the texture refactor, change the way samplers work. + // Sadly, not all texture instructions specify the type of texture their sampler + // uses. This must be fixed at a later instance. + const std::string sampler = + GetSampler(instr.sampler, Tegra::Shader::TextureType::Texture2D, false); + switch (instr.txq.query_type) { + case Tegra::Shader::TextureQueryType::Dimension: { + const std::string texture = "textureQueryLevels(" + sampler + ')'; + regs.SetRegisterToInteger(instr.gpr0, true, 0, texture, 1, 1); + break; + } + default: { + LOG_CRITICAL(HW_GPU, "Unhandled texture query type: {}", + static_cast<u32>(instr.txq.query_type.Value())); + UNREACHABLE(); + } + } + break; + } + case OpCode::Id::TMML: { + const std::string op_a = regs.GetRegisterAsFloat(instr.gpr8); + const std::string op_b = regs.GetRegisterAsFloat(instr.gpr8.Value() + 1); + const bool is_array = instr.tmml.array != 0; + auto texture_type = instr.tmml.texture_type.Value(); + const std::string sampler = GetSampler(instr.sampler, texture_type, is_array); + + // TODO: add coordinates for different samplers once other texture types are + // implemented. + std::string coord; + switch (texture_type) { + case Tegra::Shader::TextureType::Texture1D: { + std::string x = regs.GetRegisterAsFloat(instr.gpr8); + coord = "float coords = " + x + ';'; + break; + } + case Tegra::Shader::TextureType::Texture2D: { + std::string x = regs.GetRegisterAsFloat(instr.gpr8); + std::string y = regs.GetRegisterAsFloat(instr.gpr8.Value() + 1); + coord = "vec2 coords = vec2(" + x + ", " + y + ");"; + break; + } + default: + LOG_CRITICAL(HW_GPU, "Unhandled texture type {}", + static_cast<u32>(texture_type)); + UNREACHABLE(); + + // Fallback to interpreting as a 2D texture for now + std::string x = regs.GetRegisterAsFloat(instr.gpr8); + std::string y = regs.GetRegisterAsFloat(instr.gpr8.Value() + 1); + coord = "vec2 coords = vec2(" + x + ", " + y + ");"; + texture_type = Tegra::Shader::TextureType::Texture2D; + } + // Add an extra scope and declare the texture coords inside to prevent + // overwriting them in case they are used as outputs of the texs instruction. + shader.AddLine('{'); + ++shader.scope; + shader.AddLine(coord); + const std::string texture = "textureQueryLod(" + sampler + ", coords)"; + const std::string tmp = "vec2 tmp = " + texture + "*vec2(256.0, 256.0);"; + shader.AddLine(tmp); + + regs.SetRegisterToInteger(instr.gpr0, true, 0, "int(tmp.y)", 1, 1); + regs.SetRegisterToInteger(instr.gpr0.Value() + 1, false, 0, "uint(tmp.x)", 1, 1); + --shader.scope; + shader.AddLine('}'); + break; + } default: { LOG_CRITICAL(HW_GPU, "Unhandled memory instruction: {}", opcode->GetName()); UNREACHABLE(); @@ -1886,12 +2131,12 @@ private: // We can't use the constant predicate as destination. ASSERT(instr.fsetp.pred3 != static_cast<u64>(Pred::UnusedIndex)); - std::string second_pred = + const std::string second_pred = GetPredicateCondition(instr.fsetp.pred39, instr.fsetp.neg_pred != 0); - std::string combiner = GetPredicateCombiner(instr.fsetp.op); + const std::string combiner = GetPredicateCombiner(instr.fsetp.op); - std::string predicate = GetPredicateComparison(instr.fsetp.cond, op_a, op_b); + const std::string predicate = GetPredicateComparison(instr.fsetp.cond, op_a, op_b); // Set the primary predicate to the result of Predicate OP SecondPredicate SetPredicate(instr.fsetp.pred3, '(' + predicate + ") " + combiner + " (" + second_pred + ')'); @@ -1905,7 +2150,8 @@ private: break; } case OpCode::Type::IntegerSetPredicate: { - std::string op_a = regs.GetRegisterAsInteger(instr.gpr8, 0, instr.isetp.is_signed); + const std::string op_a = + regs.GetRegisterAsInteger(instr.gpr8, 0, instr.isetp.is_signed); std::string op_b; if (instr.is_b_imm) { @@ -1922,12 +2168,12 @@ private: // We can't use the constant predicate as destination. ASSERT(instr.isetp.pred3 != static_cast<u64>(Pred::UnusedIndex)); - std::string second_pred = + const std::string second_pred = GetPredicateCondition(instr.isetp.pred39, instr.isetp.neg_pred != 0); - std::string combiner = GetPredicateCombiner(instr.isetp.op); + const std::string combiner = GetPredicateCombiner(instr.isetp.op); - std::string predicate = GetPredicateComparison(instr.isetp.cond, op_a, op_b); + const std::string predicate = GetPredicateComparison(instr.isetp.cond, op_a, op_b); // Set the primary predicate to the result of Predicate OP SecondPredicate SetPredicate(instr.isetp.pred3, '(' + predicate + ") " + combiner + " (" + second_pred + ')'); @@ -1940,21 +2186,45 @@ private: } break; } + case OpCode::Type::PredicateSetRegister: { + const std::string op_a = + GetPredicateCondition(instr.pset.pred12, instr.pset.neg_pred12 != 0); + const std::string op_b = + GetPredicateCondition(instr.pset.pred29, instr.pset.neg_pred29 != 0); + + const std::string second_pred = + GetPredicateCondition(instr.pset.pred39, instr.pset.neg_pred39 != 0); + + const std::string combiner = GetPredicateCombiner(instr.pset.op); + + const std::string predicate = + '(' + op_a + ") " + GetPredicateCombiner(instr.pset.cond) + " (" + op_b + ')'; + const std::string result = '(' + predicate + ") " + combiner + " (" + second_pred + ')'; + if (instr.pset.bf == 0) { + const std::string value = '(' + result + ") ? 0xFFFFFFFF : 0"; + regs.SetRegisterToInteger(instr.gpr0, false, 0, value, 1, 1); + } else { + const std::string value = '(' + result + ") ? 1.0 : 0.0"; + regs.SetRegisterToFloat(instr.gpr0, 0, value, 1, 1); + } + + break; + } case OpCode::Type::PredicateSetPredicate: { - std::string op_a = + const std::string op_a = GetPredicateCondition(instr.psetp.pred12, instr.psetp.neg_pred12 != 0); - std::string op_b = + const std::string op_b = GetPredicateCondition(instr.psetp.pred29, instr.psetp.neg_pred29 != 0); // We can't use the constant predicate as destination. ASSERT(instr.psetp.pred3 != static_cast<u64>(Pred::UnusedIndex)); - std::string second_pred = + const std::string second_pred = GetPredicateCondition(instr.psetp.pred39, instr.psetp.neg_pred39 != 0); - std::string combiner = GetPredicateCombiner(instr.psetp.op); + const std::string combiner = GetPredicateCombiner(instr.psetp.op); - std::string predicate = + const std::string predicate = '(' + op_a + ") " + GetPredicateCombiner(instr.psetp.cond) + " (" + op_b + ')'; // Set the primary predicate to the result of Predicate OP SecondPredicate @@ -1980,7 +2250,7 @@ private: std::string op_b = instr.fset.neg_b ? "-" : ""; if (instr.is_b_imm) { - std::string imm = GetImmediate19(instr); + const std::string imm = GetImmediate19(instr); if (instr.fset.neg_imm) op_b += "(-" + imm + ')'; else @@ -2000,13 +2270,14 @@ private: // The fset instruction sets a register to 1.0 or -1 (depending on the bf bit) if the // condition is true, and to 0 otherwise. - std::string second_pred = + const std::string second_pred = GetPredicateCondition(instr.fset.pred39, instr.fset.neg_pred != 0); - std::string combiner = GetPredicateCombiner(instr.fset.op); + const std::string combiner = GetPredicateCombiner(instr.fset.op); - std::string predicate = "((" + GetPredicateComparison(instr.fset.cond, op_a, op_b) + - ") " + combiner + " (" + second_pred + "))"; + const std::string predicate = "((" + + GetPredicateComparison(instr.fset.cond, op_a, op_b) + + ") " + combiner + " (" + second_pred + "))"; if (instr.fset.bf) { regs.SetRegisterToFloat(instr.gpr0, 0, predicate + " ? 1.0 : 0.0", 1, 1); @@ -2017,7 +2288,7 @@ private: break; } case OpCode::Type::IntegerSet: { - std::string op_a = regs.GetRegisterAsInteger(instr.gpr8, 0, instr.iset.is_signed); + const std::string op_a = regs.GetRegisterAsInteger(instr.gpr8, 0, instr.iset.is_signed); std::string op_b; @@ -2034,13 +2305,14 @@ private: // The iset instruction sets a register to 1.0 or -1 (depending on the bf bit) if the // condition is true, and to 0 otherwise. - std::string second_pred = + const std::string second_pred = GetPredicateCondition(instr.iset.pred39, instr.iset.neg_pred != 0); - std::string combiner = GetPredicateCombiner(instr.iset.op); + const std::string combiner = GetPredicateCombiner(instr.iset.op); - std::string predicate = "((" + GetPredicateComparison(instr.iset.cond, op_a, op_b) + - ") " + combiner + " (" + second_pred + "))"; + const std::string predicate = "((" + + GetPredicateComparison(instr.iset.cond, op_a, op_b) + + ") " + combiner + " (" + second_pred + "))"; if (instr.iset.bf) { regs.SetRegisterToFloat(instr.gpr0, 0, predicate + " ? 1.0 : 0.0", 1, 1); @@ -2190,7 +2462,7 @@ private: case OpCode::Id::BRA: { ASSERT_MSG(instr.bra.constant_buffer == 0, "BRA with constant buffers are not implemented"); - u32 target = offset + instr.bra.GetBranchTarget(); + const u32 target = offset + instr.bra.GetBranchTarget(); shader.AddLine("{ jmp_to = " + std::to_string(target) + "u; break; }"); break; } @@ -2214,7 +2486,7 @@ private: // has a similar structure to the BRA opcode. ASSERT_MSG(instr.bra.constant_buffer == 0, "Constant buffer SSY is not supported"); - u32 target = offset + instr.bra.GetBranchTarget(); + const u32 target = offset + instr.bra.GetBranchTarget(); EmitPushToSSYStack(target); break; } @@ -2308,10 +2580,10 @@ private: shader.AddLine("case " + std::to_string(label) + "u: {"); ++shader.scope; - auto next_it = labels.lower_bound(label + 1); - u32 next_label = next_it == labels.end() ? subroutine.end : *next_it; + const auto next_it = labels.lower_bound(label + 1); + const u32 next_label = next_it == labels.end() ? subroutine.end : *next_it; - u32 compile_end = CompileRange(label, next_label); + const u32 compile_end = CompileRange(label, next_label); if (compile_end > next_label && compile_end != PROGRAM_END) { // This happens only when there is a label inside a IF/LOOP block shader.AddLine(" jmp_to = " + std::to_string(compile_end) + "u; break; }"); @@ -2374,7 +2646,8 @@ boost::optional<ProgramResult> DecompileProgram(const ProgramCode& program_code, Maxwell3D::Regs::ShaderStage stage, const std::string& suffix) { try { - auto subroutines = ControlFlowAnalyzer(program_code, main_offset, suffix).GetSubroutines(); + const auto subroutines = + ControlFlowAnalyzer(program_code, main_offset, suffix).GetSubroutines(); GLSLGenerator generator(subroutines, program_code, main_offset, stage, suffix); return ProgramResult{generator.GetShaderCode(), generator.GetEntries()}; } catch (const DecompileFail& exception) { diff --git a/src/video_core/renderer_opengl/gl_shader_gen.cpp b/src/video_core/renderer_opengl/gl_shader_gen.cpp index e1b1a9d73..b0466c18f 100644 --- a/src/video_core/renderer_opengl/gl_shader_gen.cpp +++ b/src/video_core/renderer_opengl/gl_shader_gen.cpp @@ -88,7 +88,14 @@ ProgramResult GenerateFragmentShader(const ShaderSetup& setup) { .get_value_or({}); out += R"( in vec4 position; -layout(location = 0) out vec4 color[8]; +layout(location = 0) out vec4 FragColor0; +layout(location = 1) out vec4 FragColor1; +layout(location = 2) out vec4 FragColor2; +layout(location = 3) out vec4 FragColor3; +layout(location = 4) out vec4 FragColor4; +layout(location = 5) out vec4 FragColor5; +layout(location = 6) out vec4 FragColor6; +layout(location = 7) out vec4 FragColor7; layout (std140) uniform fs_config { vec4 viewport_flip; diff --git a/src/video_core/renderer_opengl/gl_shader_gen.h b/src/video_core/renderer_opengl/gl_shader_gen.h index cbb2090ea..a43e2997b 100644 --- a/src/video_core/renderer_opengl/gl_shader_gen.h +++ b/src/video_core/renderer_opengl/gl_shader_gen.h @@ -9,6 +9,7 @@ #include <vector> #include "common/common_types.h" +#include "video_core/engines/shader_bytecode.h" namespace OpenGL::GLShader { @@ -73,8 +74,9 @@ class SamplerEntry { using Maxwell = Tegra::Engines::Maxwell3D::Regs; public: - SamplerEntry(Maxwell::ShaderStage stage, size_t offset, size_t index) - : offset(offset), stage(stage), sampler_index(index) {} + SamplerEntry(Maxwell::ShaderStage stage, size_t offset, size_t index, + Tegra::Shader::TextureType type, bool is_array) + : offset(offset), stage(stage), sampler_index(index), type(type), is_array(is_array) {} size_t GetOffset() const { return offset; @@ -89,8 +91,41 @@ public: } std::string GetName() const { - return std::string(TextureSamplerNames[static_cast<size_t>(stage)]) + '[' + - std::to_string(sampler_index) + ']'; + return std::string(TextureSamplerNames[static_cast<size_t>(stage)]) + '_' + + std::to_string(sampler_index); + } + + std::string GetTypeString() const { + using Tegra::Shader::TextureType; + std::string glsl_type; + + switch (type) { + case TextureType::Texture1D: + glsl_type = "sampler1D"; + break; + case TextureType::Texture2D: + glsl_type = "sampler2D"; + break; + case TextureType::Texture3D: + glsl_type = "sampler3D"; + break; + case TextureType::TextureCube: + glsl_type = "samplerCube"; + break; + default: + UNIMPLEMENTED(); + } + if (is_array) + glsl_type += "Array"; + return glsl_type; + } + + Tegra::Shader::TextureType GetType() const { + return type; + } + + bool IsArray() const { + return is_array; } u32 GetHash() const { @@ -105,11 +140,14 @@ private: static constexpr std::array<const char*, Maxwell::MaxShaderStage> TextureSamplerNames = { "tex_vs", "tex_tessc", "tex_tesse", "tex_gs", "tex_fs", }; + /// Offset in TSC memory from which to read the sampler object, as specified by the sampling /// instruction. size_t offset; - Maxwell::ShaderStage stage; ///< Shader stage where this sampler was used. - size_t sampler_index; ///< Value used to index into the generated GLSL sampler array. + Maxwell::ShaderStage stage; ///< Shader stage where this sampler was used. + size_t sampler_index; ///< Value used to index into the generated GLSL sampler array. + Tegra::Shader::TextureType type; ///< The type used to sample this texture (Texture2D, etc) + bool is_array; ///< Whether the texture is being sampled as an array texture or not. }; struct ShaderEntries { diff --git a/src/video_core/renderer_opengl/gl_shader_util.cpp b/src/video_core/renderer_opengl/gl_shader_util.cpp index 5781d9d16..5f3fe067e 100644 --- a/src/video_core/renderer_opengl/gl_shader_util.cpp +++ b/src/video_core/renderer_opengl/gl_shader_util.cpp @@ -25,7 +25,7 @@ GLuint LoadShader(const char* source, GLenum type) { default: UNREACHABLE(); } - GLuint shader_id = glCreateShader(type); + const GLuint shader_id = glCreateShader(type); glShaderSource(shader_id, 1, &source, nullptr); LOG_DEBUG(Render_OpenGL, "Compiling {} shader...", debug_type); glCompileShader(shader_id); diff --git a/src/video_core/renderer_opengl/gl_state.cpp b/src/video_core/renderer_opengl/gl_state.cpp index 60a4defd1..6f70deb96 100644 --- a/src/video_core/renderer_opengl/gl_state.cpp +++ b/src/video_core/renderer_opengl/gl_state.cpp @@ -200,9 +200,9 @@ void OpenGLState::Apply() const { const auto& texture_unit = texture_units[i]; const auto& cur_state_texture_unit = cur_state.texture_units[i]; - if (texture_unit.texture_2d != cur_state_texture_unit.texture_2d) { + if (texture_unit.texture != cur_state_texture_unit.texture) { glActiveTexture(TextureUnits::MaxwellTexture(static_cast<int>(i)).Enum()); - glBindTexture(GL_TEXTURE_2D, texture_unit.texture_2d); + glBindTexture(texture_unit.target, texture_unit.texture); } if (texture_unit.sampler != cur_state_texture_unit.sampler) { glBindSampler(static_cast<GLuint>(i), texture_unit.sampler); @@ -214,7 +214,7 @@ void OpenGLState::Apply() const { texture_unit.swizzle.a != cur_state_texture_unit.swizzle.a) { std::array<GLint, 4> mask = {texture_unit.swizzle.r, texture_unit.swizzle.g, texture_unit.swizzle.b, texture_unit.swizzle.a}; - glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_RGBA, mask.data()); + glTexParameteriv(texture_unit.target, GL_TEXTURE_SWIZZLE_RGBA, mask.data()); } } @@ -287,7 +287,7 @@ void OpenGLState::Apply() const { OpenGLState& OpenGLState::UnbindTexture(GLuint handle) { for (auto& unit : texture_units) { - if (unit.texture_2d == handle) { + if (unit.texture == handle) { unit.Unbind(); } } diff --git a/src/video_core/renderer_opengl/gl_state.h b/src/video_core/renderer_opengl/gl_state.h index 46e96a97d..e3e24b9e7 100644 --- a/src/video_core/renderer_opengl/gl_state.h +++ b/src/video_core/renderer_opengl/gl_state.h @@ -94,8 +94,9 @@ public: // 3 texture units - one for each that is used in PICA fragment shader emulation struct TextureUnit { - GLuint texture_2d; // GL_TEXTURE_BINDING_2D - GLuint sampler; // GL_SAMPLER_BINDING + GLuint texture; // GL_TEXTURE_BINDING_2D + GLuint sampler; // GL_SAMPLER_BINDING + GLenum target; struct { GLint r; // GL_TEXTURE_SWIZZLE_R GLint g; // GL_TEXTURE_SWIZZLE_G @@ -104,7 +105,7 @@ public: } swizzle; void Unbind() { - texture_2d = 0; + texture = 0; swizzle.r = GL_RED; swizzle.g = GL_GREEN; swizzle.b = GL_BLUE; @@ -114,6 +115,7 @@ public: void Reset() { Unbind(); sampler = 0; + target = GL_TEXTURE_2D; } }; std::array<TextureUnit, 32> texture_units; diff --git a/src/video_core/renderer_opengl/gl_stream_buffer.cpp b/src/video_core/renderer_opengl/gl_stream_buffer.cpp index e565afcee..aadf68f16 100644 --- a/src/video_core/renderer_opengl/gl_stream_buffer.cpp +++ b/src/video_core/renderer_opengl/gl_stream_buffer.cpp @@ -29,7 +29,7 @@ OGLStreamBuffer::OGLStreamBuffer(GLenum target, GLsizeiptr size, bool prefer_coh if (GLAD_GL_ARB_buffer_storage) { persistent = true; coherent = prefer_coherent; - GLbitfield flags = + const GLbitfield flags = GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT | (coherent ? GL_MAP_COHERENT_BIT : 0); glBufferStorage(gl_target, allocate_size, nullptr, flags); mapped_ptr = static_cast<u8*>(glMapBufferRange( diff --git a/src/video_core/renderer_opengl/renderer_opengl.cpp b/src/video_core/renderer_opengl/renderer_opengl.cpp index 411a73d50..96d916b07 100644 --- a/src/video_core/renderer_opengl/renderer_opengl.cpp +++ b/src/video_core/renderer_opengl/renderer_opengl.cpp @@ -177,7 +177,7 @@ void RendererOpenGL::LoadFBToScreenInfo(const Tegra::FramebufferConfig& framebuf Memory::GetPointer(framebuffer_addr), gl_framebuffer_data.data(), true); - state.texture_units[0].texture_2d = screen_info.texture.resource.handle; + state.texture_units[0].texture = screen_info.texture.resource.handle; state.Apply(); glActiveTexture(GL_TEXTURE0); @@ -194,7 +194,7 @@ void RendererOpenGL::LoadFBToScreenInfo(const Tegra::FramebufferConfig& framebuf glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); - state.texture_units[0].texture_2d = 0; + state.texture_units[0].texture = 0; state.Apply(); } } @@ -205,7 +205,7 @@ void RendererOpenGL::LoadFBToScreenInfo(const Tegra::FramebufferConfig& framebuf */ void RendererOpenGL::LoadColorToActiveGLTexture(u8 color_r, u8 color_g, u8 color_b, u8 color_a, const TextureInfo& texture) { - state.texture_units[0].texture_2d = texture.resource.handle; + state.texture_units[0].texture = texture.resource.handle; state.Apply(); glActiveTexture(GL_TEXTURE0); @@ -214,7 +214,7 @@ void RendererOpenGL::LoadColorToActiveGLTexture(u8 color_r, u8 color_g, u8 color // Update existing texture glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, framebuffer_data); - state.texture_units[0].texture_2d = 0; + state.texture_units[0].texture = 0; state.Apply(); } @@ -260,7 +260,7 @@ void RendererOpenGL::InitOpenGLObjects() { // Allocation of storage is deferred until the first frame, when we // know the framebuffer size. - state.texture_units[0].texture_2d = screen_info.texture.resource.handle; + state.texture_units[0].texture = screen_info.texture.resource.handle; state.Apply(); glActiveTexture(GL_TEXTURE0); @@ -272,7 +272,7 @@ void RendererOpenGL::InitOpenGLObjects() { screen_info.display_texture = screen_info.texture.resource.handle; - state.texture_units[0].texture_2d = 0; + state.texture_units[0].texture = 0; state.Apply(); // Clear screen to black @@ -305,14 +305,14 @@ void RendererOpenGL::ConfigureFramebufferTexture(TextureInfo& texture, UNREACHABLE(); } - state.texture_units[0].texture_2d = texture.resource.handle; + state.texture_units[0].texture = texture.resource.handle; state.Apply(); glActiveTexture(GL_TEXTURE0); glTexImage2D(GL_TEXTURE_2D, 0, internal_format, texture.width, texture.height, 0, texture.gl_format, texture.gl_type, nullptr); - state.texture_units[0].texture_2d = 0; + state.texture_units[0].texture = 0; state.Apply(); } @@ -354,14 +354,14 @@ void RendererOpenGL::DrawScreenTriangles(const ScreenInfo& screen_info, float x, ScreenRectVertex(x + w, y + h, texcoords.bottom * scale_u, right * scale_v), }}; - state.texture_units[0].texture_2d = screen_info.display_texture; + state.texture_units[0].texture = screen_info.display_texture; state.texture_units[0].swizzle = {GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA}; state.Apply(); glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(vertices), vertices.data()); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); - state.texture_units[0].texture_2d = 0; + state.texture_units[0].texture = 0; state.Apply(); } @@ -369,6 +369,12 @@ void RendererOpenGL::DrawScreenTriangles(const ScreenInfo& screen_info, float x, * Draws the emulated screens to the emulator window. */ void RendererOpenGL::DrawScreen() { + if (renderer_settings.set_background_color) { + // Update background color before drawing + glClearColor(Settings::values.bg_red, Settings::values.bg_green, Settings::values.bg_blue, + 0.0f); + } + const auto& layout = render_window.GetFramebufferLayout(); const auto& screen = layout.screen; diff --git a/src/video_core/textures/texture.h b/src/video_core/textures/texture.h index c6bd2f4b9..c2fb824b2 100644 --- a/src/video_core/textures/texture.h +++ b/src/video_core/textures/texture.h @@ -170,8 +170,12 @@ struct TICEntry { BitField<0, 16, u32> width_minus_1; BitField<23, 4, TextureType> texture_type; }; - u16 height_minus_1; - INSERT_PADDING_BYTES(10); + union { + BitField<0, 16, u32> height_minus_1; + BitField<16, 15, u32> depth_minus_1; + }; + + INSERT_PADDING_BYTES(8); GPUVAddr Address() const { return static_cast<GPUVAddr>((static_cast<GPUVAddr>(address_high) << 32) | address_low); @@ -192,6 +196,10 @@ struct TICEntry { return height_minus_1 + 1; } + u32 Depth() const { + return depth_minus_1 + 1; + } + u32 BlockHeight() const { ASSERT(header_version == TICHeaderVersion::BlockLinear || header_version == TICHeaderVersion::BlockLinearColorKey); diff --git a/src/yuzu/CMakeLists.txt b/src/yuzu/CMakeLists.txt index a2b6e984e..f48b69809 100644 --- a/src/yuzu/CMakeLists.txt +++ b/src/yuzu/CMakeLists.txt @@ -9,6 +9,8 @@ add_executable(yuzu about_dialog.h bootmanager.cpp bootmanager.h + compatibility_list.cpp + compatibility_list.h configuration/config.cpp configuration/config.h configuration/configure_audio.cpp diff --git a/src/yuzu/bootmanager.cpp b/src/yuzu/bootmanager.cpp index 4a60f450a..4e4c108ab 100644 --- a/src/yuzu/bootmanager.cpp +++ b/src/yuzu/bootmanager.cpp @@ -112,6 +112,7 @@ GRenderWindow::GRenderWindow(QWidget* parent, EmuThread* emu_thread) setWindowTitle(QString::fromStdString(window_title)); InputCommon::Init(); + InputCommon::StartJoystickEventHandler(); } GRenderWindow::~GRenderWindow() { diff --git a/src/yuzu/compatibility_list.cpp b/src/yuzu/compatibility_list.cpp new file mode 100644 index 000000000..2d2cfd03c --- /dev/null +++ b/src/yuzu/compatibility_list.cpp @@ -0,0 +1,18 @@ +// Copyright 2018 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include <algorithm> + +#include <fmt/format.h> + +#include "yuzu/compatibility_list.h" + +CompatibilityList::const_iterator FindMatchingCompatibilityEntry( + const CompatibilityList& compatibility_list, u64 program_id) { + return std::find_if(compatibility_list.begin(), compatibility_list.end(), + [program_id](const auto& element) { + std::string pid = fmt::format("{:016X}", program_id); + return element.first == pid; + }); +} diff --git a/src/yuzu/compatibility_list.h b/src/yuzu/compatibility_list.h new file mode 100644 index 000000000..bc0175bd3 --- /dev/null +++ b/src/yuzu/compatibility_list.h @@ -0,0 +1,17 @@ +// Copyright 2018 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include <string> +#include <unordered_map> + +#include <QString> + +#include "common/common_types.h" + +using CompatibilityList = std::unordered_map<std::string, std::pair<QString, QString>>; + +CompatibilityList::const_iterator FindMatchingCompatibilityEntry( + const CompatibilityList& compatibility_list, u64 program_id); diff --git a/src/yuzu/configuration/configure_general.cpp b/src/yuzu/configuration/configure_general.cpp index d8caee1e8..9292d9a42 100644 --- a/src/yuzu/configuration/configure_general.cpp +++ b/src/yuzu/configuration/configure_general.cpp @@ -20,7 +20,6 @@ ConfigureGeneral::ConfigureGeneral(QWidget* parent) this->setConfiguration(); ui->use_cpu_jit->setEnabled(!Core::System::GetInstance().IsPoweredOn()); - ui->use_multi_core->setEnabled(!Core::System::GetInstance().IsPoweredOn()); ui->use_docked_mode->setEnabled(!Core::System::GetInstance().IsPoweredOn()); } @@ -31,7 +30,6 @@ void ConfigureGeneral::setConfiguration() { ui->toggle_check_exit->setChecked(UISettings::values.confirm_before_closing); ui->theme_combobox->setCurrentIndex(ui->theme_combobox->findData(UISettings::values.theme)); ui->use_cpu_jit->setChecked(Settings::values.use_cpu_jit); - ui->use_multi_core->setChecked(Settings::values.use_multi_core); ui->use_docked_mode->setChecked(Settings::values.use_docked_mode); } @@ -46,6 +44,5 @@ void ConfigureGeneral::applyConfiguration() { ui->theme_combobox->itemData(ui->theme_combobox->currentIndex()).toString(); Settings::values.use_cpu_jit = ui->use_cpu_jit->isChecked(); - Settings::values.use_multi_core = ui->use_multi_core->isChecked(); Settings::values.use_docked_mode = ui->use_docked_mode->isChecked(); } diff --git a/src/yuzu/configuration/configure_general.ui b/src/yuzu/configuration/configure_general.ui index 233adbe27..1775c4d40 100644 --- a/src/yuzu/configuration/configure_general.ui +++ b/src/yuzu/configuration/configure_general.ui @@ -58,13 +58,6 @@ </property> </widget> </item> - <item> - <widget class="QCheckBox" name="use_multi_core"> - <property name="text"> - <string>Enable multi-core</string> - </property> - </widget> - </item> </layout> </item> </layout> diff --git a/src/yuzu/configuration/configure_graphics.cpp b/src/yuzu/configuration/configure_graphics.cpp index ee1287028..839d58f59 100644 --- a/src/yuzu/configuration/configure_graphics.cpp +++ b/src/yuzu/configuration/configure_graphics.cpp @@ -2,6 +2,7 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. +#include <QColorDialog> #include "core/core.h" #include "core/settings.h" #include "ui_configure_graphics.h" @@ -16,6 +17,14 @@ ConfigureGraphics::ConfigureGraphics(QWidget* parent) ui->frame_limit->setEnabled(Settings::values.use_frame_limit); connect(ui->toggle_frame_limit, &QCheckBox::stateChanged, ui->frame_limit, &QSpinBox::setEnabled); + connect(ui->bg_button, &QPushButton::clicked, this, [this] { + const QColor new_bg_color = QColorDialog::getColor(bg_color); + if (!new_bg_color.isValid()) + return; + bg_color = new_bg_color; + ui->bg_button->setStyleSheet( + QString("QPushButton { background-color: %1 }").arg(bg_color.name())); + }); } ConfigureGraphics::~ConfigureGraphics() = default; @@ -65,6 +74,10 @@ void ConfigureGraphics::setConfiguration() { ui->toggle_frame_limit->setChecked(Settings::values.use_frame_limit); ui->frame_limit->setValue(Settings::values.frame_limit); ui->use_accurate_framebuffers->setChecked(Settings::values.use_accurate_framebuffers); + bg_color = QColor::fromRgbF(Settings::values.bg_red, Settings::values.bg_green, + Settings::values.bg_blue); + ui->bg_button->setStyleSheet( + QString("QPushButton { background-color: %1 }").arg(bg_color.name())); } void ConfigureGraphics::applyConfiguration() { @@ -73,4 +86,7 @@ void ConfigureGraphics::applyConfiguration() { Settings::values.use_frame_limit = ui->toggle_frame_limit->isChecked(); Settings::values.frame_limit = ui->frame_limit->value(); Settings::values.use_accurate_framebuffers = ui->use_accurate_framebuffers->isChecked(); + Settings::values.bg_red = static_cast<float>(bg_color.redF()); + Settings::values.bg_green = static_cast<float>(bg_color.greenF()); + Settings::values.bg_blue = static_cast<float>(bg_color.blueF()); } diff --git a/src/yuzu/configuration/configure_graphics.h b/src/yuzu/configuration/configure_graphics.h index 5497a55f7..9bda26fd6 100644 --- a/src/yuzu/configuration/configure_graphics.h +++ b/src/yuzu/configuration/configure_graphics.h @@ -25,4 +25,5 @@ private: private: std::unique_ptr<Ui::ConfigureGraphics> ui; + QColor bg_color; }; diff --git a/src/yuzu/configuration/configure_graphics.ui b/src/yuzu/configuration/configure_graphics.ui index 3bc18c26e..8fc00af1b 100644 --- a/src/yuzu/configuration/configure_graphics.ui +++ b/src/yuzu/configuration/configure_graphics.ui @@ -96,6 +96,27 @@ </item> </layout> </item> + <item> + <layout class="QHBoxLayout" name="horizontalLayout_6"> + <item> + <widget class="QLabel" name="bg_label"> + <property name="text"> + <string>Background Color:</string> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="bg_button"> + <property name="maximumSize"> + <size> + <width>40</width> + <height>16777215</height> + </size> + </property> + </widget> + </item> + </layout> + </item> </layout> </widget> </item> diff --git a/src/yuzu/configuration/configure_input.cpp b/src/yuzu/configuration/configure_input.cpp index 5e7badedf..d29abb74b 100644 --- a/src/yuzu/configuration/configure_input.cpp +++ b/src/yuzu/configuration/configure_input.cpp @@ -1,4 +1,4 @@ -// Copyright 2016 Citra Emulator Project +// Copyright 2016 Citra Emulator Project // Licensed under GPLv2 or any later version // Refer to the license.txt file included. @@ -53,19 +53,18 @@ static QString ButtonToText(const Common::ParamPackage& param) { } 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()); + return 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()); + return 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 QString(QObject::tr("Button %1")).arg(param.Get("button", "").c_str()); } - return text; + return QString(); } else { return QObject::tr("[unknown]"); } @@ -81,13 +80,12 @@ static QString AnalogToText(const Common::ParamPackage& param, const std::string 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()); + return 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 QString(QObject::tr("Axis %1")).arg(param.Get("axis_y", "").c_str()); } - return text; + return QString(); } else { return QObject::tr("[unknown]"); } diff --git a/src/yuzu/game_list.cpp b/src/yuzu/game_list.cpp index 86532e4a9..3b3b551bb 100644 --- a/src/yuzu/game_list.cpp +++ b/src/yuzu/game_list.cpp @@ -19,6 +19,7 @@ #include "common/file_util.h" #include "common/logging/log.h" #include "core/file_sys/patch_manager.h" +#include "yuzu/compatibility_list.h" #include "yuzu/game_list.h" #include "yuzu/game_list_p.h" #include "yuzu/game_list_worker.h" @@ -365,7 +366,7 @@ void GameList::LoadCompatibilityList() { QJsonDocument json = QJsonDocument::fromJson(string_content.toUtf8()); QJsonArray arr = json.array(); - for (const QJsonValue& value : arr) { + for (const QJsonValueRef& value : arr) { QJsonObject game = value.toObject(); if (game.contains("compatibility") && game["compatibility"].isDouble()) { @@ -373,9 +374,9 @@ void GameList::LoadCompatibilityList() { QString directory = game["directory"].toString(); QJsonArray ids = game["releases"].toArray(); - for (const QJsonValue& value : ids) { - QJsonObject object = value.toObject(); - QString id = object["id"].toString(); + for (const QJsonValueRef& id_ref : ids) { + QJsonObject id_object = id_ref.toObject(); + QString id = id_object["id"].toString(); compatibility_list.emplace( id.toUpper().toStdString(), std::make_pair(QString::number(compatibility), directory)); diff --git a/src/yuzu/game_list.h b/src/yuzu/game_list.h index 3fcb298ed..2713e7b54 100644 --- a/src/yuzu/game_list.h +++ b/src/yuzu/game_list.h @@ -4,8 +4,6 @@ #pragma once -#include <unordered_map> - #include <QFileSystemWatcher> #include <QHBoxLayout> #include <QLabel> @@ -21,6 +19,7 @@ #include <QWidget> #include "common/common_types.h" +#include "yuzu/compatibility_list.h" class GameListWorker; class GMainWindow; @@ -90,9 +89,8 @@ signals: void GameChosen(QString game_path); void ShouldCancelWorker(); void OpenFolderRequested(u64 program_id, GameListOpenTarget target); - void NavigateToGamedbEntryRequested( - u64 program_id, - std::unordered_map<std::string, std::pair<QString, QString>>& compatibility_list); + void NavigateToGamedbEntryRequested(u64 program_id, + const CompatibilityList& compatibility_list); private slots: void onTextChanged(const QString& newText); @@ -114,7 +112,7 @@ private: QStandardItemModel* item_model = nullptr; GameListWorker* current_worker = nullptr; QFileSystemWatcher* watcher = nullptr; - std::unordered_map<std::string, std::pair<QString, QString>> compatibility_list; + CompatibilityList compatibility_list; }; Q_DECLARE_METATYPE(GameListOpenTarget); diff --git a/src/yuzu/game_list_p.h b/src/yuzu/game_list_p.h index 2720bf143..f22e422e5 100644 --- a/src/yuzu/game_list_p.h +++ b/src/yuzu/game_list_p.h @@ -176,14 +176,3 @@ public: return data(SizeRole).toULongLong() < other.data(SizeRole).toULongLong(); } }; - -inline auto FindMatchingCompatibilityEntry( - const std::unordered_map<std::string, std::pair<QString, QString>>& compatibility_list, - u64 program_id) { - return std::find_if( - compatibility_list.begin(), compatibility_list.end(), - [program_id](const std::pair<std::string, std::pair<QString, QString>>& element) { - std::string pid = fmt::format("{:016X}", program_id); - return element.first == pid; - }); -} diff --git a/src/yuzu/game_list_worker.cpp b/src/yuzu/game_list_worker.cpp index 9f26935d6..e228d61bd 100644 --- a/src/yuzu/game_list_worker.cpp +++ b/src/yuzu/game_list_worker.cpp @@ -20,6 +20,7 @@ #include "core/file_sys/registered_cache.h" #include "core/hle/service/filesystem/filesystem.h" #include "core/loader/loader.h" +#include "yuzu/compatibility_list.h" #include "yuzu/game_list.h" #include "yuzu/game_list_p.h" #include "yuzu/game_list_worker.h" @@ -75,9 +76,8 @@ QString FormatPatchNameVersions(const FileSys::PatchManager& patch_manager, bool } } // Anonymous namespace -GameListWorker::GameListWorker( - FileSys::VirtualFilesystem vfs, QString dir_path, bool deep_scan, - const std::unordered_map<std::string, std::pair<QString, QString>>& compatibility_list) +GameListWorker::GameListWorker(FileSys::VirtualFilesystem vfs, QString dir_path, bool deep_scan, + const CompatibilityList& compatibility_list) : vfs(std::move(vfs)), dir_path(std::move(dir_path)), deep_scan(deep_scan), compatibility_list(compatibility_list) {} diff --git a/src/yuzu/game_list_worker.h b/src/yuzu/game_list_worker.h index 42c93fc31..09d20c42f 100644 --- a/src/yuzu/game_list_worker.h +++ b/src/yuzu/game_list_worker.h @@ -16,6 +16,7 @@ #include <QString> #include "common/common_types.h" +#include "yuzu/compatibility_list.h" class QStandardItem; @@ -32,9 +33,8 @@ class GameListWorker : public QObject, public QRunnable { Q_OBJECT public: - GameListWorker( - std::shared_ptr<FileSys::VfsFilesystem> vfs, QString dir_path, bool deep_scan, - const std::unordered_map<std::string, std::pair<QString, QString>>& compatibility_list); + GameListWorker(std::shared_ptr<FileSys::VfsFilesystem> vfs, QString dir_path, bool deep_scan, + const CompatibilityList& compatibility_list); ~GameListWorker() override; /// Starts the processing of directory tree information. @@ -67,6 +67,6 @@ private: QStringList watch_list; QString dir_path; bool deep_scan; - const std::unordered_map<std::string, std::pair<QString, QString>>& compatibility_list; + const CompatibilityList& compatibility_list; std::atomic_bool stop_processing; }; diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index 2cd282a51..05a4a55e8 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -47,6 +47,7 @@ #include "video_core/debug_utils/debug_utils.h" #include "yuzu/about_dialog.h" #include "yuzu/bootmanager.h" +#include "yuzu/compatibility_list.h" #include "yuzu/configuration/config.h" #include "yuzu/configuration/configure_dialog.h" #include "yuzu/debugger/console.h" @@ -446,6 +447,8 @@ QStringList GMainWindow::GetUnsupportedGLExtensions() { unsupported_ext.append("ARB_texture_mirror_clamp_to_edge"); if (!GLAD_GL_ARB_base_instance) unsupported_ext.append("ARB_base_instance"); + if (!GLAD_GL_ARB_texture_storage) + unsupported_ext.append("ARB_texture_storage"); // Extensions required to support some texture formats. if (!GLAD_GL_EXT_texture_compression_s3tc) @@ -608,7 +611,7 @@ void GMainWindow::BootGame(const QString& filename) { } setWindowTitle(QString("yuzu %1| %4 | %2-%3") - .arg(Common::g_build_name, Common::g_scm_branch, Common::g_scm_desc, + .arg(Common::g_build_fullname, Common::g_scm_branch, Common::g_scm_desc, QString::fromStdString(title_name))); render_window->show(); @@ -643,7 +646,7 @@ void GMainWindow::ShutdownGame() { game_list->show(); game_list->setFilterFocus(); setWindowTitle(QString("yuzu %1| %2-%3") - .arg(Common::g_build_name, Common::g_scm_branch, Common::g_scm_desc)); + .arg(Common::g_build_fullname, Common::g_scm_branch, Common::g_scm_desc)); // Disable status bar updates status_bar_update_timer.stop(); @@ -725,14 +728,11 @@ void GMainWindow::OnGameListOpenFolder(u64 program_id, GameListOpenTarget target QDesktopServices::openUrl(QUrl::fromLocalFile(qpath)); } -void GMainWindow::OnGameListNavigateToGamedbEntry( - u64 program_id, - std::unordered_map<std::string, std::pair<QString, QString>>& compatibility_list) { - - auto it = FindMatchingCompatibilityEntry(compatibility_list, program_id); +void GMainWindow::OnGameListNavigateToGamedbEntry(u64 program_id, + const CompatibilityList& compatibility_list) { + const auto it = FindMatchingCompatibilityEntry(compatibility_list, program_id); QString directory; - if (it != compatibility_list.end()) directory = it->second.second; diff --git a/src/yuzu/main.h b/src/yuzu/main.h index 089ea2445..552e3e61c 100644 --- a/src/yuzu/main.h +++ b/src/yuzu/main.h @@ -13,6 +13,7 @@ #include "common/common_types.h" #include "core/core.h" #include "ui_main.h" +#include "yuzu/compatibility_list.h" #include "yuzu/hotkeys.h" class Config; @@ -137,9 +138,8 @@ private slots: /// Called whenever a user selects a game in the game list widget. void OnGameListLoadFile(QString game_path); void OnGameListOpenFolder(u64 program_id, GameListOpenTarget target); - void OnGameListNavigateToGamedbEntry( - u64 program_id, - std::unordered_map<std::string, std::pair<QString, QString>>& compatibility_list); + void OnGameListNavigateToGamedbEntry(u64 program_id, + const CompatibilityList& compatibility_list); void OnMenuLoadFile(); void OnMenuLoadFolder(); void OnMenuInstallToNAND(); diff --git a/src/yuzu_cmd/emu_window/emu_window_sdl2.cpp b/src/yuzu_cmd/emu_window/emu_window_sdl2.cpp index 2f7916256..d213929bd 100644 --- a/src/yuzu_cmd/emu_window/emu_window_sdl2.cpp +++ b/src/yuzu_cmd/emu_window/emu_window_sdl2.cpp @@ -16,6 +16,7 @@ #include "input_common/keyboard.h" #include "input_common/main.h" #include "input_common/motion_emu.h" +#include "input_common/sdl/sdl.h" #include "yuzu_cmd/emu_window/emu_window_sdl2.h" void EmuWindow_SDL2::OnMouseMotion(s32 x, s32 y) { @@ -93,6 +94,8 @@ bool EmuWindow_SDL2::SupportsRequiredGLExtensions() { unsupported_ext.push_back("ARB_texture_mirror_clamp_to_edge"); if (!GLAD_GL_ARB_base_instance) unsupported_ext.push_back("ARB_base_instance"); + if (!GLAD_GL_ARB_texture_storage) + unsupported_ext.push_back("ARB_texture_storage"); // Extensions required to support some texture formats. if (!GLAD_GL_EXT_texture_compression_s3tc) @@ -116,7 +119,7 @@ EmuWindow_SDL2::EmuWindow_SDL2(bool fullscreen) { SDL_SetMainReady(); // Initialize the window - if (SDL_Init(SDL_INIT_VIDEO) < 0) { + if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_JOYSTICK) < 0) { LOG_CRITICAL(Frontend, "Failed to initialize SDL2! Exiting..."); exit(1); } @@ -176,6 +179,7 @@ EmuWindow_SDL2::EmuWindow_SDL2(bool fullscreen) { } EmuWindow_SDL2::~EmuWindow_SDL2() { + InputCommon::SDL::CloseSDLJoysticks(); SDL_GL_DeleteContext(gl_context); SDL_Quit(); @@ -220,6 +224,9 @@ void EmuWindow_SDL2::PollEvents() { case SDL_QUIT: is_open = false; break; + default: + InputCommon::SDL::HandleGameControllerEvent(event); + break; } } } diff --git a/src/yuzu_cmd/yuzu.cpp b/src/yuzu_cmd/yuzu.cpp index 173ac0e0f..b1c364fbb 100644 --- a/src/yuzu_cmd/yuzu.cpp +++ b/src/yuzu_cmd/yuzu.cpp @@ -82,6 +82,9 @@ int main(int argc, char** argv) { int option_index = 0; bool use_gdbstub = Settings::values.use_gdbstub; u32 gdb_port = static_cast<u32>(Settings::values.gdbstub_port); + + InitializeLogging(); + char* endarg; #ifdef _WIN32 int argc_w; @@ -144,8 +147,6 @@ int main(int argc, char** argv) { LocalFree(argv_w); #endif - InitializeLogging(); - MicroProfileOnThreadCreate("EmuThread"); SCOPE_EXIT({ MicroProfileShutdown(); }); |