Compare commits
43 Commits
__refs_pul
...
__refs_pul
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
275db94bb8 | ||
|
|
6ca8ed9e58 | ||
|
|
21ff0a3d6e | ||
|
|
db07ca6c7f | ||
|
|
a98f14e9b0 | ||
|
|
8c9febe8f7 | ||
|
|
23b3333f72 | ||
|
|
5acf020389 | ||
|
|
124e3b4819 | ||
|
|
f771d92e44 | ||
|
|
d05e6003f0 | ||
|
|
5593a3716e | ||
|
|
d923ec5805 | ||
|
|
1bb46b7d64 | ||
|
|
92887a65f0 | ||
|
|
6053f2e1fe | ||
|
|
353be2306c | ||
|
|
c4cd82fa7c | ||
|
|
ab206d6378 | ||
|
|
5da97c57cd | ||
|
|
2717e79c74 | ||
|
|
e2c42ec5e2 | ||
|
|
ef29ed75b0 | ||
|
|
3109d1c3db | ||
|
|
a24224e274 | ||
|
|
a6359fe9ae | ||
|
|
d7cd316a6c | ||
|
|
00e100de08 | ||
|
|
f8964dd89a | ||
|
|
ec56a17acd | ||
|
|
075a744e38 | ||
|
|
296728ec46 | ||
|
|
c27ddb44de | ||
|
|
e490ddf327 | ||
|
|
90f3678ada | ||
|
|
f5f04cce01 | ||
|
|
b9b48aee7d | ||
|
|
66a0cedba3 | ||
|
|
09fb41dc63 | ||
|
|
f6f0383b49 | ||
|
|
09d6cc9943 | ||
|
|
d8b00fd863 | ||
|
|
b11c81cc13 |
@@ -496,7 +496,7 @@ endif()
|
||||
# Ensure libusb is properly configured (based on dolphin libusb include)
|
||||
if(NOT APPLE AND NOT YUZU_USE_BUNDLED_LIBUSB)
|
||||
include(FindPkgConfig)
|
||||
if (PKG_CONFIG_FOUND)
|
||||
if (PKG_CONFIG_FOUND AND NOT CMAKE_SYSTEM_NAME MATCHES "DragonFly|FreeBSD")
|
||||
pkg_check_modules(LIBUSB QUIET libusb-1.0>=1.0.24)
|
||||
else()
|
||||
find_package(LibUSB)
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
|
||||
@@ -46,6 +46,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.
|
||||
*
|
||||
|
||||
@@ -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{};
|
||||
|
||||
@@ -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
|
||||
@@ -322,11 +327,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"};
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -339,13 +339,16 @@ std::optional<ApplicationLanguage> ConvertToApplicationLanguage(
|
||||
case Set::LanguageCode::FR_CA:
|
||||
return ApplicationLanguage::CanadianFrench;
|
||||
case Set::LanguageCode::PT:
|
||||
case Set::LanguageCode::PT_BR:
|
||||
return ApplicationLanguage::Portuguese;
|
||||
case Set::LanguageCode::RU:
|
||||
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:
|
||||
|
||||
@@ -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
|
||||
@@ -12,7 +12,7 @@
|
||||
|
||||
namespace Service::Set {
|
||||
namespace {
|
||||
constexpr std::array<LanguageCode, 17> available_language_codes = {{
|
||||
constexpr std::array<LanguageCode, 18> available_language_codes = {{
|
||||
LanguageCode::JA,
|
||||
LanguageCode::EN_US,
|
||||
LanguageCode::FR,
|
||||
@@ -30,6 +30,7 @@ constexpr std::array<LanguageCode, 17> available_language_codes = {{
|
||||
LanguageCode::ES_419,
|
||||
LanguageCode::ZH_HANS,
|
||||
LanguageCode::ZH_HANT,
|
||||
LanguageCode::PT_BR,
|
||||
}};
|
||||
|
||||
enum class KeyboardLayout : u64 {
|
||||
@@ -50,7 +51,7 @@ enum class KeyboardLayout : u64 {
|
||||
ChineseTraditional = 14,
|
||||
};
|
||||
|
||||
constexpr std::array<std::pair<LanguageCode, KeyboardLayout>, 17> language_to_layout{{
|
||||
constexpr std::array<std::pair<LanguageCode, KeyboardLayout>, 18> language_to_layout{{
|
||||
{LanguageCode::JA, KeyboardLayout::Japanese},
|
||||
{LanguageCode::EN_US, KeyboardLayout::EnglishUs},
|
||||
{LanguageCode::FR, KeyboardLayout::French},
|
||||
@@ -68,10 +69,11 @@ constexpr std::array<std::pair<LanguageCode, KeyboardLayout>, 17> language_to_la
|
||||
{LanguageCode::ES_419, KeyboardLayout::SpanishLatin},
|
||||
{LanguageCode::ZH_HANS, KeyboardLayout::ChineseSimplified},
|
||||
{LanguageCode::ZH_HANT, KeyboardLayout::ChineseTraditional},
|
||||
{LanguageCode::PT_BR, KeyboardLayout::Portuguese},
|
||||
}};
|
||||
|
||||
constexpr std::size_t pre4_0_0_max_entries = 15;
|
||||
constexpr std::size_t post4_0_0_max_entries = 17;
|
||||
constexpr std::size_t PRE_4_0_0_MAX_ENTRIES = 0xF;
|
||||
constexpr std::size_t POST_4_0_0_MAX_ENTRIES = 0x40;
|
||||
|
||||
constexpr ResultCode ERR_INVALID_LANGUAGE{ErrorModule::Settings, 625};
|
||||
|
||||
@@ -81,9 +83,9 @@ void PushResponseLanguageCode(Kernel::HLERequestContext& ctx, std::size_t num_la
|
||||
rb.Push(static_cast<u32>(num_language_codes));
|
||||
}
|
||||
|
||||
void GetAvailableLanguageCodesImpl(Kernel::HLERequestContext& ctx, std::size_t max_size) {
|
||||
void GetAvailableLanguageCodesImpl(Kernel::HLERequestContext& ctx, std::size_t max_entries) {
|
||||
const std::size_t requested_amount = ctx.GetWriteBufferSize() / sizeof(LanguageCode);
|
||||
const std::size_t copy_amount = std::min(requested_amount, max_size);
|
||||
const std::size_t copy_amount = std::min(requested_amount, max_entries);
|
||||
const std::size_t copy_size = copy_amount * sizeof(LanguageCode);
|
||||
|
||||
ctx.WriteBuffer(available_language_codes.data(), copy_size);
|
||||
@@ -118,7 +120,7 @@ LanguageCode GetLanguageCodeFromIndex(std::size_t index) {
|
||||
void SET::GetAvailableLanguageCodes(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_SET, "called");
|
||||
|
||||
GetAvailableLanguageCodesImpl(ctx, pre4_0_0_max_entries);
|
||||
GetAvailableLanguageCodesImpl(ctx, PRE_4_0_0_MAX_ENTRIES);
|
||||
}
|
||||
|
||||
void SET::MakeLanguageCode(Kernel::HLERequestContext& ctx) {
|
||||
@@ -140,19 +142,19 @@ void SET::MakeLanguageCode(Kernel::HLERequestContext& ctx) {
|
||||
void SET::GetAvailableLanguageCodes2(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_SET, "called");
|
||||
|
||||
GetAvailableLanguageCodesImpl(ctx, post4_0_0_max_entries);
|
||||
GetAvailableLanguageCodesImpl(ctx, POST_4_0_0_MAX_ENTRIES);
|
||||
}
|
||||
|
||||
void SET::GetAvailableLanguageCodeCount(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_SET, "called");
|
||||
|
||||
PushResponseLanguageCode(ctx, pre4_0_0_max_entries);
|
||||
PushResponseLanguageCode(ctx, PRE_4_0_0_MAX_ENTRIES);
|
||||
}
|
||||
|
||||
void SET::GetAvailableLanguageCodeCount2(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_SET, "called");
|
||||
|
||||
PushResponseLanguageCode(ctx, post4_0_0_max_entries);
|
||||
PushResponseLanguageCode(ctx, POST_4_0_0_MAX_ENTRIES);
|
||||
}
|
||||
|
||||
void SET::GetQuestFlag(Kernel::HLERequestContext& ctx) {
|
||||
|
||||
@@ -31,6 +31,7 @@ enum class LanguageCode : u64 {
|
||||
ES_419 = 0x00003931342D7365,
|
||||
ZH_HANS = 0x00736E61482D687A,
|
||||
ZH_HANT = 0x00746E61482D687A,
|
||||
PT_BR = 0x00000052422D7470,
|
||||
};
|
||||
LanguageCode GetLanguageCodeFromIndex(std::size_t idx);
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdexcept>
|
||||
#include <exception>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <utility>
|
||||
@@ -17,7 +17,7 @@ class Exception : public std::exception {
|
||||
public:
|
||||
explicit Exception(std::string message) noexcept : err_message{std::move(message)} {}
|
||||
|
||||
const char* what() const noexcept override {
|
||||
[[nodiscard]] const char* what() const noexcept override {
|
||||
return err_message.c_str();
|
||||
}
|
||||
|
||||
@@ -36,21 +36,21 @@ private:
|
||||
class LogicError : public Exception {
|
||||
public:
|
||||
template <typename... Args>
|
||||
LogicError(const char* message, Args&&... args)
|
||||
explicit LogicError(const char* message, Args&&... args)
|
||||
: Exception{fmt::format(fmt::runtime(message), std::forward<Args>(args)...)} {}
|
||||
};
|
||||
|
||||
class RuntimeError : public Exception {
|
||||
public:
|
||||
template <typename... Args>
|
||||
RuntimeError(const char* message, Args&&... args)
|
||||
explicit RuntimeError(const char* message, Args&&... args)
|
||||
: Exception{fmt::format(fmt::runtime(message), std::forward<Args>(args)...)} {}
|
||||
};
|
||||
|
||||
class NotImplementedException : public Exception {
|
||||
public:
|
||||
template <typename... Args>
|
||||
NotImplementedException(const char* message, Args&&... args)
|
||||
explicit NotImplementedException(const char* message, Args&&... args)
|
||||
: Exception{fmt::format(fmt::runtime(message), std::forward<Args>(args)...)} {
|
||||
Append(" is not implemented");
|
||||
}
|
||||
@@ -59,7 +59,7 @@ public:
|
||||
class InvalidArgument : public Exception {
|
||||
public:
|
||||
template <typename... Args>
|
||||
InvalidArgument(const char* message, Args&&... args)
|
||||
explicit InvalidArgument(const char* message, Args&&... args)
|
||||
: Exception{fmt::format(fmt::runtime(message), std::forward<Args>(args)...)} {}
|
||||
};
|
||||
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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()) {
|
||||
return false;
|
||||
}
|
||||
const IR::U32 factor_b{lhs_mul->Arg(1)};
|
||||
if (lhs_mul->Arg(0).IsImmediate() || rhs_mul->Arg(0).IsImmediate()) {
|
||||
if (factor_b.Resolve() != rhs_mul->Arg(1).Resolve()) {
|
||||
return false;
|
||||
}
|
||||
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:
|
||||
|
||||
@@ -817,7 +817,6 @@ void BufferCache<P>::CommitAsyncFlushesHigh() {
|
||||
const std::size_t size = interval.upper() - interval.lower();
|
||||
const VAddr cpu_addr = interval.lower();
|
||||
ForEachBufferInRange(cpu_addr, size, [&](BufferId buffer_id, Buffer& buffer) {
|
||||
boost::container::small_vector<BufferCopy, 1> copies;
|
||||
buffer.ForEachDownloadRangeAndClear(
|
||||
cpu_addr, size, [&](u64 range_offset, u64 range_size) {
|
||||
const VAddr buffer_addr = buffer.CpuAddr();
|
||||
|
||||
@@ -299,7 +299,7 @@ public:
|
||||
};
|
||||
|
||||
private:
|
||||
VideoCore::RasterizerInterface* rasterizer;
|
||||
VideoCore::RasterizerInterface* rasterizer = nullptr;
|
||||
|
||||
/// Performs the copy from the source surface to the destination surface as configured in the
|
||||
/// registers.
|
||||
|
||||
@@ -227,7 +227,7 @@ private:
|
||||
Core::System& system;
|
||||
|
||||
MemoryManager& memory_manager;
|
||||
VideoCore::RasterizerInterface* rasterizer;
|
||||
VideoCore::RasterizerInterface* rasterizer = nullptr;
|
||||
|
||||
std::vector<u8> read_buffer;
|
||||
std::vector<u8> write_buffer;
|
||||
|
||||
@@ -441,7 +441,6 @@ std::unique_ptr<GraphicsPipeline> ShaderCache::CreateGraphicsPipeline(
|
||||
|
||||
std::array<const Shader::Info*, Maxwell::MaxShaderStage> infos{};
|
||||
|
||||
OGLProgram source_program;
|
||||
std::array<std::string, 5> sources;
|
||||
std::array<std::vector<u32>, 5> sources_spirv;
|
||||
Shader::Backend::Bindings binding;
|
||||
|
||||
@@ -258,10 +258,9 @@ std::pair<VkBuffer, VkDeviceSize> Uint8Pass::Assemble(u32 num_vertices, VkBuffer
|
||||
update_descriptor_queue.AddBuffer(src_buffer, src_offset, num_vertices);
|
||||
update_descriptor_queue.AddBuffer(staging.buffer, staging.offset, staging_size);
|
||||
const void* const descriptor_data{update_descriptor_queue.UpdateData()};
|
||||
const VkBuffer buffer{staging.buffer};
|
||||
|
||||
scheduler.RequestOutsideRenderPassOperationContext();
|
||||
scheduler.Record([this, buffer, descriptor_data, num_vertices](vk::CommandBuffer cmdbuf) {
|
||||
scheduler.Record([this, descriptor_data, num_vertices](vk::CommandBuffer cmdbuf) {
|
||||
static constexpr u32 DISPATCH_SIZE = 1024;
|
||||
static constexpr VkMemoryBarrier WRITE_BARRIER{
|
||||
.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER,
|
||||
@@ -319,7 +318,7 @@ std::pair<VkBuffer, VkDeviceSize> QuadIndexedPass::Assemble(
|
||||
const void* const descriptor_data{update_descriptor_queue.UpdateData()};
|
||||
|
||||
scheduler.RequestOutsideRenderPassOperationContext();
|
||||
scheduler.Record([this, buffer = staging.buffer, descriptor_data, num_tri_vertices, base_vertex,
|
||||
scheduler.Record([this, descriptor_data, num_tri_vertices, base_vertex,
|
||||
index_shift](vk::CommandBuffer cmdbuf) {
|
||||
static constexpr u32 DISPATCH_SIZE = 1024;
|
||||
static constexpr VkMemoryBarrier WRITE_BARRIER{
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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.",
|
||||
|
||||
@@ -1332,7 +1332,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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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()) {
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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)));
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -401,6 +401,11 @@
|
||||
<string>Traditional Chinese (正體中文)</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Brazilian Portuguese (português do Brasil)</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="0">
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -363,7 +363,7 @@ custom_rtc =
|
||||
# Sets the systems language index
|
||||
# 0: Japanese, 1: English (default), 2: French, 3: German, 4: Italian, 5: Spanish, 6: Chinese,
|
||||
# 7: Korean, 8: Dutch, 9: Portuguese, 10: Russian, 11: Taiwanese, 12: British English, 13: Canadian French,
|
||||
# 14: Latin American Spanish, 15: Simplified Chinese, 16: Traditional Chinese
|
||||
# 14: Latin American Spanish, 15: Simplified Chinese, 16: Traditional Chinese, 17: Brazilian Portuguese
|
||||
language_index =
|
||||
|
||||
# The system region that yuzu will use during emulation
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user