summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/audio_core/audio_renderer.cpp99
-rw-r--r--src/audio_core/audio_renderer.h10
-rw-r--r--src/audio_core/common.h1
-rw-r--r--src/common/CMakeLists.txt2
-rw-r--r--src/common/time_zone.cpp49
-rw-r--r--src/common/time_zone.h18
-rw-r--r--src/core/hle/service/time/time_manager.cpp11
-rw-r--r--src/core/hle/service/time/time_zone_content_manager.cpp24
-rw-r--r--src/core/settings.cpp16
-rw-r--r--src/core/settings.h4
-rw-r--r--src/video_core/engines/shader_bytecode.h28
-rw-r--r--src/video_core/renderer_opengl/gl_shader_decompiler.cpp110
-rw-r--r--src/video_core/renderer_vulkan/vk_shader_decompiler.cpp27
-rw-r--r--src/video_core/shader/decode.cpp2
-rw-r--r--src/video_core/shader/decode/xmad.cpp12
-rw-r--r--src/video_core/shader/node.h21
-rw-r--r--src/video_core/shader/shader_ir.cpp109
-rw-r--r--src/yuzu/configuration/config.cpp3
-rw-r--r--src/yuzu/configuration/configure_system.cpp2
-rw-r--r--src/yuzu/configuration/configure_system.h1
-rw-r--r--src/yuzu/configuration/configure_system.ui257
-rw-r--r--src/yuzu_cmd/config.cpp5
-rw-r--r--src/yuzu_cmd/default_ini.h4
23 files changed, 654 insertions, 161 deletions
diff --git a/src/audio_core/audio_renderer.cpp b/src/audio_core/audio_renderer.cpp
index d18ef6940..50846a854 100644
--- a/src/audio_core/audio_renderer.cpp
+++ b/src/audio_core/audio_renderer.cpp
@@ -17,7 +17,7 @@ namespace AudioCore {
17 17
18constexpr u32 STREAM_SAMPLE_RATE{48000}; 18constexpr u32 STREAM_SAMPLE_RATE{48000};
19constexpr u32 STREAM_NUM_CHANNELS{2}; 19constexpr u32 STREAM_NUM_CHANNELS{2};
20 20using VoiceChannelHolder = std::array<VoiceResourceInformation*, 6>;
21class AudioRenderer::VoiceState { 21class AudioRenderer::VoiceState {
22public: 22public:
23 bool IsPlaying() const { 23 bool IsPlaying() const {
@@ -37,9 +37,10 @@ public:
37 } 37 }
38 38
39 void SetWaveIndex(std::size_t index); 39 void SetWaveIndex(std::size_t index);
40 std::vector<s16> DequeueSamples(std::size_t sample_count, Core::Memory::Memory& memory); 40 std::vector<s16> DequeueSamples(std::size_t sample_count, Core::Memory::Memory& memory,
41 const VoiceChannelHolder& voice_resources);
41 void UpdateState(); 42 void UpdateState();
42 void RefreshBuffer(Core::Memory::Memory& memory); 43 void RefreshBuffer(Core::Memory::Memory& memory, const VoiceChannelHolder& voice_resources);
43 44
44private: 45private:
45 bool is_in_use{}; 46 bool is_in_use{};
@@ -79,7 +80,7 @@ AudioRenderer::AudioRenderer(Core::Timing::CoreTiming& core_timing, Core::Memory
79 std::shared_ptr<Kernel::WritableEvent> buffer_event, 80 std::shared_ptr<Kernel::WritableEvent> buffer_event,
80 std::size_t instance_number) 81 std::size_t instance_number)
81 : worker_params{params}, buffer_event{buffer_event}, voices(params.voice_count), 82 : worker_params{params}, buffer_event{buffer_event}, voices(params.voice_count),
82 effects(params.effect_count), memory{memory_} { 83 voice_resources(params.voice_count), effects(params.effect_count), memory{memory_} {
83 behavior_info.SetUserRevision(params.revision); 84 behavior_info.SetUserRevision(params.revision);
84 audio_out = std::make_unique<AudioCore::AudioOut>(); 85 audio_out = std::make_unique<AudioCore::AudioOut>();
85 stream = audio_out->OpenStream(core_timing, STREAM_SAMPLE_RATE, STREAM_NUM_CHANNELS, 86 stream = audio_out->OpenStream(core_timing, STREAM_SAMPLE_RATE, STREAM_NUM_CHANNELS,
@@ -127,6 +128,12 @@ ResultVal<std::vector<u8>> AudioRenderer::UpdateAudioRenderer(const std::vector<
127 input_params.data() + sizeof(UpdateDataHeader) + config.behavior_size, 128 input_params.data() + sizeof(UpdateDataHeader) + config.behavior_size,
128 memory_pool_count * sizeof(MemoryPoolInfo)); 129 memory_pool_count * sizeof(MemoryPoolInfo));
129 130
131 // Copy voice resources
132 const std::size_t voice_resource_offset{sizeof(UpdateDataHeader) + config.behavior_size +
133 config.memory_pools_size};
134 std::memcpy(voice_resources.data(), input_params.data() + voice_resource_offset,
135 sizeof(VoiceResourceInformation) * voice_resources.size());
136
130 // Copy VoiceInfo structs 137 // Copy VoiceInfo structs
131 std::size_t voice_offset{sizeof(UpdateDataHeader) + config.behavior_size + 138 std::size_t voice_offset{sizeof(UpdateDataHeader) + config.behavior_size +
132 config.memory_pools_size + config.voice_resource_size}; 139 config.memory_pools_size + config.voice_resource_size};
@@ -220,14 +227,15 @@ void AudioRenderer::VoiceState::SetWaveIndex(std::size_t index) {
220 is_refresh_pending = true; 227 is_refresh_pending = true;
221} 228}
222 229
223std::vector<s16> AudioRenderer::VoiceState::DequeueSamples(std::size_t sample_count, 230std::vector<s16> AudioRenderer::VoiceState::DequeueSamples(
224 Core::Memory::Memory& memory) { 231 std::size_t sample_count, Core::Memory::Memory& memory,
232 const VoiceChannelHolder& voice_resources) {
225 if (!IsPlaying()) { 233 if (!IsPlaying()) {
226 return {}; 234 return {};
227 } 235 }
228 236
229 if (is_refresh_pending) { 237 if (is_refresh_pending) {
230 RefreshBuffer(memory); 238 RefreshBuffer(memory, voice_resources);
231 } 239 }
232 240
233 const std::size_t max_size{samples.size() - offset}; 241 const std::size_t max_size{samples.size() - offset};
@@ -271,7 +279,8 @@ void AudioRenderer::VoiceState::UpdateState() {
271 is_in_use = info.is_in_use; 279 is_in_use = info.is_in_use;
272} 280}
273 281
274void AudioRenderer::VoiceState::RefreshBuffer(Core::Memory::Memory& memory) { 282void AudioRenderer::VoiceState::RefreshBuffer(Core::Memory::Memory& memory,
283 const VoiceChannelHolder& voice_resources) {
275 const auto wave_buffer_address = info.wave_buffer[wave_index].buffer_addr; 284 const auto wave_buffer_address = info.wave_buffer[wave_index].buffer_addr;
276 const auto wave_buffer_size = info.wave_buffer[wave_index].buffer_sz; 285 const auto wave_buffer_size = info.wave_buffer[wave_index].buffer_sz;
277 std::vector<s16> new_samples(wave_buffer_size / sizeof(s16)); 286 std::vector<s16> new_samples(wave_buffer_size / sizeof(s16));
@@ -296,17 +305,77 @@ void AudioRenderer::VoiceState::RefreshBuffer(Core::Memory::Memory& memory) {
296 } 305 }
297 306
298 switch (info.channel_count) { 307 switch (info.channel_count) {
299 case 1: 308 case 1: {
300 // 1 channel is upsampled to 2 channel 309 // 1 channel is upsampled to 2 channel
301 samples.resize(new_samples.size() * 2); 310 samples.resize(new_samples.size() * 2);
311
302 for (std::size_t index = 0; index < new_samples.size(); ++index) { 312 for (std::size_t index = 0; index < new_samples.size(); ++index) {
303 samples[index * 2] = new_samples[index]; 313 auto sample = static_cast<float>(new_samples[index]);
304 samples[index * 2 + 1] = new_samples[index]; 314 if (voice_resources[0]->in_use) {
315 sample *= voice_resources[0]->mix_volumes[0];
316 }
317
318 samples[index * 2] = static_cast<s16>(sample * info.volume);
319 samples[index * 2 + 1] = static_cast<s16>(sample * info.volume);
305 } 320 }
306 break; 321 break;
322 }
307 case 2: { 323 case 2: {
308 // 2 channel is played as is 324 // 2 channel is played as is
309 samples = std::move(new_samples); 325 samples = std::move(new_samples);
326 const std::size_t sample_count = (samples.size() / 2);
327 for (std::size_t index = 0; index < sample_count; ++index) {
328 const std::size_t index_l = index * 2;
329 const std::size_t index_r = index * 2 + 1;
330
331 auto sample_l = static_cast<float>(samples[index_l]);
332 auto sample_r = static_cast<float>(samples[index_r]);
333
334 if (voice_resources[0]->in_use) {
335 sample_l *= voice_resources[0]->mix_volumes[0];
336 }
337
338 if (voice_resources[1]->in_use) {
339 sample_r *= voice_resources[1]->mix_volumes[1];
340 }
341
342 samples[index_l] = static_cast<s16>(sample_l * info.volume);
343 samples[index_r] = static_cast<s16>(sample_r * info.volume);
344 }
345 break;
346 }
347 case 6: {
348 samples.resize((new_samples.size() / 6) * 2);
349 const std::size_t sample_count = samples.size() / 2;
350
351 for (std::size_t index = 0; index < sample_count; ++index) {
352 auto FL = static_cast<float>(new_samples[index * 6]);
353 auto FR = static_cast<float>(new_samples[index * 6 + 1]);
354 auto FC = static_cast<float>(new_samples[index * 6 + 2]);
355 auto BL = static_cast<float>(new_samples[index * 6 + 4]);
356 auto BR = static_cast<float>(new_samples[index * 6 + 5]);
357
358 if (voice_resources[0]->in_use) {
359 FL *= voice_resources[0]->mix_volumes[0];
360 }
361 if (voice_resources[1]->in_use) {
362 FR *= voice_resources[1]->mix_volumes[1];
363 }
364 if (voice_resources[2]->in_use) {
365 FC *= voice_resources[2]->mix_volumes[2];
366 }
367 if (voice_resources[4]->in_use) {
368 BL *= voice_resources[4]->mix_volumes[4];
369 }
370 if (voice_resources[5]->in_use) {
371 BR *= voice_resources[5]->mix_volumes[5];
372 }
373
374 samples[index * 2] =
375 static_cast<s16>((0.3694f * FL + 0.2612f * FC + 0.3694f * BL) * info.volume);
376 samples[index * 2 + 1] =
377 static_cast<s16>((0.3694f * FR + 0.2612f * FC + 0.3694f * BR) * info.volume);
378 }
310 break; 379 break;
311 } 380 }
312 default: 381 default:
@@ -352,11 +421,17 @@ void AudioRenderer::QueueMixedBuffer(Buffer::Tag tag) {
352 if (!voice.IsPlaying()) { 421 if (!voice.IsPlaying()) {
353 continue; 422 continue;
354 } 423 }
424 VoiceChannelHolder resources{};
425 for (u32 channel = 0; channel < voice.GetInfo().channel_count; channel++) {
426 const auto channel_resource_id = voice.GetInfo().voice_channel_resource_ids[channel];
427 resources[channel] = &voice_resources[channel_resource_id];
428 }
355 429
356 std::size_t offset{}; 430 std::size_t offset{};
357 s64 samples_remaining{BUFFER_SIZE}; 431 s64 samples_remaining{BUFFER_SIZE};
358 while (samples_remaining > 0) { 432 while (samples_remaining > 0) {
359 const std::vector<s16> samples{voice.DequeueSamples(samples_remaining, memory)}; 433 const std::vector<s16> samples{
434 voice.DequeueSamples(samples_remaining, memory, resources)};
360 435
361 if (samples.empty()) { 436 if (samples.empty()) {
362 break; 437 break;
diff --git a/src/audio_core/audio_renderer.h b/src/audio_core/audio_renderer.h
index b42770fae..1f9114c07 100644
--- a/src/audio_core/audio_renderer.h
+++ b/src/audio_core/audio_renderer.h
@@ -9,6 +9,7 @@
9#include <vector> 9#include <vector>
10 10
11#include "audio_core/behavior_info.h" 11#include "audio_core/behavior_info.h"
12#include "audio_core/common.h"
12#include "audio_core/stream.h" 13#include "audio_core/stream.h"
13#include "common/common_funcs.h" 14#include "common/common_funcs.h"
14#include "common/common_types.h" 15#include "common/common_types.h"
@@ -116,6 +117,14 @@ struct WaveBuffer {
116}; 117};
117static_assert(sizeof(WaveBuffer) == 0x38, "WaveBuffer has wrong size"); 118static_assert(sizeof(WaveBuffer) == 0x38, "WaveBuffer has wrong size");
118 119
120struct VoiceResourceInformation {
121 s32_le id{};
122 std::array<float_le, MAX_MIX_BUFFERS> mix_volumes{};
123 bool in_use{};
124 INSERT_PADDING_BYTES(11);
125};
126static_assert(sizeof(VoiceResourceInformation) == 0x70, "VoiceResourceInformation has wrong size");
127
119struct VoiceInfo { 128struct VoiceInfo {
120 u32_le id; 129 u32_le id;
121 u32_le node_id; 130 u32_le node_id;
@@ -244,6 +253,7 @@ private:
244 AudioRendererParameter worker_params; 253 AudioRendererParameter worker_params;
245 std::shared_ptr<Kernel::WritableEvent> buffer_event; 254 std::shared_ptr<Kernel::WritableEvent> buffer_event;
246 std::vector<VoiceState> voices; 255 std::vector<VoiceState> voices;
256 std::vector<VoiceResourceInformation> voice_resources;
247 std::vector<EffectState> effects; 257 std::vector<EffectState> effects;
248 std::unique_ptr<AudioOut> audio_out; 258 std::unique_ptr<AudioOut> audio_out;
249 StreamPtr stream; 259 StreamPtr stream;
diff --git a/src/audio_core/common.h b/src/audio_core/common.h
index 98478b66b..7bb145c53 100644
--- a/src/audio_core/common.h
+++ b/src/audio_core/common.h
@@ -14,6 +14,7 @@ constexpr ResultCode ERR_INVALID_PARAMETERS{ErrorModule::Audio, 41};
14} 14}
15 15
16constexpr u32_le CURRENT_PROCESS_REVISION = Common::MakeMagic('R', 'E', 'V', '8'); 16constexpr u32_le CURRENT_PROCESS_REVISION = Common::MakeMagic('R', 'E', 'V', '8');
17constexpr std::size_t MAX_MIX_BUFFERS = 24;
17 18
18static constexpr u32 VersionFromRevision(u32_le rev) { 19static constexpr u32 VersionFromRevision(u32_le rev) {
19 // "REV7" -> 7 20 // "REV7" -> 7
diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt
index d1ec8ff08..e6769a5f3 100644
--- a/src/common/CMakeLists.txt
+++ b/src/common/CMakeLists.txt
@@ -148,6 +148,8 @@ add_library(common STATIC
148 thread.h 148 thread.h
149 thread_queue_list.h 149 thread_queue_list.h
150 threadsafe_queue.h 150 threadsafe_queue.h
151 time_zone.cpp
152 time_zone.h
151 timer.cpp 153 timer.cpp
152 timer.h 154 timer.h
153 uint128.cpp 155 uint128.cpp
diff --git a/src/common/time_zone.cpp b/src/common/time_zone.cpp
new file mode 100644
index 000000000..ce239eb63
--- /dev/null
+++ b/src/common/time_zone.cpp
@@ -0,0 +1,49 @@
1// Copyright 2020 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include <chrono>
6#include <iomanip>
7#include <sstream>
8
9#include "common/logging/log.h"
10#include "common/time_zone.h"
11
12namespace Common::TimeZone {
13
14std::string GetDefaultTimeZone() {
15 return "GMT";
16}
17
18static std::string GetOsTimeZoneOffset() {
19 const std::time_t t{std::time(nullptr)};
20 const std::tm tm{*std::localtime(&t)};
21
22 std::stringstream ss;
23 ss << std::put_time(&tm, "%z"); // Get the current timezone offset, e.g. "-400", as a string
24
25 return ss.str();
26}
27
28static int ConvertOsTimeZoneOffsetToInt(const std::string& timezone) {
29 try {
30 return std::stoi(timezone);
31 } catch (const std::invalid_argument&) {
32 LOG_CRITICAL(Common, "invalid_argument with {}!", timezone);
33 return 0;
34 } catch (const std::out_of_range&) {
35 LOG_CRITICAL(Common, "out_of_range with {}!", timezone);
36 return 0;
37 }
38}
39
40std::chrono::seconds GetCurrentOffsetSeconds() {
41 const int offset{ConvertOsTimeZoneOffsetToInt(GetOsTimeZoneOffset())};
42
43 int seconds{(offset / 100) * 60 * 60}; // Convert hour component to seconds
44 seconds += (offset % 100) * 60; // Convert minute component to seconds
45
46 return std::chrono::seconds{seconds};
47}
48
49} // namespace Common::TimeZone
diff --git a/src/common/time_zone.h b/src/common/time_zone.h
new file mode 100644
index 000000000..945daa09c
--- /dev/null
+++ b/src/common/time_zone.h
@@ -0,0 +1,18 @@
1// Copyright 2020 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <chrono>
8#include <string>
9
10namespace Common::TimeZone {
11
12/// Gets the default timezone, i.e. "GMT"
13std::string GetDefaultTimeZone();
14
15/// Gets the offset of the current timezone (from the default), in seconds
16std::chrono::seconds GetCurrentOffsetSeconds();
17
18} // namespace Common::TimeZone
diff --git a/src/core/hle/service/time/time_manager.cpp b/src/core/hle/service/time/time_manager.cpp
index 9d6c55865..b4dfe45e5 100644
--- a/src/core/hle/service/time/time_manager.cpp
+++ b/src/core/hle/service/time/time_manager.cpp
@@ -5,6 +5,7 @@
5#include <chrono> 5#include <chrono>
6#include <ctime> 6#include <ctime>
7 7
8#include "common/time_zone.h"
8#include "core/hle/service/time/ephemeral_network_system_clock_context_writer.h" 9#include "core/hle/service/time/ephemeral_network_system_clock_context_writer.h"
9#include "core/hle/service/time/local_system_clock_context_writer.h" 10#include "core/hle/service/time/local_system_clock_context_writer.h"
10#include "core/hle/service/time/network_system_clock_context_writer.h" 11#include "core/hle/service/time/network_system_clock_context_writer.h"
@@ -21,8 +22,16 @@ static std::chrono::seconds GetSecondsSinceEpoch() {
21 Settings::values.custom_rtc_differential; 22 Settings::values.custom_rtc_differential;
22} 23}
23 24
25static s64 GetExternalTimeZoneOffset() {
26 // With "auto" timezone setting, we use the external system's timezone offset
27 if (Settings::GetTimeZoneString() == "auto") {
28 return Common::TimeZone::GetCurrentOffsetSeconds().count();
29 }
30 return 0;
31}
32
24static s64 GetExternalRtcValue() { 33static s64 GetExternalRtcValue() {
25 return GetSecondsSinceEpoch().count(); 34 return GetSecondsSinceEpoch().count() + GetExternalTimeZoneOffset();
26} 35}
27 36
28TimeManager::TimeManager(Core::System& system) 37TimeManager::TimeManager(Core::System& system)
diff --git a/src/core/hle/service/time/time_zone_content_manager.cpp b/src/core/hle/service/time/time_zone_content_manager.cpp
index 78d4acd95..c070d6e97 100644
--- a/src/core/hle/service/time/time_zone_content_manager.cpp
+++ b/src/core/hle/service/time/time_zone_content_manager.cpp
@@ -5,6 +5,7 @@
5#include <sstream> 5#include <sstream>
6 6
7#include "common/logging/log.h" 7#include "common/logging/log.h"
8#include "common/time_zone.h"
8#include "core/core.h" 9#include "core/core.h"
9#include "core/file_sys/content_archive.h" 10#include "core/file_sys/content_archive.h"
10#include "core/file_sys/nca_metadata.h" 11#include "core/file_sys/nca_metadata.h"
@@ -14,6 +15,7 @@
14#include "core/hle/service/filesystem/filesystem.h" 15#include "core/hle/service/filesystem/filesystem.h"
15#include "core/hle/service/time/time_manager.h" 16#include "core/hle/service/time/time_manager.h"
16#include "core/hle/service/time/time_zone_content_manager.h" 17#include "core/hle/service/time/time_zone_content_manager.h"
18#include "core/settings.h"
17 19
18namespace Service::Time::TimeZone { 20namespace Service::Time::TimeZone {
19 21
@@ -68,10 +70,22 @@ static std::vector<std::string> BuildLocationNameCache(Core::System& system) {
68 70
69TimeZoneContentManager::TimeZoneContentManager(TimeManager& time_manager, Core::System& system) 71TimeZoneContentManager::TimeZoneContentManager(TimeManager& time_manager, Core::System& system)
70 : system{system}, location_name_cache{BuildLocationNameCache(system)} { 72 : system{system}, location_name_cache{BuildLocationNameCache(system)} {
71 if (FileSys::VirtualFile vfs_file; GetTimeZoneInfoFile("GMT", vfs_file) == RESULT_SUCCESS) { 73
74 std::string location_name;
75 const auto timezone_setting = Settings::GetTimeZoneString();
76 if (timezone_setting == "auto") {
77 location_name = Common::TimeZone::GetDefaultTimeZone();
78 } else if (timezone_setting == "default") {
79 location_name = location_name;
80 } else {
81 location_name = timezone_setting;
82 }
83
84 if (FileSys::VirtualFile vfs_file;
85 GetTimeZoneInfoFile(location_name, vfs_file) == RESULT_SUCCESS) {
72 const auto time_point{ 86 const auto time_point{
73 time_manager.GetStandardSteadyClockCore().GetCurrentTimePoint(system)}; 87 time_manager.GetStandardSteadyClockCore().GetCurrentTimePoint(system)};
74 time_manager.SetupTimeZoneManager("GMT", time_point, location_name_cache.size(), {}, 88 time_manager.SetupTimeZoneManager(location_name, time_point, location_name_cache.size(), {},
75 vfs_file); 89 vfs_file);
76 } else { 90 } else {
77 time_zone_manager.MarkAsInitialized(); 91 time_zone_manager.MarkAsInitialized();
@@ -114,6 +128,12 @@ ResultCode TimeZoneContentManager::GetTimeZoneInfoFile(const std::string& locati
114 128
115 vfs_file = zoneinfo_dir->GetFile(location_name); 129 vfs_file = zoneinfo_dir->GetFile(location_name);
116 if (!vfs_file) { 130 if (!vfs_file) {
131 LOG_ERROR(Service_Time, "{:016X} has no file \"{}\"! Using default timezone.",
132 time_zone_binary_titleid, location_name);
133 vfs_file = zoneinfo_dir->GetFile(Common::TimeZone::GetDefaultTimeZone());
134 }
135
136 if (!vfs_file) {
117 LOG_ERROR(Service_Time, "{:016X} has no file \"{}\"!", time_zone_binary_titleid, 137 LOG_ERROR(Service_Time, "{:016X} has no file \"{}\"!", time_zone_binary_titleid,
118 location_name); 138 location_name);
119 return ERROR_TIME_NOT_FOUND; 139 return ERROR_TIME_NOT_FOUND;
diff --git a/src/core/settings.cpp b/src/core/settings.cpp
index 2b0bdc4d3..da53cde05 100644
--- a/src/core/settings.cpp
+++ b/src/core/settings.cpp
@@ -63,6 +63,21 @@ const std::array<const char*, NumMouseButtons> mapping = {{
63 63
64Values values = {}; 64Values values = {};
65 65
66std::string GetTimeZoneString() {
67 static constexpr std::array<const char*, 46> timezones{{
68 "auto", "default", "CET", "CST6CDT", "Cuba", "EET", "Egypt", "Eire",
69 "EST", "EST5EDT", "GB", "GB-Eire", "GMT", "GMT+0", "GMT-0", "GMT0",
70 "Greenwich", "Hongkong", "HST", "Iceland", "Iran", "Israel", "Jamaica", "Japan",
71 "Kwajalein", "Libya", "MET", "MST", "MST7MDT", "Navajo", "NZ", "NZ-CHAT",
72 "Poland", "Portugal", "PRC", "PST8PDT", "ROC", "ROK", "Singapore", "Turkey",
73 "UCT", "Universal", "UTC", "W-SU", "WET", "Zulu",
74 }};
75
76 ASSERT(Settings::values.time_zone_index < timezones.size());
77
78 return timezones[Settings::values.time_zone_index];
79}
80
66void Apply() { 81void Apply() {
67 GDBStub::SetServerPort(values.gdbstub_port); 82 GDBStub::SetServerPort(values.gdbstub_port);
68 GDBStub::ToggleServer(values.use_gdbstub); 83 GDBStub::ToggleServer(values.use_gdbstub);
@@ -87,6 +102,7 @@ void LogSettings() {
87 LogSetting("System_CurrentUser", Settings::values.current_user); 102 LogSetting("System_CurrentUser", Settings::values.current_user);
88 LogSetting("System_LanguageIndex", Settings::values.language_index); 103 LogSetting("System_LanguageIndex", Settings::values.language_index);
89 LogSetting("System_RegionIndex", Settings::values.region_index); 104 LogSetting("System_RegionIndex", Settings::values.region_index);
105 LogSetting("System_TimeZoneIndex", Settings::values.time_zone_index);
90 LogSetting("Core_UseMultiCore", Settings::values.use_multi_core); 106 LogSetting("Core_UseMultiCore", Settings::values.use_multi_core);
91 LogSetting("Renderer_UseResolutionFactor", Settings::values.resolution_factor); 107 LogSetting("Renderer_UseResolutionFactor", Settings::values.resolution_factor);
92 LogSetting("Renderer_UseFrameLimit", Settings::values.use_frame_limit); 108 LogSetting("Renderer_UseFrameLimit", Settings::values.use_frame_limit);
diff --git a/src/core/settings.h b/src/core/settings.h
index 163900f0b..c1266b341 100644
--- a/src/core/settings.h
+++ b/src/core/settings.h
@@ -394,6 +394,7 @@ struct Values {
394 s32 current_user; 394 s32 current_user;
395 s32 language_index; 395 s32 language_index;
396 s32 region_index; 396 s32 region_index;
397 s32 time_zone_index;
397 s32 sound_index; 398 s32 sound_index;
398 399
399 // Controls 400 // Controls
@@ -490,6 +491,9 @@ struct Values {
490bool IsGPULevelExtreme(); 491bool IsGPULevelExtreme();
491bool IsGPULevelHigh(); 492bool IsGPULevelHigh();
492 493
494std::string GetTimeZoneString();
495
493void Apply(); 496void Apply();
494void LogSettings(); 497void LogSettings();
498
495} // namespace Settings 499} // namespace Settings
diff --git a/src/video_core/engines/shader_bytecode.h b/src/video_core/engines/shader_bytecode.h
index 8dae754d4..e7cb87589 100644
--- a/src/video_core/engines/shader_bytecode.h
+++ b/src/video_core/engines/shader_bytecode.h
@@ -168,18 +168,22 @@ enum class Pred : u64 {
168}; 168};
169 169
170enum class PredCondition : u64 { 170enum class PredCondition : u64 {
171 LessThan = 1, 171 F = 0, // Always false
172 Equal = 2, 172 LT = 1, // Ordered less than
173 LessEqual = 3, 173 EQ = 2, // Ordered equal
174 GreaterThan = 4, 174 LE = 3, // Ordered less than or equal
175 NotEqual = 5, 175 GT = 4, // Ordered greater than
176 GreaterEqual = 6, 176 NE = 5, // Ordered not equal
177 LessThanWithNan = 9, 177 GE = 6, // Ordered greater than or equal
178 LessEqualWithNan = 11, 178 NUM = 7, // Ordered
179 GreaterThanWithNan = 12, 179 NAN_ = 8, // Unordered
180 NotEqualWithNan = 13, 180 LTU = 9, // Unordered less than
181 GreaterEqualWithNan = 14, 181 EQU = 10, // Unordered equal
182 // TODO(Subv): Other condition types 182 LEU = 11, // Unordered less than or equal
183 GTU = 12, // Unordered greater than
184 NEU = 13, // Unordered not equal
185 GEU = 14, // Unordered greater than or equal
186 T = 15, // Always true
183}; 187};
184 188
185enum class PredOperation : u64 { 189enum class PredOperation : u64 {
diff --git a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
index 99fd4ae2c..960ebf1a1 100644
--- a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
+++ b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
@@ -1840,34 +1840,40 @@ private:
1840 Type::HalfFloat}; 1840 Type::HalfFloat};
1841 } 1841 }
1842 1842
1843 template <Type type> 1843 template <const std::string_view& op, Type type, bool unordered = false>
1844 Expression LogicalLessThan(Operation operation) { 1844 Expression Comparison(Operation operation) {
1845 return GenerateBinaryInfix(operation, "<", Type::Bool, type, type); 1845 static_assert(!unordered || type == Type::Float);
1846 } 1846
1847 1847 const Expression expr = GenerateBinaryInfix(operation, op, Type::Bool, type, type);
1848 template <Type type> 1848
1849 Expression LogicalEqual(Operation operation) { 1849 if constexpr (op.compare("!=") == 0 && type == Type::Float && !unordered) {
1850 return GenerateBinaryInfix(operation, "==", Type::Bool, type, type); 1850 // GLSL's operator!=(float, float) doesn't seem be ordered. This happens on both AMD's
1851 } 1851 // and Nvidia's proprietary stacks. Manually force an ordered comparison.
1852 1852 return {fmt::format("({} && !isnan({}) && !isnan({}))", expr.AsBool(),
1853 template <Type type> 1853 VisitOperand(operation, 0).AsFloat(),
1854 Expression LogicalLessEqual(Operation operation) { 1854 VisitOperand(operation, 1).AsFloat()),
1855 return GenerateBinaryInfix(operation, "<=", Type::Bool, type, type); 1855 Type::Bool};
1856 } 1856 }
1857 1857 if constexpr (!unordered) {
1858 template <Type type> 1858 return expr;
1859 Expression LogicalGreaterThan(Operation operation) { 1859 }
1860 return GenerateBinaryInfix(operation, ">", Type::Bool, type, type); 1860 // Unordered comparisons are always true for NaN operands.
1861 return {fmt::format("({} || isnan({}) || isnan({}))", expr.AsBool(),
1862 VisitOperand(operation, 0).AsFloat(),
1863 VisitOperand(operation, 1).AsFloat()),
1864 Type::Bool};
1861 } 1865 }
1862 1866
1863 template <Type type> 1867 Expression FOrdered(Operation operation) {
1864 Expression LogicalNotEqual(Operation operation) { 1868 return {fmt::format("(!isnan({}) && !isnan({}))", VisitOperand(operation, 0).AsFloat(),
1865 return GenerateBinaryInfix(operation, "!=", Type::Bool, type, type); 1869 VisitOperand(operation, 1).AsFloat()),
1870 Type::Bool};
1866 } 1871 }
1867 1872
1868 template <Type type> 1873 Expression FUnordered(Operation operation) {
1869 Expression LogicalGreaterEqual(Operation operation) { 1874 return {fmt::format("(isnan({}) || isnan({}))", VisitOperand(operation, 0).AsFloat(),
1870 return GenerateBinaryInfix(operation, ">=", Type::Bool, type, type); 1875 VisitOperand(operation, 1).AsFloat()),
1876 Type::Bool};
1871 } 1877 }
1872 1878
1873 Expression LogicalAddCarry(Operation operation) { 1879 Expression LogicalAddCarry(Operation operation) {
@@ -2324,6 +2330,13 @@ private:
2324 Func() = delete; 2330 Func() = delete;
2325 ~Func() = delete; 2331 ~Func() = delete;
2326 2332
2333 static constexpr std::string_view LessThan = "<";
2334 static constexpr std::string_view Equal = "==";
2335 static constexpr std::string_view LessEqual = "<=";
2336 static constexpr std::string_view GreaterThan = ">";
2337 static constexpr std::string_view NotEqual = "!=";
2338 static constexpr std::string_view GreaterEqual = ">=";
2339
2327 static constexpr std::string_view Add = "Add"; 2340 static constexpr std::string_view Add = "Add";
2328 static constexpr std::string_view Min = "Min"; 2341 static constexpr std::string_view Min = "Min";
2329 static constexpr std::string_view Max = "Max"; 2342 static constexpr std::string_view Max = "Max";
@@ -2425,27 +2438,34 @@ private:
2425 &GLSLDecompiler::LogicalPick2, 2438 &GLSLDecompiler::LogicalPick2,
2426 &GLSLDecompiler::LogicalAnd2, 2439 &GLSLDecompiler::LogicalAnd2,
2427 2440
2428 &GLSLDecompiler::LogicalLessThan<Type::Float>, 2441 &GLSLDecompiler::Comparison<Func::LessThan, Type::Float, false>,
2429 &GLSLDecompiler::LogicalEqual<Type::Float>, 2442 &GLSLDecompiler::Comparison<Func::Equal, Type::Float, false>,
2430 &GLSLDecompiler::LogicalLessEqual<Type::Float>, 2443 &GLSLDecompiler::Comparison<Func::LessEqual, Type::Float, false>,
2431 &GLSLDecompiler::LogicalGreaterThan<Type::Float>, 2444 &GLSLDecompiler::Comparison<Func::GreaterThan, Type::Float, false>,
2432 &GLSLDecompiler::LogicalNotEqual<Type::Float>, 2445 &GLSLDecompiler::Comparison<Func::NotEqual, Type::Float, false>,
2433 &GLSLDecompiler::LogicalGreaterEqual<Type::Float>, 2446 &GLSLDecompiler::Comparison<Func::GreaterEqual, Type::Float, false>,
2434 &GLSLDecompiler::LogicalFIsNan, 2447 &GLSLDecompiler::FOrdered,
2435 2448 &GLSLDecompiler::FUnordered,
2436 &GLSLDecompiler::LogicalLessThan<Type::Int>, 2449 &GLSLDecompiler::Comparison<Func::LessThan, Type::Float, true>,
2437 &GLSLDecompiler::LogicalEqual<Type::Int>, 2450 &GLSLDecompiler::Comparison<Func::Equal, Type::Float, true>,
2438 &GLSLDecompiler::LogicalLessEqual<Type::Int>, 2451 &GLSLDecompiler::Comparison<Func::LessEqual, Type::Float, true>,
2439 &GLSLDecompiler::LogicalGreaterThan<Type::Int>, 2452 &GLSLDecompiler::Comparison<Func::GreaterThan, Type::Float, true>,
2440 &GLSLDecompiler::LogicalNotEqual<Type::Int>, 2453 &GLSLDecompiler::Comparison<Func::NotEqual, Type::Float, true>,
2441 &GLSLDecompiler::LogicalGreaterEqual<Type::Int>, 2454 &GLSLDecompiler::Comparison<Func::GreaterEqual, Type::Float, true>,
2442 2455
2443 &GLSLDecompiler::LogicalLessThan<Type::Uint>, 2456 &GLSLDecompiler::Comparison<Func::LessThan, Type::Int>,
2444 &GLSLDecompiler::LogicalEqual<Type::Uint>, 2457 &GLSLDecompiler::Comparison<Func::Equal, Type::Int>,
2445 &GLSLDecompiler::LogicalLessEqual<Type::Uint>, 2458 &GLSLDecompiler::Comparison<Func::LessEqual, Type::Int>,
2446 &GLSLDecompiler::LogicalGreaterThan<Type::Uint>, 2459 &GLSLDecompiler::Comparison<Func::GreaterThan, Type::Int>,
2447 &GLSLDecompiler::LogicalNotEqual<Type::Uint>, 2460 &GLSLDecompiler::Comparison<Func::NotEqual, Type::Int>,
2448 &GLSLDecompiler::LogicalGreaterEqual<Type::Uint>, 2461 &GLSLDecompiler::Comparison<Func::GreaterEqual, Type::Int>,
2462
2463 &GLSLDecompiler::Comparison<Func::LessThan, Type::Uint>,
2464 &GLSLDecompiler::Comparison<Func::Equal, Type::Uint>,
2465 &GLSLDecompiler::Comparison<Func::LessEqual, Type::Uint>,
2466 &GLSLDecompiler::Comparison<Func::GreaterThan, Type::Uint>,
2467 &GLSLDecompiler::Comparison<Func::NotEqual, Type::Uint>,
2468 &GLSLDecompiler::Comparison<Func::GreaterEqual, Type::Uint>,
2449 2469
2450 &GLSLDecompiler::LogicalAddCarry, 2470 &GLSLDecompiler::LogicalAddCarry,
2451 2471
diff --git a/src/video_core/renderer_vulkan/vk_shader_decompiler.cpp b/src/video_core/renderer_vulkan/vk_shader_decompiler.cpp
index 18678968c..167e20e91 100644
--- a/src/video_core/renderer_vulkan/vk_shader_decompiler.cpp
+++ b/src/video_core/renderer_vulkan/vk_shader_decompiler.cpp
@@ -1618,6 +1618,24 @@ private:
1618 return {}; 1618 return {};
1619 } 1619 }
1620 1620
1621 Expression LogicalFOrdered(Operation operation) {
1622 // Emulate SPIR-V's OpOrdered
1623 const Id op_a = AsFloat(Visit(operation[0]));
1624 const Id op_b = AsFloat(Visit(operation[1]));
1625 const Id is_num_a = OpFOrdEqual(t_bool, op_a, op_a);
1626 const Id is_num_b = OpFOrdEqual(t_bool, op_b, op_b);
1627 return {OpLogicalAnd(t_bool, is_num_a, is_num_b), Type::Bool};
1628 }
1629
1630 Expression LogicalFUnordered(Operation operation) {
1631 // Emulate SPIR-V's OpUnordered
1632 const Id op_a = AsFloat(Visit(operation[0]));
1633 const Id op_b = AsFloat(Visit(operation[1]));
1634 const Id is_nan_a = OpIsNan(t_bool, op_a);
1635 const Id is_nan_b = OpIsNan(t_bool, op_b);
1636 return {OpLogicalOr(t_bool, is_nan_a, is_nan_b), Type::Bool};
1637 }
1638
1621 Id GetTextureSampler(Operation operation) { 1639 Id GetTextureSampler(Operation operation) {
1622 const auto& meta = std::get<MetaTexture>(operation.GetMeta()); 1640 const auto& meta = std::get<MetaTexture>(operation.GetMeta());
1623 ASSERT(!meta.sampler.is_buffer); 1641 ASSERT(!meta.sampler.is_buffer);
@@ -2511,7 +2529,14 @@ private:
2511 &SPIRVDecompiler::Binary<&Module::OpFOrdGreaterThan, Type::Bool, Type::Float>, 2529 &SPIRVDecompiler::Binary<&Module::OpFOrdGreaterThan, Type::Bool, Type::Float>,
2512 &SPIRVDecompiler::Binary<&Module::OpFOrdNotEqual, Type::Bool, Type::Float>, 2530 &SPIRVDecompiler::Binary<&Module::OpFOrdNotEqual, Type::Bool, Type::Float>,
2513 &SPIRVDecompiler::Binary<&Module::OpFOrdGreaterThanEqual, Type::Bool, Type::Float>, 2531 &SPIRVDecompiler::Binary<&Module::OpFOrdGreaterThanEqual, Type::Bool, Type::Float>,
2514 &SPIRVDecompiler::Unary<&Module::OpIsNan, Type::Bool, Type::Float>, 2532 &SPIRVDecompiler::LogicalFOrdered,
2533 &SPIRVDecompiler::LogicalFUnordered,
2534 &SPIRVDecompiler::Binary<&Module::OpFUnordLessThan, Type::Bool, Type::Float>,
2535 &SPIRVDecompiler::Binary<&Module::OpFUnordEqual, Type::Bool, Type::Float>,
2536 &SPIRVDecompiler::Binary<&Module::OpFUnordLessThanEqual, Type::Bool, Type::Float>,
2537 &SPIRVDecompiler::Binary<&Module::OpFUnordGreaterThan, Type::Bool, Type::Float>,
2538 &SPIRVDecompiler::Binary<&Module::OpFUnordNotEqual, Type::Bool, Type::Float>,
2539 &SPIRVDecompiler::Binary<&Module::OpFUnordGreaterThanEqual, Type::Bool, Type::Float>,
2515 2540
2516 &SPIRVDecompiler::Binary<&Module::OpSLessThan, Type::Bool, Type::Int>, 2541 &SPIRVDecompiler::Binary<&Module::OpSLessThan, Type::Bool, Type::Int>,
2517 &SPIRVDecompiler::Binary<&Module::OpIEqual, Type::Bool, Type::Int>, 2542 &SPIRVDecompiler::Binary<&Module::OpIEqual, Type::Bool, Type::Int>,
diff --git a/src/video_core/shader/decode.cpp b/src/video_core/shader/decode.cpp
index a75a5cc63..eeac328a6 100644
--- a/src/video_core/shader/decode.cpp
+++ b/src/video_core/shader/decode.cpp
@@ -255,7 +255,7 @@ void ShaderIR::InsertControlFlow(NodeBlock& bb, const ShaderBlock& block) {
255 Node n = Operation(OperationCode::Branch, Immediate(branch_case.address)); 255 Node n = Operation(OperationCode::Branch, Immediate(branch_case.address));
256 Node op_b = Immediate(branch_case.cmp_value); 256 Node op_b = Immediate(branch_case.cmp_value);
257 Node condition = 257 Node condition =
258 GetPredicateComparisonInteger(Tegra::Shader::PredCondition::Equal, false, op_a, op_b); 258 GetPredicateComparisonInteger(Tegra::Shader::PredCondition::EQ, false, op_a, op_b);
259 auto result = Conditional(condition, {n}); 259 auto result = Conditional(condition, {n});
260 bb.push_back(result); 260 bb.push_back(result);
261 global_code.push_back(result); 261 global_code.push_back(result);
diff --git a/src/video_core/shader/decode/xmad.cpp b/src/video_core/shader/decode/xmad.cpp
index 6191ffba1..c83dc6615 100644
--- a/src/video_core/shader/decode/xmad.cpp
+++ b/src/video_core/shader/decode/xmad.cpp
@@ -97,19 +97,19 @@ u32 ShaderIR::DecodeXmad(NodeBlock& bb, u32 pc) {
97 return SignedOperation(OperationCode::IAdd, is_signed_c, original_c, shifted_b); 97 return SignedOperation(OperationCode::IAdd, is_signed_c, original_c, shifted_b);
98 } 98 }
99 case Tegra::Shader::XmadMode::CSfu: { 99 case Tegra::Shader::XmadMode::CSfu: {
100 const Node comp_a = GetPredicateComparisonInteger(PredCondition::Equal, is_signed_a, 100 const Node comp_a =
101 op_a, Immediate(0)); 101 GetPredicateComparisonInteger(PredCondition::EQ, is_signed_a, op_a, Immediate(0));
102 const Node comp_b = GetPredicateComparisonInteger(PredCondition::Equal, is_signed_b, 102 const Node comp_b =
103 op_b, Immediate(0)); 103 GetPredicateComparisonInteger(PredCondition::EQ, is_signed_b, op_b, Immediate(0));
104 const Node comp = Operation(OperationCode::LogicalOr, comp_a, comp_b); 104 const Node comp = Operation(OperationCode::LogicalOr, comp_a, comp_b);
105 105
106 const Node comp_minus_a = GetPredicateComparisonInteger( 106 const Node comp_minus_a = GetPredicateComparisonInteger(
107 PredCondition::NotEqual, is_signed_a, 107 PredCondition::NE, is_signed_a,
108 SignedOperation(OperationCode::IBitwiseAnd, is_signed_a, op_a, 108 SignedOperation(OperationCode::IBitwiseAnd, is_signed_a, op_a,
109 Immediate(0x80000000)), 109 Immediate(0x80000000)),
110 Immediate(0)); 110 Immediate(0));
111 const Node comp_minus_b = GetPredicateComparisonInteger( 111 const Node comp_minus_b = GetPredicateComparisonInteger(
112 PredCondition::NotEqual, is_signed_b, 112 PredCondition::NE, is_signed_b,
113 SignedOperation(OperationCode::IBitwiseAnd, is_signed_b, op_b, 113 SignedOperation(OperationCode::IBitwiseAnd, is_signed_b, op_b,
114 Immediate(0x80000000)), 114 Immediate(0x80000000)),
115 Immediate(0)); 115 Immediate(0));
diff --git a/src/video_core/shader/node.h b/src/video_core/shader/node.h
index 601c822d2..f75b62240 100644
--- a/src/video_core/shader/node.h
+++ b/src/video_core/shader/node.h
@@ -110,13 +110,20 @@ enum class OperationCode {
110 LogicalPick2, /// (bool2 pair, uint index) -> bool 110 LogicalPick2, /// (bool2 pair, uint index) -> bool
111 LogicalAnd2, /// (bool2 a) -> bool 111 LogicalAnd2, /// (bool2 a) -> bool
112 112
113 LogicalFLessThan, /// (float a, float b) -> bool 113 LogicalFOrdLessThan, /// (float a, float b) -> bool
114 LogicalFEqual, /// (float a, float b) -> bool 114 LogicalFOrdEqual, /// (float a, float b) -> bool
115 LogicalFLessEqual, /// (float a, float b) -> bool 115 LogicalFOrdLessEqual, /// (float a, float b) -> bool
116 LogicalFGreaterThan, /// (float a, float b) -> bool 116 LogicalFOrdGreaterThan, /// (float a, float b) -> bool
117 LogicalFNotEqual, /// (float a, float b) -> bool 117 LogicalFOrdNotEqual, /// (float a, float b) -> bool
118 LogicalFGreaterEqual, /// (float a, float b) -> bool 118 LogicalFOrdGreaterEqual, /// (float a, float b) -> bool
119 LogicalFIsNan, /// (float a) -> bool 119 LogicalFOrdered, /// (float a, float b) -> bool
120 LogicalFUnordered, /// (float a, float b) -> bool
121 LogicalFUnordLessThan, /// (float a, float b) -> bool
122 LogicalFUnordEqual, /// (float a, float b) -> bool
123 LogicalFUnordLessEqual, /// (float a, float b) -> bool
124 LogicalFUnordGreaterThan, /// (float a, float b) -> bool
125 LogicalFUnordNotEqual, /// (float a, float b) -> bool
126 LogicalFUnordGreaterEqual, /// (float a, float b) -> bool
120 127
121 LogicalILessThan, /// (int a, int b) -> bool 128 LogicalILessThan, /// (int a, int b) -> bool
122 LogicalIEqual, /// (int a, int b) -> bool 129 LogicalIEqual, /// (int a, int b) -> bool
diff --git a/src/video_core/shader/shader_ir.cpp b/src/video_core/shader/shader_ir.cpp
index 822674926..e322c3402 100644
--- a/src/video_core/shader/shader_ir.cpp
+++ b/src/video_core/shader/shader_ir.cpp
@@ -10,6 +10,7 @@
10#include "common/common_types.h" 10#include "common/common_types.h"
11#include "common/logging/log.h" 11#include "common/logging/log.h"
12#include "video_core/engines/shader_bytecode.h" 12#include "video_core/engines/shader_bytecode.h"
13#include "video_core/shader/node.h"
13#include "video_core/shader/node_helper.h" 14#include "video_core/shader/node_helper.h"
14#include "video_core/shader/registry.h" 15#include "video_core/shader/registry.h"
15#include "video_core/shader/shader_ir.h" 16#include "video_core/shader/shader_ir.h"
@@ -243,56 +244,44 @@ Node ShaderIR::GetSaturatedHalfFloat(Node value, bool saturate) {
243} 244}
244 245
245Node ShaderIR::GetPredicateComparisonFloat(PredCondition condition, Node op_a, Node op_b) { 246Node ShaderIR::GetPredicateComparisonFloat(PredCondition condition, Node op_a, Node op_b) {
247 if (condition == PredCondition::T) {
248 return GetPredicate(true);
249 } else if (condition == PredCondition::F) {
250 return GetPredicate(false);
251 }
252
246 static constexpr std::array comparison_table{ 253 static constexpr std::array comparison_table{
247 std::pair{PredCondition::LessThan, OperationCode::LogicalFLessThan}, 254 OperationCode(0),
248 std::pair{PredCondition::Equal, OperationCode::LogicalFEqual}, 255 OperationCode::LogicalFOrdLessThan, // LT
249 std::pair{PredCondition::LessEqual, OperationCode::LogicalFLessEqual}, 256 OperationCode::LogicalFOrdEqual, // EQ
250 std::pair{PredCondition::GreaterThan, OperationCode::LogicalFGreaterThan}, 257 OperationCode::LogicalFOrdLessEqual, // LE
251 std::pair{PredCondition::NotEqual, OperationCode::LogicalFNotEqual}, 258 OperationCode::LogicalFOrdGreaterThan, // GT
252 std::pair{PredCondition::GreaterEqual, OperationCode::LogicalFGreaterEqual}, 259 OperationCode::LogicalFOrdNotEqual, // NE
253 std::pair{PredCondition::LessThanWithNan, OperationCode::LogicalFLessThan}, 260 OperationCode::LogicalFOrdGreaterEqual, // GE
254 std::pair{PredCondition::NotEqualWithNan, OperationCode::LogicalFNotEqual}, 261 OperationCode::LogicalFOrdered, // NUM
255 std::pair{PredCondition::LessEqualWithNan, OperationCode::LogicalFLessEqual}, 262 OperationCode::LogicalFUnordered, // NAN
256 std::pair{PredCondition::GreaterThanWithNan, OperationCode::LogicalFGreaterThan}, 263 OperationCode::LogicalFUnordLessThan, // LTU
257 std::pair{PredCondition::GreaterEqualWithNan, OperationCode::LogicalFGreaterEqual}, 264 OperationCode::LogicalFUnordEqual, // EQU
265 OperationCode::LogicalFUnordLessEqual, // LEU
266 OperationCode::LogicalFUnordGreaterThan, // GTU
267 OperationCode::LogicalFUnordNotEqual, // NEU
268 OperationCode::LogicalFUnordGreaterEqual, // GEU
258 }; 269 };
270 const std::size_t index = static_cast<std::size_t>(condition);
271 ASSERT_MSG(index < std::size(comparison_table), "Invalid condition={}", index);
259 272
260 const auto comparison = 273 return Operation(comparison_table[index], op_a, op_b);
261 std::find_if(comparison_table.cbegin(), comparison_table.cend(),
262 [condition](const auto entry) { return condition == entry.first; });
263 UNIMPLEMENTED_IF_MSG(comparison == comparison_table.cend(),
264 "Unknown predicate comparison operation");
265
266 Node predicate = Operation(comparison->second, NO_PRECISE, op_a, op_b);
267
268 if (condition == PredCondition::LessThanWithNan ||
269 condition == PredCondition::NotEqualWithNan ||
270 condition == PredCondition::LessEqualWithNan ||
271 condition == PredCondition::GreaterThanWithNan ||
272 condition == PredCondition::GreaterEqualWithNan) {
273 predicate = Operation(OperationCode::LogicalOr, predicate,
274 Operation(OperationCode::LogicalFIsNan, op_a));
275 predicate = Operation(OperationCode::LogicalOr, predicate,
276 Operation(OperationCode::LogicalFIsNan, op_b));
277 }
278
279 return predicate;
280} 274}
281 275
282Node ShaderIR::GetPredicateComparisonInteger(PredCondition condition, bool is_signed, Node op_a, 276Node ShaderIR::GetPredicateComparisonInteger(PredCondition condition, bool is_signed, Node op_a,
283 Node op_b) { 277 Node op_b) {
284 static constexpr std::array comparison_table{ 278 static constexpr std::array comparison_table{
285 std::pair{PredCondition::LessThan, OperationCode::LogicalILessThan}, 279 std::pair{PredCondition::LT, OperationCode::LogicalILessThan},
286 std::pair{PredCondition::Equal, OperationCode::LogicalIEqual}, 280 std::pair{PredCondition::EQ, OperationCode::LogicalIEqual},
287 std::pair{PredCondition::LessEqual, OperationCode::LogicalILessEqual}, 281 std::pair{PredCondition::LE, OperationCode::LogicalILessEqual},
288 std::pair{PredCondition::GreaterThan, OperationCode::LogicalIGreaterThan}, 282 std::pair{PredCondition::GT, OperationCode::LogicalIGreaterThan},
289 std::pair{PredCondition::NotEqual, OperationCode::LogicalINotEqual}, 283 std::pair{PredCondition::NE, OperationCode::LogicalINotEqual},
290 std::pair{PredCondition::GreaterEqual, OperationCode::LogicalIGreaterEqual}, 284 std::pair{PredCondition::GE, OperationCode::LogicalIGreaterEqual},
291 std::pair{PredCondition::LessThanWithNan, OperationCode::LogicalILessThan},
292 std::pair{PredCondition::NotEqualWithNan, OperationCode::LogicalINotEqual},
293 std::pair{PredCondition::LessEqualWithNan, OperationCode::LogicalILessEqual},
294 std::pair{PredCondition::GreaterThanWithNan, OperationCode::LogicalIGreaterThan},
295 std::pair{PredCondition::GreaterEqualWithNan, OperationCode::LogicalIGreaterEqual},
296 }; 285 };
297 286
298 const auto comparison = 287 const auto comparison =
@@ -301,32 +290,24 @@ Node ShaderIR::GetPredicateComparisonInteger(PredCondition condition, bool is_si
301 UNIMPLEMENTED_IF_MSG(comparison == comparison_table.cend(), 290 UNIMPLEMENTED_IF_MSG(comparison == comparison_table.cend(),
302 "Unknown predicate comparison operation"); 291 "Unknown predicate comparison operation");
303 292
304 Node predicate = SignedOperation(comparison->second, is_signed, NO_PRECISE, std::move(op_a), 293 return SignedOperation(comparison->second, is_signed, NO_PRECISE, std::move(op_a),
305 std::move(op_b)); 294 std::move(op_b));
306
307 UNIMPLEMENTED_IF_MSG(condition == PredCondition::LessThanWithNan ||
308 condition == PredCondition::NotEqualWithNan ||
309 condition == PredCondition::LessEqualWithNan ||
310 condition == PredCondition::GreaterThanWithNan ||
311 condition == PredCondition::GreaterEqualWithNan,
312 "NaN comparisons for integers are not implemented");
313 return predicate;
314} 295}
315 296
316Node ShaderIR::GetPredicateComparisonHalf(Tegra::Shader::PredCondition condition, Node op_a, 297Node ShaderIR::GetPredicateComparisonHalf(Tegra::Shader::PredCondition condition, Node op_a,
317 Node op_b) { 298 Node op_b) {
318 static constexpr std::array comparison_table{ 299 static constexpr std::array comparison_table{
319 std::pair{PredCondition::LessThan, OperationCode::Logical2HLessThan}, 300 std::pair{PredCondition::LT, OperationCode::Logical2HLessThan},
320 std::pair{PredCondition::Equal, OperationCode::Logical2HEqual}, 301 std::pair{PredCondition::EQ, OperationCode::Logical2HEqual},
321 std::pair{PredCondition::LessEqual, OperationCode::Logical2HLessEqual}, 302 std::pair{PredCondition::LE, OperationCode::Logical2HLessEqual},
322 std::pair{PredCondition::GreaterThan, OperationCode::Logical2HGreaterThan}, 303 std::pair{PredCondition::GT, OperationCode::Logical2HGreaterThan},
323 std::pair{PredCondition::NotEqual, OperationCode::Logical2HNotEqual}, 304 std::pair{PredCondition::NE, OperationCode::Logical2HNotEqual},
324 std::pair{PredCondition::GreaterEqual, OperationCode::Logical2HGreaterEqual}, 305 std::pair{PredCondition::GE, OperationCode::Logical2HGreaterEqual},
325 std::pair{PredCondition::LessThanWithNan, OperationCode::Logical2HLessThanWithNan}, 306 std::pair{PredCondition::LTU, OperationCode::Logical2HLessThanWithNan},
326 std::pair{PredCondition::NotEqualWithNan, OperationCode::Logical2HNotEqualWithNan}, 307 std::pair{PredCondition::LEU, OperationCode::Logical2HLessEqualWithNan},
327 std::pair{PredCondition::LessEqualWithNan, OperationCode::Logical2HLessEqualWithNan}, 308 std::pair{PredCondition::GTU, OperationCode::Logical2HGreaterThanWithNan},
328 std::pair{PredCondition::GreaterThanWithNan, OperationCode::Logical2HGreaterThanWithNan}, 309 std::pair{PredCondition::NEU, OperationCode::Logical2HNotEqualWithNan},
329 std::pair{PredCondition::GreaterEqualWithNan, OperationCode::Logical2HGreaterEqualWithNan}, 310 std::pair{PredCondition::GEU, OperationCode::Logical2HGreaterEqualWithNan},
330 }; 311 };
331 312
332 const auto comparison = 313 const auto comparison =
@@ -397,7 +378,7 @@ void ShaderIR::SetInternalFlagsFromFloat(NodeBlock& bb, Node value, bool sets_cc
397 if (!sets_cc) { 378 if (!sets_cc) {
398 return; 379 return;
399 } 380 }
400 Node zerop = Operation(OperationCode::LogicalFEqual, std::move(value), Immediate(0.0f)); 381 Node zerop = Operation(OperationCode::LogicalFOrdEqual, std::move(value), Immediate(0.0f));
401 SetInternalFlag(bb, InternalFlag::Zero, std::move(zerop)); 382 SetInternalFlag(bb, InternalFlag::Zero, std::move(zerop));
402 LOG_WARNING(HW_GPU, "Condition codes implementation is incomplete"); 383 LOG_WARNING(HW_GPU, "Condition codes implementation is incomplete");
403} 384}
diff --git a/src/yuzu/configuration/config.cpp b/src/yuzu/configuration/config.cpp
index 75c6cf20b..27775701d 100644
--- a/src/yuzu/configuration/config.cpp
+++ b/src/yuzu/configuration/config.cpp
@@ -687,6 +687,8 @@ void Config::ReadSystemValues() {
687 687
688 Settings::values.region_index = ReadSetting(QStringLiteral("region_index"), 1).toInt(); 688 Settings::values.region_index = ReadSetting(QStringLiteral("region_index"), 1).toInt();
689 689
690 Settings::values.time_zone_index = ReadSetting(QStringLiteral("time_zone_index"), 0).toInt();
691
690 const auto rng_seed_enabled = ReadSetting(QStringLiteral("rng_seed_enabled"), false).toBool(); 692 const auto rng_seed_enabled = ReadSetting(QStringLiteral("rng_seed_enabled"), false).toBool();
691 if (rng_seed_enabled) { 693 if (rng_seed_enabled) {
692 Settings::values.rng_seed = ReadSetting(QStringLiteral("rng_seed"), 0).toULongLong(); 694 Settings::values.rng_seed = ReadSetting(QStringLiteral("rng_seed"), 0).toULongLong();
@@ -1126,6 +1128,7 @@ void Config::SaveSystemValues() {
1126 WriteSetting(QStringLiteral("current_user"), Settings::values.current_user, 0); 1128 WriteSetting(QStringLiteral("current_user"), Settings::values.current_user, 0);
1127 WriteSetting(QStringLiteral("language_index"), Settings::values.language_index, 1); 1129 WriteSetting(QStringLiteral("language_index"), Settings::values.language_index, 1);
1128 WriteSetting(QStringLiteral("region_index"), Settings::values.region_index, 1); 1130 WriteSetting(QStringLiteral("region_index"), Settings::values.region_index, 1);
1131 WriteSetting(QStringLiteral("time_zone_index"), Settings::values.time_zone_index, 0);
1129 1132
1130 WriteSetting(QStringLiteral("rng_seed_enabled"), Settings::values.rng_seed.has_value(), false); 1133 WriteSetting(QStringLiteral("rng_seed_enabled"), Settings::values.rng_seed.has_value(), false);
1131 WriteSetting(QStringLiteral("rng_seed"), Settings::values.rng_seed.value_or(0), 0); 1134 WriteSetting(QStringLiteral("rng_seed"), Settings::values.rng_seed.value_or(0), 0);
diff --git a/src/yuzu/configuration/configure_system.cpp b/src/yuzu/configuration/configure_system.cpp
index f49cd4c8f..10315e7a6 100644
--- a/src/yuzu/configuration/configure_system.cpp
+++ b/src/yuzu/configuration/configure_system.cpp
@@ -57,6 +57,7 @@ void ConfigureSystem::SetConfiguration() {
57 57
58 ui->combo_language->setCurrentIndex(Settings::values.language_index); 58 ui->combo_language->setCurrentIndex(Settings::values.language_index);
59 ui->combo_region->setCurrentIndex(Settings::values.region_index); 59 ui->combo_region->setCurrentIndex(Settings::values.region_index);
60 ui->combo_time_zone->setCurrentIndex(Settings::values.time_zone_index);
60 ui->combo_sound->setCurrentIndex(Settings::values.sound_index); 61 ui->combo_sound->setCurrentIndex(Settings::values.sound_index);
61 62
62 ui->rng_seed_checkbox->setChecked(Settings::values.rng_seed.has_value()); 63 ui->rng_seed_checkbox->setChecked(Settings::values.rng_seed.has_value());
@@ -84,6 +85,7 @@ void ConfigureSystem::ApplyConfiguration() {
84 85
85 Settings::values.language_index = ui->combo_language->currentIndex(); 86 Settings::values.language_index = ui->combo_language->currentIndex();
86 Settings::values.region_index = ui->combo_region->currentIndex(); 87 Settings::values.region_index = ui->combo_region->currentIndex();
88 Settings::values.time_zone_index = ui->combo_time_zone->currentIndex();
87 Settings::values.sound_index = ui->combo_sound->currentIndex(); 89 Settings::values.sound_index = ui->combo_sound->currentIndex();
88 90
89 if (ui->rng_seed_checkbox->isChecked()) { 91 if (ui->rng_seed_checkbox->isChecked()) {
diff --git a/src/yuzu/configuration/configure_system.h b/src/yuzu/configuration/configure_system.h
index d8fa2d2cc..26d42d5c5 100644
--- a/src/yuzu/configuration/configure_system.h
+++ b/src/yuzu/configuration/configure_system.h
@@ -37,5 +37,6 @@ private:
37 37
38 int language_index = 0; 38 int language_index = 0;
39 int region_index = 0; 39 int region_index = 0;
40 int time_zone_index = 0;
40 int sound_index = 0; 41 int sound_index = 0;
41}; 42};
diff --git a/src/yuzu/configuration/configure_system.ui b/src/yuzu/configuration/configure_system.ui
index 4e2c7e76e..9c8cca6dc 100644
--- a/src/yuzu/configuration/configure_system.ui
+++ b/src/yuzu/configuration/configure_system.ui
@@ -22,14 +22,14 @@
22 <string>System Settings</string> 22 <string>System Settings</string>
23 </property> 23 </property>
24 <layout class="QGridLayout" name="gridLayout"> 24 <layout class="QGridLayout" name="gridLayout">
25 <item row="2" column="0"> 25 <item row="3" column="0">
26 <widget class="QLabel" name="label_sound"> 26 <widget class="QLabel" name="label_sound">
27 <property name="text"> 27 <property name="text">
28 <string>Sound output mode</string> 28 <string>Sound output mode</string>
29 </property> 29 </property>
30 </widget> 30 </widget>
31 </item> 31 </item>
32 <item row="3" column="0"> 32 <item row="4" column="0">
33 <widget class="QLabel" name="label_console_id"> 33 <widget class="QLabel" name="label_console_id">
34 <property name="text"> 34 <property name="text">
35 <string>Console ID:</string> 35 <string>Console ID:</string>
@@ -174,14 +174,255 @@
174 </item> 174 </item>
175 </widget> 175 </widget>
176 </item> 176 </item>
177 <item row="5" column="0"> 177 <item row="2" column="0">
178 <widget class="QLabel" name="label_timezone">
179 <property name="text">
180 <string>Time Zone:</string>
181 </property>
182 </widget>
183 </item>
184 <item row="2" column="1">
185 <widget class="QComboBox" name="combo_time_zone">
186 <item>
187 <property name="text">
188 <string>Auto</string>
189 </property>
190 </item>
191 <item>
192 <property name="text">
193 <string>Default</string>
194 </property>
195 </item>
196 <item>
197 <property name="text">
198 <string>CET</string>
199 </property>
200 </item>
201 <item>
202 <property name="text">
203 <string>CST6CDT</string>
204 </property>
205 </item>
206 <item>
207 <property name="text">
208 <string>Cuba</string>
209 </property>
210 </item>
211 <item>
212 <property name="text">
213 <string>EET</string>
214 </property>
215 </item>
216 <item>
217 <property name="text">
218 <string>Egypt</string>
219 </property>
220 </item>
221 <item>
222 <property name="text">
223 <string>Eire</string>
224 </property>
225 </item>
226 <item>
227 <property name="text">
228 <string>EST</string>
229 </property>
230 </item>
231 <item>
232 <property name="text">
233 <string>EST5EDT</string>
234 </property>
235 </item>
236 <item>
237 <property name="text">
238 <string>GB</string>
239 </property>
240 </item>
241 <item>
242 <property name="text">
243 <string>GB-Eire</string>
244 </property>
245 </item>
246 <item>
247 <property name="text">
248 <string>GMT</string>
249 </property>
250 </item>
251 <item>
252 <property name="text">
253 <string>GMT+0</string>
254 </property>
255 </item>
256 <item>
257 <property name="text">
258 <string>GMT-0</string>
259 </property>
260 </item>
261 <item>
262 <property name="text">
263 <string>GMT0</string>
264 </property>
265 </item>
266 <item>
267 <property name="text">
268 <string>Greenwich</string>
269 </property>
270 </item>
271 <item>
272 <property name="text">
273 <string>Hongkong</string>
274 </property>
275 </item>
276 <item>
277 <property name="text">
278 <string>HST</string>
279 </property>
280 </item>
281 <item>
282 <property name="text">
283 <string>Iceland</string>
284 </property>
285 </item>
286 <item>
287 <property name="text">
288 <string>Iran</string>
289 </property>
290 </item>
291 <item>
292 <property name="text">
293 <string>Israel</string>
294 </property>
295 </item>
296 <item>
297 <property name="text">
298 <string>Jamaica</string>
299 </property>
300 </item>
301 <item>
302 <property name="text">
303 <string>Japan</string>
304 </property>
305 </item>
306 <item>
307 <property name="text">
308 <string>Kwajalein</string>
309 </property>
310 </item>
311 <item>
312 <property name="text">
313 <string>Libya</string>
314 </property>
315 </item>
316 <item>
317 <property name="text">
318 <string>MET</string>
319 </property>
320 </item>
321 <item>
322 <property name="text">
323 <string>MST</string>
324 </property>
325 </item>
326 <item>
327 <property name="text">
328 <string>MST7MDT</string>
329 </property>
330 </item>
331 <item>
332 <property name="text">
333 <string>Navajo</string>
334 </property>
335 </item>
336 <item>
337 <property name="text">
338 <string>NZ</string>
339 </property>
340 </item>
341 <item>
342 <property name="text">
343 <string>NZ-CHAT</string>
344 </property>
345 </item>
346 <item>
347 <property name="text">
348 <string>Poland</string>
349 </property>
350 </item>
351 <item>
352 <property name="text">
353 <string>Portugal</string>
354 </property>
355 </item>
356 <item>
357 <property name="text">
358 <string>PRC</string>
359 </property>
360 </item>
361 <item>
362 <property name="text">
363 <string>PST8PDT</string>
364 </property>
365 </item>
366 <item>
367 <property name="text">
368 <string>ROC</string>
369 </property>
370 </item>
371 <item>
372 <property name="text">
373 <string>ROK</string>
374 </property>
375 </item>
376 <item>
377 <property name="text">
378 <string>Singapore</string>
379 </property>
380 </item>
381 <item>
382 <property name="text">
383 <string>Turkey</string>
384 </property>
385 </item>
386 <item>
387 <property name="text">
388 <string>UCT</string>
389 </property>
390 </item>
391 <item>
392 <property name="text">
393 <string>Universal</string>
394 </property>
395 </item>
396 <item>
397 <property name="text">
398 <string>UTC</string>
399 </property>
400 </item>
401 <item>
402 <property name="text">
403 <string>W-SU</string>
404 </property>
405 </item>
406 <item>
407 <property name="text">
408 <string>WET</string>
409 </property>
410 </item>
411 <item>
412 <property name="text">
413 <string>Zulu</string>
414 </property>
415 </item>
416 </widget>
417 </item>
418 <item row="6" column="0">
178 <widget class="QCheckBox" name="rng_seed_checkbox"> 419 <widget class="QCheckBox" name="rng_seed_checkbox">
179 <property name="text"> 420 <property name="text">
180 <string>RNG Seed</string> 421 <string>RNG Seed</string>
181 </property> 422 </property>
182 </widget> 423 </widget>
183 </item> 424 </item>
184 <item row="2" column="1"> 425 <item row="3" column="1">
185 <widget class="QComboBox" name="combo_sound"> 426 <widget class="QComboBox" name="combo_sound">
186 <item> 427 <item>
187 <property name="text"> 428 <property name="text">
@@ -207,7 +448,7 @@
207 </property> 448 </property>
208 </widget> 449 </widget>
209 </item> 450 </item>
210 <item row="3" column="1"> 451 <item row="4" column="1">
211 <widget class="QPushButton" name="button_regenerate_console_id"> 452 <widget class="QPushButton" name="button_regenerate_console_id">
212 <property name="sizePolicy"> 453 <property name="sizePolicy">
213 <sizepolicy hsizetype="Fixed" vsizetype="Fixed"> 454 <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
@@ -223,14 +464,14 @@
223 </property> 464 </property>
224 </widget> 465 </widget>
225 </item> 466 </item>
226 <item row="4" column="0"> 467 <item row="5" column="0">
227 <widget class="QCheckBox" name="custom_rtc_checkbox"> 468 <widget class="QCheckBox" name="custom_rtc_checkbox">
228 <property name="text"> 469 <property name="text">
229 <string>Custom RTC</string> 470 <string>Custom RTC</string>
230 </property> 471 </property>
231 </widget> 472 </widget>
232 </item> 473 </item>
233 <item row="4" column="1"> 474 <item row="5" column="1">
234 <widget class="QDateTimeEdit" name="custom_rtc_edit"> 475 <widget class="QDateTimeEdit" name="custom_rtc_edit">
235 <property name="minimumDate"> 476 <property name="minimumDate">
236 <date> 477 <date>
@@ -244,7 +485,7 @@
244 </property> 485 </property>
245 </widget> 486 </widget>
246 </item> 487 </item>
247 <item row="5" column="1"> 488 <item row="6" column="1">
248 <widget class="QLineEdit" name="rng_seed_edit"> 489 <widget class="QLineEdit" name="rng_seed_edit">
249 <property name="sizePolicy"> 490 <property name="sizePolicy">
250 <sizepolicy hsizetype="Minimum" vsizetype="Fixed"> 491 <sizepolicy hsizetype="Minimum" vsizetype="Fixed">
diff --git a/src/yuzu_cmd/config.cpp b/src/yuzu_cmd/config.cpp
index 8476a5a16..2348e6e0d 100644
--- a/src/yuzu_cmd/config.cpp
+++ b/src/yuzu_cmd/config.cpp
@@ -367,6 +367,9 @@ void Config::ReadValues() {
367 Settings::values.custom_rtc = std::nullopt; 367 Settings::values.custom_rtc = std::nullopt;
368 } 368 }
369 369
370 Settings::values.language_index = sdl2_config->GetInteger("System", "language_index", 1);
371 Settings::values.time_zone_index = sdl2_config->GetInteger("System", "time_zone_index", 0);
372
370 // Core 373 // Core
371 Settings::values.use_multi_core = sdl2_config->GetBoolean("Core", "use_multi_core", false); 374 Settings::values.use_multi_core = sdl2_config->GetBoolean("Core", "use_multi_core", false);
372 375
@@ -409,8 +412,6 @@ void Config::ReadValues() {
409 Settings::values.audio_device_id = sdl2_config->Get("Audio", "output_device", "auto"); 412 Settings::values.audio_device_id = sdl2_config->Get("Audio", "output_device", "auto");
410 Settings::values.volume = static_cast<float>(sdl2_config->GetReal("Audio", "volume", 1)); 413 Settings::values.volume = static_cast<float>(sdl2_config->GetReal("Audio", "volume", 1));
411 414
412 Settings::values.language_index = sdl2_config->GetInteger("System", "language_index", 1);
413
414 // Miscellaneous 415 // Miscellaneous
415 Settings::values.log_filter = sdl2_config->Get("Miscellaneous", "log_filter", "*:Trace"); 416 Settings::values.log_filter = sdl2_config->Get("Miscellaneous", "log_filter", "*:Trace");
416 Settings::values.use_dev_keys = sdl2_config->GetBoolean("Miscellaneous", "use_dev_keys", false); 417 Settings::values.use_dev_keys = sdl2_config->GetBoolean("Miscellaneous", "use_dev_keys", false);
diff --git a/src/yuzu_cmd/default_ini.h b/src/yuzu_cmd/default_ini.h
index 60b1a62fa..ae94b51c4 100644
--- a/src/yuzu_cmd/default_ini.h
+++ b/src/yuzu_cmd/default_ini.h
@@ -262,6 +262,10 @@ language_index =
262# -1: Auto-select (default), 0: Japan, 1: USA, 2: Europe, 3: Australia, 4: China, 5: Korea, 6: Taiwan 262# -1: Auto-select (default), 0: Japan, 1: USA, 2: Europe, 3: Australia, 4: China, 5: Korea, 6: Taiwan
263region_value = 263region_value =
264 264
265# The system time zone that yuzu will use during emulation
266# 0: Auto-select (default), 1: Default (system archive value), Others: Index for specified time zone
267time_zone_index =
268
265[Miscellaneous] 269[Miscellaneous]
266# A filter which removes logs below a certain logging level. 270# A filter which removes logs below a certain logging level.
267# Examples: *:Debug Kernel.SVC:Trace Service.*:Critical 271# Examples: *:Debug Kernel.SVC:Trace Service.*:Critical