summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/common/logging/backend.cpp9
-rw-r--r--src/common/settings.h5
-rw-r--r--src/common/threadsafe_queue.h10
-rw-r--r--src/common/x64/xbyak_abi.h2
-rw-r--r--src/common/x64/xbyak_util.h2
-rw-r--r--src/core/CMakeLists.txt2
-rw-r--r--src/core/core.cpp10
-rw-r--r--src/core/core.h7
-rw-r--r--src/core/hle/kernel/kernel.cpp23
-rw-r--r--src/core/hle/kernel/svc.cpp2
-rw-r--r--src/core/hle/service/am/applets/applet_error.cpp31
-rw-r--r--src/core/hle/service/nifm/nifm.cpp45
-rw-r--r--src/core/hle/service/vi/vi.cpp2
-rw-r--r--src/core/network/network.cpp64
-rw-r--r--src/core/network/network.h24
-rw-r--r--src/core/network/network_interface.cpp203
-rw-r--r--src/core/network/network_interface.h29
-rw-r--r--src/shader_recompiler/backend/spirv/emit_spirv_context_get_set.cpp8
-rw-r--r--src/video_core/macro/macro_jit_x64.h2
-rw-r--r--src/video_core/memory_manager.cpp1
-rw-r--r--src/video_core/renderer_vulkan/vk_pipeline_cache.cpp2
-rw-r--r--src/video_core/textures/decoders.cpp173
-rw-r--r--src/video_core/textures/texture.h2
-rw-r--r--src/video_core/vulkan_common/vulkan_device.cpp16
-rw-r--r--src/video_core/vulkan_common/vulkan_device.h10
-rw-r--r--src/yuzu/CMakeLists.txt15
-rw-r--r--src/yuzu/applets/qt_software_keyboard.cpp2
-rw-r--r--src/yuzu/configuration/config.cpp6
-rw-r--r--src/yuzu/configuration/config.h2
-rw-r--r--src/yuzu/configuration/configure.ui10
-rw-r--r--src/yuzu/configuration/configure_dialog.cpp4
-rw-r--r--src/yuzu/configuration/configure_input_player_widget.cpp34
-rw-r--r--src/yuzu/configuration/configure_network.cpp (renamed from src/yuzu/configuration/configure_service.cpp)39
-rw-r--r--src/yuzu/configuration/configure_network.h (renamed from src/yuzu/configuration/configure_service.h)10
-rw-r--r--src/yuzu/configuration/configure_network.ui (renamed from src/yuzu/configuration/configure_service.ui)63
-rw-r--r--src/yuzu/main.cpp2
36 files changed, 638 insertions, 233 deletions
diff --git a/src/common/logging/backend.cpp b/src/common/logging/backend.cpp
index 4e7cfdc99..6f1d251e1 100644
--- a/src/common/logging/backend.cpp
+++ b/src/common/logging/backend.cpp
@@ -5,6 +5,7 @@
5#include <atomic> 5#include <atomic>
6#include <chrono> 6#include <chrono>
7#include <climits> 7#include <climits>
8#include <exception>
8#include <thread> 9#include <thread>
9#include <vector> 10#include <vector>
10 11
@@ -160,7 +161,7 @@ public:
160 void EnableForStacktrace() override {} 161 void EnableForStacktrace() override {}
161}; 162};
162 163
163bool initialization_in_progress_suppress_logging = false; 164bool initialization_in_progress_suppress_logging = true;
164 165
165#ifdef YUZU_LINUX_GCC_BACKTRACE 166#ifdef YUZU_LINUX_GCC_BACKTRACE
166[[noreturn]] void SleepForever() { 167[[noreturn]] void SleepForever() {
@@ -177,17 +178,17 @@ class Impl {
177public: 178public:
178 static Impl& Instance() { 179 static Impl& Instance() {
179 if (!instance) { 180 if (!instance) {
180 abort(); 181 throw std::runtime_error("Using Logging instance before its initialization");
181 } 182 }
182 return *instance; 183 return *instance;
183 } 184 }
184 185
185 static void Initialize() { 186 static void Initialize() {
186 if (instance) { 187 if (instance) {
187 abort(); 188 LOG_WARNING(Log, "Reinitializing logging backend");
189 return;
188 } 190 }
189 using namespace Common::FS; 191 using namespace Common::FS;
190 initialization_in_progress_suppress_logging = true;
191 const auto& log_dir = GetYuzuPath(YuzuPath::LogDir); 192 const auto& log_dir = GetYuzuPath(YuzuPath::LogDir);
192 void(CreateDir(log_dir)); 193 void(CreateDir(log_dir));
193 Filter filter; 194 Filter filter;
diff --git a/src/common/settings.h b/src/common/settings.h
index 1ba9b606c..20769d310 100644
--- a/src/common/settings.h
+++ b/src/common/settings.h
@@ -489,7 +489,7 @@ struct Values {
489 std::chrono::seconds custom_rtc_differential; 489 std::chrono::seconds custom_rtc_differential;
490 490
491 BasicSetting<s32> current_user{0, "current_user"}; 491 BasicSetting<s32> current_user{0, "current_user"};
492 RangedSetting<s32> language_index{1, 0, 16, "language_index"}; 492 RangedSetting<s32> language_index{1, 0, 17, "language_index"};
493 RangedSetting<s32> region_index{1, 0, 6, "region_index"}; 493 RangedSetting<s32> region_index{1, 0, 6, "region_index"};
494 RangedSetting<s32> time_zone_index{0, 0, 45, "time_zone_index"}; 494 RangedSetting<s32> time_zone_index{0, 0, 45, "time_zone_index"};
495 RangedSetting<s32> sound_index{1, 0, 2, "sound_index"}; 495 RangedSetting<s32> sound_index{1, 0, 2, "sound_index"};
@@ -558,9 +558,10 @@ struct Values {
558 BasicSetting<std::string> log_filter{"*:Info", "log_filter"}; 558 BasicSetting<std::string> log_filter{"*:Info", "log_filter"};
559 BasicSetting<bool> use_dev_keys{false, "use_dev_keys"}; 559 BasicSetting<bool> use_dev_keys{false, "use_dev_keys"};
560 560
561 // Services 561 // Network
562 BasicSetting<std::string> bcat_backend{"none", "bcat_backend"}; 562 BasicSetting<std::string> bcat_backend{"none", "bcat_backend"};
563 BasicSetting<bool> bcat_boxcat_local{false, "bcat_boxcat_local"}; 563 BasicSetting<bool> bcat_boxcat_local{false, "bcat_boxcat_local"};
564 BasicSetting<std::string> network_interface{std::string(), "network_interface"};
564 565
565 // WebService 566 // WebService
566 BasicSetting<bool> enable_telemetry{true, "enable_telemetry"}; 567 BasicSetting<bool> enable_telemetry{true, "enable_telemetry"};
diff --git a/src/common/threadsafe_queue.h b/src/common/threadsafe_queue.h
index ad04df8ca..8430b9778 100644
--- a/src/common/threadsafe_queue.h
+++ b/src/common/threadsafe_queue.h
@@ -46,15 +46,13 @@ public:
46 ElementPtr* new_ptr = new ElementPtr(); 46 ElementPtr* new_ptr = new ElementPtr();
47 write_ptr->next.store(new_ptr, std::memory_order_release); 47 write_ptr->next.store(new_ptr, std::memory_order_release);
48 write_ptr = new_ptr; 48 write_ptr = new_ptr;
49 ++size;
49 50
50 const size_t previous_size{size++}; 51 // cv_mutex must be held or else there will be a missed wakeup if the other thread is in the
51 52 // line before cv.wait
52 // Acquire the mutex and then immediately release it as a fence.
53 // TODO(bunnei): This can be replaced with C++20 waitable atomics when properly supported. 53 // TODO(bunnei): This can be replaced with C++20 waitable atomics when properly supported.
54 // See discussion on https://github.com/yuzu-emu/yuzu/pull/3173 for details. 54 // See discussion on https://github.com/yuzu-emu/yuzu/pull/3173 for details.
55 if (previous_size == 0) { 55 std::lock_guard lock{cv_mutex};
56 std::lock_guard lock{cv_mutex};
57 }
58 cv.notify_one(); 56 cv.notify_one();
59 } 57 }
60 58
diff --git a/src/common/x64/xbyak_abi.h b/src/common/x64/xbyak_abi.h
index c2c9b6134..0ddf9b83e 100644
--- a/src/common/x64/xbyak_abi.h
+++ b/src/common/x64/xbyak_abi.h
@@ -6,7 +6,7 @@
6 6
7#include <bitset> 7#include <bitset>
8#include <initializer_list> 8#include <initializer_list>
9#include <xbyak.h> 9#include <xbyak/xbyak.h>
10#include "common/assert.h" 10#include "common/assert.h"
11 11
12namespace Common::X64 { 12namespace Common::X64 {
diff --git a/src/common/x64/xbyak_util.h b/src/common/x64/xbyak_util.h
index df17f8cbe..44d2558f1 100644
--- a/src/common/x64/xbyak_util.h
+++ b/src/common/x64/xbyak_util.h
@@ -5,7 +5,7 @@
5#pragma once 5#pragma once
6 6
7#include <type_traits> 7#include <type_traits>
8#include <xbyak.h> 8#include <xbyak/xbyak.h>
9#include "common/x64/xbyak_abi.h" 9#include "common/x64/xbyak_abi.h"
10 10
11namespace Common::X64 { 11namespace Common::X64 {
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index 5c99c00f5..f5cf5c16a 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -636,6 +636,8 @@ add_library(core STATIC
636 memory.h 636 memory.h
637 network/network.cpp 637 network/network.cpp
638 network/network.h 638 network/network.h
639 network/network_interface.cpp
640 network/network_interface.h
639 network/sockets.h 641 network/sockets.h
640 perf_stats.cpp 642 perf_stats.cpp
641 perf_stats.h 643 perf_stats.h
diff --git a/src/core/core.cpp b/src/core/core.cpp
index 0d3c4182a..ba4629993 100644
--- a/src/core/core.cpp
+++ b/src/core/core.cpp
@@ -4,6 +4,7 @@
4 4
5#include <array> 5#include <array>
6#include <atomic> 6#include <atomic>
7#include <exception>
7#include <memory> 8#include <memory>
8#include <utility> 9#include <utility>
9 10
@@ -423,9 +424,16 @@ struct System::Impl {
423System::System() : impl{std::make_unique<Impl>(*this)} {} 424System::System() : impl{std::make_unique<Impl>(*this)} {}
424System::~System() = default; 425System::~System() = default;
425 426
427System& System::GetInstance() {
428 if (!s_instance) {
429 throw std::runtime_error("Using System instance before its initialization");
430 }
431 return *s_instance;
432}
433
426void System::InitializeGlobalInstance() { 434void System::InitializeGlobalInstance() {
427 if (s_instance) { 435 if (s_instance) {
428 abort(); 436 throw std::runtime_error("Reinitializing Global System instance.");
429 } 437 }
430 s_instance = std::unique_ptr<System>(new System); 438 s_instance = std::unique_ptr<System>(new System);
431} 439}
diff --git a/src/core/core.h b/src/core/core.h
index 85836f2f8..715ab88e7 100644
--- a/src/core/core.h
+++ b/src/core/core.h
@@ -120,12 +120,7 @@ public:
120 * Gets the instance of the System singleton class. 120 * Gets the instance of the System singleton class.
121 * @returns Reference to the instance of the System singleton class. 121 * @returns Reference to the instance of the System singleton class.
122 */ 122 */
123 [[deprecated("Use of the global system instance is deprecated")]] static System& GetInstance() { 123 [[deprecated("Use of the global system instance is deprecated")]] static System& GetInstance();
124 if (!s_instance) {
125 abort();
126 }
127 return *s_instance;
128 }
129 124
130 static void InitializeGlobalInstance(); 125 static void InitializeGlobalInstance();
131 126
diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp
index 92fbc5532..bea945301 100644
--- a/src/core/hle/kernel/kernel.cpp
+++ b/src/core/hle/kernel/kernel.cpp
@@ -267,20 +267,23 @@ struct KernelCore::Impl {
267 } 267 }
268 } 268 }
269 269
270 /// Creates a new host thread ID, should only be called by GetHostThreadId 270 static inline thread_local u32 host_thread_id = UINT32_MAX;
271 u32 AllocateHostThreadId(std::optional<std::size_t> core_id) { 271
272 if (core_id) { 272 /// Gets the host thread ID for the caller, allocating a new one if this is the first time
273 // The first for slots are reserved for CPU core threads 273 u32 GetHostThreadId(std::size_t core_id) {
274 ASSERT(*core_id < Core::Hardware::NUM_CPU_CORES); 274 if (host_thread_id == UINT32_MAX) {
275 return static_cast<u32>(*core_id); 275 // The first four slots are reserved for CPU core threads
276 } else { 276 ASSERT(core_id < Core::Hardware::NUM_CPU_CORES);
277 return next_host_thread_id++; 277 host_thread_id = static_cast<u32>(core_id);
278 } 278 }
279 return host_thread_id;
279 } 280 }
280 281
281 /// Gets the host thread ID for the caller, allocating a new one if this is the first time 282 /// Gets the host thread ID for the caller, allocating a new one if this is the first time
282 u32 GetHostThreadId(std::optional<std::size_t> core_id = std::nullopt) { 283 u32 GetHostThreadId() {
283 const thread_local auto host_thread_id{AllocateHostThreadId(core_id)}; 284 if (host_thread_id == UINT32_MAX) {
285 host_thread_id = next_host_thread_id++;
286 }
284 return host_thread_id; 287 return host_thread_id;
285 } 288 }
286 289
diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp
index 2eb532472..62fb06c45 100644
--- a/src/core/hle/kernel/svc.cpp
+++ b/src/core/hle/kernel/svc.cpp
@@ -1078,8 +1078,8 @@ static ResultCode GetThreadContext(Core::System& system, VAddr out_context, Hand
1078 for (auto i = 0; i < static_cast<s32>(Core::Hardware::NUM_CPU_CORES); ++i) { 1078 for (auto i = 0; i < static_cast<s32>(Core::Hardware::NUM_CPU_CORES); ++i) {
1079 if (thread.GetPointerUnsafe() == kernel.Scheduler(i).GetCurrentThread()) { 1079 if (thread.GetPointerUnsafe() == kernel.Scheduler(i).GetCurrentThread()) {
1080 current = true; 1080 current = true;
1081 break;
1081 } 1082 }
1082 break;
1083 } 1083 }
1084 1084
1085 // If the thread is current, retry until it isn't. 1085 // If the thread is current, retry until it isn't.
diff --git a/src/core/hle/service/am/applets/applet_error.cpp b/src/core/hle/service/am/applets/applet_error.cpp
index ef6854d62..36a4aa9cd 100644
--- a/src/core/hle/service/am/applets/applet_error.cpp
+++ b/src/core/hle/service/am/applets/applet_error.cpp
@@ -16,6 +16,30 @@
16 16
17namespace Service::AM::Applets { 17namespace Service::AM::Applets {
18 18
19struct ErrorCode {
20 u32 error_category{};
21 u32 error_number{};
22
23 static constexpr ErrorCode FromU64(u64 error_code) {
24 return {
25 .error_category{static_cast<u32>(error_code >> 32)},
26 .error_number{static_cast<u32>(error_code & 0xFFFFFFFF)},
27 };
28 }
29
30 static constexpr ErrorCode FromResultCode(ResultCode result) {
31 return {
32 .error_category{2000 + static_cast<u32>(result.module.Value())},
33 .error_number{result.description.Value()},
34 };
35 }
36
37 constexpr ResultCode ToResultCode() const {
38 return ResultCode{static_cast<ErrorModule>(error_category - 2000), error_number};
39 }
40};
41static_assert(sizeof(ErrorCode) == 0x8, "ErrorCode has incorrect size.");
42
19#pragma pack(push, 4) 43#pragma pack(push, 4)
20struct ShowError { 44struct ShowError {
21 u8 mode; 45 u8 mode;
@@ -76,12 +100,7 @@ void CopyArgumentData(const std::vector<u8>& data, T& variable) {
76} 100}
77 101
78ResultCode Decode64BitError(u64 error) { 102ResultCode Decode64BitError(u64 error) {
79 const auto description = (error >> 32) & 0x1FFF; 103 return ErrorCode::FromU64(error).ToResultCode();
80 auto module = error & 0x3FF;
81 if (module >= 2000)
82 module -= 2000;
83 module &= 0x1FF;
84 return {static_cast<ErrorModule>(module), static_cast<u32>(description)};
85} 104}
86 105
87} // Anonymous namespace 106} // Anonymous namespace
diff --git a/src/core/hle/service/nifm/nifm.cpp b/src/core/hle/service/nifm/nifm.cpp
index e742db48f..0a53c0c81 100644
--- a/src/core/hle/service/nifm/nifm.cpp
+++ b/src/core/hle/service/nifm/nifm.cpp
@@ -11,6 +11,7 @@
11#include "core/hle/service/nifm/nifm.h" 11#include "core/hle/service/nifm/nifm.h"
12#include "core/hle/service/service.h" 12#include "core/hle/service/service.h"
13#include "core/network/network.h" 13#include "core/network/network.h"
14#include "core/network/network_interface.h"
14 15
15namespace Service::NIFM { 16namespace Service::NIFM {
16 17
@@ -179,10 +180,10 @@ private:
179 IPC::ResponseBuilder rb{ctx, 3}; 180 IPC::ResponseBuilder rb{ctx, 3};
180 rb.Push(ResultSuccess); 181 rb.Push(ResultSuccess);
181 182
182 if (Settings::values.bcat_backend.GetValue() == "none") { 183 if (Network::GetHostIPv4Address().has_value()) {
183 rb.PushEnum(RequestState::NotSubmitted);
184 } else {
185 rb.PushEnum(RequestState::Connected); 184 rb.PushEnum(RequestState::Connected);
185 } else {
186 rb.PushEnum(RequestState::NotSubmitted);
186 } 187 }
187 } 188 }
188 189
@@ -322,12 +323,15 @@ private:
322 void GetCurrentIpAddress(Kernel::HLERequestContext& ctx) { 323 void GetCurrentIpAddress(Kernel::HLERequestContext& ctx) {
323 LOG_WARNING(Service_NIFM, "(STUBBED) called"); 324 LOG_WARNING(Service_NIFM, "(STUBBED) called");
324 325
325 const auto [ipv4, error] = Network::GetHostIPv4Address(); 326 auto ipv4 = Network::GetHostIPv4Address();
326 UNIMPLEMENTED_IF(error != Network::Errno::SUCCESS); 327 if (!ipv4) {
328 LOG_ERROR(Service_NIFM, "Couldn't get host IPv4 address, defaulting to 0.0.0.0");
329 ipv4.emplace(Network::IPv4Address{0, 0, 0, 0});
330 }
327 331
328 IPC::ResponseBuilder rb{ctx, 3}; 332 IPC::ResponseBuilder rb{ctx, 3};
329 rb.Push(ResultSuccess); 333 rb.Push(ResultSuccess);
330 rb.PushRaw(ipv4); 334 rb.PushRaw(*ipv4);
331 } 335 }
332 void CreateTemporaryNetworkProfile(Kernel::HLERequestContext& ctx) { 336 void CreateTemporaryNetworkProfile(Kernel::HLERequestContext& ctx) {
333 LOG_DEBUG(Service_NIFM, "called"); 337 LOG_DEBUG(Service_NIFM, "called");
@@ -354,10 +358,10 @@ private:
354 static_assert(sizeof(IpConfigInfo) == sizeof(IpAddressSetting) + sizeof(DnsSetting), 358 static_assert(sizeof(IpConfigInfo) == sizeof(IpAddressSetting) + sizeof(DnsSetting),
355 "IpConfigInfo has incorrect size."); 359 "IpConfigInfo has incorrect size.");
356 360
357 const IpConfigInfo ip_config_info{ 361 IpConfigInfo ip_config_info{
358 .ip_address_setting{ 362 .ip_address_setting{
359 .is_automatic{true}, 363 .is_automatic{true},
360 .current_address{192, 168, 1, 100}, 364 .current_address{0, 0, 0, 0},
361 .subnet_mask{255, 255, 255, 0}, 365 .subnet_mask{255, 255, 255, 0},
362 .gateway{192, 168, 1, 1}, 366 .gateway{192, 168, 1, 1},
363 }, 367 },
@@ -368,6 +372,19 @@ private:
368 }, 372 },
369 }; 373 };
370 374
375 const auto iface = Network::GetSelectedNetworkInterface();
376 if (iface) {
377 ip_config_info.ip_address_setting =
378 IpAddressSetting{.is_automatic{true},
379 .current_address{Network::TranslateIPv4(iface->ip_address)},
380 .subnet_mask{Network::TranslateIPv4(iface->subnet_mask)},
381 .gateway{Network::TranslateIPv4(iface->gateway)}};
382
383 } else {
384 LOG_ERROR(Service_NIFM,
385 "Couldn't get host network configuration info, using default values");
386 }
387
371 IPC::ResponseBuilder rb{ctx, 2 + (sizeof(IpConfigInfo) + 3) / sizeof(u32)}; 388 IPC::ResponseBuilder rb{ctx, 2 + (sizeof(IpConfigInfo) + 3) / sizeof(u32)};
372 rb.Push(ResultSuccess); 389 rb.Push(ResultSuccess);
373 rb.PushRaw<IpConfigInfo>(ip_config_info); 390 rb.PushRaw<IpConfigInfo>(ip_config_info);
@@ -384,10 +401,10 @@ private:
384 401
385 IPC::ResponseBuilder rb{ctx, 3}; 402 IPC::ResponseBuilder rb{ctx, 3};
386 rb.Push(ResultSuccess); 403 rb.Push(ResultSuccess);
387 if (Settings::values.bcat_backend.GetValue() == "none") { 404 if (Network::GetHostIPv4Address().has_value()) {
388 rb.Push<u8>(0);
389 } else {
390 rb.Push<u8>(1); 405 rb.Push<u8>(1);
406 } else {
407 rb.Push<u8>(0);
391 } 408 }
392 } 409 }
393 void IsAnyInternetRequestAccepted(Kernel::HLERequestContext& ctx) { 410 void IsAnyInternetRequestAccepted(Kernel::HLERequestContext& ctx) {
@@ -395,10 +412,10 @@ private:
395 412
396 IPC::ResponseBuilder rb{ctx, 3}; 413 IPC::ResponseBuilder rb{ctx, 3};
397 rb.Push(ResultSuccess); 414 rb.Push(ResultSuccess);
398 if (Settings::values.bcat_backend.GetValue() == "none") { 415 if (Network::GetHostIPv4Address().has_value()) {
399 rb.Push<u8>(0);
400 } else {
401 rb.Push<u8>(1); 416 rb.Push<u8>(1);
417 } else {
418 rb.Push<u8>(0);
402 } 419 }
403 } 420 }
404}; 421};
diff --git a/src/core/hle/service/vi/vi.cpp b/src/core/hle/service/vi/vi.cpp
index 3e5949d52..8e8fc40ca 100644
--- a/src/core/hle/service/vi/vi.cpp
+++ b/src/core/hle/service/vi/vi.cpp
@@ -1158,7 +1158,7 @@ private:
1158 1158
1159 const auto layer_id = nv_flinger.CreateLayer(display_id); 1159 const auto layer_id = nv_flinger.CreateLayer(display_id);
1160 if (!layer_id) { 1160 if (!layer_id) {
1161 LOG_ERROR(Service_VI, "Layer not found! layer_id={}", *layer_id); 1161 LOG_ERROR(Service_VI, "Layer not found! display_id={}", display_id);
1162 IPC::ResponseBuilder rb{ctx, 2}; 1162 IPC::ResponseBuilder rb{ctx, 2};
1163 rb.Push(ERR_NOT_FOUND); 1163 rb.Push(ERR_NOT_FOUND);
1164 return; 1164 return;
diff --git a/src/core/network/network.cpp b/src/core/network/network.cpp
index 375bc79ec..4732d4485 100644
--- a/src/core/network/network.cpp
+++ b/src/core/network/network.cpp
@@ -10,9 +10,10 @@
10#include "common/common_funcs.h" 10#include "common/common_funcs.h"
11 11
12#ifdef _WIN32 12#ifdef _WIN32
13#define _WINSOCK_DEPRECATED_NO_WARNINGS // gethostname
14#include <winsock2.h> 13#include <winsock2.h>
14#include <ws2tcpip.h>
15#elif YUZU_UNIX 15#elif YUZU_UNIX
16#include <arpa/inet.h>
16#include <errno.h> 17#include <errno.h>
17#include <fcntl.h> 18#include <fcntl.h>
18#include <netdb.h> 19#include <netdb.h>
@@ -27,7 +28,9 @@
27#include "common/assert.h" 28#include "common/assert.h"
28#include "common/common_types.h" 29#include "common/common_types.h"
29#include "common/logging/log.h" 30#include "common/logging/log.h"
31#include "common/settings.h"
30#include "core/network/network.h" 32#include "core/network/network.h"
33#include "core/network/network_interface.h"
31#include "core/network/sockets.h" 34#include "core/network/sockets.h"
32 35
33namespace Network { 36namespace Network {
@@ -47,11 +50,6 @@ void Finalize() {
47 WSACleanup(); 50 WSACleanup();
48} 51}
49 52
50constexpr IPv4Address TranslateIPv4(in_addr addr) {
51 auto& bytes = addr.S_un.S_un_b;
52 return IPv4Address{bytes.s_b1, bytes.s_b2, bytes.s_b3, bytes.s_b4};
53}
54
55sockaddr TranslateFromSockAddrIn(SockAddrIn input) { 53sockaddr TranslateFromSockAddrIn(SockAddrIn input) {
56 sockaddr_in result; 54 sockaddr_in result;
57 55
@@ -138,12 +136,6 @@ void Initialize() {}
138 136
139void Finalize() {} 137void Finalize() {}
140 138
141constexpr IPv4Address TranslateIPv4(in_addr addr) {
142 const u32 bytes = addr.s_addr;
143 return IPv4Address{static_cast<u8>(bytes), static_cast<u8>(bytes >> 8),
144 static_cast<u8>(bytes >> 16), static_cast<u8>(bytes >> 24)};
145}
146
147sockaddr TranslateFromSockAddrIn(SockAddrIn input) { 139sockaddr TranslateFromSockAddrIn(SockAddrIn input) {
148 sockaddr_in result; 140 sockaddr_in result;
149 141
@@ -182,7 +174,7 @@ linger MakeLinger(bool enable, u32 linger_value) {
182} 174}
183 175
184bool EnableNonBlock(int fd, bool enable) { 176bool EnableNonBlock(int fd, bool enable) {
185 int flags = fcntl(fd, F_GETFD); 177 int flags = fcntl(fd, F_GETFL);
186 if (flags == -1) { 178 if (flags == -1) {
187 return false; 179 return false;
188 } 180 }
@@ -191,7 +183,7 @@ bool EnableNonBlock(int fd, bool enable) {
191 } else { 183 } else {
192 flags &= ~O_NONBLOCK; 184 flags &= ~O_NONBLOCK;
193 } 185 }
194 return fcntl(fd, F_SETFD, flags) == 0; 186 return fcntl(fd, F_SETFL, flags) == 0;
195} 187}
196 188
197Errno TranslateNativeError(int e) { 189Errno TranslateNativeError(int e) {
@@ -227,8 +219,12 @@ Errno GetAndLogLastError() {
227#else 219#else
228 int e = errno; 220 int e = errno;
229#endif 221#endif
222 const Errno err = TranslateNativeError(e);
223 if (err == Errno::AGAIN) {
224 return err;
225 }
230 LOG_ERROR(Network, "Socket operation error: {}", NativeErrorToString(e)); 226 LOG_ERROR(Network, "Socket operation error: {}", NativeErrorToString(e));
231 return TranslateNativeError(e); 227 return err;
232} 228}
233 229
234int TranslateDomain(Domain domain) { 230int TranslateDomain(Domain domain) {
@@ -353,27 +349,29 @@ NetworkInstance::~NetworkInstance() {
353 Finalize(); 349 Finalize();
354} 350}
355 351
356std::pair<IPv4Address, Errno> GetHostIPv4Address() { 352std::optional<IPv4Address> GetHostIPv4Address() {
357 std::array<char, 256> name{}; 353 const std::string& selected_network_interface = Settings::values.network_interface.GetValue();
358 if (gethostname(name.data(), static_cast<int>(name.size()) - 1) == SOCKET_ERROR) { 354 const auto network_interfaces = Network::GetAvailableNetworkInterfaces();
359 return {IPv4Address{}, GetAndLogLastError()}; 355 if (network_interfaces.size() == 0) {
356 LOG_ERROR(Network, "GetAvailableNetworkInterfaces returned no interfaces");
357 return {};
360 } 358 }
361 359
362 hostent* const ent = gethostbyname(name.data()); 360 const auto res =
363 if (!ent) { 361 std::ranges::find_if(network_interfaces, [&selected_network_interface](const auto& iface) {
364 return {IPv4Address{}, GetAndLogLastError()}; 362 return iface.name == selected_network_interface;
365 } 363 });
366 if (ent->h_addr_list == nullptr) { 364
367 UNIMPLEMENTED_MSG("No addr provided in hostent->h_addr_list"); 365 if (res != network_interfaces.end()) {
368 return {IPv4Address{}, Errno::SUCCESS}; 366 char ip_addr[16] = {};
369 } 367 ASSERT(inet_ntop(AF_INET, &res->ip_address, ip_addr, sizeof(ip_addr)) != nullptr);
370 if (ent->h_length != sizeof(in_addr)) { 368 LOG_INFO(Network, "IP address: {}", ip_addr);
371 UNIMPLEMENTED_MSG("Unexpected size={} in hostent->h_length", ent->h_length);
372 }
373 369
374 in_addr addr; 370 return TranslateIPv4(res->ip_address);
375 std::memcpy(&addr, ent->h_addr_list[0], sizeof(addr)); 371 } else {
376 return {TranslateIPv4(addr), Errno::SUCCESS}; 372 LOG_ERROR(Network, "Couldn't find selected interface \"{}\"", selected_network_interface);
373 return {};
374 }
377} 375}
378 376
379std::pair<s32, Errno> Poll(std::vector<PollFD>& pollfds, s32 timeout) { 377std::pair<s32, Errno> Poll(std::vector<PollFD>& pollfds, s32 timeout) {
diff --git a/src/core/network/network.h b/src/core/network/network.h
index bd30f1899..fdd3e4655 100644
--- a/src/core/network/network.h
+++ b/src/core/network/network.h
@@ -5,11 +5,18 @@
5#pragma once 5#pragma once
6 6
7#include <array> 7#include <array>
8#include <optional>
8#include <utility> 9#include <utility>
9 10
10#include "common/common_funcs.h" 11#include "common/common_funcs.h"
11#include "common/common_types.h" 12#include "common/common_types.h"
12 13
14#ifdef _WIN32
15#include <winsock2.h>
16#elif YUZU_UNIX
17#include <netinet/in.h>
18#endif
19
13namespace Network { 20namespace Network {
14 21
15class Socket; 22class Socket;
@@ -92,8 +99,21 @@ public:
92 ~NetworkInstance(); 99 ~NetworkInstance();
93}; 100};
94 101
102#ifdef _WIN32
103constexpr IPv4Address TranslateIPv4(in_addr addr) {
104 auto& bytes = addr.S_un.S_un_b;
105 return IPv4Address{bytes.s_b1, bytes.s_b2, bytes.s_b3, bytes.s_b4};
106}
107#elif YUZU_UNIX
108constexpr IPv4Address TranslateIPv4(in_addr addr) {
109 const u32 bytes = addr.s_addr;
110 return IPv4Address{static_cast<u8>(bytes), static_cast<u8>(bytes >> 8),
111 static_cast<u8>(bytes >> 16), static_cast<u8>(bytes >> 24)};
112}
113#endif
114
95/// @brief Returns host's IPv4 address 115/// @brief Returns host's IPv4 address
96/// @return Pair of an array of human ordered IPv4 address (e.g. 192.168.0.1) and an error code 116/// @return human ordered IPv4 address (e.g. 192.168.0.1) as an array
97std::pair<IPv4Address, Errno> GetHostIPv4Address(); 117std::optional<IPv4Address> GetHostIPv4Address();
98 118
99} // namespace Network 119} // namespace Network
diff --git a/src/core/network/network_interface.cpp b/src/core/network/network_interface.cpp
new file mode 100644
index 000000000..cecc9aa11
--- /dev/null
+++ b/src/core/network/network_interface.cpp
@@ -0,0 +1,203 @@
1// Copyright 2021 yuzu emulator team
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include <algorithm>
6#include <fstream>
7#include <sstream>
8#include <vector>
9
10#include "common/bit_cast.h"
11#include "common/common_types.h"
12#include "common/logging/log.h"
13#include "common/settings.h"
14#include "common/string_util.h"
15#include "core/network/network_interface.h"
16
17#ifdef _WIN32
18#include <iphlpapi.h>
19#else
20#include <cerrno>
21#include <ifaddrs.h>
22#include <net/if.h>
23#endif
24
25namespace Network {
26
27#ifdef _WIN32
28
29std::vector<NetworkInterface> GetAvailableNetworkInterfaces() {
30 std::vector<IP_ADAPTER_ADDRESSES> adapter_addresses;
31 DWORD ret = ERROR_BUFFER_OVERFLOW;
32 DWORD buf_size = 0;
33
34 // retry up to 5 times
35 for (int i = 0; i < 5 && ret == ERROR_BUFFER_OVERFLOW; i++) {
36 ret = GetAdaptersAddresses(
37 AF_INET, GAA_FLAG_SKIP_MULTICAST | GAA_FLAG_SKIP_DNS_SERVER | GAA_FLAG_INCLUDE_GATEWAYS,
38 nullptr, adapter_addresses.data(), &buf_size);
39
40 if (ret == ERROR_BUFFER_OVERFLOW) {
41 adapter_addresses.resize((buf_size / sizeof(IP_ADAPTER_ADDRESSES)) + 1);
42 } else {
43 break;
44 }
45 }
46
47 if (ret == NO_ERROR) {
48 std::vector<NetworkInterface> result;
49
50 for (auto current_address = adapter_addresses.data(); current_address != nullptr;
51 current_address = current_address->Next) {
52 if (current_address->FirstUnicastAddress == nullptr ||
53 current_address->FirstUnicastAddress->Address.lpSockaddr == nullptr) {
54 continue;
55 }
56
57 if (current_address->OperStatus != IfOperStatusUp) {
58 continue;
59 }
60
61 const auto ip_addr = Common::BitCast<struct sockaddr_in>(
62 *current_address->FirstUnicastAddress->Address.lpSockaddr)
63 .sin_addr;
64
65 ULONG mask = 0;
66 if (ConvertLengthToIpv4Mask(current_address->FirstUnicastAddress->OnLinkPrefixLength,
67 &mask) != NO_ERROR) {
68 LOG_ERROR(Network, "Failed to convert IPv4 prefix length to subnet mask");
69 continue;
70 }
71
72 struct in_addr gateway = {.S_un{.S_addr{0}}};
73 if (current_address->FirstGatewayAddress != nullptr &&
74 current_address->FirstGatewayAddress->Address.lpSockaddr != nullptr) {
75 gateway = Common::BitCast<struct sockaddr_in>(
76 *current_address->FirstGatewayAddress->Address.lpSockaddr)
77 .sin_addr;
78 }
79
80 result.push_back(NetworkInterface{
81 .name{Common::UTF16ToUTF8(std::wstring{current_address->FriendlyName})},
82 .ip_address{ip_addr},
83 .subnet_mask = in_addr{.S_un{.S_addr{mask}}},
84 .gateway = gateway});
85 }
86
87 return result;
88 } else {
89 LOG_ERROR(Network, "Failed to get network interfaces with GetAdaptersAddresses");
90 return {};
91 }
92}
93
94#else
95
96std::vector<NetworkInterface> GetAvailableNetworkInterfaces() {
97 std::vector<NetworkInterface> result;
98
99 struct ifaddrs* ifaddr = nullptr;
100
101 if (getifaddrs(&ifaddr) != 0) {
102 LOG_ERROR(Network, "Failed to get network interfaces with getifaddrs: {}",
103 std::strerror(errno));
104 return result;
105 }
106
107 for (auto ifa = ifaddr; ifa != nullptr; ifa = ifa->ifa_next) {
108 if (ifa->ifa_addr == nullptr || ifa->ifa_netmask == nullptr) {
109 continue;
110 }
111
112 if (ifa->ifa_addr->sa_family != AF_INET) {
113 continue;
114 }
115
116 if ((ifa->ifa_flags & IFF_UP) == 0 || (ifa->ifa_flags & IFF_LOOPBACK) != 0) {
117 continue;
118 }
119
120 std::uint32_t gateway{0};
121 std::ifstream file{"/proc/net/route"};
122 if (file.is_open()) {
123
124 // ignore header
125 file.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
126
127 bool gateway_found = false;
128
129 for (std::string line; std::getline(file, line);) {
130 std::istringstream iss{line};
131
132 std::string iface_name{};
133 iss >> iface_name;
134 if (iface_name != ifa->ifa_name) {
135 continue;
136 }
137
138 iss >> std::hex;
139
140 std::uint32_t dest{0};
141 iss >> dest;
142 if (dest != 0) {
143 // not the default route
144 continue;
145 }
146
147 iss >> gateway;
148
149 std::uint16_t flags{0};
150 iss >> flags;
151
152 // flag RTF_GATEWAY (defined in <linux/route.h>)
153 if ((flags & 0x2) == 0) {
154 continue;
155 }
156
157 gateway_found = true;
158 break;
159 }
160
161 if (!gateway_found) {
162 gateway = 0;
163 }
164 } else {
165 LOG_ERROR(Network, "Failed to open \"/proc/net/route\"");
166 }
167
168 result.push_back(NetworkInterface{
169 .name{ifa->ifa_name},
170 .ip_address{Common::BitCast<struct sockaddr_in>(*ifa->ifa_addr).sin_addr},
171 .subnet_mask{Common::BitCast<struct sockaddr_in>(*ifa->ifa_netmask).sin_addr},
172 .gateway{in_addr{.s_addr = gateway}}});
173 }
174
175 freeifaddrs(ifaddr);
176
177 return result;
178}
179
180#endif
181
182std::optional<NetworkInterface> GetSelectedNetworkInterface() {
183 const std::string& selected_network_interface = Settings::values.network_interface.GetValue();
184 const auto network_interfaces = Network::GetAvailableNetworkInterfaces();
185 if (network_interfaces.size() == 0) {
186 LOG_ERROR(Network, "GetAvailableNetworkInterfaces returned no interfaces");
187 return {};
188 }
189
190 const auto res =
191 std::ranges::find_if(network_interfaces, [&selected_network_interface](const auto& iface) {
192 return iface.name == selected_network_interface;
193 });
194
195 if (res != network_interfaces.end()) {
196 return *res;
197 } else {
198 LOG_ERROR(Network, "Couldn't find selected interface \"{}\"", selected_network_interface);
199 return {};
200 }
201}
202
203} // namespace Network
diff --git a/src/core/network/network_interface.h b/src/core/network/network_interface.h
new file mode 100644
index 000000000..980edb2f5
--- /dev/null
+++ b/src/core/network/network_interface.h
@@ -0,0 +1,29 @@
1// Copyright 2021 yuzu emulator team
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <optional>
8#include <string>
9#include <vector>
10
11#ifdef _WIN32
12#include <winsock2.h>
13#else
14#include <netinet/in.h>
15#endif
16
17namespace Network {
18
19struct NetworkInterface {
20 std::string name;
21 struct in_addr ip_address;
22 struct in_addr subnet_mask;
23 struct in_addr gateway;
24};
25
26std::vector<NetworkInterface> GetAvailableNetworkInterfaces();
27std::optional<NetworkInterface> GetSelectedNetworkInterface();
28
29} // namespace Network
diff --git a/src/shader_recompiler/backend/spirv/emit_spirv_context_get_set.cpp b/src/shader_recompiler/backend/spirv/emit_spirv_context_get_set.cpp
index fb8c02a77..14c77f162 100644
--- a/src/shader_recompiler/backend/spirv/emit_spirv_context_get_set.cpp
+++ b/src/shader_recompiler/backend/spirv/emit_spirv_context_get_set.cpp
@@ -298,14 +298,10 @@ Id EmitGetAttribute(EmitContext& ctx, IR::Attribute attr, Id vertex) {
298 if (IR::IsGeneric(attr)) { 298 if (IR::IsGeneric(attr)) {
299 const u32 index{IR::GenericAttributeIndex(attr)}; 299 const u32 index{IR::GenericAttributeIndex(attr)};
300 const std::optional<AttrInfo> type{AttrTypes(ctx, index)}; 300 const std::optional<AttrInfo> type{AttrTypes(ctx, index)};
301 if (!type) { 301 if (!type || !ctx.runtime_info.previous_stage_stores.Generic(index, element)) {
302 // Attribute is disabled 302 // Attribute is disabled or varying component is not written
303 return ctx.Const(element == 3 ? 1.0f : 0.0f); 303 return ctx.Const(element == 3 ? 1.0f : 0.0f);
304 } 304 }
305 if (!ctx.runtime_info.previous_stage_stores.Generic(index, element)) {
306 // Varying component is not written
307 return ctx.Const(type && element == 3 ? 1.0f : 0.0f);
308 }
309 const Id generic_id{ctx.input_generics.at(index)}; 305 const Id generic_id{ctx.input_generics.at(index)};
310 const Id pointer{AttrPointer(ctx, type->pointer, vertex, generic_id, ctx.Const(element))}; 306 const Id pointer{AttrPointer(ctx, type->pointer, vertex, generic_id, ctx.Const(element))};
311 const Id value{ctx.OpLoad(type->id, pointer)}; 307 const Id value{ctx.OpLoad(type->id, pointer)};
diff --git a/src/video_core/macro/macro_jit_x64.h b/src/video_core/macro/macro_jit_x64.h
index 7f50ac2f8..d03d480b4 100644
--- a/src/video_core/macro/macro_jit_x64.h
+++ b/src/video_core/macro/macro_jit_x64.h
@@ -6,7 +6,7 @@
6 6
7#include <array> 7#include <array>
8#include <bitset> 8#include <bitset>
9#include <xbyak.h> 9#include <xbyak/xbyak.h>
10#include "common/bit_field.h" 10#include "common/bit_field.h"
11#include "common/common_types.h" 11#include "common/common_types.h"
12#include "common/x64/xbyak_abi.h" 12#include "common/x64/xbyak_abi.h"
diff --git a/src/video_core/memory_manager.cpp b/src/video_core/memory_manager.cpp
index 882eff880..c60ed6453 100644
--- a/src/video_core/memory_manager.cpp
+++ b/src/video_core/memory_manager.cpp
@@ -463,6 +463,7 @@ std::vector<std::pair<GPUVAddr, std::size_t>> MemoryManager::GetSubmappedRange(
463 ++page_index; 463 ++page_index;
464 page_offset = 0; 464 page_offset = 0;
465 remaining_size -= num_bytes; 465 remaining_size -= num_bytes;
466 old_page_addr = page_addr;
466 } 467 }
467 split(); 468 split();
468 return result; 469 return result;
diff --git a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp
index a37ca1fdf..f316c4f92 100644
--- a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp
+++ b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp
@@ -281,7 +281,7 @@ PipelineCache::PipelineCache(RasterizerVulkan& rasterizer_, Tegra::Engines::Maxw
281 .supported_spirv = device.IsKhrSpirv1_4Supported() ? 0x00010400U : 0x00010000U, 281 .supported_spirv = device.IsKhrSpirv1_4Supported() ? 0x00010400U : 0x00010000U,
282 .unified_descriptor_binding = true, 282 .unified_descriptor_binding = true,
283 .support_descriptor_aliasing = true, 283 .support_descriptor_aliasing = true,
284 .support_int8 = true, 284 .support_int8 = device.IsInt8Supported(),
285 .support_int16 = device.IsShaderInt16Supported(), 285 .support_int16 = device.IsShaderInt16Supported(),
286 .support_int64 = device.IsShaderInt64Supported(), 286 .support_int64 = device.IsShaderInt64Supported(),
287 .support_vertex_instance_id = false, 287 .support_vertex_instance_id = false,
diff --git a/src/video_core/textures/decoders.cpp b/src/video_core/textures/decoders.cpp
index c32ae956a..c010b9353 100644
--- a/src/video_core/textures/decoders.cpp
+++ b/src/video_core/textures/decoders.cpp
@@ -84,56 +84,31 @@ template <bool TO_LINEAR>
84void Swizzle(std::span<u8> output, std::span<const u8> input, u32 bytes_per_pixel, u32 width, 84void Swizzle(std::span<u8> output, std::span<const u8> input, u32 bytes_per_pixel, u32 width,
85 u32 height, u32 depth, u32 block_height, u32 block_depth, u32 stride_alignment) { 85 u32 height, u32 depth, u32 block_height, u32 block_depth, u32 stride_alignment) {
86 switch (bytes_per_pixel) { 86 switch (bytes_per_pixel) {
87 case 1: 87#define BPP_CASE(x) \
88 return SwizzleImpl<TO_LINEAR, 1>(output, input, width, height, depth, block_height, 88 case x: \
89 return SwizzleImpl<TO_LINEAR, x>(output, input, width, height, depth, block_height, \
89 block_depth, stride_alignment); 90 block_depth, stride_alignment);
90 case 2: 91 BPP_CASE(1)
91 return SwizzleImpl<TO_LINEAR, 2>(output, input, width, height, depth, block_height, 92 BPP_CASE(2)
92 block_depth, stride_alignment); 93 BPP_CASE(3)
93 case 3: 94 BPP_CASE(4)
94 return SwizzleImpl<TO_LINEAR, 3>(output, input, width, height, depth, block_height, 95 BPP_CASE(6)
95 block_depth, stride_alignment); 96 BPP_CASE(8)
96 case 4: 97 BPP_CASE(12)
97 return SwizzleImpl<TO_LINEAR, 4>(output, input, width, height, depth, block_height, 98 BPP_CASE(16)
98 block_depth, stride_alignment); 99#undef BPP_CASE
99 case 6:
100 return SwizzleImpl<TO_LINEAR, 6>(output, input, width, height, depth, block_height,
101 block_depth, stride_alignment);
102 case 8:
103 return SwizzleImpl<TO_LINEAR, 8>(output, input, width, height, depth, block_height,
104 block_depth, stride_alignment);
105 case 12:
106 return SwizzleImpl<TO_LINEAR, 12>(output, input, width, height, depth, block_height,
107 block_depth, stride_alignment);
108 case 16:
109 return SwizzleImpl<TO_LINEAR, 16>(output, input, width, height, depth, block_height,
110 block_depth, stride_alignment);
111 default: 100 default:
112 UNREACHABLE_MSG("Invalid bytes_per_pixel={}", bytes_per_pixel); 101 UNREACHABLE_MSG("Invalid bytes_per_pixel={}", bytes_per_pixel);
113 } 102 }
114} 103}
115} // Anonymous namespace
116
117void UnswizzleTexture(std::span<u8> output, std::span<const u8> input, u32 bytes_per_pixel,
118 u32 width, u32 height, u32 depth, u32 block_height, u32 block_depth,
119 u32 stride_alignment) {
120 Swizzle<false>(output, input, bytes_per_pixel, width, height, depth, block_height, block_depth,
121 stride_alignment);
122}
123
124void SwizzleTexture(std::span<u8> output, std::span<const u8> input, u32 bytes_per_pixel, u32 width,
125 u32 height, u32 depth, u32 block_height, u32 block_depth,
126 u32 stride_alignment) {
127 Swizzle<true>(output, input, bytes_per_pixel, width, height, depth, block_height, block_depth,
128 stride_alignment);
129}
130 104
105template <u32 BYTES_PER_PIXEL>
131void SwizzleSubrect(u32 subrect_width, u32 subrect_height, u32 source_pitch, u32 swizzled_width, 106void SwizzleSubrect(u32 subrect_width, u32 subrect_height, u32 source_pitch, u32 swizzled_width,
132 u32 bytes_per_pixel, u8* swizzled_data, const u8* unswizzled_data, 107 u8* swizzled_data, const u8* unswizzled_data, u32 block_height_bit,
133 u32 block_height_bit, u32 offset_x, u32 offset_y) { 108 u32 offset_x, u32 offset_y) {
134 const u32 block_height = 1U << block_height_bit; 109 const u32 block_height = 1U << block_height_bit;
135 const u32 image_width_in_gobs = 110 const u32 image_width_in_gobs =
136 (swizzled_width * bytes_per_pixel + (GOB_SIZE_X - 1)) / GOB_SIZE_X; 111 (swizzled_width * BYTES_PER_PIXEL + (GOB_SIZE_X - 1)) / GOB_SIZE_X;
137 for (u32 line = 0; line < subrect_height; ++line) { 112 for (u32 line = 0; line < subrect_height; ++line) {
138 const u32 dst_y = line + offset_y; 113 const u32 dst_y = line + offset_y;
139 const u32 gob_address_y = 114 const u32 gob_address_y =
@@ -143,20 +118,21 @@ void SwizzleSubrect(u32 subrect_width, u32 subrect_height, u32 source_pitch, u32
143 for (u32 x = 0; x < subrect_width; ++x) { 118 for (u32 x = 0; x < subrect_width; ++x) {
144 const u32 dst_x = x + offset_x; 119 const u32 dst_x = x + offset_x;
145 const u32 gob_address = 120 const u32 gob_address =
146 gob_address_y + (dst_x * bytes_per_pixel / GOB_SIZE_X) * GOB_SIZE * block_height; 121 gob_address_y + (dst_x * BYTES_PER_PIXEL / GOB_SIZE_X) * GOB_SIZE * block_height;
147 const u32 swizzled_offset = gob_address + table[(dst_x * bytes_per_pixel) % GOB_SIZE_X]; 122 const u32 swizzled_offset = gob_address + table[(dst_x * BYTES_PER_PIXEL) % GOB_SIZE_X];
148 const u32 unswizzled_offset = line * source_pitch + x * bytes_per_pixel; 123 const u32 unswizzled_offset = line * source_pitch + x * BYTES_PER_PIXEL;
149 124
150 const u8* const source_line = unswizzled_data + unswizzled_offset; 125 const u8* const source_line = unswizzled_data + unswizzled_offset;
151 u8* const dest_addr = swizzled_data + swizzled_offset; 126 u8* const dest_addr = swizzled_data + swizzled_offset;
152 std::memcpy(dest_addr, source_line, bytes_per_pixel); 127 std::memcpy(dest_addr, source_line, BYTES_PER_PIXEL);
153 } 128 }
154 } 129 }
155} 130}
156 131
157void UnswizzleSubrect(u32 line_length_in, u32 line_count, u32 pitch, u32 width, u32 bytes_per_pixel, 132template <u32 BYTES_PER_PIXEL>
158 u32 block_height, u32 origin_x, u32 origin_y, u8* output, const u8* input) { 133void UnswizzleSubrect(u32 line_length_in, u32 line_count, u32 pitch, u32 width, u32 block_height,
159 const u32 stride = width * bytes_per_pixel; 134 u32 origin_x, u32 origin_y, u8* output, const u8* input) {
135 const u32 stride = width * BYTES_PER_PIXEL;
160 const u32 gobs_in_x = (stride + GOB_SIZE_X - 1) / GOB_SIZE_X; 136 const u32 gobs_in_x = (stride + GOB_SIZE_X - 1) / GOB_SIZE_X;
161 const u32 block_size = gobs_in_x << (GOB_SIZE_SHIFT + block_height); 137 const u32 block_size = gobs_in_x << (GOB_SIZE_SHIFT + block_height);
162 138
@@ -171,24 +147,25 @@ void UnswizzleSubrect(u32 line_length_in, u32 line_count, u32 pitch, u32 width,
171 const u32 src_offset_y = (block_y >> block_height) * block_size + 147 const u32 src_offset_y = (block_y >> block_height) * block_size +
172 ((block_y & block_height_mask) << GOB_SIZE_SHIFT); 148 ((block_y & block_height_mask) << GOB_SIZE_SHIFT);
173 for (u32 column = 0; column < line_length_in; ++column) { 149 for (u32 column = 0; column < line_length_in; ++column) {
174 const u32 src_x = (column + origin_x) * bytes_per_pixel; 150 const u32 src_x = (column + origin_x) * BYTES_PER_PIXEL;
175 const u32 src_offset_x = (src_x >> GOB_SIZE_X_SHIFT) << x_shift; 151 const u32 src_offset_x = (src_x >> GOB_SIZE_X_SHIFT) << x_shift;
176 152
177 const u32 swizzled_offset = src_offset_y + src_offset_x + table[src_x % GOB_SIZE_X]; 153 const u32 swizzled_offset = src_offset_y + src_offset_x + table[src_x % GOB_SIZE_X];
178 const u32 unswizzled_offset = line * pitch + column * bytes_per_pixel; 154 const u32 unswizzled_offset = line * pitch + column * BYTES_PER_PIXEL;
179 155
180 std::memcpy(output + unswizzled_offset, input + swizzled_offset, bytes_per_pixel); 156 std::memcpy(output + unswizzled_offset, input + swizzled_offset, BYTES_PER_PIXEL);
181 } 157 }
182 } 158 }
183} 159}
184 160
161template <u32 BYTES_PER_PIXEL>
185void SwizzleSliceToVoxel(u32 line_length_in, u32 line_count, u32 pitch, u32 width, u32 height, 162void SwizzleSliceToVoxel(u32 line_length_in, u32 line_count, u32 pitch, u32 width, u32 height,
186 u32 bytes_per_pixel, u32 block_height, u32 block_depth, u32 origin_x, 163 u32 block_height, u32 block_depth, u32 origin_x, u32 origin_y, u8* output,
187 u32 origin_y, u8* output, const u8* input) { 164 const u8* input) {
188 UNIMPLEMENTED_IF(origin_x > 0); 165 UNIMPLEMENTED_IF(origin_x > 0);
189 UNIMPLEMENTED_IF(origin_y > 0); 166 UNIMPLEMENTED_IF(origin_y > 0);
190 167
191 const u32 stride = width * bytes_per_pixel; 168 const u32 stride = width * BYTES_PER_PIXEL;
192 const u32 gobs_in_x = (stride + GOB_SIZE_X - 1) / GOB_SIZE_X; 169 const u32 gobs_in_x = (stride + GOB_SIZE_X - 1) / GOB_SIZE_X;
193 const u32 block_size = gobs_in_x << (GOB_SIZE_SHIFT + block_height + block_depth); 170 const u32 block_size = gobs_in_x << (GOB_SIZE_SHIFT + block_height + block_depth);
194 171
@@ -203,11 +180,93 @@ void SwizzleSliceToVoxel(u32 line_length_in, u32 line_count, u32 pitch, u32 widt
203 for (u32 x = 0; x < line_length_in; ++x) { 180 for (u32 x = 0; x < line_length_in; ++x) {
204 const u32 dst_offset = 181 const u32 dst_offset =
205 ((x / GOB_SIZE_X) << x_shift) + dst_offset_y + table[x % GOB_SIZE_X]; 182 ((x / GOB_SIZE_X) << x_shift) + dst_offset_y + table[x % GOB_SIZE_X];
206 const u32 src_offset = x * bytes_per_pixel + line * pitch; 183 const u32 src_offset = x * BYTES_PER_PIXEL + line * pitch;
207 std::memcpy(output + dst_offset, input + src_offset, bytes_per_pixel); 184 std::memcpy(output + dst_offset, input + src_offset, BYTES_PER_PIXEL);
208 } 185 }
209 } 186 }
210} 187}
188} // Anonymous namespace
189
190void UnswizzleTexture(std::span<u8> output, std::span<const u8> input, u32 bytes_per_pixel,
191 u32 width, u32 height, u32 depth, u32 block_height, u32 block_depth,
192 u32 stride_alignment) {
193 Swizzle<false>(output, input, bytes_per_pixel, width, height, depth, block_height, block_depth,
194 stride_alignment);
195}
196
197void SwizzleTexture(std::span<u8> output, std::span<const u8> input, u32 bytes_per_pixel, u32 width,
198 u32 height, u32 depth, u32 block_height, u32 block_depth,
199 u32 stride_alignment) {
200 Swizzle<true>(output, input, bytes_per_pixel, width, height, depth, block_height, block_depth,
201 stride_alignment);
202}
203
204void SwizzleSubrect(u32 subrect_width, u32 subrect_height, u32 source_pitch, u32 swizzled_width,
205 u32 bytes_per_pixel, u8* swizzled_data, const u8* unswizzled_data,
206 u32 block_height_bit, u32 offset_x, u32 offset_y) {
207 switch (bytes_per_pixel) {
208#define BPP_CASE(x) \
209 case x: \
210 return SwizzleSubrect<x>(subrect_width, subrect_height, source_pitch, swizzled_width, \
211 swizzled_data, unswizzled_data, block_height_bit, offset_x, \
212 offset_y);
213 BPP_CASE(1)
214 BPP_CASE(2)
215 BPP_CASE(3)
216 BPP_CASE(4)
217 BPP_CASE(6)
218 BPP_CASE(8)
219 BPP_CASE(12)
220 BPP_CASE(16)
221#undef BPP_CASE
222 default:
223 UNREACHABLE_MSG("Invalid bytes_per_pixel={}", bytes_per_pixel);
224 }
225}
226
227void UnswizzleSubrect(u32 line_length_in, u32 line_count, u32 pitch, u32 width, u32 bytes_per_pixel,
228 u32 block_height, u32 origin_x, u32 origin_y, u8* output, const u8* input) {
229 switch (bytes_per_pixel) {
230#define BPP_CASE(x) \
231 case x: \
232 return UnswizzleSubrect<x>(line_length_in, line_count, pitch, width, block_height, \
233 origin_x, origin_y, output, input);
234 BPP_CASE(1)
235 BPP_CASE(2)
236 BPP_CASE(3)
237 BPP_CASE(4)
238 BPP_CASE(6)
239 BPP_CASE(8)
240 BPP_CASE(12)
241 BPP_CASE(16)
242#undef BPP_CASE
243 default:
244 UNREACHABLE_MSG("Invalid bytes_per_pixel={}", bytes_per_pixel);
245 }
246}
247
248void SwizzleSliceToVoxel(u32 line_length_in, u32 line_count, u32 pitch, u32 width, u32 height,
249 u32 bytes_per_pixel, u32 block_height, u32 block_depth, u32 origin_x,
250 u32 origin_y, u8* output, const u8* input) {
251 switch (bytes_per_pixel) {
252#define BPP_CASE(x) \
253 case x: \
254 return SwizzleSliceToVoxel<x>(line_length_in, line_count, pitch, width, height, \
255 block_height, block_depth, origin_x, origin_y, output, \
256 input);
257 BPP_CASE(1)
258 BPP_CASE(2)
259 BPP_CASE(3)
260 BPP_CASE(4)
261 BPP_CASE(6)
262 BPP_CASE(8)
263 BPP_CASE(12)
264 BPP_CASE(16)
265#undef BPP_CASE
266 default:
267 UNREACHABLE_MSG("Invalid bytes_per_pixel={}", bytes_per_pixel);
268 }
269}
211 270
212void SwizzleKepler(const u32 width, const u32 height, const u32 dst_x, const u32 dst_y, 271void SwizzleKepler(const u32 width, const u32 height, const u32 dst_x, const u32 dst_y,
213 const u32 block_height_bit, const std::size_t copy_size, const u8* source_data, 272 const u32 block_height_bit, const std::size_t copy_size, const u8* source_data,
@@ -228,7 +287,7 @@ void SwizzleKepler(const u32 width, const u32 height, const u32 dst_x, const u32
228 u8* dest_addr = swizzle_data + swizzled_offset; 287 u8* dest_addr = swizzle_data + swizzled_offset;
229 count++; 288 count++;
230 289
231 std::memcpy(dest_addr, source_line, 1); 290 *dest_addr = *source_line;
232 } 291 }
233 } 292 }
234} 293}
diff --git a/src/video_core/textures/texture.h b/src/video_core/textures/texture.h
index 1a9399455..7994cb859 100644
--- a/src/video_core/textures/texture.h
+++ b/src/video_core/textures/texture.h
@@ -159,7 +159,7 @@ static_assert(sizeof(TextureHandle) == 4, "TextureHandle has wrong size");
159 return {raw, raw}; 159 return {raw, raw};
160 } else { 160 } else {
161 const Tegra::Texture::TextureHandle handle{raw}; 161 const Tegra::Texture::TextureHandle handle{raw};
162 return {handle.tic_id, via_header_index ? handle.tic_id : handle.tsc_id}; 162 return {handle.tic_id, handle.tsc_id};
163 } 163 }
164} 164}
165 165
diff --git a/src/video_core/vulkan_common/vulkan_device.cpp b/src/video_core/vulkan_common/vulkan_device.cpp
index 8e56a89e1..86ca4be54 100644
--- a/src/video_core/vulkan_common/vulkan_device.cpp
+++ b/src/video_core/vulkan_common/vulkan_device.cpp
@@ -368,18 +368,21 @@ Device::Device(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR
368 }; 368 };
369 SetNext(next, demote); 369 SetNext(next, demote);
370 370
371 VkPhysicalDeviceFloat16Int8FeaturesKHR float16_int8; 371 if (is_int8_supported || is_float16_supported) {
372 if (is_float16_supported) { 372 VkPhysicalDeviceFloat16Int8FeaturesKHR float16_int8{
373 float16_int8 = {
374 .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FLOAT16_INT8_FEATURES_KHR, 373 .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FLOAT16_INT8_FEATURES_KHR,
375 .pNext = nullptr, 374 .pNext = nullptr,
376 .shaderFloat16 = true, 375 .shaderFloat16 = is_float16_supported,
377 .shaderInt8 = false, 376 .shaderInt8 = is_int8_supported,
378 }; 377 };
379 SetNext(next, float16_int8); 378 SetNext(next, float16_int8);
380 } else { 379 }
380 if (!is_float16_supported) {
381 LOG_INFO(Render_Vulkan, "Device doesn't support float16 natively"); 381 LOG_INFO(Render_Vulkan, "Device doesn't support float16 natively");
382 } 382 }
383 if (!is_int8_supported) {
384 LOG_INFO(Render_Vulkan, "Device doesn't support int8 natively");
385 }
383 386
384 if (!nv_viewport_swizzle) { 387 if (!nv_viewport_swizzle) {
385 LOG_INFO(Render_Vulkan, "Device doesn't support viewport swizzles"); 388 LOG_INFO(Render_Vulkan, "Device doesn't support viewport swizzles");
@@ -909,6 +912,7 @@ std::vector<const char*> Device::LoadExtensions(bool requires_surface) {
909 912
910 physical.GetFeatures2KHR(features); 913 physical.GetFeatures2KHR(features);
911 is_float16_supported = float16_int8_features.shaderFloat16; 914 is_float16_supported = float16_int8_features.shaderFloat16;
915 is_int8_supported = float16_int8_features.shaderInt8;
912 extensions.push_back(VK_KHR_SHADER_FLOAT16_INT8_EXTENSION_NAME); 916 extensions.push_back(VK_KHR_SHADER_FLOAT16_INT8_EXTENSION_NAME);
913 } 917 }
914 if (has_ext_subgroup_size_control) { 918 if (has_ext_subgroup_size_control) {
diff --git a/src/video_core/vulkan_common/vulkan_device.h b/src/video_core/vulkan_common/vulkan_device.h
index c19f40746..234d74129 100644
--- a/src/video_core/vulkan_common/vulkan_device.h
+++ b/src/video_core/vulkan_common/vulkan_device.h
@@ -139,11 +139,16 @@ public:
139 return is_optimal_astc_supported; 139 return is_optimal_astc_supported;
140 } 140 }
141 141
142 /// Returns true if the device supports float16 natively 142 /// Returns true if the device supports float16 natively.
143 bool IsFloat16Supported() const { 143 bool IsFloat16Supported() const {
144 return is_float16_supported; 144 return is_float16_supported;
145 } 145 }
146 146
147 /// Returns true if the device supports int8 natively.
148 bool IsInt8Supported() const {
149 return is_int8_supported;
150 }
151
147 /// Returns true if the device warp size can potentially be bigger than guest's warp size. 152 /// Returns true if the device warp size can potentially be bigger than guest's warp size.
148 bool IsWarpSizePotentiallyBiggerThanGuest() const { 153 bool IsWarpSizePotentiallyBiggerThanGuest() const {
149 return is_warp_potentially_bigger; 154 return is_warp_potentially_bigger;
@@ -367,7 +372,8 @@ private:
367 u64 device_access_memory{}; ///< Total size of device local memory in bytes. 372 u64 device_access_memory{}; ///< Total size of device local memory in bytes.
368 u32 max_push_descriptors{}; ///< Maximum number of push descriptors 373 u32 max_push_descriptors{}; ///< Maximum number of push descriptors
369 bool is_optimal_astc_supported{}; ///< Support for native ASTC. 374 bool is_optimal_astc_supported{}; ///< Support for native ASTC.
370 bool is_float16_supported{}; ///< Support for float16 arithmetics. 375 bool is_float16_supported{}; ///< Support for float16 arithmetic.
376 bool is_int8_supported{}; ///< Support for int8 arithmetic.
371 bool is_warp_potentially_bigger{}; ///< Host warp size can be bigger than guest. 377 bool is_warp_potentially_bigger{}; ///< Host warp size can be bigger than guest.
372 bool is_formatless_image_load_supported{}; ///< Support for shader image read without format. 378 bool is_formatless_image_load_supported{}; ///< Support for shader image read without format.
373 bool is_depth_bounds_supported{}; ///< Support for depth bounds. 379 bool is_depth_bounds_supported{}; ///< Support for depth bounds.
diff --git a/src/yuzu/CMakeLists.txt b/src/yuzu/CMakeLists.txt
index cb4bdcc7e..19ba0dbba 100644
--- a/src/yuzu/CMakeLists.txt
+++ b/src/yuzu/CMakeLists.txt
@@ -102,9 +102,9 @@ add_executable(yuzu
102 configuration/configure_profile_manager.cpp 102 configuration/configure_profile_manager.cpp
103 configuration/configure_profile_manager.h 103 configuration/configure_profile_manager.h
104 configuration/configure_profile_manager.ui 104 configuration/configure_profile_manager.ui
105 configuration/configure_service.cpp 105 configuration/configure_network.cpp
106 configuration/configure_service.h 106 configuration/configure_network.h
107 configuration/configure_service.ui 107 configuration/configure_network.ui
108 configuration/configure_system.cpp 108 configuration/configure_system.cpp
109 configuration/configure_system.h 109 configuration/configure_system.h
110 configuration/configure_system.ui 110 configuration/configure_system.ui
@@ -182,7 +182,14 @@ if (ENABLE_QT_TRANSLATION)
182 # Update source TS file if enabled 182 # Update source TS file if enabled
183 if (GENERATE_QT_TRANSLATION) 183 if (GENERATE_QT_TRANSLATION)
184 get_target_property(SRCS yuzu SOURCES) 184 get_target_property(SRCS yuzu SOURCES)
185 qt5_create_translation(QM_FILES ${SRCS} ${UIS} ${YUZU_QT_LANGUAGES}/en.ts) 185 qt5_create_translation(QM_FILES
186 ${SRCS}
187 ${UIS}
188 ${YUZU_QT_LANGUAGES}/en.ts
189 OPTIONS
190 -source-language en_US
191 -target-language en_US
192 )
186 add_custom_target(translation ALL DEPENDS ${YUZU_QT_LANGUAGES}/en.ts) 193 add_custom_target(translation ALL DEPENDS ${YUZU_QT_LANGUAGES}/en.ts)
187 endif() 194 endif()
188 195
diff --git a/src/yuzu/applets/qt_software_keyboard.cpp b/src/yuzu/applets/qt_software_keyboard.cpp
index 848801cec..8fc0c5a36 100644
--- a/src/yuzu/applets/qt_software_keyboard.cpp
+++ b/src/yuzu/applets/qt_software_keyboard.cpp
@@ -438,7 +438,7 @@ void QtSoftwareKeyboardDialog::ShowInlineKeyboard(
438 initialize_parameters.key_disable_flags = appear_parameters.key_disable_flags; 438 initialize_parameters.key_disable_flags = appear_parameters.key_disable_flags;
439 initialize_parameters.enable_backspace_button = appear_parameters.enable_backspace_button; 439 initialize_parameters.enable_backspace_button = appear_parameters.enable_backspace_button;
440 initialize_parameters.enable_return_button = appear_parameters.enable_return_button; 440 initialize_parameters.enable_return_button = appear_parameters.enable_return_button;
441 initialize_parameters.disable_cancel_button = initialize_parameters.disable_cancel_button; 441 initialize_parameters.disable_cancel_button = appear_parameters.disable_cancel_button;
442 442
443 SetKeyboardType(); 443 SetKeyboardType();
444 SetControllerImage(); 444 SetControllerImage();
diff --git a/src/yuzu/configuration/config.cpp b/src/yuzu/configuration/config.cpp
index 380379eb4..377795326 100644
--- a/src/yuzu/configuration/config.cpp
+++ b/src/yuzu/configuration/config.cpp
@@ -692,6 +692,7 @@ void Config::ReadServiceValues() {
692 qt_config->beginGroup(QStringLiteral("Services")); 692 qt_config->beginGroup(QStringLiteral("Services"));
693 ReadBasicSetting(Settings::values.bcat_backend); 693 ReadBasicSetting(Settings::values.bcat_backend);
694 ReadBasicSetting(Settings::values.bcat_boxcat_local); 694 ReadBasicSetting(Settings::values.bcat_boxcat_local);
695 ReadBasicSetting(Settings::values.network_interface);
695 qt_config->endGroup(); 696 qt_config->endGroup();
696} 697}
697 698
@@ -1144,7 +1145,7 @@ void Config::SaveValues() {
1144 SaveDataStorageValues(); 1145 SaveDataStorageValues();
1145 SaveDebuggingValues(); 1146 SaveDebuggingValues();
1146 SaveDisabledAddOnValues(); 1147 SaveDisabledAddOnValues();
1147 SaveServiceValues(); 1148 SaveNetworkValues();
1148 SaveUIValues(); 1149 SaveUIValues();
1149 SaveWebServiceValues(); 1150 SaveWebServiceValues();
1150 SaveMiscellaneousValues(); 1151 SaveMiscellaneousValues();
@@ -1238,11 +1239,12 @@ void Config::SaveDebuggingValues() {
1238 qt_config->endGroup(); 1239 qt_config->endGroup();
1239} 1240}
1240 1241
1241void Config::SaveServiceValues() { 1242void Config::SaveNetworkValues() {
1242 qt_config->beginGroup(QStringLiteral("Services")); 1243 qt_config->beginGroup(QStringLiteral("Services"));
1243 1244
1244 WriteBasicSetting(Settings::values.bcat_backend); 1245 WriteBasicSetting(Settings::values.bcat_backend);
1245 WriteBasicSetting(Settings::values.bcat_boxcat_local); 1246 WriteBasicSetting(Settings::values.bcat_boxcat_local);
1247 WriteBasicSetting(Settings::values.network_interface);
1246 1248
1247 qt_config->endGroup(); 1249 qt_config->endGroup();
1248} 1250}
diff --git a/src/yuzu/configuration/config.h b/src/yuzu/configuration/config.h
index c1d7feb9f..9555f4498 100644
--- a/src/yuzu/configuration/config.h
+++ b/src/yuzu/configuration/config.h
@@ -88,7 +88,7 @@ private:
88 void SaveCoreValues(); 88 void SaveCoreValues();
89 void SaveDataStorageValues(); 89 void SaveDataStorageValues();
90 void SaveDebuggingValues(); 90 void SaveDebuggingValues();
91 void SaveServiceValues(); 91 void SaveNetworkValues();
92 void SaveDisabledAddOnValues(); 92 void SaveDisabledAddOnValues();
93 void SaveMiscellaneousValues(); 93 void SaveMiscellaneousValues();
94 void SavePathValues(); 94 void SavePathValues();
diff --git a/src/yuzu/configuration/configure.ui b/src/yuzu/configuration/configure.ui
index fca9aed5f..6258dcf20 100644
--- a/src/yuzu/configuration/configure.ui
+++ b/src/yuzu/configuration/configure.ui
@@ -147,12 +147,12 @@
147 <string>Web</string> 147 <string>Web</string>
148 </attribute> 148 </attribute>
149 </widget> 149 </widget>
150 <widget class="ConfigureService" name="serviceTab"> 150 <widget class="ConfigureNetwork" name="networkTab">
151 <property name="accessibleName"> 151 <property name="accessibleName">
152 <string>Services</string> 152 <string>Network</string>
153 </property> 153 </property>
154 <attribute name="title"> 154 <attribute name="title">
155 <string>Services</string> 155 <string>Network</string>
156 </attribute> 156 </attribute>
157 </widget> 157 </widget>
158 </widget> 158 </widget>
@@ -242,9 +242,9 @@
242 <container>1</container> 242 <container>1</container>
243 </customwidget> 243 </customwidget>
244 <customwidget> 244 <customwidget>
245 <class>ConfigureService</class> 245 <class>ConfigureNetwork</class>
246 <extends>QWidget</extends> 246 <extends>QWidget</extends>
247 <header>configuration/configure_service.h</header> 247 <header>configuration/configure_network.h</header>
248 <container>1</container> 248 <container>1</container>
249 </customwidget> 249 </customwidget>
250 <customwidget> 250 <customwidget>
diff --git a/src/yuzu/configuration/configure_dialog.cpp b/src/yuzu/configuration/configure_dialog.cpp
index bc009b6b3..fe4186157 100644
--- a/src/yuzu/configuration/configure_dialog.cpp
+++ b/src/yuzu/configuration/configure_dialog.cpp
@@ -67,7 +67,7 @@ void ConfigureDialog::ApplyConfiguration() {
67 ui->audioTab->ApplyConfiguration(); 67 ui->audioTab->ApplyConfiguration();
68 ui->debugTab->ApplyConfiguration(); 68 ui->debugTab->ApplyConfiguration();
69 ui->webTab->ApplyConfiguration(); 69 ui->webTab->ApplyConfiguration();
70 ui->serviceTab->ApplyConfiguration(); 70 ui->networkTab->ApplyConfiguration();
71 Core::System::GetInstance().ApplySettings(); 71 Core::System::GetInstance().ApplySettings();
72 Settings::LogSettings(); 72 Settings::LogSettings();
73} 73}
@@ -103,7 +103,7 @@ Q_DECLARE_METATYPE(QList<QWidget*>);
103void ConfigureDialog::PopulateSelectionList() { 103void ConfigureDialog::PopulateSelectionList() {
104 const std::array<std::pair<QString, QList<QWidget*>>, 6> items{ 104 const std::array<std::pair<QString, QList<QWidget*>>, 6> items{
105 {{tr("General"), {ui->generalTab, ui->hotkeysTab, ui->uiTab, ui->webTab, ui->debugTab}}, 105 {{tr("General"), {ui->generalTab, ui->hotkeysTab, ui->uiTab, ui->webTab, ui->debugTab}},
106 {tr("System"), {ui->systemTab, ui->profileManagerTab, ui->serviceTab, ui->filesystemTab}}, 106 {tr("System"), {ui->systemTab, ui->profileManagerTab, ui->networkTab, ui->filesystemTab}},
107 {tr("CPU"), {ui->cpuTab}}, 107 {tr("CPU"), {ui->cpuTab}},
108 {tr("Graphics"), {ui->graphicsTab, ui->graphicsAdvancedTab}}, 108 {tr("Graphics"), {ui->graphicsTab, ui->graphicsAdvancedTab}},
109 {tr("Audio"), {ui->audioTab}}, 109 {tr("Audio"), {ui->audioTab}},
diff --git a/src/yuzu/configuration/configure_input_player_widget.cpp b/src/yuzu/configuration/configure_input_player_widget.cpp
index cd633e45f..9c890ed5d 100644
--- a/src/yuzu/configuration/configure_input_player_widget.cpp
+++ b/src/yuzu/configuration/configure_input_player_widget.cpp
@@ -647,18 +647,18 @@ void PlayerControlPreview::DrawHandheldController(QPainter& p, const QPointF cen
647 // Face buttons 647 // Face buttons
648 p.setPen(colors.outline); 648 p.setPen(colors.outline);
649 button_color = colors.button; 649 button_color = colors.button;
650 DrawCircleButton(p, face_center + QPoint(face_distance, 0), button_values[A], face_radius); 650 DrawCircleButton(p, face_center + QPointF(face_distance, 0), button_values[A], face_radius);
651 DrawCircleButton(p, face_center + QPoint(0, face_distance), button_values[B], face_radius); 651 DrawCircleButton(p, face_center + QPointF(0, face_distance), button_values[B], face_radius);
652 DrawCircleButton(p, face_center + QPoint(0, -face_distance), button_values[X], face_radius); 652 DrawCircleButton(p, face_center + QPointF(0, -face_distance), button_values[X], face_radius);
653 DrawCircleButton(p, face_center + QPoint(-face_distance, 0), button_values[Y], face_radius); 653 DrawCircleButton(p, face_center + QPointF(-face_distance, 0), button_values[Y], face_radius);
654 654
655 // Face buttons text 655 // Face buttons text
656 p.setPen(colors.transparent); 656 p.setPen(colors.transparent);
657 p.setBrush(colors.font); 657 p.setBrush(colors.font);
658 DrawSymbol(p, face_center + QPoint(face_distance, 0), Symbol::A, text_size); 658 DrawSymbol(p, face_center + QPointF(face_distance, 0), Symbol::A, text_size);
659 DrawSymbol(p, face_center + QPoint(0, face_distance), Symbol::B, text_size); 659 DrawSymbol(p, face_center + QPointF(0, face_distance), Symbol::B, text_size);
660 DrawSymbol(p, face_center + QPoint(0, -face_distance), Symbol::X, text_size); 660 DrawSymbol(p, face_center + QPointF(0, -face_distance), Symbol::X, text_size);
661 DrawSymbol(p, face_center + QPoint(-face_distance, 1), Symbol::Y, text_size); 661 DrawSymbol(p, face_center + QPointF(-face_distance, 1), Symbol::Y, text_size);
662 662
663 // D-pad constants 663 // D-pad constants
664 const QPointF dpad_center = center + QPoint(-171, 8); 664 const QPointF dpad_center = center + QPoint(-171, 8);
@@ -669,18 +669,20 @@ void PlayerControlPreview::DrawHandheldController(QPainter& p, const QPointF cen
669 // D-pad buttons 669 // D-pad buttons
670 p.setPen(colors.outline); 670 p.setPen(colors.outline);
671 button_color = colors.button; 671 button_color = colors.button;
672 DrawCircleButton(p, dpad_center + QPoint(dpad_distance, 0), button_values[DRight], dpad_radius); 672 DrawCircleButton(p, dpad_center + QPointF(dpad_distance, 0), button_values[DRight],
673 DrawCircleButton(p, dpad_center + QPoint(0, dpad_distance), button_values[DDown], dpad_radius); 673 dpad_radius);
674 DrawCircleButton(p, dpad_center + QPoint(0, -dpad_distance), button_values[DUp], dpad_radius); 674 DrawCircleButton(p, dpad_center + QPointF(0, dpad_distance), button_values[DDown], dpad_radius);
675 DrawCircleButton(p, dpad_center + QPoint(-dpad_distance, 0), button_values[DLeft], dpad_radius); 675 DrawCircleButton(p, dpad_center + QPointF(0, -dpad_distance), button_values[DUp], dpad_radius);
676 DrawCircleButton(p, dpad_center + QPointF(-dpad_distance, 0), button_values[DLeft],
677 dpad_radius);
676 678
677 // D-pad arrows 679 // D-pad arrows
678 p.setPen(colors.font2); 680 p.setPen(colors.font2);
679 p.setBrush(colors.font2); 681 p.setBrush(colors.font2);
680 DrawArrow(p, dpad_center + QPoint(dpad_distance, 0), Direction::Right, dpad_arrow_size); 682 DrawArrow(p, dpad_center + QPointF(dpad_distance, 0), Direction::Right, dpad_arrow_size);
681 DrawArrow(p, dpad_center + QPoint(0, dpad_distance), Direction::Down, dpad_arrow_size); 683 DrawArrow(p, dpad_center + QPointF(0, dpad_distance), Direction::Down, dpad_arrow_size);
682 DrawArrow(p, dpad_center + QPoint(0, -dpad_distance), Direction::Up, dpad_arrow_size); 684 DrawArrow(p, dpad_center + QPointF(0, -dpad_distance), Direction::Up, dpad_arrow_size);
683 DrawArrow(p, dpad_center + QPoint(-dpad_distance, 0), Direction::Left, dpad_arrow_size); 685 DrawArrow(p, dpad_center + QPointF(-dpad_distance, 0), Direction::Left, dpad_arrow_size);
684 686
685 // ZL and ZR buttons 687 // ZL and ZR buttons
686 p.setPen(colors.outline); 688 p.setPen(colors.outline);
diff --git a/src/yuzu/configuration/configure_service.cpp b/src/yuzu/configuration/configure_network.cpp
index 4aa424803..ae22f1018 100644
--- a/src/yuzu/configuration/configure_service.cpp
+++ b/src/yuzu/configuration/configure_network.cpp
@@ -5,9 +5,11 @@
5#include <QGraphicsItem> 5#include <QGraphicsItem>
6#include <QtConcurrent/QtConcurrent> 6#include <QtConcurrent/QtConcurrent>
7#include "common/settings.h" 7#include "common/settings.h"
8#include "core/core.h"
8#include "core/hle/service/bcat/backend/boxcat.h" 9#include "core/hle/service/bcat/backend/boxcat.h"
9#include "ui_configure_service.h" 10#include "core/network/network_interface.h"
10#include "yuzu/configuration/configure_service.h" 11#include "ui_configure_network.h"
12#include "yuzu/configuration/configure_network.h"
11 13
12#ifdef YUZU_ENABLE_BOXCAT 14#ifdef YUZU_ENABLE_BOXCAT
13namespace { 15namespace {
@@ -35,8 +37,8 @@ QString FormatEventStatusString(const Service::BCAT::EventStatus& status) {
35} // Anonymous namespace 37} // Anonymous namespace
36#endif 38#endif
37 39
38ConfigureService::ConfigureService(QWidget* parent) 40ConfigureNetwork::ConfigureNetwork(QWidget* parent)
39 : QWidget(parent), ui(std::make_unique<Ui::ConfigureService>()) { 41 : QWidget(parent), ui(std::make_unique<Ui::ConfigureNetwork>()) {
40 ui->setupUi(this); 42 ui->setupUi(this);
41 43
42 ui->bcat_source->addItem(QStringLiteral("None")); 44 ui->bcat_source->addItem(QStringLiteral("None"));
@@ -47,29 +49,42 @@ ConfigureService::ConfigureService(QWidget* parent)
47 ui->bcat_source->addItem(QStringLiteral("Boxcat"), QStringLiteral("boxcat")); 49 ui->bcat_source->addItem(QStringLiteral("Boxcat"), QStringLiteral("boxcat"));
48#endif 50#endif
49 51
52 ui->network_interface->addItem(tr("None"));
53 for (const auto& iface : Network::GetAvailableNetworkInterfaces()) {
54 ui->network_interface->addItem(QString::fromStdString(iface.name));
55 }
56
50 connect(ui->bcat_source, QOverload<int>::of(&QComboBox::currentIndexChanged), this, 57 connect(ui->bcat_source, QOverload<int>::of(&QComboBox::currentIndexChanged), this,
51 &ConfigureService::OnBCATImplChanged); 58 &ConfigureNetwork::OnBCATImplChanged);
52 59
53 this->SetConfiguration(); 60 this->SetConfiguration();
54} 61}
55 62
56ConfigureService::~ConfigureService() = default; 63ConfigureNetwork::~ConfigureNetwork() = default;
57 64
58void ConfigureService::ApplyConfiguration() { 65void ConfigureNetwork::ApplyConfiguration() {
59 Settings::values.bcat_backend = ui->bcat_source->currentText().toLower().toStdString(); 66 Settings::values.bcat_backend = ui->bcat_source->currentText().toLower().toStdString();
67 Settings::values.network_interface = ui->network_interface->currentText().toStdString();
60} 68}
61 69
62void ConfigureService::RetranslateUi() { 70void ConfigureNetwork::RetranslateUi() {
63 ui->retranslateUi(this); 71 ui->retranslateUi(this);
64} 72}
65 73
66void ConfigureService::SetConfiguration() { 74void ConfigureNetwork::SetConfiguration() {
75 const bool runtime_lock = !Core::System::GetInstance().IsPoweredOn();
76
67 const int index = 77 const int index =
68 ui->bcat_source->findData(QString::fromStdString(Settings::values.bcat_backend.GetValue())); 78 ui->bcat_source->findData(QString::fromStdString(Settings::values.bcat_backend.GetValue()));
69 ui->bcat_source->setCurrentIndex(index == -1 ? 0 : index); 79 ui->bcat_source->setCurrentIndex(index == -1 ? 0 : index);
80
81 const std::string& network_interface = Settings::values.network_interface.GetValue();
82
83 ui->network_interface->setCurrentText(QString::fromStdString(network_interface));
84 ui->network_interface->setEnabled(runtime_lock);
70} 85}
71 86
72std::pair<QString, QString> ConfigureService::BCATDownloadEvents() { 87std::pair<QString, QString> ConfigureNetwork::BCATDownloadEvents() {
73#ifdef YUZU_ENABLE_BOXCAT 88#ifdef YUZU_ENABLE_BOXCAT
74 std::optional<std::string> global; 89 std::optional<std::string> global;
75 std::map<std::string, Service::BCAT::EventStatus> map; 90 std::map<std::string, Service::BCAT::EventStatus> map;
@@ -114,7 +129,7 @@ std::pair<QString, QString> ConfigureService::BCATDownloadEvents() {
114#endif 129#endif
115} 130}
116 131
117void ConfigureService::OnBCATImplChanged() { 132void ConfigureNetwork::OnBCATImplChanged() {
118#ifdef YUZU_ENABLE_BOXCAT 133#ifdef YUZU_ENABLE_BOXCAT
119 const auto boxcat = ui->bcat_source->currentText() == QStringLiteral("Boxcat"); 134 const auto boxcat = ui->bcat_source->currentText() == QStringLiteral("Boxcat");
120 ui->bcat_empty_header->setHidden(!boxcat); 135 ui->bcat_empty_header->setHidden(!boxcat);
@@ -133,7 +148,7 @@ void ConfigureService::OnBCATImplChanged() {
133#endif 148#endif
134} 149}
135 150
136void ConfigureService::OnUpdateBCATEmptyLabel(std::pair<QString, QString> string) { 151void ConfigureNetwork::OnUpdateBCATEmptyLabel(std::pair<QString, QString> string) {
137#ifdef YUZU_ENABLE_BOXCAT 152#ifdef YUZU_ENABLE_BOXCAT
138 const auto boxcat = ui->bcat_source->currentText() == QStringLiteral("Boxcat"); 153 const auto boxcat = ui->bcat_source->currentText() == QStringLiteral("Boxcat");
139 if (boxcat) { 154 if (boxcat) {
diff --git a/src/yuzu/configuration/configure_service.h b/src/yuzu/configuration/configure_network.h
index f5c1b703a..442b68e6b 100644
--- a/src/yuzu/configuration/configure_service.h
+++ b/src/yuzu/configuration/configure_network.h
@@ -9,15 +9,15 @@
9#include <QWidget> 9#include <QWidget>
10 10
11namespace Ui { 11namespace Ui {
12class ConfigureService; 12class ConfigureNetwork;
13} 13}
14 14
15class ConfigureService : public QWidget { 15class ConfigureNetwork : public QWidget {
16 Q_OBJECT 16 Q_OBJECT
17 17
18public: 18public:
19 explicit ConfigureService(QWidget* parent = nullptr); 19 explicit ConfigureNetwork(QWidget* parent = nullptr);
20 ~ConfigureService() override; 20 ~ConfigureNetwork() override;
21 21
22 void ApplyConfiguration(); 22 void ApplyConfiguration();
23 void RetranslateUi(); 23 void RetranslateUi();
@@ -29,6 +29,6 @@ private:
29 void OnBCATImplChanged(); 29 void OnBCATImplChanged();
30 void OnUpdateBCATEmptyLabel(std::pair<QString, QString> string); 30 void OnUpdateBCATEmptyLabel(std::pair<QString, QString> string);
31 31
32 std::unique_ptr<Ui::ConfigureService> ui; 32 std::unique_ptr<Ui::ConfigureNetwork> ui;
33 QFutureWatcher<std::pair<QString, QString>> watcher{this}; 33 QFutureWatcher<std::pair<QString, QString>> watcher{this};
34}; 34};
diff --git a/src/yuzu/configuration/configure_service.ui b/src/yuzu/configuration/configure_network.ui
index 9668dd557..5f9b7e97b 100644
--- a/src/yuzu/configuration/configure_service.ui
+++ b/src/yuzu/configuration/configure_network.ui
@@ -1,7 +1,7 @@
1<?xml version="1.0" encoding="UTF-8"?> 1<?xml version="1.0" encoding="UTF-8"?>
2<ui version="4.0"> 2<ui version="4.0">
3 <class>ConfigureService</class> 3 <class>ConfigureNetwork</class>
4 <widget class="QWidget" name="ConfigureService"> 4 <widget class="QWidget" name="ConfigureNetwork">
5 <property name="geometry"> 5 <property name="geometry">
6 <rect> 6 <rect>
7 <x>0</x> 7 <x>0</x>
@@ -17,21 +17,37 @@
17 <item> 17 <item>
18 <layout class="QVBoxLayout" name="verticalLayout_3"> 18 <layout class="QVBoxLayout" name="verticalLayout_3">
19 <item> 19 <item>
20 <widget class="QGroupBox" name="groupBox_2">
21 <property name="title">
22 <string>General</string>
23 </property>
24 <layout class="QGridLayout" name="gridLayout_2">
25 <item row="1" column="1">
26 <widget class="QComboBox" name="network_interface"/>
27 </item>
28 <item row="1" column="0">
29 <widget class="QLabel" name="label_4">
30 <property name="text">
31 <string>Network Interface</string>
32 </property>
33 </widget>
34 </item>
35 </layout>
36 </widget>
37 </item>
38 <item>
20 <widget class="QGroupBox" name="groupBox"> 39 <widget class="QGroupBox" name="groupBox">
21 <property name="title"> 40 <property name="title">
22 <string>BCAT</string> 41 <string>BCAT</string>
23 </property> 42 </property>
24 <layout class="QGridLayout" name="gridLayout"> 43 <layout class="QGridLayout" name="gridLayout">
25 <item row="1" column="1" colspan="2"> 44 <item row="3" column="0">
26 <widget class="QLabel" name="label_2"> 45 <widget class="QLabel" name="bcat_empty_header">
27 <property name="maximumSize">
28 <size>
29 <width>260</width>
30 <height>16777215</height>
31 </size>
32 </property>
33 <property name="text"> 46 <property name="text">
34 <string>BCAT is Nintendo's way of sending data to games to engage its community and unlock additional content.</string> 47 <string/>
48 </property>
49 <property name="alignment">
50 <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
35 </property> 51 </property>
36 <property name="wordWrap"> 52 <property name="wordWrap">
37 <bool>true</bool> 53 <bool>true</bool>
@@ -51,11 +67,8 @@
51 </property> 67 </property>
52 </widget> 68 </widget>
53 </item> 69 </item>
54 <item row="3" column="1" colspan="2"> 70 <item row="1" column="1" colspan="2">
55 <widget class="QLabel" name="bcat_empty_label"> 71 <widget class="QLabel" name="label_2">
56 <property name="enabled">
57 <bool>true</bool>
58 </property>
59 <property name="maximumSize"> 72 <property name="maximumSize">
60 <size> 73 <size>
61 <width>260</width> 74 <width>260</width>
@@ -63,10 +76,7 @@
63 </size> 76 </size>
64 </property> 77 </property>
65 <property name="text"> 78 <property name="text">
66 <string/> 79 <string>BCAT is Nintendo's way of sending data to games to engage its community and unlock additional content.</string>
67 </property>
68 <property name="alignment">
69 <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
70 </property> 80 </property>
71 <property name="wordWrap"> 81 <property name="wordWrap">
72 <bool>true</bool> 82 <bool>true</bool>
@@ -86,8 +96,17 @@
86 <item row="0" column="1" colspan="2"> 96 <item row="0" column="1" colspan="2">
87 <widget class="QComboBox" name="bcat_source"/> 97 <widget class="QComboBox" name="bcat_source"/>
88 </item> 98 </item>
89 <item row="3" column="0"> 99 <item row="3" column="1" colspan="2">
90 <widget class="QLabel" name="bcat_empty_header"> 100 <widget class="QLabel" name="bcat_empty_label">
101 <property name="enabled">
102 <bool>true</bool>
103 </property>
104 <property name="maximumSize">
105 <size>
106 <width>260</width>
107 <height>16777215</height>
108 </size>
109 </property>
91 <property name="text"> 110 <property name="text">
92 <string/> 111 <string/>
93 </property> 112 </property>
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp
index 1bae1489f..e36774cc6 100644
--- a/src/yuzu/main.cpp
+++ b/src/yuzu/main.cpp
@@ -192,6 +192,7 @@ GMainWindow::GMainWindow()
192 : input_subsystem{std::make_shared<InputCommon::InputSubsystem>()}, 192 : input_subsystem{std::make_shared<InputCommon::InputSubsystem>()},
193 config{std::make_unique<Config>()}, vfs{std::make_shared<FileSys::RealVfsFilesystem>()}, 193 config{std::make_unique<Config>()}, vfs{std::make_shared<FileSys::RealVfsFilesystem>()},
194 provider{std::make_unique<FileSys::ManualContentProvider>()} { 194 provider{std::make_unique<FileSys::ManualContentProvider>()} {
195 Common::Log::Initialize();
195 LoadTranslation(); 196 LoadTranslation();
196 197
197 setAcceptDrops(true); 198 setAcceptDrops(true);
@@ -3381,7 +3382,6 @@ void GMainWindow::SetDiscordEnabled([[maybe_unused]] bool state) {
3381#endif 3382#endif
3382 3383
3383int main(int argc, char* argv[]) { 3384int main(int argc, char* argv[]) {
3384 Common::Log::Initialize();
3385 Common::DetachedTasks detached_tasks; 3385 Common::DetachedTasks detached_tasks;
3386 MicroProfileOnThreadCreate("Frontend"); 3386 MicroProfileOnThreadCreate("Frontend");
3387 SCOPE_EXIT({ MicroProfileShutdown(); }); 3387 SCOPE_EXIT({ MicroProfileShutdown(); });