diff options
Diffstat (limited to 'src')
26 files changed, 308 insertions, 142 deletions
diff --git a/src/common/fs/fs_util.cpp b/src/common/fs/fs_util.cpp index 357cf5855..9f8671982 100644 --- a/src/common/fs/fs_util.cpp +++ b/src/common/fs/fs_util.cpp @@ -20,6 +20,10 @@ std::string ToUTF8String(std::u8string_view u8_string) { return std::string{u8_string.begin(), u8_string.end()}; } +std::string BufferToUTF8String(std::span<const u8> buffer) { + return std::string{buffer.begin(), std::ranges::find(buffer, u8{0})}; +} + std::string PathToUTF8String(const std::filesystem::path& path) { return ToUTF8String(path.u8string()); } diff --git a/src/common/fs/fs_util.h b/src/common/fs/fs_util.h index ec9950ee7..1ec82eb35 100644 --- a/src/common/fs/fs_util.h +++ b/src/common/fs/fs_util.h @@ -47,6 +47,17 @@ concept IsChar = std::same_as<T, char>; [[nodiscard]] std::string ToUTF8String(std::u8string_view u8_string); /** + * Converts a buffer of bytes to a UTF8-encoded std::string. + * This converts from the start of the buffer until the first encountered null-terminator. + * If no null-terminator is found, this converts the entire buffer instead. + * + * @param buffer Buffer of bytes + * + * @returns UTF-8 encoded std::string. + */ +[[nodiscard]] std::string BufferToUTF8String(std::span<const u8> buffer); + +/** * Converts a filesystem path to a UTF-8 encoded std::string. * * @param path Filesystem path diff --git a/src/common/host_memory.cpp b/src/common/host_memory.cpp index 2a5a7596c..6661244cf 100644 --- a/src/common/host_memory.cpp +++ b/src/common/host_memory.cpp @@ -6,7 +6,7 @@ #include <windows.h> #include "common/dynamic_library.h" -#elif defined(__linux__) // ^^^ Windows ^^^ vvv Linux vvv +#elif defined(__linux__) || defined(__FreeBSD__) // ^^^ Windows ^^^ vvv Linux vvv #ifndef _GNU_SOURCE #define _GNU_SOURCE @@ -343,7 +343,7 @@ private: std::unordered_map<size_t, size_t> placeholder_host_pointers; ///< Placeholder backing offset }; -#elif defined(__linux__) // ^^^ Windows ^^^ vvv Linux vvv +#elif defined(__linux__) || defined(__FreeBSD__) // ^^^ Windows ^^^ vvv Linux vvv class HostMemory::Impl { public: @@ -357,7 +357,12 @@ public: }); // Backing memory initialization +#if defined(__FreeBSD__) && __FreeBSD__ < 13 + // XXX Drop after FreeBSD 12.* reaches EOL on 2024-06-30 + fd = shm_open(SHM_ANON, O_RDWR, 0600); +#else fd = memfd_create("HostMemory", 0); +#endif if (fd == -1) { LOG_CRITICAL(HW_Memory, "memfd_create failed: {}", strerror(errno)); throw std::bad_alloc{}; diff --git a/src/common/settings.h b/src/common/settings.h index 375569450..a88ee045d 100644 --- a/src/common/settings.h +++ b/src/common/settings.h @@ -42,6 +42,11 @@ enum class CPUAccuracy : u32 { Unsafe = 2, }; +enum class FullscreenMode : u32 { + Borderless = 0, + Exclusive = 1, +}; + /** The BasicSetting class is a simple resource manager. It defines a label and default value * alongside the actual value of the setting for simpler and less-error prone use with frontend * configurations. Setting a default value and label is required, though subclasses may deviate from @@ -323,11 +328,11 @@ struct Values { Setting<u16> resolution_factor{1, "resolution_factor"}; // *nix platforms may have issues with the borderless windowed fullscreen mode. // Default to exclusive fullscreen on these platforms for now. - Setting<int> fullscreen_mode{ + Setting<FullscreenMode> fullscreen_mode{ #ifdef _WIN32 - 0, + FullscreenMode::Borderless, #else - 1, + FullscreenMode::Exclusive, #endif "fullscreen_mode"}; Setting<int> aspect_ratio{0, "aspect_ratio"}; diff --git a/src/common/uuid.cpp b/src/common/uuid.cpp index 26db03fba..18303a1e3 100644 --- a/src/common/uuid.cpp +++ b/src/common/uuid.cpp @@ -18,7 +18,7 @@ UUID UUID::Generate() { } std::string UUID::Format() const { - return fmt::format("0x{:016X}{:016X}", uuid[1], uuid[0]); + return fmt::format("{:016x}{:016x}", uuid[1], uuid[0]); } std::string UUID::FormatSwitch() const { diff --git a/src/core/hle/service/acc/acc.cpp b/src/core/hle/service/acc/acc.cpp index 2e969f2a8..882fc1492 100644 --- a/src/core/hle/service/acc/acc.cpp +++ b/src/core/hle/service/acc/acc.cpp @@ -292,7 +292,7 @@ public: protected: void Get(Kernel::HLERequestContext& ctx) { - LOG_DEBUG(Service_ACC, "called user_id={}", user_id.Format()); + LOG_DEBUG(Service_ACC, "called user_id=0x{}", user_id.Format()); ProfileBase profile_base{}; ProfileData data{}; if (profile_manager.GetProfileBaseAndData(user_id, profile_base, data)) { @@ -301,7 +301,7 @@ protected: rb.Push(ResultSuccess); rb.PushRaw(profile_base); } else { - LOG_ERROR(Service_ACC, "Failed to get profile base and data for user={}", + LOG_ERROR(Service_ACC, "Failed to get profile base and data for user=0x{}", user_id.Format()); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(ResultUnknown); // TODO(ogniK): Get actual error code @@ -309,14 +309,14 @@ protected: } void GetBase(Kernel::HLERequestContext& ctx) { - LOG_DEBUG(Service_ACC, "called user_id={}", user_id.Format()); + LOG_DEBUG(Service_ACC, "called user_id=0x{}", user_id.Format()); ProfileBase profile_base{}; if (profile_manager.GetProfileBase(user_id, profile_base)) { IPC::ResponseBuilder rb{ctx, 16}; rb.Push(ResultSuccess); rb.PushRaw(profile_base); } else { - LOG_ERROR(Service_ACC, "Failed to get profile base for user={}", user_id.Format()); + LOG_ERROR(Service_ACC, "Failed to get profile base for user=0x{}", user_id.Format()); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(ResultUnknown); // TODO(ogniK): Get actual error code } @@ -372,7 +372,7 @@ protected: const auto user_data = ctx.ReadBuffer(); - LOG_DEBUG(Service_ACC, "called, username='{}', timestamp={:016X}, uuid={}", + LOG_DEBUG(Service_ACC, "called, username='{}', timestamp={:016X}, uuid=0x{}", Common::StringFromFixedZeroTerminatedBuffer( reinterpret_cast<const char*>(base.username.data()), base.username.size()), base.timestamp, base.user_uuid.Format()); @@ -405,7 +405,7 @@ protected: const auto user_data = ctx.ReadBuffer(); const auto image_data = ctx.ReadBuffer(1); - LOG_DEBUG(Service_ACC, "called, username='{}', timestamp={:016X}, uuid={}", + LOG_DEBUG(Service_ACC, "called, username='{}', timestamp={:016X}, uuid=0x{}", Common::StringFromFixedZeroTerminatedBuffer( reinterpret_cast<const char*>(base.username.data()), base.username.size()), base.timestamp, base.user_uuid.Format()); @@ -662,7 +662,7 @@ void Module::Interface::GetUserCount(Kernel::HLERequestContext& ctx) { void Module::Interface::GetUserExistence(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; Common::UUID user_id = rp.PopRaw<Common::UUID>(); - LOG_DEBUG(Service_ACC, "called user_id={}", user_id.Format()); + LOG_DEBUG(Service_ACC, "called user_id=0x{}", user_id.Format()); IPC::ResponseBuilder rb{ctx, 3}; rb.Push(ResultSuccess); @@ -693,7 +693,7 @@ void Module::Interface::GetLastOpenedUser(Kernel::HLERequestContext& ctx) { void Module::Interface::GetProfile(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; Common::UUID user_id = rp.PopRaw<Common::UUID>(); - LOG_DEBUG(Service_ACC, "called user_id={}", user_id.Format()); + LOG_DEBUG(Service_ACC, "called user_id=0x{}", user_id.Format()); IPC::ResponseBuilder rb{ctx, 2, 0, 1}; rb.Push(ResultSuccess); @@ -802,7 +802,7 @@ void Module::Interface::GetProfileEditor(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; Common::UUID user_id = rp.PopRaw<Common::UUID>(); - LOG_DEBUG(Service_ACC, "called, user_id={}", user_id.Format()); + LOG_DEBUG(Service_ACC, "called, user_id=0x{}", user_id.Format()); IPC::ResponseBuilder rb{ctx, 2, 0, 1}; rb.Push(ResultSuccess); @@ -844,7 +844,7 @@ void Module::Interface::StoreSaveDataThumbnailApplication(Kernel::HLERequestCont IPC::RequestParser rp{ctx}; const auto uuid = rp.PopRaw<Common::UUID>(); - LOG_WARNING(Service_ACC, "(STUBBED) called, uuid={}", uuid.Format()); + LOG_WARNING(Service_ACC, "(STUBBED) called, uuid=0x{}", uuid.Format()); // TODO(ogniK): Check if application ID is zero on acc initialize. As we don't have a reliable // way of confirming things like the TID, we're going to assume a non zero value for the time @@ -858,7 +858,7 @@ void Module::Interface::StoreSaveDataThumbnailSystem(Kernel::HLERequestContext& const auto uuid = rp.PopRaw<Common::UUID>(); const auto tid = rp.Pop<u64_le>(); - LOG_WARNING(Service_ACC, "(STUBBED) called, uuid={}, tid={:016X}", uuid.Format(), tid); + LOG_WARNING(Service_ACC, "(STUBBED) called, uuid=0x{}, tid={:016X}", uuid.Format(), tid); StoreSaveDataThumbnail(ctx, uuid, tid); } diff --git a/src/core/hle/service/am/applets/applet_software_keyboard.cpp b/src/core/hle/service/am/applets/applet_software_keyboard.cpp index 7cae90609..673abb755 100644 --- a/src/core/hle/service/am/applets/applet_software_keyboard.cpp +++ b/src/core/hle/service/am/applets/applet_software_keyboard.cpp @@ -377,7 +377,7 @@ void SoftwareKeyboard::SubmitForTextCheck(std::u16string submitted_text) { if (swkbd_config_common.use_utf8) { std::string utf8_submitted_text = Common::UTF16ToUTF8(current_text); - const u64 buffer_size = sizeof(u64) + utf8_submitted_text.size(); + const u64 buffer_size = utf8_submitted_text.size(); LOG_DEBUG(Service_AM, "\nBuffer Size: {}\nUTF-8 Submitted Text: {}", buffer_size, utf8_submitted_text); @@ -386,7 +386,7 @@ void SoftwareKeyboard::SubmitForTextCheck(std::u16string submitted_text) { std::memcpy(out_data.data() + sizeof(u64), utf8_submitted_text.data(), utf8_submitted_text.size()); } else { - const u64 buffer_size = sizeof(u64) + current_text.size() * sizeof(char16_t); + const u64 buffer_size = current_text.size() * sizeof(char16_t); LOG_DEBUG(Service_AM, "\nBuffer Size: {}\nUTF-16 Submitted Text: {}", buffer_size, Common::UTF16ToUTF8(current_text)); diff --git a/src/core/hle/service/friend/friend.cpp b/src/core/hle/service/friend/friend.cpp index a3c939c0c..b58c152ce 100644 --- a/src/core/hle/service/friend/friend.cpp +++ b/src/core/hle/service/friend/friend.cpp @@ -158,7 +158,7 @@ private: const auto local_play = rp.Pop<bool>(); const auto uuid = rp.PopRaw<Common::UUID>(); - LOG_WARNING(Service_Friend, "(STUBBED) called local_play={} uuid={}", local_play, + LOG_WARNING(Service_Friend, "(STUBBED) called, local_play={}, uuid=0x{}", local_play, uuid.Format()); IPC::ResponseBuilder rb{ctx, 2}; @@ -171,7 +171,7 @@ private: const auto uuid = rp.PopRaw<Common::UUID>(); [[maybe_unused]] const auto filter = rp.PopRaw<SizedFriendFilter>(); const auto pid = rp.Pop<u64>(); - LOG_WARNING(Service_Friend, "(STUBBED) called, offset={}, uuid={}, pid={}", friend_offset, + LOG_WARNING(Service_Friend, "(STUBBED) called, offset={}, uuid=0x{}, pid={}", friend_offset, uuid.Format(), pid); IPC::ResponseBuilder rb{ctx, 3}; @@ -289,7 +289,7 @@ void Module::Interface::CreateNotificationService(Kernel::HLERequestContext& ctx IPC::RequestParser rp{ctx}; auto uuid = rp.PopRaw<Common::UUID>(); - LOG_DEBUG(Service_Friend, "called, uuid={}", uuid.Format()); + LOG_DEBUG(Service_Friend, "called, uuid=0x{}", uuid.Format()); IPC::ResponseBuilder rb{ctx, 2, 0, 1}; rb.Push(ResultSuccess); diff --git a/src/core/hle/service/ns/language.cpp b/src/core/hle/service/ns/language.cpp index 29c4a820c..54b644830 100644 --- a/src/core/hle/service/ns/language.cpp +++ b/src/core/hle/service/ns/language.cpp @@ -344,8 +344,10 @@ std::optional<ApplicationLanguage> ConvertToApplicationLanguage( return ApplicationLanguage::Russian; case Set::LanguageCode::KO: return ApplicationLanguage::Korean; + case Set::LanguageCode::ZH_TW: case Set::LanguageCode::ZH_HANT: return ApplicationLanguage::TraditionalChinese; + case Set::LanguageCode::ZH_CN: case Set::LanguageCode::ZH_HANS: return ApplicationLanguage::SimplifiedChinese; default: diff --git a/src/core/hle/service/ns/ns_language.h b/src/core/hle/service/ns/ns_language.h deleted file mode 100644 index 59ac85a19..000000000 --- a/src/core/hle/service/ns/ns_language.h +++ /dev/null @@ -1,42 +0,0 @@ -// Copyright 2019 yuzu emulator team -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#pragma once -#include <optional> -#include <string> -#include "common/common_types.h" -#include "core/hle/service/set/set.h" - -namespace Service::NS { -/// This is nn::ns::detail::ApplicationLanguage -enum class ApplicationLanguage : u8 { - AmericanEnglish = 0, - BritishEnglish, - Japanese, - French, - German, - LatinAmericanSpanish, - Spanish, - Italian, - Dutch, - CanadianFrench, - Portuguese, - Russian, - Korean, - TraditionalChinese, - SimplifiedChinese, - Count -}; -using ApplicationLanguagePriorityList = - const std::array<ApplicationLanguage, static_cast<std::size_t>(ApplicationLanguage::Count)>; - -constexpr u32 GetSupportedLanguageFlag(const ApplicationLanguage lang) { - return 1U << static_cast<u32>(lang); -} - -const ApplicationLanguagePriorityList* GetApplicationLanguagePriorityList(ApplicationLanguage lang); -std::optional<ApplicationLanguage> ConvertToApplicationLanguage( - Service::Set::LanguageCode language_code); -std::optional<Service::Set::LanguageCode> ConvertToLanguageCode(ApplicationLanguage lang); -} // namespace Service::NS
\ No newline at end of file diff --git a/src/shader_recompiler/frontend/ir/value.h b/src/shader_recompiler/frontend/ir/value.h index 795194d41..334bb47aa 100644 --- a/src/shader_recompiler/frontend/ir/value.h +++ b/src/shader_recompiler/frontend/ir/value.h @@ -57,6 +57,7 @@ public: [[nodiscard]] IR::Inst* Inst() const; [[nodiscard]] IR::Inst* InstRecursive() const; + [[nodiscard]] IR::Inst* TryInstRecursive() const; [[nodiscard]] IR::Value Resolve() const; [[nodiscard]] IR::Reg Reg() const; [[nodiscard]] IR::Pred Pred() const; @@ -308,6 +309,13 @@ inline IR::Inst* Value::InstRecursive() const { return inst; } +inline IR::Inst* Value::TryInstRecursive() const { + if (IsIdentity()) { + return inst->Arg(0).TryInstRecursive(); + } + return type == Type::Opaque ? inst : nullptr; +} + inline IR::Value Value::Resolve() const { if (IsIdentity()) { return inst->Arg(0).Resolve(); diff --git a/src/shader_recompiler/ir_opt/collect_shader_info_pass.cpp b/src/shader_recompiler/ir_opt/collect_shader_info_pass.cpp index 5ead930f1..f69e1c9cc 100644 --- a/src/shader_recompiler/ir_opt/collect_shader_info_pass.cpp +++ b/src/shader_recompiler/ir_opt/collect_shader_info_pass.cpp @@ -111,6 +111,8 @@ void VisitUsages(Info& info, IR::Inst& inst) { case IR::Opcode::ConvertF16U16: case IR::Opcode::ConvertF16U32: case IR::Opcode::ConvertF16U64: + case IR::Opcode::ConvertF16F32: + case IR::Opcode::ConvertF32F16: case IR::Opcode::FPAbs16: case IR::Opcode::FPAdd16: case IR::Opcode::FPCeil16: diff --git a/src/shader_recompiler/ir_opt/constant_propagation_pass.cpp b/src/shader_recompiler/ir_opt/constant_propagation_pass.cpp index 8dd6d6c2c..d089fdd12 100644 --- a/src/shader_recompiler/ir_opt/constant_propagation_pass.cpp +++ b/src/shader_recompiler/ir_opt/constant_propagation_pass.cpp @@ -3,6 +3,7 @@ // Refer to the license.txt file included. #include <algorithm> +#include <functional> #include <tuple> #include <type_traits> @@ -88,6 +89,26 @@ bool FoldWhenAllImmediates(IR::Inst& inst, Func&& func) { return true; } +/// Return true when all values in a range are equal +template <typename Range> +bool AreEqual(const Range& range) { + auto resolver{[](const auto& value) { return value.Resolve(); }}; + auto equal{[](const IR::Value& lhs, const IR::Value& rhs) { + if (lhs == rhs) { + return true; + } + // Not equal, but try to match if they read the same constant buffer + if (!lhs.IsImmediate() && !rhs.IsImmediate() && + lhs.Inst()->GetOpcode() == IR::Opcode::GetCbufU32 && + rhs.Inst()->GetOpcode() == IR::Opcode::GetCbufU32 && + lhs.Inst()->Arg(0) == rhs.Inst()->Arg(0) && lhs.Inst()->Arg(1) == rhs.Inst()->Arg(1)) { + return true; + } + return false; + }}; + return std::ranges::adjacent_find(range, std::not_fn(equal), resolver) == std::end(range); +} + void FoldGetRegister(IR::Inst& inst) { if (inst.Arg(0).Reg() == IR::Reg::RZ) { inst.ReplaceUsesWith(IR::Value{u32{0}}); @@ -100,6 +121,157 @@ void FoldGetPred(IR::Inst& inst) { } } +/// Replaces the XMAD pattern generated by an integer FMA +bool FoldXmadMultiplyAdd(IR::Block& block, IR::Inst& inst) { + /* + * We are looking for this specific pattern: + * %6 = BitFieldUExtract %op_b, #0, #16 + * %7 = BitFieldUExtract %op_a', #16, #16 + * %8 = IMul32 %6, %7 + * %10 = BitFieldUExtract %op_a', #0, #16 + * %11 = BitFieldInsert %8, %10, #16, #16 + * %15 = BitFieldUExtract %op_b, #0, #16 + * %16 = BitFieldUExtract %op_a, #0, #16 + * %17 = IMul32 %15, %16 + * %18 = IAdd32 %17, %op_c + * %22 = BitFieldUExtract %op_b, #16, #16 + * %23 = BitFieldUExtract %11, #16, #16 + * %24 = IMul32 %22, %23 + * %25 = ShiftLeftLogical32 %24, #16 + * %26 = ShiftLeftLogical32 %11, #16 + * %27 = IAdd32 %26, %18 + * %result = IAdd32 %25, %27 + * + * And replace it with: + * %temp = IMul32 %op_a, %op_b + * %result = IAdd32 %temp, %op_c + * + * This optimization has been proven safe by Nvidia's compiler logic being reversed. + * (If Nvidia generates this code from 'fma(a, b, c)', we can do the same in the reverse order.) + */ + const IR::Value zero{0u}; + const IR::Value sixteen{16u}; + IR::Inst* const _25{inst.Arg(0).TryInstRecursive()}; + IR::Inst* const _27{inst.Arg(1).TryInstRecursive()}; + if (!_25 || !_27) { + return false; + } + if (_27->GetOpcode() != IR::Opcode::IAdd32) { + return false; + } + if (_25->GetOpcode() != IR::Opcode::ShiftLeftLogical32 || _25->Arg(1) != sixteen) { + return false; + } + IR::Inst* const _24{_25->Arg(0).TryInstRecursive()}; + if (!_24 || _24->GetOpcode() != IR::Opcode::IMul32) { + return false; + } + IR::Inst* const _22{_24->Arg(0).TryInstRecursive()}; + IR::Inst* const _23{_24->Arg(1).TryInstRecursive()}; + if (!_22 || !_23) { + return false; + } + if (_22->GetOpcode() != IR::Opcode::BitFieldUExtract) { + return false; + } + if (_23->GetOpcode() != IR::Opcode::BitFieldUExtract) { + return false; + } + if (_22->Arg(1) != sixteen || _22->Arg(2) != sixteen) { + return false; + } + if (_23->Arg(1) != sixteen || _23->Arg(2) != sixteen) { + return false; + } + IR::Inst* const _11{_23->Arg(0).TryInstRecursive()}; + if (!_11 || _11->GetOpcode() != IR::Opcode::BitFieldInsert) { + return false; + } + if (_11->Arg(2) != sixteen || _11->Arg(3) != sixteen) { + return false; + } + IR::Inst* const _8{_11->Arg(0).TryInstRecursive()}; + IR::Inst* const _10{_11->Arg(1).TryInstRecursive()}; + if (!_8 || !_10) { + return false; + } + if (_8->GetOpcode() != IR::Opcode::IMul32) { + return false; + } + if (_10->GetOpcode() != IR::Opcode::BitFieldUExtract) { + return false; + } + IR::Inst* const _6{_8->Arg(0).TryInstRecursive()}; + IR::Inst* const _7{_8->Arg(1).TryInstRecursive()}; + if (!_6 || !_7) { + return false; + } + if (_6->GetOpcode() != IR::Opcode::BitFieldUExtract) { + return false; + } + if (_7->GetOpcode() != IR::Opcode::BitFieldUExtract) { + return false; + } + if (_6->Arg(1) != zero || _6->Arg(2) != sixteen) { + return false; + } + if (_7->Arg(1) != sixteen || _7->Arg(2) != sixteen) { + return false; + } + IR::Inst* const _26{_27->Arg(0).TryInstRecursive()}; + IR::Inst* const _18{_27->Arg(1).TryInstRecursive()}; + if (!_26 || !_18) { + return false; + } + if (_26->GetOpcode() != IR::Opcode::ShiftLeftLogical32 || _26->Arg(1) != sixteen) { + return false; + } + if (_26->Arg(0).InstRecursive() != _11) { + return false; + } + if (_18->GetOpcode() != IR::Opcode::IAdd32) { + return false; + } + IR::Inst* const _17{_18->Arg(0).TryInstRecursive()}; + if (!_17 || _17->GetOpcode() != IR::Opcode::IMul32) { + return false; + } + IR::Inst* const _15{_17->Arg(0).TryInstRecursive()}; + IR::Inst* const _16{_17->Arg(1).TryInstRecursive()}; + if (!_15 || !_16) { + return false; + } + if (_15->GetOpcode() != IR::Opcode::BitFieldUExtract) { + return false; + } + if (_16->GetOpcode() != IR::Opcode::BitFieldUExtract) { + return false; + } + if (_15->Arg(1) != zero || _16->Arg(1) != zero || _10->Arg(1) != zero) { + return false; + } + if (_15->Arg(2) != sixteen || _16->Arg(2) != sixteen || _10->Arg(2) != sixteen) { + return false; + } + const std::array<IR::Value, 3> op_as{ + _7->Arg(0).Resolve(), + _16->Arg(0).Resolve(), + _10->Arg(0).Resolve(), + }; + const std::array<IR::Value, 3> op_bs{ + _22->Arg(0).Resolve(), + _6->Arg(0).Resolve(), + _15->Arg(0).Resolve(), + }; + const IR::U32 op_c{_18->Arg(1)}; + if (!AreEqual(op_as) || !AreEqual(op_bs)) { + return false; + } + IR::IREmitter ir{block, IR::Block::InstructionList::s_iterator_to(inst)}; + inst.ReplaceUsesWith(ir.IAdd(ir.IMul(IR::U32{op_as[0]}, IR::U32{op_bs[1]}), op_c)); + return true; +} + /// Replaces the pattern generated by two XMAD multiplications bool FoldXmadMultiply(IR::Block& block, IR::Inst& inst) { /* @@ -116,33 +288,31 @@ bool FoldXmadMultiply(IR::Block& block, IR::Inst& inst) { * * This optimization has been proven safe by LLVM and MSVC. */ - const IR::Value lhs_arg{inst.Arg(0)}; - const IR::Value rhs_arg{inst.Arg(1)}; - if (lhs_arg.IsImmediate() || rhs_arg.IsImmediate()) { + IR::Inst* const lhs_shl{inst.Arg(0).TryInstRecursive()}; + IR::Inst* const rhs_mul{inst.Arg(1).TryInstRecursive()}; + if (!lhs_shl || !rhs_mul) { return false; } - IR::Inst* const lhs_shl{lhs_arg.InstRecursive()}; if (lhs_shl->GetOpcode() != IR::Opcode::ShiftLeftLogical32 || lhs_shl->Arg(1) != IR::Value{16U}) { return false; } - if (lhs_shl->Arg(0).IsImmediate()) { + IR::Inst* const lhs_mul{lhs_shl->Arg(0).TryInstRecursive()}; + if (!lhs_mul) { return false; } - IR::Inst* const lhs_mul{lhs_shl->Arg(0).InstRecursive()}; - IR::Inst* const rhs_mul{rhs_arg.InstRecursive()}; if (lhs_mul->GetOpcode() != IR::Opcode::IMul32 || rhs_mul->GetOpcode() != IR::Opcode::IMul32) { return false; } - if (lhs_mul->Arg(1).Resolve() != rhs_mul->Arg(1).Resolve()) { + const IR::U32 factor_b{lhs_mul->Arg(1)}; + if (factor_b.Resolve() != rhs_mul->Arg(1).Resolve()) { return false; } - const IR::U32 factor_b{lhs_mul->Arg(1)}; - if (lhs_mul->Arg(0).IsImmediate() || rhs_mul->Arg(0).IsImmediate()) { + IR::Inst* const lhs_bfe{lhs_mul->Arg(0).TryInstRecursive()}; + IR::Inst* const rhs_bfe{rhs_mul->Arg(0).TryInstRecursive()}; + if (!lhs_bfe || !rhs_bfe) { return false; } - IR::Inst* const lhs_bfe{lhs_mul->Arg(0).InstRecursive()}; - IR::Inst* const rhs_bfe{rhs_mul->Arg(0).InstRecursive()}; if (lhs_bfe->GetOpcode() != IR::Opcode::BitFieldUExtract) { return false; } @@ -155,10 +325,10 @@ bool FoldXmadMultiply(IR::Block& block, IR::Inst& inst) { if (rhs_bfe->Arg(1) != IR::Value{0U} || rhs_bfe->Arg(2) != IR::Value{16U}) { return false; } - if (lhs_bfe->Arg(0).Resolve() != rhs_bfe->Arg(0).Resolve()) { + const IR::U32 factor_a{lhs_bfe->Arg(0)}; + if (factor_a.Resolve() != rhs_bfe->Arg(0).Resolve()) { return false; } - const IR::U32 factor_a{lhs_bfe->Arg(0)}; IR::IREmitter ir{block, IR::Block::InstructionList::s_iterator_to(inst)}; inst.ReplaceUsesWith(ir.IMul(factor_a, factor_b)); return true; @@ -181,6 +351,9 @@ void FoldAdd(IR::Block& block, IR::Inst& inst) { if (FoldXmadMultiply(block, inst)) { return; } + if (FoldXmadMultiplyAdd(block, inst)) { + return; + } } } @@ -476,6 +649,10 @@ void ConstantPropagation(IR::Block& block, IR::Inst& inst) { return FoldInverseFunc(inst, IR::Opcode::UnpackHalf2x16); case IR::Opcode::UnpackHalf2x16: return FoldInverseFunc(inst, IR::Opcode::PackHalf2x16); + case IR::Opcode::PackFloat2x16: + return FoldInverseFunc(inst, IR::Opcode::UnpackFloat2x16); + case IR::Opcode::UnpackFloat2x16: + return FoldInverseFunc(inst, IR::Opcode::PackFloat2x16); case IR::Opcode::SelectU1: case IR::Opcode::SelectU8: case IR::Opcode::SelectU16: diff --git a/src/video_core/texture_cache/render_targets.h b/src/video_core/texture_cache/render_targets.h index 9b9544b07..0cb227d69 100644 --- a/src/video_core/texture_cache/render_targets.h +++ b/src/video_core/texture_cache/render_targets.h @@ -24,10 +24,10 @@ struct RenderTargets { return std::ranges::any_of(color_buffer_ids, contains) || contains(depth_buffer_id); } - std::array<ImageViewId, NUM_RT> color_buffer_ids; - ImageViewId depth_buffer_id; + std::array<ImageViewId, NUM_RT> color_buffer_ids{}; + ImageViewId depth_buffer_id{}; std::array<u8, NUM_RT> draw_buffers{}; - Extent2D size; + Extent2D size{}; }; } // namespace VideoCommon diff --git a/src/yuzu/applets/qt_web_browser.cpp b/src/yuzu/applets/qt_web_browser.cpp index b112dd7b0..652d99570 100644 --- a/src/yuzu/applets/qt_web_browser.cpp +++ b/src/yuzu/applets/qt_web_browser.cpp @@ -107,6 +107,7 @@ void QtNXWebEngineView::LoadLocalWebPage(const std::string& main_url, is_local = true; LoadExtractedFonts(); + FocusFirstLinkElement(); SetUserAgent(UserAgent::WebApplet); SetFinished(false); SetExitReason(Service::AM::Applets::WebExitReason::EndButtonPressed); @@ -121,6 +122,7 @@ void QtNXWebEngineView::LoadExternalWebPage(const std::string& main_url, const std::string& additional_args) { is_local = false; + FocusFirstLinkElement(); SetUserAgent(UserAgent::WebApplet); SetFinished(false); SetExitReason(Service::AM::Applets::WebExitReason::EndButtonPressed); @@ -208,7 +210,7 @@ void QtNXWebEngineView::HandleWindowFooterButtonPressedOnce() { if (input_interpreter->IsButtonPressedOnce(button)) { page()->runJavaScript( QStringLiteral("yuzu_key_callbacks[%1] == null;").arg(static_cast<u8>(button)), - [&](const QVariant& variant) { + [this, button](const QVariant& variant) { if (variant.toBool()) { switch (button) { case HIDButton::A: @@ -364,6 +366,17 @@ void QtNXWebEngineView::LoadExtractedFonts() { Qt::QueuedConnection); } +void QtNXWebEngineView::FocusFirstLinkElement() { + QWebEngineScript focus_link_element; + + focus_link_element.setName(QStringLiteral("focus_link_element.js")); + focus_link_element.setSourceCode(QString::fromStdString(FOCUS_LINK_ELEMENT_SCRIPT)); + focus_link_element.setWorldId(QWebEngineScript::MainWorld); + focus_link_element.setInjectionPoint(QWebEngineScript::Deferred); + focus_link_element.setRunsOnSubFrames(true); + default_profile->scripts()->insert(focus_link_element); +} + #endif QtWebBrowser::QtWebBrowser(GMainWindow& main_window) { diff --git a/src/yuzu/applets/qt_web_browser.h b/src/yuzu/applets/qt_web_browser.h index 7ad07409f..7e9f703fc 100644 --- a/src/yuzu/applets/qt_web_browser.h +++ b/src/yuzu/applets/qt_web_browser.h @@ -161,6 +161,9 @@ private: /// Loads the extracted fonts using JavaScript. void LoadExtractedFonts(); + /// Brings focus to the first available link element. + void FocusFirstLinkElement(); + InputCommon::InputSubsystem* input_subsystem; std::unique_ptr<UrlRequestInterceptor> url_interceptor; diff --git a/src/yuzu/applets/qt_web_browser_scripts.h b/src/yuzu/applets/qt_web_browser_scripts.h index 992837a85..c4ba8d40f 100644 --- a/src/yuzu/applets/qt_web_browser_scripts.h +++ b/src/yuzu/applets/qt_web_browser_scripts.h @@ -73,6 +73,12 @@ constexpr char LOAD_NX_FONT[] = R"( })(); )"; +constexpr char FOCUS_LINK_ELEMENT_SCRIPT[] = R"( +if (document.getElementsByTagName("a").length > 0) { + document.getElementsByTagName("a")[0].focus(); +} +)"; + constexpr char GAMEPAD_SCRIPT[] = R"( window.addEventListener("gamepadconnected", function(e) { console.log("Gamepad connected at index %d: %s. %d buttons, %d axes.", diff --git a/src/yuzu/configuration/config.cpp b/src/yuzu/configuration/config.cpp index 91b6217db..f3b8787f5 100644 --- a/src/yuzu/configuration/config.cpp +++ b/src/yuzu/configuration/config.cpp @@ -1333,7 +1333,10 @@ void Config::SaveRendererValues() { static_cast<u32>(Settings::values.renderer_backend.GetDefault()), Settings::values.renderer_backend.UsingGlobal()); WriteGlobalSetting(Settings::values.vulkan_device); - WriteGlobalSetting(Settings::values.fullscreen_mode); + WriteSetting(QString::fromStdString(Settings::values.fullscreen_mode.GetLabel()), + static_cast<u32>(Settings::values.fullscreen_mode.GetValue(global)), + static_cast<u32>(Settings::values.fullscreen_mode.GetDefault()), + Settings::values.fullscreen_mode.UsingGlobal()); WriteGlobalSetting(Settings::values.aspect_ratio); WriteGlobalSetting(Settings::values.max_anisotropy); WriteGlobalSetting(Settings::values.use_speed_limit); diff --git a/src/yuzu/configuration/config.h b/src/yuzu/configuration/config.h index 4bbb9f1cd..c1d7feb9f 100644 --- a/src/yuzu/configuration/config.h +++ b/src/yuzu/configuration/config.h @@ -181,5 +181,6 @@ private: // These metatype declarations cannot be in common/settings.h because core is devoid of QT Q_DECLARE_METATYPE(Settings::CPUAccuracy); Q_DECLARE_METATYPE(Settings::GPUAccuracy); +Q_DECLARE_METATYPE(Settings::FullscreenMode); Q_DECLARE_METATYPE(Settings::RendererBackend); Q_DECLARE_METATYPE(Settings::ShaderBackend); diff --git a/src/yuzu/configuration/configuration_shared.cpp b/src/yuzu/configuration/configuration_shared.cpp index 096e42e94..251aab912 100644 --- a/src/yuzu/configuration/configuration_shared.cpp +++ b/src/yuzu/configuration/configuration_shared.cpp @@ -25,20 +25,6 @@ void ConfigurationShared::ApplyPerGameSetting(Settings::Setting<bool>* setting, } } -void ConfigurationShared::ApplyPerGameSetting(Settings::Setting<int>* setting, - const QComboBox* combobox) { - if (Settings::IsConfiguringGlobal() && setting->UsingGlobal()) { - setting->SetValue(combobox->currentIndex()); - } else if (!Settings::IsConfiguringGlobal()) { - if (combobox->currentIndex() == ConfigurationShared::USE_GLOBAL_INDEX) { - setting->SetGlobal(true); - } else { - setting->SetGlobal(false); - setting->SetValue(combobox->currentIndex() - ConfigurationShared::USE_GLOBAL_OFFSET); - } - } -} - void ConfigurationShared::SetPerGameSetting(QCheckBox* checkbox, const Settings::Setting<bool>* setting) { if (setting->UsingGlobal()) { diff --git a/src/yuzu/configuration/configuration_shared.h b/src/yuzu/configuration/configuration_shared.h index 1e0ef01ca..5423dbc92 100644 --- a/src/yuzu/configuration/configuration_shared.h +++ b/src/yuzu/configuration/configuration_shared.h @@ -28,7 +28,20 @@ enum class CheckState { // ApplyPerGameSetting, given a Settings::Setting and a Qt UI element, properly applies a Setting void ApplyPerGameSetting(Settings::Setting<bool>* setting, const QCheckBox* checkbox, const CheckState& tracker); -void ApplyPerGameSetting(Settings::Setting<int>* setting, const QComboBox* combobox); +template <typename Type> +void ApplyPerGameSetting(Settings::Setting<Type>* setting, const QComboBox* combobox) { + if (Settings::IsConfiguringGlobal() && setting->UsingGlobal()) { + setting->SetValue(static_cast<Type>(combobox->currentIndex())); + } else if (!Settings::IsConfiguringGlobal()) { + if (combobox->currentIndex() == ConfigurationShared::USE_GLOBAL_INDEX) { + setting->SetGlobal(true); + } else { + setting->SetGlobal(false); + setting->SetValue(static_cast<Type>(combobox->currentIndex() - + ConfigurationShared::USE_GLOBAL_OFFSET)); + } + } +} // Sets a Qt UI element given a Settings::Setting void SetPerGameSetting(QCheckBox* checkbox, const Settings::Setting<bool>* setting); diff --git a/src/yuzu/configuration/configure_cpu.cpp b/src/yuzu/configuration/configure_cpu.cpp index 8d7171487..784b6484e 100644 --- a/src/yuzu/configuration/configure_cpu.cpp +++ b/src/yuzu/configuration/configure_cpu.cpp @@ -65,6 +65,7 @@ void ConfigureCpu::UpdateGroup(int index) { } void ConfigureCpu::ApplyConfiguration() { + ConfigurationShared::ApplyPerGameSetting(&Settings::values.cpu_accuracy, ui->accuracy); ConfigurationShared::ApplyPerGameSetting(&Settings::values.cpuopt_unsafe_unfuse_fma, ui->cpuopt_unsafe_unfuse_fma, cpuopt_unsafe_unfuse_fma); @@ -80,22 +81,6 @@ void ConfigureCpu::ApplyConfiguration() { ConfigurationShared::ApplyPerGameSetting(&Settings::values.cpuopt_unsafe_fastmem_check, ui->cpuopt_unsafe_fastmem_check, cpuopt_unsafe_fastmem_check); - - if (Settings::IsConfiguringGlobal()) { - // Guard if during game and set to game-specific value - if (Settings::values.cpu_accuracy.UsingGlobal()) { - Settings::values.cpu_accuracy.SetValue( - static_cast<Settings::CPUAccuracy>(ui->accuracy->currentIndex())); - } - } else { - if (ui->accuracy->currentIndex() == ConfigurationShared::USE_GLOBAL_INDEX) { - Settings::values.cpu_accuracy.SetGlobal(true); - } else { - Settings::values.cpu_accuracy.SetGlobal(false); - Settings::values.cpu_accuracy.SetValue(static_cast<Settings::CPUAccuracy>( - ui->accuracy->currentIndex() - ConfigurationShared::USE_GLOBAL_OFFSET)); - } - } } void ConfigureCpu::changeEvent(QEvent* event) { diff --git a/src/yuzu/configuration/configure_graphics.cpp b/src/yuzu/configuration/configure_graphics.cpp index 1bc477c96..37e896258 100644 --- a/src/yuzu/configuration/configure_graphics.cpp +++ b/src/yuzu/configuration/configure_graphics.cpp @@ -98,7 +98,8 @@ void ConfigureGraphics::SetConfiguration() { if (Settings::IsConfiguringGlobal()) { ui->api->setCurrentIndex(static_cast<int>(Settings::values.renderer_backend.GetValue())); - ui->fullscreen_mode_combobox->setCurrentIndex(Settings::values.fullscreen_mode.GetValue()); + ui->fullscreen_mode_combobox->setCurrentIndex( + static_cast<int>(Settings::values.fullscreen_mode.GetValue())); ui->aspect_ratio_combobox->setCurrentIndex(Settings::values.aspect_ratio.GetValue()); } else { ConfigurationShared::SetPerGameSetting(ui->api, &Settings::values.renderer_backend); @@ -310,8 +311,9 @@ void ConfigureGraphics::SetupPerGameUI() { ConfigurationShared::SetColoredComboBox(ui->aspect_ratio_combobox, ui->ar_label, Settings::values.aspect_ratio.GetValue(true)); - ConfigurationShared::SetColoredComboBox(ui->fullscreen_mode_combobox, ui->fullscreen_mode_label, - Settings::values.fullscreen_mode.GetValue(true)); + ConfigurationShared::SetColoredComboBox( + ui->fullscreen_mode_combobox, ui->fullscreen_mode_label, + static_cast<int>(Settings::values.fullscreen_mode.GetValue(true))); ConfigurationShared::InsertGlobalItem( ui->api, static_cast<int>(Settings::values.renderer_backend.GetValue(true))); } diff --git a/src/yuzu/configuration/configure_graphics_advanced.cpp b/src/yuzu/configuration/configure_graphics_advanced.cpp index 38276feb1..a31b8e192 100644 --- a/src/yuzu/configuration/configure_graphics_advanced.cpp +++ b/src/yuzu/configuration/configure_graphics_advanced.cpp @@ -48,11 +48,7 @@ void ConfigureGraphicsAdvanced::SetConfiguration() { } void ConfigureGraphicsAdvanced::ApplyConfiguration() { - // Subtract 2 if configuring per-game (separator and "use global configuration" take 2 slots) - const auto gpu_accuracy = static_cast<Settings::GPUAccuracy>( - ui->gpu_accuracy->currentIndex() - - ((Settings::IsConfiguringGlobal()) ? 0 : ConfigurationShared::USE_GLOBAL_OFFSET)); - + ConfigurationShared::ApplyPerGameSetting(&Settings::values.gpu_accuracy, ui->gpu_accuracy); ConfigurationShared::ApplyPerGameSetting(&Settings::values.max_anisotropy, ui->anisotropic_filtering_combobox); ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_vsync, ui->use_vsync, use_vsync); @@ -63,20 +59,6 @@ void ConfigureGraphicsAdvanced::ApplyConfiguration() { use_caches_gc); ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_fast_gpu_time, ui->use_fast_gpu_time, use_fast_gpu_time); - - if (Settings::IsConfiguringGlobal()) { - // Must guard in case of a during-game configuration when set to be game-specific. - if (Settings::values.gpu_accuracy.UsingGlobal()) { - Settings::values.gpu_accuracy.SetValue(gpu_accuracy); - } - } else { - if (ui->gpu_accuracy->currentIndex() == ConfigurationShared::USE_GLOBAL_INDEX) { - Settings::values.gpu_accuracy.SetGlobal(true); - } else { - Settings::values.gpu_accuracy.SetGlobal(false); - Settings::values.gpu_accuracy.SetValue(gpu_accuracy); - } - } } void ConfigureGraphicsAdvanced::changeEvent(QEvent* event) { diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index e172d2ff4..9544f0fb0 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -2513,7 +2513,7 @@ void GMainWindow::ShowFullscreen() { ui.menubar->hide(); statusBar()->hide(); - if (Settings::values.fullscreen_mode.GetValue() == 1) { + if (Settings::values.fullscreen_mode.GetValue() == Settings::FullscreenMode::Exclusive) { showFullScreen(); return; } @@ -2528,7 +2528,7 @@ void GMainWindow::ShowFullscreen() { } else { UISettings::values.renderwindow_geometry = render_window->saveGeometry(); - if (Settings::values.fullscreen_mode.GetValue() == 1) { + if (Settings::values.fullscreen_mode.GetValue() == Settings::FullscreenMode::Exclusive) { render_window->showFullScreen(); return; } @@ -2545,7 +2545,7 @@ void GMainWindow::ShowFullscreen() { void GMainWindow::HideFullscreen() { if (ui.action_Single_Window_Mode->isChecked()) { - if (Settings::values.fullscreen_mode.GetValue() == 1) { + if (Settings::values.fullscreen_mode.GetValue() == Settings::FullscreenMode::Exclusive) { showNormal(); restoreGeometry(UISettings::values.geometry); } else { @@ -2559,7 +2559,7 @@ void GMainWindow::HideFullscreen() { statusBar()->setVisible(ui.action_Show_Status_Bar->isChecked()); ui.menubar->show(); } else { - if (Settings::values.fullscreen_mode.GetValue() == 1) { + if (Settings::values.fullscreen_mode.GetValue() == Settings::FullscreenMode::Exclusive) { render_window->showNormal(); render_window->restoreGeometry(UISettings::values.renderwindow_geometry); } else { diff --git a/src/yuzu_cmd/emu_window/emu_window_sdl2.cpp b/src/yuzu_cmd/emu_window/emu_window_sdl2.cpp index 353e51ea7..ea3e0ada4 100644 --- a/src/yuzu_cmd/emu_window/emu_window_sdl2.cpp +++ b/src/yuzu_cmd/emu_window/emu_window_sdl2.cpp @@ -124,7 +124,7 @@ void EmuWindow_SDL2::OnResize() { void EmuWindow_SDL2::Fullscreen() { switch (Settings::values.fullscreen_mode.GetValue()) { - case 1: // Exclusive fullscreen + case Settings::FullscreenMode::Exclusive: // Set window size to render size before entering fullscreen -- SDL does not resize to // display dimensions in this mode. // TODO: Multiply the window size by resolution_factor (for both docked modes) @@ -140,7 +140,7 @@ void EmuWindow_SDL2::Fullscreen() { LOG_ERROR(Frontend, "Fullscreening failed: {}", SDL_GetError()); LOG_INFO(Frontend, "Attempting to use borderless fullscreen..."); [[fallthrough]]; - case 0: // Borderless window + case Settings::FullscreenMode::Borderless: if (SDL_SetWindowFullscreen(render_window, SDL_WINDOW_FULLSCREEN_DESKTOP) == 0) { return; } |