summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/common/telemetry.cpp15
-rw-r--r--src/common/x64/cpu_detect.cpp68
-rw-r--r--src/common/x64/cpu_detect.h31
-rw-r--r--src/core/CMakeLists.txt30
-rw-r--r--src/core/file_sys/system_archive/system_archive.cpp3
-rw-r--r--src/core/file_sys/system_archive/time_zone_binary.cpp657
-rw-r--r--src/core/file_sys/system_archive/time_zone_binary.h14
-rw-r--r--src/core/hle/kernel/physical_memory.h5
-rw-r--r--src/core/hle/kernel/vm_manager.cpp37
-rw-r--r--src/core/hle/service/acc/acc.cpp2
-rw-r--r--src/core/hle/service/acc/profile_manager.cpp14
-rw-r--r--src/core/hle/service/acc/profile_manager.h27
-rw-r--r--src/core/hle/service/friend/friend.cpp2
-rw-r--r--src/core/hle/service/mii/mii_manager.h156
-rw-r--r--src/core/hle/service/time/clock_types.h103
-rw-r--r--src/core/hle/service/time/ephemeral_network_system_clock_context_writer.h16
-rw-r--r--src/core/hle/service/time/ephemeral_network_system_clock_core.h17
-rw-r--r--src/core/hle/service/time/errors.h22
-rw-r--r--src/core/hle/service/time/interface.cpp19
-rw-r--r--src/core/hle/service/time/interface.h11
-rw-r--r--src/core/hle/service/time/local_system_clock_context_writer.h28
-rw-r--r--src/core/hle/service/time/network_system_clock_context_writer.h28
-rw-r--r--src/core/hle/service/time/standard_local_system_clock_core.h17
-rw-r--r--src/core/hle/service/time/standard_network_system_clock_core.h46
-rw-r--r--src/core/hle/service/time/standard_steady_clock_core.cpp26
-rw-r--r--src/core/hle/service/time/standard_steady_clock_core.h42
-rw-r--r--src/core/hle/service/time/standard_user_system_clock_core.cpp77
-rw-r--r--src/core/hle/service/time/standard_user_system_clock_core.h57
-rw-r--r--src/core/hle/service/time/steady_clock_core.h55
-rw-r--r--src/core/hle/service/time/system_clock_context_update_callback.cpp55
-rw-r--r--src/core/hle/service/time/system_clock_context_update_callback.h43
-rw-r--r--src/core/hle/service/time/system_clock_core.cpp72
-rw-r--r--src/core/hle/service/time/system_clock_core.h71
-rw-r--r--src/core/hle/service/time/tick_based_steady_clock_core.cpp24
-rw-r--r--src/core/hle/service/time/tick_based_steady_clock_core.h29
-rw-r--r--src/core/hle/service/time/time.cpp474
-rw-r--r--src/core/hle/service/time/time.h101
-rw-r--r--src/core/hle/service/time/time_manager.cpp137
-rw-r--r--src/core/hle/service/time/time_manager.h117
-rw-r--r--src/core/hle/service/time/time_sharedmemory.cpp53
-rw-r--r--src/core/hle/service/time/time_sharedmemory.h35
-rw-r--r--src/core/hle/service/time/time_zone_content_manager.cpp125
-rw-r--r--src/core/hle/service/time/time_zone_content_manager.h46
-rw-r--r--src/core/hle/service/time/time_zone_manager.cpp1030
-rw-r--r--src/core/hle/service/time/time_zone_manager.h53
-rw-r--r--src/core/hle/service/time/time_zone_service.cpp148
-rw-r--r--src/core/hle/service/time/time_zone_service.h30
-rw-r--r--src/core/hle/service/time/time_zone_types.h87
-rw-r--r--src/core/loader/elf.cpp3
-rw-r--r--src/core/loader/kip.cpp5
-rw-r--r--src/core/loader/nso.cpp12
-rw-r--r--src/core/memory.cpp11
-rw-r--r--src/core/memory.h16
-rw-r--r--src/video_core/CMakeLists.txt2
-rw-r--r--src/video_core/engines/maxwell_3d.h10
-rw-r--r--src/video_core/engines/shader_bytecode.h37
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.cpp1
-rw-r--r--src/video_core/renderer_opengl/gl_shader_decompiler.cpp44
-rw-r--r--src/video_core/renderer_opengl/gl_state.cpp1
-rw-r--r--src/video_core/renderer_opengl/gl_state.h3
-rw-r--r--src/video_core/renderer_opengl/gl_texture_cache.cpp16
-rw-r--r--src/video_core/renderer_vulkan/renderer_vulkan.h72
-rw-r--r--src/video_core/renderer_vulkan/vk_rasterizer.cpp1141
-rw-r--r--src/video_core/renderer_vulkan/vk_rasterizer.h252
-rw-r--r--src/video_core/renderer_vulkan/vk_shader_decompiler.cpp7
-rw-r--r--src/video_core/shader/decode/memory.cpp19
-rw-r--r--src/video_core/shader/node.h2
-rw-r--r--src/yuzu/configuration/configure_gamelist.cpp53
-rw-r--r--src/yuzu/configuration/configure_gamelist.h3
-rw-r--r--src/yuzu/game_list_p.h11
-rw-r--r--src/yuzu/main.cpp16
-rw-r--r--src/yuzu/main.ui3
72 files changed, 5355 insertions, 740 deletions
diff --git a/src/common/telemetry.cpp b/src/common/telemetry.cpp
index f53a8d193..200c6489a 100644
--- a/src/common/telemetry.cpp
+++ b/src/common/telemetry.cpp
@@ -44,20 +44,6 @@ template class Field<std::string>;
44template class Field<const char*>; 44template class Field<const char*>;
45template class Field<std::chrono::microseconds>; 45template class Field<std::chrono::microseconds>;
46 46
47#ifdef ARCHITECTURE_x86_64
48static const char* CpuVendorToStr(Common::CPUVendor vendor) {
49 switch (vendor) {
50 case Common::CPUVendor::INTEL:
51 return "Intel";
52 case Common::CPUVendor::AMD:
53 return "Amd";
54 case Common::CPUVendor::OTHER:
55 return "Other";
56 }
57 UNREACHABLE();
58}
59#endif
60
61void AppendBuildInfo(FieldCollection& fc) { 47void AppendBuildInfo(FieldCollection& fc) {
62 const bool is_git_dirty{std::strstr(Common::g_scm_desc, "dirty") != nullptr}; 48 const bool is_git_dirty{std::strstr(Common::g_scm_desc, "dirty") != nullptr};
63 fc.AddField(FieldType::App, "Git_IsDirty", is_git_dirty); 49 fc.AddField(FieldType::App, "Git_IsDirty", is_git_dirty);
@@ -71,7 +57,6 @@ void AppendCPUInfo(FieldCollection& fc) {
71#ifdef ARCHITECTURE_x86_64 57#ifdef ARCHITECTURE_x86_64
72 fc.AddField(FieldType::UserSystem, "CPU_Model", Common::GetCPUCaps().cpu_string); 58 fc.AddField(FieldType::UserSystem, "CPU_Model", Common::GetCPUCaps().cpu_string);
73 fc.AddField(FieldType::UserSystem, "CPU_BrandString", Common::GetCPUCaps().brand_string); 59 fc.AddField(FieldType::UserSystem, "CPU_BrandString", Common::GetCPUCaps().brand_string);
74 fc.AddField(FieldType::UserSystem, "CPU_Vendor", CpuVendorToStr(Common::GetCPUCaps().vendor));
75 fc.AddField(FieldType::UserSystem, "CPU_Extension_x64_AES", Common::GetCPUCaps().aes); 60 fc.AddField(FieldType::UserSystem, "CPU_Extension_x64_AES", Common::GetCPUCaps().aes);
76 fc.AddField(FieldType::UserSystem, "CPU_Extension_x64_AVX", Common::GetCPUCaps().avx); 61 fc.AddField(FieldType::UserSystem, "CPU_Extension_x64_AVX", Common::GetCPUCaps().avx);
77 fc.AddField(FieldType::UserSystem, "CPU_Extension_x64_AVX2", Common::GetCPUCaps().avx2); 62 fc.AddField(FieldType::UserSystem, "CPU_Extension_x64_AVX2", Common::GetCPUCaps().avx2);
diff --git a/src/common/x64/cpu_detect.cpp b/src/common/x64/cpu_detect.cpp
index 2dfcd39c8..c9349a6b4 100644
--- a/src/common/x64/cpu_detect.cpp
+++ b/src/common/x64/cpu_detect.cpp
@@ -3,8 +3,6 @@
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <cstring> 5#include <cstring>
6#include <string>
7#include <thread>
8#include "common/common_types.h" 6#include "common/common_types.h"
9#include "common/x64/cpu_detect.h" 7#include "common/x64/cpu_detect.h"
10 8
@@ -51,8 +49,6 @@ namespace Common {
51static CPUCaps Detect() { 49static CPUCaps Detect() {
52 CPUCaps caps = {}; 50 CPUCaps caps = {};
53 51
54 caps.num_cores = std::thread::hardware_concurrency();
55
56 // Assumes the CPU supports the CPUID instruction. Those that don't would likely not support 52 // Assumes the CPU supports the CPUID instruction. Those that don't would likely not support
57 // yuzu at all anyway 53 // yuzu at all anyway
58 54
@@ -70,12 +66,6 @@ static CPUCaps Detect() {
70 __cpuid(cpu_id, 0x80000000); 66 __cpuid(cpu_id, 0x80000000);
71 67
72 u32 max_ex_fn = cpu_id[0]; 68 u32 max_ex_fn = cpu_id[0];
73 if (!strcmp(caps.brand_string, "GenuineIntel"))
74 caps.vendor = CPUVendor::INTEL;
75 else if (!strcmp(caps.brand_string, "AuthenticAMD"))
76 caps.vendor = CPUVendor::AMD;
77 else
78 caps.vendor = CPUVendor::OTHER;
79 69
80 // Set reasonable default brand string even if brand string not available 70 // Set reasonable default brand string even if brand string not available
81 strcpy(caps.cpu_string, caps.brand_string); 71 strcpy(caps.cpu_string, caps.brand_string);
@@ -96,15 +86,9 @@ static CPUCaps Detect() {
96 caps.sse4_1 = true; 86 caps.sse4_1 = true;
97 if ((cpu_id[2] >> 20) & 1) 87 if ((cpu_id[2] >> 20) & 1)
98 caps.sse4_2 = true; 88 caps.sse4_2 = true;
99 if ((cpu_id[2] >> 22) & 1)
100 caps.movbe = true;
101 if ((cpu_id[2] >> 25) & 1) 89 if ((cpu_id[2] >> 25) & 1)
102 caps.aes = true; 90 caps.aes = true;
103 91
104 if ((cpu_id[3] >> 24) & 1) {
105 caps.fxsave_fxrstor = true;
106 }
107
108 // AVX support requires 3 separate checks: 92 // AVX support requires 3 separate checks:
109 // - Is the AVX bit set in CPUID? 93 // - Is the AVX bit set in CPUID?
110 // - Is the XSAVE bit set in CPUID? 94 // - Is the XSAVE bit set in CPUID?
@@ -129,8 +113,6 @@ static CPUCaps Detect() {
129 } 113 }
130 } 114 }
131 115
132 caps.flush_to_zero = caps.sse;
133
134 if (max_ex_fn >= 0x80000004) { 116 if (max_ex_fn >= 0x80000004) {
135 // Extract CPU model string 117 // Extract CPU model string
136 __cpuid(cpu_id, 0x80000002); 118 __cpuid(cpu_id, 0x80000002);
@@ -144,14 +126,8 @@ static CPUCaps Detect() {
144 if (max_ex_fn >= 0x80000001) { 126 if (max_ex_fn >= 0x80000001) {
145 // Check for more features 127 // Check for more features
146 __cpuid(cpu_id, 0x80000001); 128 __cpuid(cpu_id, 0x80000001);
147 if (cpu_id[2] & 1)
148 caps.lahf_sahf_64 = true;
149 if ((cpu_id[2] >> 5) & 1)
150 caps.lzcnt = true;
151 if ((cpu_id[2] >> 16) & 1) 129 if ((cpu_id[2] >> 16) & 1)
152 caps.fma4 = true; 130 caps.fma4 = true;
153 if ((cpu_id[3] >> 29) & 1)
154 caps.long_mode = true;
155 } 131 }
156 132
157 return caps; 133 return caps;
@@ -162,48 +138,4 @@ const CPUCaps& GetCPUCaps() {
162 return caps; 138 return caps;
163} 139}
164 140
165std::string GetCPUCapsString() {
166 auto caps = GetCPUCaps();
167
168 std::string sum(caps.cpu_string);
169 sum += " (";
170 sum += caps.brand_string;
171 sum += ")";
172
173 if (caps.sse)
174 sum += ", SSE";
175 if (caps.sse2) {
176 sum += ", SSE2";
177 if (!caps.flush_to_zero)
178 sum += " (without DAZ)";
179 }
180
181 if (caps.sse3)
182 sum += ", SSE3";
183 if (caps.ssse3)
184 sum += ", SSSE3";
185 if (caps.sse4_1)
186 sum += ", SSE4.1";
187 if (caps.sse4_2)
188 sum += ", SSE4.2";
189 if (caps.avx)
190 sum += ", AVX";
191 if (caps.avx2)
192 sum += ", AVX2";
193 if (caps.bmi1)
194 sum += ", BMI1";
195 if (caps.bmi2)
196 sum += ", BMI2";
197 if (caps.fma)
198 sum += ", FMA";
199 if (caps.aes)
200 sum += ", AES";
201 if (caps.movbe)
202 sum += ", MOVBE";
203 if (caps.long_mode)
204 sum += ", 64-bit support";
205
206 return sum;
207}
208
209} // namespace Common 141} // namespace Common
diff --git a/src/common/x64/cpu_detect.h b/src/common/x64/cpu_detect.h
index 0af3a8adb..20f2ba234 100644
--- a/src/common/x64/cpu_detect.h
+++ b/src/common/x64/cpu_detect.h
@@ -4,23 +4,12 @@
4 4
5#pragma once 5#pragma once
6 6
7#include <string>
8
9namespace Common { 7namespace Common {
10 8
11/// x86/x64 CPU vendors that may be detected by this module
12enum class CPUVendor {
13 INTEL,
14 AMD,
15 OTHER,
16};
17
18/// x86/x64 CPU capabilities that may be detected by this module 9/// x86/x64 CPU capabilities that may be detected by this module
19struct CPUCaps { 10struct CPUCaps {
20 CPUVendor vendor;
21 char cpu_string[0x21]; 11 char cpu_string[0x21];
22 char brand_string[0x41]; 12 char brand_string[0x41];
23 int num_cores;
24 bool sse; 13 bool sse;
25 bool sse2; 14 bool sse2;
26 bool sse3; 15 bool sse3;
@@ -35,20 +24,6 @@ struct CPUCaps {
35 bool fma; 24 bool fma;
36 bool fma4; 25 bool fma4;
37 bool aes; 26 bool aes;
38
39 // Support for the FXSAVE and FXRSTOR instructions
40 bool fxsave_fxrstor;
41
42 bool movbe;
43
44 // This flag indicates that the hardware supports some mode in which denormal inputs and outputs
45 // are automatically set to (signed) zero.
46 bool flush_to_zero;
47
48 // Support for LAHF and SAHF instructions in 64-bit mode
49 bool lahf_sahf_64;
50
51 bool long_mode;
52}; 27};
53 28
54/** 29/**
@@ -57,10 +32,4 @@ struct CPUCaps {
57 */ 32 */
58const CPUCaps& GetCPUCaps(); 33const CPUCaps& GetCPUCaps();
59 34
60/**
61 * Gets a string summary of the name and supported capabilities of the host CPU
62 * @return String summary
63 */
64std::string GetCPUCapsString();
65
66} // namespace Common 35} // namespace Common
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index 7fd226050..1a3647a67 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -96,6 +96,8 @@ add_library(core STATIC
96 file_sys/system_archive/system_archive.h 96 file_sys/system_archive/system_archive.h
97 file_sys/system_archive/system_version.cpp 97 file_sys/system_archive/system_version.cpp
98 file_sys/system_archive/system_version.h 98 file_sys/system_archive/system_version.h
99 file_sys/system_archive/time_zone_binary.cpp
100 file_sys/system_archive/time_zone_binary.h
99 file_sys/vfs.cpp 101 file_sys/vfs.cpp
100 file_sys/vfs.h 102 file_sys/vfs.h
101 file_sys/vfs_concat.cpp 103 file_sys/vfs_concat.cpp
@@ -461,12 +463,40 @@ add_library(core STATIC
461 hle/service/spl/spl.h 463 hle/service/spl/spl.h
462 hle/service/ssl/ssl.cpp 464 hle/service/ssl/ssl.cpp
463 hle/service/ssl/ssl.h 465 hle/service/ssl/ssl.h
466 hle/service/time/clock_types.h
467 hle/service/time/ephemeral_network_system_clock_context_writer.h
468 hle/service/time/ephemeral_network_system_clock_core.h
469 hle/service/time/errors.h
464 hle/service/time/interface.cpp 470 hle/service/time/interface.cpp
465 hle/service/time/interface.h 471 hle/service/time/interface.h
472 hle/service/time/local_system_clock_context_writer.h
473 hle/service/time/network_system_clock_context_writer.h
474 hle/service/time/standard_local_system_clock_core.h
475 hle/service/time/standard_network_system_clock_core.h
476 hle/service/time/standard_steady_clock_core.cpp
477 hle/service/time/standard_steady_clock_core.h
478 hle/service/time/standard_user_system_clock_core.cpp
479 hle/service/time/standard_user_system_clock_core.h
480 hle/service/time/steady_clock_core.h
481 hle/service/time/system_clock_context_update_callback.cpp
482 hle/service/time/system_clock_context_update_callback.h
483 hle/service/time/system_clock_core.cpp
484 hle/service/time/system_clock_core.h
485 hle/service/time/tick_based_steady_clock_core.cpp
486 hle/service/time/tick_based_steady_clock_core.h
466 hle/service/time/time.cpp 487 hle/service/time/time.cpp
467 hle/service/time/time.h 488 hle/service/time/time.h
489 hle/service/time/time_manager.cpp
490 hle/service/time/time_manager.h
468 hle/service/time/time_sharedmemory.cpp 491 hle/service/time/time_sharedmemory.cpp
469 hle/service/time/time_sharedmemory.h 492 hle/service/time/time_sharedmemory.h
493 hle/service/time/time_zone_content_manager.cpp
494 hle/service/time/time_zone_content_manager.h
495 hle/service/time/time_zone_manager.cpp
496 hle/service/time/time_zone_manager.h
497 hle/service/time/time_zone_service.cpp
498 hle/service/time/time_zone_service.h
499 hle/service/time/time_zone_types.h
470 hle/service/usb/usb.cpp 500 hle/service/usb/usb.cpp
471 hle/service/usb/usb.h 501 hle/service/usb/usb.h
472 hle/service/vi/display/vi_display.cpp 502 hle/service/vi/display/vi_display.cpp
diff --git a/src/core/file_sys/system_archive/system_archive.cpp b/src/core/file_sys/system_archive/system_archive.cpp
index e93d100a5..a6696024e 100644
--- a/src/core/file_sys/system_archive/system_archive.cpp
+++ b/src/core/file_sys/system_archive/system_archive.cpp
@@ -9,6 +9,7 @@
9#include "core/file_sys/system_archive/shared_font.h" 9#include "core/file_sys/system_archive/shared_font.h"
10#include "core/file_sys/system_archive/system_archive.h" 10#include "core/file_sys/system_archive/system_archive.h"
11#include "core/file_sys/system_archive/system_version.h" 11#include "core/file_sys/system_archive/system_version.h"
12#include "core/file_sys/system_archive/time_zone_binary.h"
12 13
13namespace FileSys::SystemArchive { 14namespace FileSys::SystemArchive {
14 15
@@ -38,7 +39,7 @@ constexpr std::array<SystemArchiveDescriptor, SYSTEM_ARCHIVE_COUNT> SYSTEM_ARCHI
38 {0x010000000000080B, "LocalNews", nullptr}, 39 {0x010000000000080B, "LocalNews", nullptr},
39 {0x010000000000080C, "Eula", nullptr}, 40 {0x010000000000080C, "Eula", nullptr},
40 {0x010000000000080D, "UrlBlackList", nullptr}, 41 {0x010000000000080D, "UrlBlackList", nullptr},
41 {0x010000000000080E, "TimeZoneBinary", nullptr}, 42 {0x010000000000080E, "TimeZoneBinary", &TimeZoneBinary},
42 {0x010000000000080F, "CertStoreCruiser", nullptr}, 43 {0x010000000000080F, "CertStoreCruiser", nullptr},
43 {0x0100000000000810, "FontNintendoExtension", &FontNintendoExtension}, 44 {0x0100000000000810, "FontNintendoExtension", &FontNintendoExtension},
44 {0x0100000000000811, "FontStandard", &FontStandard}, 45 {0x0100000000000811, "FontStandard", &FontStandard},
diff --git a/src/core/file_sys/system_archive/time_zone_binary.cpp b/src/core/file_sys/system_archive/time_zone_binary.cpp
new file mode 100644
index 000000000..9806bd197
--- /dev/null
+++ b/src/core/file_sys/system_archive/time_zone_binary.cpp
@@ -0,0 +1,657 @@
1// Copyright 2019 yuzu emulator team
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include "common/swap.h"
6#include "core/file_sys/system_archive/time_zone_binary.h"
7#include "core/file_sys/vfs_vector.h"
8#include "core/hle/service/time/time_zone_types.h"
9
10namespace FileSys::SystemArchive {
11
12static constexpr std::array<u8, 9633> LOCATION_NAMES{
13 0x43, 0x45, 0x54, 0x0d, 0x0a, 0x43, 0x53, 0x54, 0x36, 0x43, 0x44, 0x54, 0x0d, 0x0a, 0x43, 0x75,
14 0x62, 0x61, 0x0d, 0x0a, 0x45, 0x45, 0x54, 0x0d, 0x0a, 0x45, 0x67, 0x79, 0x70, 0x74, 0x0d, 0x0a,
15 0x45, 0x69, 0x72, 0x65, 0x0d, 0x0a, 0x45, 0x53, 0x54, 0x0d, 0x0a, 0x45, 0x53, 0x54, 0x35, 0x45,
16 0x44, 0x54, 0x0d, 0x0a, 0x47, 0x42, 0x0d, 0x0a, 0x47, 0x42, 0x2d, 0x45, 0x69, 0x72, 0x65, 0x0d,
17 0x0a, 0x47, 0x4d, 0x54, 0x0d, 0x0a, 0x47, 0x4d, 0x54, 0x2b, 0x30, 0x0d, 0x0a, 0x47, 0x4d, 0x54,
18 0x2d, 0x30, 0x0d, 0x0a, 0x47, 0x4d, 0x54, 0x30, 0x0d, 0x0a, 0x47, 0x72, 0x65, 0x65, 0x6e, 0x77,
19 0x69, 0x63, 0x68, 0x0d, 0x0a, 0x48, 0x6f, 0x6e, 0x67, 0x6b, 0x6f, 0x6e, 0x67, 0x0d, 0x0a, 0x48,
20 0x53, 0x54, 0x0d, 0x0a, 0x49, 0x63, 0x65, 0x6c, 0x61, 0x6e, 0x64, 0x0d, 0x0a, 0x49, 0x72, 0x61,
21 0x6e, 0x0d, 0x0a, 0x49, 0x73, 0x72, 0x61, 0x65, 0x6c, 0x0d, 0x0a, 0x4a, 0x61, 0x6d, 0x61, 0x69,
22 0x63, 0x61, 0x0d, 0x0a, 0x4a, 0x61, 0x70, 0x61, 0x6e, 0x0d, 0x0a, 0x4b, 0x77, 0x61, 0x6a, 0x61,
23 0x6c, 0x65, 0x69, 0x6e, 0x0d, 0x0a, 0x4c, 0x69, 0x62, 0x79, 0x61, 0x0d, 0x0a, 0x4d, 0x45, 0x54,
24 0x0d, 0x0a, 0x4d, 0x53, 0x54, 0x0d, 0x0a, 0x4d, 0x53, 0x54, 0x37, 0x4d, 0x44, 0x54, 0x0d, 0x0a,
25 0x4e, 0x61, 0x76, 0x61, 0x6a, 0x6f, 0x0d, 0x0a, 0x4e, 0x5a, 0x0d, 0x0a, 0x4e, 0x5a, 0x2d, 0x43,
26 0x48, 0x41, 0x54, 0x0d, 0x0a, 0x50, 0x6f, 0x6c, 0x61, 0x6e, 0x64, 0x0d, 0x0a, 0x50, 0x6f, 0x72,
27 0x74, 0x75, 0x67, 0x61, 0x6c, 0x0d, 0x0a, 0x50, 0x52, 0x43, 0x0d, 0x0a, 0x50, 0x53, 0x54, 0x38,
28 0x50, 0x44, 0x54, 0x0d, 0x0a, 0x52, 0x4f, 0x43, 0x0d, 0x0a, 0x52, 0x4f, 0x4b, 0x0d, 0x0a, 0x53,
29 0x69, 0x6e, 0x67, 0x61, 0x70, 0x6f, 0x72, 0x65, 0x0d, 0x0a, 0x54, 0x75, 0x72, 0x6b, 0x65, 0x79,
30 0x0d, 0x0a, 0x55, 0x43, 0x54, 0x0d, 0x0a, 0x55, 0x6e, 0x69, 0x76, 0x65, 0x72, 0x73, 0x61, 0x6c,
31 0x0d, 0x0a, 0x55, 0x54, 0x43, 0x0d, 0x0a, 0x57, 0x2d, 0x53, 0x55, 0x0d, 0x0a, 0x57, 0x45, 0x54,
32 0x0d, 0x0a, 0x5a, 0x75, 0x6c, 0x75, 0x0d, 0x0a, 0x41, 0x66, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x41,
33 0x62, 0x69, 0x64, 0x6a, 0x61, 0x6e, 0x0d, 0x0a, 0x41, 0x66, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x41,
34 0x63, 0x63, 0x72, 0x61, 0x0d, 0x0a, 0x41, 0x66, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x41, 0x64, 0x64,
35 0x69, 0x73, 0x5f, 0x41, 0x62, 0x61, 0x62, 0x61, 0x0d, 0x0a, 0x41, 0x66, 0x72, 0x69, 0x63, 0x61,
36 0x2f, 0x41, 0x6c, 0x67, 0x69, 0x65, 0x72, 0x73, 0x0d, 0x0a, 0x41, 0x66, 0x72, 0x69, 0x63, 0x61,
37 0x2f, 0x41, 0x73, 0x6d, 0x61, 0x72, 0x61, 0x0d, 0x0a, 0x41, 0x66, 0x72, 0x69, 0x63, 0x61, 0x2f,
38 0x41, 0x73, 0x6d, 0x65, 0x72, 0x61, 0x0d, 0x0a, 0x41, 0x66, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x42,
39 0x61, 0x6d, 0x61, 0x6b, 0x6f, 0x0d, 0x0a, 0x41, 0x66, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x42, 0x61,
40 0x6e, 0x67, 0x75, 0x69, 0x0d, 0x0a, 0x41, 0x66, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x42, 0x61, 0x6e,
41 0x6a, 0x75, 0x6c, 0x0d, 0x0a, 0x41, 0x66, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x42, 0x69, 0x73, 0x73,
42 0x61, 0x75, 0x0d, 0x0a, 0x41, 0x66, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x42, 0x6c, 0x61, 0x6e, 0x74,
43 0x79, 0x72, 0x65, 0x0d, 0x0a, 0x41, 0x66, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x42, 0x72, 0x61, 0x7a,
44 0x7a, 0x61, 0x76, 0x69, 0x6c, 0x6c, 0x65, 0x0d, 0x0a, 0x41, 0x66, 0x72, 0x69, 0x63, 0x61, 0x2f,
45 0x42, 0x75, 0x6a, 0x75, 0x6d, 0x62, 0x75, 0x72, 0x61, 0x0d, 0x0a, 0x41, 0x66, 0x72, 0x69, 0x63,
46 0x61, 0x2f, 0x43, 0x61, 0x69, 0x72, 0x6f, 0x0d, 0x0a, 0x41, 0x66, 0x72, 0x69, 0x63, 0x61, 0x2f,
47 0x43, 0x61, 0x73, 0x61, 0x62, 0x6c, 0x61, 0x6e, 0x63, 0x61, 0x0d, 0x0a, 0x41, 0x66, 0x72, 0x69,
48 0x63, 0x61, 0x2f, 0x43, 0x65, 0x75, 0x74, 0x61, 0x0d, 0x0a, 0x41, 0x66, 0x72, 0x69, 0x63, 0x61,
49 0x2f, 0x43, 0x6f, 0x6e, 0x61, 0x6b, 0x72, 0x79, 0x0d, 0x0a, 0x41, 0x66, 0x72, 0x69, 0x63, 0x61,
50 0x2f, 0x44, 0x61, 0x6b, 0x61, 0x72, 0x0d, 0x0a, 0x41, 0x66, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x44,
51 0x61, 0x72, 0x5f, 0x65, 0x73, 0x5f, 0x53, 0x61, 0x6c, 0x61, 0x61, 0x6d, 0x0d, 0x0a, 0x41, 0x66,
52 0x72, 0x69, 0x63, 0x61, 0x2f, 0x44, 0x6a, 0x69, 0x62, 0x6f, 0x75, 0x74, 0x69, 0x0d, 0x0a, 0x41,
53 0x66, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x44, 0x6f, 0x75, 0x61, 0x6c, 0x61, 0x0d, 0x0a, 0x41, 0x66,
54 0x72, 0x69, 0x63, 0x61, 0x2f, 0x45, 0x6c, 0x5f, 0x41, 0x61, 0x69, 0x75, 0x6e, 0x0d, 0x0a, 0x41,
55 0x66, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x46, 0x72, 0x65, 0x65, 0x74, 0x6f, 0x77, 0x6e, 0x0d, 0x0a,
56 0x41, 0x66, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x47, 0x61, 0x62, 0x6f, 0x72, 0x6f, 0x6e, 0x65, 0x0d,
57 0x0a, 0x41, 0x66, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x48, 0x61, 0x72, 0x61, 0x72, 0x65, 0x0d, 0x0a,
58 0x41, 0x66, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4a, 0x6f, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x73, 0x62,
59 0x75, 0x72, 0x67, 0x0d, 0x0a, 0x41, 0x66, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4a, 0x75, 0x62, 0x61,
60 0x0d, 0x0a, 0x41, 0x66, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4b, 0x61, 0x6d, 0x70, 0x61, 0x6c, 0x61,
61 0x0d, 0x0a, 0x41, 0x66, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4b, 0x68, 0x61, 0x72, 0x74, 0x6f, 0x75,
62 0x6d, 0x0d, 0x0a, 0x41, 0x66, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4b, 0x69, 0x67, 0x61, 0x6c, 0x69,
63 0x0d, 0x0a, 0x41, 0x66, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4b, 0x69, 0x6e, 0x73, 0x68, 0x61, 0x73,
64 0x61, 0x0d, 0x0a, 0x41, 0x66, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4c, 0x61, 0x67, 0x6f, 0x73, 0x0d,
65 0x0a, 0x41, 0x66, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4c, 0x69, 0x62, 0x72, 0x65, 0x76, 0x69, 0x6c,
66 0x6c, 0x65, 0x0d, 0x0a, 0x41, 0x66, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4c, 0x6f, 0x6d, 0x65, 0x0d,
67 0x0a, 0x41, 0x66, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4c, 0x75, 0x61, 0x6e, 0x64, 0x61, 0x0d, 0x0a,
68 0x41, 0x66, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4c, 0x75, 0x62, 0x75, 0x6d, 0x62, 0x61, 0x73, 0x68,
69 0x69, 0x0d, 0x0a, 0x41, 0x66, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4c, 0x75, 0x73, 0x61, 0x6b, 0x61,
70 0x0d, 0x0a, 0x41, 0x66, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4d, 0x61, 0x6c, 0x61, 0x62, 0x6f, 0x0d,
71 0x0a, 0x41, 0x66, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4d, 0x61, 0x70, 0x75, 0x74, 0x6f, 0x0d, 0x0a,
72 0x41, 0x66, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4d, 0x61, 0x73, 0x65, 0x72, 0x75, 0x0d, 0x0a, 0x41,
73 0x66, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4d, 0x62, 0x61, 0x62, 0x61, 0x6e, 0x65, 0x0d, 0x0a, 0x41,
74 0x66, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4d, 0x6f, 0x67, 0x61, 0x64, 0x69, 0x73, 0x68, 0x75, 0x0d,
75 0x0a, 0x41, 0x66, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4d, 0x6f, 0x6e, 0x72, 0x6f, 0x76, 0x69, 0x61,
76 0x0d, 0x0a, 0x41, 0x66, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4e, 0x61, 0x69, 0x72, 0x6f, 0x62, 0x69,
77 0x0d, 0x0a, 0x41, 0x66, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4e, 0x64, 0x6a, 0x61, 0x6d, 0x65, 0x6e,
78 0x61, 0x0d, 0x0a, 0x41, 0x66, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4e, 0x69, 0x61, 0x6d, 0x65, 0x79,
79 0x0d, 0x0a, 0x41, 0x66, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4e, 0x6f, 0x75, 0x61, 0x6b, 0x63, 0x68,
80 0x6f, 0x74, 0x74, 0x0d, 0x0a, 0x41, 0x66, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4f, 0x75, 0x61, 0x67,
81 0x61, 0x64, 0x6f, 0x75, 0x67, 0x6f, 0x75, 0x0d, 0x0a, 0x41, 0x66, 0x72, 0x69, 0x63, 0x61, 0x2f,
82 0x50, 0x6f, 0x72, 0x74, 0x6f, 0x2d, 0x4e, 0x6f, 0x76, 0x6f, 0x0d, 0x0a, 0x41, 0x66, 0x72, 0x69,
83 0x63, 0x61, 0x2f, 0x53, 0x61, 0x6f, 0x5f, 0x54, 0x6f, 0x6d, 0x65, 0x0d, 0x0a, 0x41, 0x66, 0x72,
84 0x69, 0x63, 0x61, 0x2f, 0x54, 0x69, 0x6d, 0x62, 0x75, 0x6b, 0x74, 0x75, 0x0d, 0x0a, 0x41, 0x66,
85 0x72, 0x69, 0x63, 0x61, 0x2f, 0x54, 0x72, 0x69, 0x70, 0x6f, 0x6c, 0x69, 0x0d, 0x0a, 0x41, 0x66,
86 0x72, 0x69, 0x63, 0x61, 0x2f, 0x54, 0x75, 0x6e, 0x69, 0x73, 0x0d, 0x0a, 0x41, 0x66, 0x72, 0x69,
87 0x63, 0x61, 0x2f, 0x57, 0x69, 0x6e, 0x64, 0x68, 0x6f, 0x65, 0x6b, 0x0d, 0x0a, 0x41, 0x6d, 0x65,
88 0x72, 0x69, 0x63, 0x61, 0x2f, 0x41, 0x64, 0x61, 0x6b, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69,
89 0x63, 0x61, 0x2f, 0x41, 0x6e, 0x63, 0x68, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x0d, 0x0a, 0x41, 0x6d,
90 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x41, 0x6e, 0x67, 0x75, 0x69, 0x6c, 0x6c, 0x61, 0x0d, 0x0a,
91 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x41, 0x6e, 0x74, 0x69, 0x67, 0x75, 0x61, 0x0d,
92 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x41, 0x72, 0x61, 0x67, 0x75, 0x61, 0x69,
93 0x6e, 0x61, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x41, 0x72, 0x75, 0x62,
94 0x61, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x41, 0x73, 0x75, 0x6e, 0x63,
95 0x69, 0x6f, 0x6e, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x41, 0x74, 0x69,
96 0x6b, 0x6f, 0x6b, 0x61, 0x6e, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x41,
97 0x74, 0x6b, 0x61, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x42, 0x61, 0x68,
98 0x69, 0x61, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x42, 0x61, 0x68, 0x69,
99 0x61, 0x5f, 0x42, 0x61, 0x6e, 0x64, 0x65, 0x72, 0x61, 0x73, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72,
100 0x69, 0x63, 0x61, 0x2f, 0x42, 0x61, 0x72, 0x62, 0x61, 0x64, 0x6f, 0x73, 0x0d, 0x0a, 0x41, 0x6d,
101 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x42, 0x65, 0x6c, 0x65, 0x6d, 0x0d, 0x0a, 0x41, 0x6d, 0x65,
102 0x72, 0x69, 0x63, 0x61, 0x2f, 0x42, 0x65, 0x6c, 0x69, 0x7a, 0x65, 0x0d, 0x0a, 0x41, 0x6d, 0x65,
103 0x72, 0x69, 0x63, 0x61, 0x2f, 0x42, 0x6c, 0x61, 0x6e, 0x63, 0x2d, 0x53, 0x61, 0x62, 0x6c, 0x6f,
104 0x6e, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x42, 0x6f, 0x61, 0x5f, 0x56,
105 0x69, 0x73, 0x74, 0x61, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x42, 0x6f,
106 0x67, 0x6f, 0x74, 0x61, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x42, 0x6f,
107 0x69, 0x73, 0x65, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x42, 0x75, 0x65,
108 0x6e, 0x6f, 0x73, 0x5f, 0x41, 0x69, 0x72, 0x65, 0x73, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69,
109 0x63, 0x61, 0x2f, 0x43, 0x61, 0x6d, 0x62, 0x72, 0x69, 0x64, 0x67, 0x65, 0x5f, 0x42, 0x61, 0x79,
110 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x43, 0x61, 0x6d, 0x70, 0x6f, 0x5f,
111 0x47, 0x72, 0x61, 0x6e, 0x64, 0x65, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f,
112 0x43, 0x61, 0x6e, 0x63, 0x75, 0x6e, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f,
113 0x43, 0x61, 0x72, 0x61, 0x63, 0x61, 0x73, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61,
114 0x2f, 0x43, 0x61, 0x74, 0x61, 0x6d, 0x61, 0x72, 0x63, 0x61, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72,
115 0x69, 0x63, 0x61, 0x2f, 0x43, 0x61, 0x79, 0x65, 0x6e, 0x6e, 0x65, 0x0d, 0x0a, 0x41, 0x6d, 0x65,
116 0x72, 0x69, 0x63, 0x61, 0x2f, 0x43, 0x61, 0x79, 0x6d, 0x61, 0x6e, 0x0d, 0x0a, 0x41, 0x6d, 0x65,
117 0x72, 0x69, 0x63, 0x61, 0x2f, 0x43, 0x68, 0x69, 0x63, 0x61, 0x67, 0x6f, 0x0d, 0x0a, 0x41, 0x6d,
118 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x43, 0x68, 0x69, 0x68, 0x75, 0x61, 0x68, 0x75, 0x61, 0x0d,
119 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x43, 0x6f, 0x72, 0x61, 0x6c, 0x5f, 0x48,
120 0x61, 0x72, 0x62, 0x6f, 0x75, 0x72, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f,
121 0x43, 0x6f, 0x72, 0x64, 0x6f, 0x62, 0x61, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61,
122 0x2f, 0x43, 0x6f, 0x73, 0x74, 0x61, 0x5f, 0x52, 0x69, 0x63, 0x61, 0x0d, 0x0a, 0x41, 0x6d, 0x65,
123 0x72, 0x69, 0x63, 0x61, 0x2f, 0x43, 0x72, 0x65, 0x73, 0x74, 0x6f, 0x6e, 0x0d, 0x0a, 0x41, 0x6d,
124 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x43, 0x75, 0x69, 0x61, 0x62, 0x61, 0x0d, 0x0a, 0x41, 0x6d,
125 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x43, 0x75, 0x72, 0x61, 0x63, 0x61, 0x6f, 0x0d, 0x0a, 0x41,
126 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x44, 0x61, 0x6e, 0x6d, 0x61, 0x72, 0x6b, 0x73, 0x68,
127 0x61, 0x76, 0x6e, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x44, 0x61, 0x77,
128 0x73, 0x6f, 0x6e, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x44, 0x61, 0x77,
129 0x73, 0x6f, 0x6e, 0x5f, 0x43, 0x72, 0x65, 0x65, 0x6b, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69,
130 0x63, 0x61, 0x2f, 0x44, 0x65, 0x6e, 0x76, 0x65, 0x72, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69,
131 0x63, 0x61, 0x2f, 0x44, 0x65, 0x74, 0x72, 0x6f, 0x69, 0x74, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72,
132 0x69, 0x63, 0x61, 0x2f, 0x44, 0x6f, 0x6d, 0x69, 0x6e, 0x69, 0x63, 0x61, 0x0d, 0x0a, 0x41, 0x6d,
133 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x45, 0x64, 0x6d, 0x6f, 0x6e, 0x74, 0x6f, 0x6e, 0x0d, 0x0a,
134 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x45, 0x69, 0x72, 0x75, 0x6e, 0x65, 0x70, 0x65,
135 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x45, 0x6c, 0x5f, 0x53, 0x61, 0x6c,
136 0x76, 0x61, 0x64, 0x6f, 0x72, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x45,
137 0x6e, 0x73, 0x65, 0x6e, 0x61, 0x64, 0x61, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61,
138 0x2f, 0x46, 0x6f, 0x72, 0x74, 0x61, 0x6c, 0x65, 0x7a, 0x61, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72,
139 0x69, 0x63, 0x61, 0x2f, 0x46, 0x6f, 0x72, 0x74, 0x5f, 0x4e, 0x65, 0x6c, 0x73, 0x6f, 0x6e, 0x0d,
140 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x46, 0x6f, 0x72, 0x74, 0x5f, 0x57, 0x61,
141 0x79, 0x6e, 0x65, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x47, 0x6c, 0x61,
142 0x63, 0x65, 0x5f, 0x42, 0x61, 0x79, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f,
143 0x47, 0x6f, 0x64, 0x74, 0x68, 0x61, 0x62, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61,
144 0x2f, 0x47, 0x6f, 0x6f, 0x73, 0x65, 0x5f, 0x42, 0x61, 0x79, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72,
145 0x69, 0x63, 0x61, 0x2f, 0x47, 0x72, 0x61, 0x6e, 0x64, 0x5f, 0x54, 0x75, 0x72, 0x6b, 0x0d, 0x0a,
146 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x47, 0x72, 0x65, 0x6e, 0x61, 0x64, 0x61, 0x0d,
147 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x47, 0x75, 0x61, 0x64, 0x65, 0x6c, 0x6f,
148 0x75, 0x70, 0x65, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x47, 0x75, 0x61,
149 0x74, 0x65, 0x6d, 0x61, 0x6c, 0x61, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f,
150 0x47, 0x75, 0x61, 0x79, 0x61, 0x71, 0x75, 0x69, 0x6c, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69,
151 0x63, 0x61, 0x2f, 0x47, 0x75, 0x79, 0x61, 0x6e, 0x61, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69,
152 0x63, 0x61, 0x2f, 0x48, 0x61, 0x6c, 0x69, 0x66, 0x61, 0x78, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72,
153 0x69, 0x63, 0x61, 0x2f, 0x48, 0x61, 0x76, 0x61, 0x6e, 0x61, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72,
154 0x69, 0x63, 0x61, 0x2f, 0x48, 0x65, 0x72, 0x6d, 0x6f, 0x73, 0x69, 0x6c, 0x6c, 0x6f, 0x0d, 0x0a,
155 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x49, 0x6e, 0x64, 0x69, 0x61, 0x6e, 0x61, 0x70,
156 0x6f, 0x6c, 0x69, 0x73, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x49, 0x6e,
157 0x75, 0x76, 0x69, 0x6b, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x49, 0x71,
158 0x61, 0x6c, 0x75, 0x69, 0x74, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4a,
159 0x61, 0x6d, 0x61, 0x69, 0x63, 0x61, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f,
160 0x4a, 0x75, 0x6a, 0x75, 0x79, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4a,
161 0x75, 0x6e, 0x65, 0x61, 0x75, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4b,
162 0x6e, 0x6f, 0x78, 0x5f, 0x49, 0x4e, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f,
163 0x4b, 0x72, 0x61, 0x6c, 0x65, 0x6e, 0x64, 0x69, 0x6a, 0x6b, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72,
164 0x69, 0x63, 0x61, 0x2f, 0x4c, 0x61, 0x5f, 0x50, 0x61, 0x7a, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72,
165 0x69, 0x63, 0x61, 0x2f, 0x4c, 0x69, 0x6d, 0x61, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63,
166 0x61, 0x2f, 0x4c, 0x6f, 0x73, 0x5f, 0x41, 0x6e, 0x67, 0x65, 0x6c, 0x65, 0x73, 0x0d, 0x0a, 0x41,
167 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4c, 0x6f, 0x75, 0x69, 0x73, 0x76, 0x69, 0x6c, 0x6c,
168 0x65, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4c, 0x6f, 0x77, 0x65, 0x72,
169 0x5f, 0x50, 0x72, 0x69, 0x6e, 0x63, 0x65, 0x73, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63,
170 0x61, 0x2f, 0x4d, 0x61, 0x63, 0x65, 0x69, 0x6f, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63,
171 0x61, 0x2f, 0x4d, 0x61, 0x6e, 0x61, 0x67, 0x75, 0x61, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69,
172 0x63, 0x61, 0x2f, 0x4d, 0x61, 0x6e, 0x61, 0x75, 0x73, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69,
173 0x63, 0x61, 0x2f, 0x4d, 0x61, 0x72, 0x69, 0x67, 0x6f, 0x74, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72,
174 0x69, 0x63, 0x61, 0x2f, 0x4d, 0x61, 0x72, 0x74, 0x69, 0x6e, 0x69, 0x71, 0x75, 0x65, 0x0d, 0x0a,
175 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4d, 0x61, 0x74, 0x61, 0x6d, 0x6f, 0x72, 0x6f,
176 0x73, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4d, 0x61, 0x7a, 0x61, 0x74,
177 0x6c, 0x61, 0x6e, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4d, 0x65, 0x6e,
178 0x64, 0x6f, 0x7a, 0x61, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4d, 0x65,
179 0x6e, 0x6f, 0x6d, 0x69, 0x6e, 0x65, 0x65, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61,
180 0x2f, 0x4d, 0x65, 0x72, 0x69, 0x64, 0x61, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61,
181 0x2f, 0x4d, 0x65, 0x74, 0x6c, 0x61, 0x6b, 0x61, 0x74, 0x6c, 0x61, 0x0d, 0x0a, 0x41, 0x6d, 0x65,
182 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4d, 0x65, 0x78, 0x69, 0x63, 0x6f, 0x5f, 0x43, 0x69, 0x74, 0x79,
183 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4d, 0x69, 0x71, 0x75, 0x65, 0x6c,
184 0x6f, 0x6e, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4d, 0x6f, 0x6e, 0x63,
185 0x74, 0x6f, 0x6e, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4d, 0x6f, 0x6e,
186 0x74, 0x65, 0x72, 0x72, 0x65, 0x79, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f,
187 0x4d, 0x6f, 0x6e, 0x74, 0x65, 0x76, 0x69, 0x64, 0x65, 0x6f, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72,
188 0x69, 0x63, 0x61, 0x2f, 0x4d, 0x6f, 0x6e, 0x74, 0x72, 0x65, 0x61, 0x6c, 0x0d, 0x0a, 0x41, 0x6d,
189 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4d, 0x6f, 0x6e, 0x74, 0x73, 0x65, 0x72, 0x72, 0x61, 0x74,
190 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4e, 0x61, 0x73, 0x73, 0x61, 0x75,
191 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4e, 0x65, 0x77, 0x5f, 0x59, 0x6f,
192 0x72, 0x6b, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4e, 0x69, 0x70, 0x69,
193 0x67, 0x6f, 0x6e, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4e, 0x6f, 0x6d,
194 0x65, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4e, 0x6f, 0x72, 0x6f, 0x6e,
195 0x68, 0x61, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4f, 0x6a, 0x69, 0x6e,
196 0x61, 0x67, 0x61, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x50, 0x61, 0x6e,
197 0x61, 0x6d, 0x61, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x50, 0x61, 0x6e,
198 0x67, 0x6e, 0x69, 0x72, 0x74, 0x75, 0x6e, 0x67, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63,
199 0x61, 0x2f, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x61, 0x72, 0x69, 0x62, 0x6f, 0x0d, 0x0a, 0x41, 0x6d,
200 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x50, 0x68, 0x6f, 0x65, 0x6e, 0x69, 0x78, 0x0d, 0x0a, 0x41,
201 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x50, 0x6f, 0x72, 0x74, 0x2d, 0x61, 0x75, 0x2d, 0x50,
202 0x72, 0x69, 0x6e, 0x63, 0x65, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x50,
203 0x6f, 0x72, 0x74, 0x6f, 0x5f, 0x41, 0x63, 0x72, 0x65, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69,
204 0x63, 0x61, 0x2f, 0x50, 0x6f, 0x72, 0x74, 0x6f, 0x5f, 0x56, 0x65, 0x6c, 0x68, 0x6f, 0x0d, 0x0a,
205 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x50, 0x6f, 0x72, 0x74, 0x5f, 0x6f, 0x66, 0x5f,
206 0x53, 0x70, 0x61, 0x69, 0x6e, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x50,
207 0x75, 0x65, 0x72, 0x74, 0x6f, 0x5f, 0x52, 0x69, 0x63, 0x6f, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72,
208 0x69, 0x63, 0x61, 0x2f, 0x50, 0x75, 0x6e, 0x74, 0x61, 0x5f, 0x41, 0x72, 0x65, 0x6e, 0x61, 0x73,
209 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x52, 0x61, 0x69, 0x6e, 0x79, 0x5f,
210 0x52, 0x69, 0x76, 0x65, 0x72, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x52,
211 0x61, 0x6e, 0x6b, 0x69, 0x6e, 0x5f, 0x49, 0x6e, 0x6c, 0x65, 0x74, 0x0d, 0x0a, 0x41, 0x6d, 0x65,
212 0x72, 0x69, 0x63, 0x61, 0x2f, 0x52, 0x65, 0x63, 0x69, 0x66, 0x65, 0x0d, 0x0a, 0x41, 0x6d, 0x65,
213 0x72, 0x69, 0x63, 0x61, 0x2f, 0x52, 0x65, 0x67, 0x69, 0x6e, 0x61, 0x0d, 0x0a, 0x41, 0x6d, 0x65,
214 0x72, 0x69, 0x63, 0x61, 0x2f, 0x52, 0x65, 0x73, 0x6f, 0x6c, 0x75, 0x74, 0x65, 0x0d, 0x0a, 0x41,
215 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x52, 0x69, 0x6f, 0x5f, 0x42, 0x72, 0x61, 0x6e, 0x63,
216 0x6f, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x52, 0x6f, 0x73, 0x61, 0x72,
217 0x69, 0x6f, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x53, 0x61, 0x6e, 0x74,
218 0x61, 0x72, 0x65, 0x6d, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x53, 0x61,
219 0x6e, 0x74, 0x61, 0x5f, 0x49, 0x73, 0x61, 0x62, 0x65, 0x6c, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72,
220 0x69, 0x63, 0x61, 0x2f, 0x53, 0x61, 0x6e, 0x74, 0x69, 0x61, 0x67, 0x6f, 0x0d, 0x0a, 0x41, 0x6d,
221 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x53, 0x61, 0x6e, 0x74, 0x6f, 0x5f, 0x44, 0x6f, 0x6d, 0x69,
222 0x6e, 0x67, 0x6f, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x53, 0x61, 0x6f,
223 0x5f, 0x50, 0x61, 0x75, 0x6c, 0x6f, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f,
224 0x53, 0x63, 0x6f, 0x72, 0x65, 0x73, 0x62, 0x79, 0x73, 0x75, 0x6e, 0x64, 0x0d, 0x0a, 0x41, 0x6d,
225 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x53, 0x68, 0x69, 0x70, 0x72, 0x6f, 0x63, 0x6b, 0x0d, 0x0a,
226 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x53, 0x69, 0x74, 0x6b, 0x61, 0x0d, 0x0a, 0x41,
227 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x53, 0x74, 0x5f, 0x42, 0x61, 0x72, 0x74, 0x68, 0x65,
228 0x6c, 0x65, 0x6d, 0x79, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x53, 0x74,
229 0x5f, 0x4a, 0x6f, 0x68, 0x6e, 0x73, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f,
230 0x53, 0x74, 0x5f, 0x4b, 0x69, 0x74, 0x74, 0x73, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63,
231 0x61, 0x2f, 0x53, 0x74, 0x5f, 0x4c, 0x75, 0x63, 0x69, 0x61, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72,
232 0x69, 0x63, 0x61, 0x2f, 0x53, 0x74, 0x5f, 0x54, 0x68, 0x6f, 0x6d, 0x61, 0x73, 0x0d, 0x0a, 0x41,
233 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x53, 0x74, 0x5f, 0x56, 0x69, 0x6e, 0x63, 0x65, 0x6e,
234 0x74, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x53, 0x77, 0x69, 0x66, 0x74,
235 0x5f, 0x43, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63,
236 0x61, 0x2f, 0x54, 0x65, 0x67, 0x75, 0x63, 0x69, 0x67, 0x61, 0x6c, 0x70, 0x61, 0x0d, 0x0a, 0x41,
237 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x54, 0x68, 0x75, 0x6c, 0x65, 0x0d, 0x0a, 0x41, 0x6d,
238 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x54, 0x68, 0x75, 0x6e, 0x64, 0x65, 0x72, 0x5f, 0x42, 0x61,
239 0x79, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x54, 0x69, 0x6a, 0x75, 0x61,
240 0x6e, 0x61, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x54, 0x6f, 0x72, 0x6f,
241 0x6e, 0x74, 0x6f, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x54, 0x6f, 0x72,
242 0x74, 0x6f, 0x6c, 0x61, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x56, 0x61,
243 0x6e, 0x63, 0x6f, 0x75, 0x76, 0x65, 0x72, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61,
244 0x2f, 0x56, 0x69, 0x72, 0x67, 0x69, 0x6e, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61,
245 0x2f, 0x57, 0x68, 0x69, 0x74, 0x65, 0x68, 0x6f, 0x72, 0x73, 0x65, 0x0d, 0x0a, 0x41, 0x6d, 0x65,
246 0x72, 0x69, 0x63, 0x61, 0x2f, 0x57, 0x69, 0x6e, 0x6e, 0x69, 0x70, 0x65, 0x67, 0x0d, 0x0a, 0x41,
247 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x59, 0x61, 0x6b, 0x75, 0x74, 0x61, 0x74, 0x0d, 0x0a,
248 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x59, 0x65, 0x6c, 0x6c, 0x6f, 0x77, 0x6b, 0x6e,
249 0x69, 0x66, 0x65, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x41, 0x72, 0x67,
250 0x65, 0x6e, 0x74, 0x69, 0x6e, 0x61, 0x2f, 0x42, 0x75, 0x65, 0x6e, 0x6f, 0x73, 0x5f, 0x41, 0x69,
251 0x72, 0x65, 0x73, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x41, 0x72, 0x67,
252 0x65, 0x6e, 0x74, 0x69, 0x6e, 0x61, 0x2f, 0x43, 0x61, 0x74, 0x61, 0x6d, 0x61, 0x72, 0x63, 0x61,
253 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x41, 0x72, 0x67, 0x65, 0x6e, 0x74,
254 0x69, 0x6e, 0x61, 0x2f, 0x43, 0x6f, 0x6d, 0x6f, 0x64, 0x52, 0x69, 0x76, 0x61, 0x64, 0x61, 0x76,
255 0x69, 0x61, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x41, 0x72, 0x67, 0x65,
256 0x6e, 0x74, 0x69, 0x6e, 0x61, 0x2f, 0x43, 0x6f, 0x72, 0x64, 0x6f, 0x62, 0x61, 0x0d, 0x0a, 0x41,
257 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x41, 0x72, 0x67, 0x65, 0x6e, 0x74, 0x69, 0x6e, 0x61,
258 0x2f, 0x4a, 0x75, 0x6a, 0x75, 0x79, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f,
259 0x41, 0x72, 0x67, 0x65, 0x6e, 0x74, 0x69, 0x6e, 0x61, 0x2f, 0x4c, 0x61, 0x5f, 0x52, 0x69, 0x6f,
260 0x6a, 0x61, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x41, 0x72, 0x67, 0x65,
261 0x6e, 0x74, 0x69, 0x6e, 0x61, 0x2f, 0x4d, 0x65, 0x6e, 0x64, 0x6f, 0x7a, 0x61, 0x0d, 0x0a, 0x41,
262 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x41, 0x72, 0x67, 0x65, 0x6e, 0x74, 0x69, 0x6e, 0x61,
263 0x2f, 0x52, 0x69, 0x6f, 0x5f, 0x47, 0x61, 0x6c, 0x6c, 0x65, 0x67, 0x6f, 0x73, 0x0d, 0x0a, 0x41,
264 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x41, 0x72, 0x67, 0x65, 0x6e, 0x74, 0x69, 0x6e, 0x61,
265 0x2f, 0x53, 0x61, 0x6c, 0x74, 0x61, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f,
266 0x41, 0x72, 0x67, 0x65, 0x6e, 0x74, 0x69, 0x6e, 0x61, 0x2f, 0x53, 0x61, 0x6e, 0x5f, 0x4a, 0x75,
267 0x61, 0x6e, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x41, 0x72, 0x67, 0x65,
268 0x6e, 0x74, 0x69, 0x6e, 0x61, 0x2f, 0x53, 0x61, 0x6e, 0x5f, 0x4c, 0x75, 0x69, 0x73, 0x0d, 0x0a,
269 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x41, 0x72, 0x67, 0x65, 0x6e, 0x74, 0x69, 0x6e,
270 0x61, 0x2f, 0x54, 0x75, 0x63, 0x75, 0x6d, 0x61, 0x6e, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69,
271 0x63, 0x61, 0x2f, 0x41, 0x72, 0x67, 0x65, 0x6e, 0x74, 0x69, 0x6e, 0x61, 0x2f, 0x55, 0x73, 0x68,
272 0x75, 0x61, 0x69, 0x61, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x49, 0x6e,
273 0x64, 0x69, 0x61, 0x6e, 0x61, 0x2f, 0x49, 0x6e, 0x64, 0x69, 0x61, 0x6e, 0x61, 0x70, 0x6f, 0x6c,
274 0x69, 0x73, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x49, 0x6e, 0x64, 0x69,
275 0x61, 0x6e, 0x61, 0x2f, 0x4b, 0x6e, 0x6f, 0x78, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63,
276 0x61, 0x2f, 0x49, 0x6e, 0x64, 0x69, 0x61, 0x6e, 0x61, 0x2f, 0x4d, 0x61, 0x72, 0x65, 0x6e, 0x67,
277 0x6f, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x49, 0x6e, 0x64, 0x69, 0x61,
278 0x6e, 0x61, 0x2f, 0x50, 0x65, 0x74, 0x65, 0x72, 0x73, 0x62, 0x75, 0x72, 0x67, 0x0d, 0x0a, 0x41,
279 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x49, 0x6e, 0x64, 0x69, 0x61, 0x6e, 0x61, 0x2f, 0x54,
280 0x65, 0x6c, 0x6c, 0x5f, 0x43, 0x69, 0x74, 0x79, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63,
281 0x61, 0x2f, 0x49, 0x6e, 0x64, 0x69, 0x61, 0x6e, 0x61, 0x2f, 0x56, 0x65, 0x76, 0x61, 0x79, 0x0d,
282 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x49, 0x6e, 0x64, 0x69, 0x61, 0x6e, 0x61,
283 0x2f, 0x56, 0x69, 0x6e, 0x63, 0x65, 0x6e, 0x6e, 0x65, 0x73, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72,
284 0x69, 0x63, 0x61, 0x2f, 0x49, 0x6e, 0x64, 0x69, 0x61, 0x6e, 0x61, 0x2f, 0x57, 0x69, 0x6e, 0x61,
285 0x6d, 0x61, 0x63, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4b, 0x65, 0x6e,
286 0x74, 0x75, 0x63, 0x6b, 0x79, 0x2f, 0x4c, 0x6f, 0x75, 0x69, 0x73, 0x76, 0x69, 0x6c, 0x6c, 0x65,
287 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4b, 0x65, 0x6e, 0x74, 0x75, 0x63,
288 0x6b, 0x79, 0x2f, 0x4d, 0x6f, 0x6e, 0x74, 0x69, 0x63, 0x65, 0x6c, 0x6c, 0x6f, 0x0d, 0x0a, 0x41,
289 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4e, 0x6f, 0x72, 0x74, 0x68, 0x5f, 0x44, 0x61, 0x6b,
290 0x6f, 0x74, 0x61, 0x2f, 0x42, 0x65, 0x75, 0x6c, 0x61, 0x68, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72,
291 0x69, 0x63, 0x61, 0x2f, 0x4e, 0x6f, 0x72, 0x74, 0x68, 0x5f, 0x44, 0x61, 0x6b, 0x6f, 0x74, 0x61,
292 0x2f, 0x43, 0x65, 0x6e, 0x74, 0x65, 0x72, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61,
293 0x2f, 0x4e, 0x6f, 0x72, 0x74, 0x68, 0x5f, 0x44, 0x61, 0x6b, 0x6f, 0x74, 0x61, 0x2f, 0x4e, 0x65,
294 0x77, 0x5f, 0x53, 0x61, 0x6c, 0x65, 0x6d, 0x0d, 0x0a, 0x41, 0x6e, 0x74, 0x61, 0x72, 0x63, 0x74,
295 0x69, 0x63, 0x61, 0x2f, 0x43, 0x61, 0x73, 0x65, 0x79, 0x0d, 0x0a, 0x41, 0x6e, 0x74, 0x61, 0x72,
296 0x63, 0x74, 0x69, 0x63, 0x61, 0x2f, 0x44, 0x61, 0x76, 0x69, 0x73, 0x0d, 0x0a, 0x41, 0x6e, 0x74,
297 0x61, 0x72, 0x63, 0x74, 0x69, 0x63, 0x61, 0x2f, 0x44, 0x75, 0x6d, 0x6f, 0x6e, 0x74, 0x44, 0x55,
298 0x72, 0x76, 0x69, 0x6c, 0x6c, 0x65, 0x0d, 0x0a, 0x41, 0x6e, 0x74, 0x61, 0x72, 0x63, 0x74, 0x69,
299 0x63, 0x61, 0x2f, 0x4d, 0x61, 0x63, 0x71, 0x75, 0x61, 0x72, 0x69, 0x65, 0x0d, 0x0a, 0x41, 0x6e,
300 0x74, 0x61, 0x72, 0x63, 0x74, 0x69, 0x63, 0x61, 0x2f, 0x4d, 0x61, 0x77, 0x73, 0x6f, 0x6e, 0x0d,
301 0x0a, 0x41, 0x6e, 0x74, 0x61, 0x72, 0x63, 0x74, 0x69, 0x63, 0x61, 0x2f, 0x4d, 0x63, 0x4d, 0x75,
302 0x72, 0x64, 0x6f, 0x0d, 0x0a, 0x41, 0x6e, 0x74, 0x61, 0x72, 0x63, 0x74, 0x69, 0x63, 0x61, 0x2f,
303 0x50, 0x61, 0x6c, 0x6d, 0x65, 0x72, 0x0d, 0x0a, 0x41, 0x6e, 0x74, 0x61, 0x72, 0x63, 0x74, 0x69,
304 0x63, 0x61, 0x2f, 0x52, 0x6f, 0x74, 0x68, 0x65, 0x72, 0x61, 0x0d, 0x0a, 0x41, 0x6e, 0x74, 0x61,
305 0x72, 0x63, 0x74, 0x69, 0x63, 0x61, 0x2f, 0x53, 0x6f, 0x75, 0x74, 0x68, 0x5f, 0x50, 0x6f, 0x6c,
306 0x65, 0x0d, 0x0a, 0x41, 0x6e, 0x74, 0x61, 0x72, 0x63, 0x74, 0x69, 0x63, 0x61, 0x2f, 0x53, 0x79,
307 0x6f, 0x77, 0x61, 0x0d, 0x0a, 0x41, 0x6e, 0x74, 0x61, 0x72, 0x63, 0x74, 0x69, 0x63, 0x61, 0x2f,
308 0x54, 0x72, 0x6f, 0x6c, 0x6c, 0x0d, 0x0a, 0x41, 0x6e, 0x74, 0x61, 0x72, 0x63, 0x74, 0x69, 0x63,
309 0x61, 0x2f, 0x56, 0x6f, 0x73, 0x74, 0x6f, 0x6b, 0x0d, 0x0a, 0x41, 0x72, 0x63, 0x74, 0x69, 0x63,
310 0x2f, 0x4c, 0x6f, 0x6e, 0x67, 0x79, 0x65, 0x61, 0x72, 0x62, 0x79, 0x65, 0x6e, 0x0d, 0x0a, 0x41,
311 0x73, 0x69, 0x61, 0x2f, 0x41, 0x64, 0x65, 0x6e, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x41,
312 0x6c, 0x6d, 0x61, 0x74, 0x79, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x41, 0x6d, 0x6d, 0x61,
313 0x6e, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x41, 0x6e, 0x61, 0x64, 0x79, 0x72, 0x0d, 0x0a,
314 0x41, 0x73, 0x69, 0x61, 0x2f, 0x41, 0x71, 0x74, 0x61, 0x75, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61,
315 0x2f, 0x41, 0x71, 0x74, 0x6f, 0x62, 0x65, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x41, 0x73,
316 0x68, 0x67, 0x61, 0x62, 0x61, 0x74, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x41, 0x73, 0x68,
317 0x6b, 0x68, 0x61, 0x62, 0x61, 0x64, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x41, 0x74, 0x79,
318 0x72, 0x61, 0x75, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x42, 0x61, 0x67, 0x68, 0x64, 0x61,
319 0x64, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x42, 0x61, 0x68, 0x72, 0x61, 0x69, 0x6e, 0x0d,
320 0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x42, 0x61, 0x6b, 0x75, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61,
321 0x2f, 0x42, 0x61, 0x6e, 0x67, 0x6b, 0x6f, 0x6b, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x42,
322 0x61, 0x72, 0x6e, 0x61, 0x75, 0x6c, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x42, 0x65, 0x69,
323 0x72, 0x75, 0x74, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x42, 0x69, 0x73, 0x68, 0x6b, 0x65,
324 0x6b, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x42, 0x72, 0x75, 0x6e, 0x65, 0x69, 0x0d, 0x0a,
325 0x41, 0x73, 0x69, 0x61, 0x2f, 0x43, 0x61, 0x6c, 0x63, 0x75, 0x74, 0x74, 0x61, 0x0d, 0x0a, 0x41,
326 0x73, 0x69, 0x61, 0x2f, 0x43, 0x68, 0x69, 0x74, 0x61, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f,
327 0x43, 0x68, 0x6f, 0x69, 0x62, 0x61, 0x6c, 0x73, 0x61, 0x6e, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61,
328 0x2f, 0x43, 0x68, 0x6f, 0x6e, 0x67, 0x71, 0x69, 0x6e, 0x67, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61,
329 0x2f, 0x43, 0x68, 0x75, 0x6e, 0x67, 0x6b, 0x69, 0x6e, 0x67, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61,
330 0x2f, 0x43, 0x6f, 0x6c, 0x6f, 0x6d, 0x62, 0x6f, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x44,
331 0x61, 0x63, 0x63, 0x61, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x44, 0x61, 0x6d, 0x61, 0x73,
332 0x63, 0x75, 0x73, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x44, 0x68, 0x61, 0x6b, 0x61, 0x0d,
333 0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x44, 0x69, 0x6c, 0x69, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61,
334 0x2f, 0x44, 0x75, 0x62, 0x61, 0x69, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x44, 0x75, 0x73,
335 0x68, 0x61, 0x6e, 0x62, 0x65, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x46, 0x61, 0x6d, 0x61,
336 0x67, 0x75, 0x73, 0x74, 0x61, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x47, 0x61, 0x7a, 0x61,
337 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x48, 0x61, 0x72, 0x62, 0x69, 0x6e, 0x0d, 0x0a, 0x41,
338 0x73, 0x69, 0x61, 0x2f, 0x48, 0x65, 0x62, 0x72, 0x6f, 0x6e, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61,
339 0x2f, 0x48, 0x6f, 0x6e, 0x67, 0x5f, 0x4b, 0x6f, 0x6e, 0x67, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61,
340 0x2f, 0x48, 0x6f, 0x76, 0x64, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x48, 0x6f, 0x5f, 0x43,
341 0x68, 0x69, 0x5f, 0x4d, 0x69, 0x6e, 0x68, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x49, 0x72,
342 0x6b, 0x75, 0x74, 0x73, 0x6b, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x49, 0x73, 0x74, 0x61,
343 0x6e, 0x62, 0x75, 0x6c, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x4a, 0x61, 0x6b, 0x61, 0x72,
344 0x74, 0x61, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x4a, 0x61, 0x79, 0x61, 0x70, 0x75, 0x72,
345 0x61, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x4a, 0x65, 0x72, 0x75, 0x73, 0x61, 0x6c, 0x65,
346 0x6d, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x4b, 0x61, 0x62, 0x75, 0x6c, 0x0d, 0x0a, 0x41,
347 0x73, 0x69, 0x61, 0x2f, 0x4b, 0x61, 0x6d, 0x63, 0x68, 0x61, 0x74, 0x6b, 0x61, 0x0d, 0x0a, 0x41,
348 0x73, 0x69, 0x61, 0x2f, 0x4b, 0x61, 0x72, 0x61, 0x63, 0x68, 0x69, 0x0d, 0x0a, 0x41, 0x73, 0x69,
349 0x61, 0x2f, 0x4b, 0x61, 0x73, 0x68, 0x67, 0x61, 0x72, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f,
350 0x4b, 0x61, 0x74, 0x68, 0x6d, 0x61, 0x6e, 0x64, 0x75, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f,
351 0x4b, 0x61, 0x74, 0x6d, 0x61, 0x6e, 0x64, 0x75, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x4b,
352 0x68, 0x61, 0x6e, 0x64, 0x79, 0x67, 0x61, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x4b, 0x6f,
353 0x6c, 0x6b, 0x61, 0x74, 0x61, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x4b, 0x72, 0x61, 0x73,
354 0x6e, 0x6f, 0x79, 0x61, 0x72, 0x73, 0x6b, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x4b, 0x75,
355 0x61, 0x6c, 0x61, 0x5f, 0x4c, 0x75, 0x6d, 0x70, 0x75, 0x72, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61,
356 0x2f, 0x4b, 0x75, 0x63, 0x68, 0x69, 0x6e, 0x67, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x4b,
357 0x75, 0x77, 0x61, 0x69, 0x74, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x4d, 0x61, 0x63, 0x61,
358 0x6f, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x4d, 0x61, 0x63, 0x61, 0x75, 0x0d, 0x0a, 0x41,
359 0x73, 0x69, 0x61, 0x2f, 0x4d, 0x61, 0x67, 0x61, 0x64, 0x61, 0x6e, 0x0d, 0x0a, 0x41, 0x73, 0x69,
360 0x61, 0x2f, 0x4d, 0x61, 0x6b, 0x61, 0x73, 0x73, 0x61, 0x72, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61,
361 0x2f, 0x4d, 0x61, 0x6e, 0x69, 0x6c, 0x61, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x4d, 0x75,
362 0x73, 0x63, 0x61, 0x74, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x4e, 0x69, 0x63, 0x6f, 0x73,
363 0x69, 0x61, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x4e, 0x6f, 0x76, 0x6f, 0x6b, 0x75, 0x7a,
364 0x6e, 0x65, 0x74, 0x73, 0x6b, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x4e, 0x6f, 0x76, 0x6f,
365 0x73, 0x69, 0x62, 0x69, 0x72, 0x73, 0x6b, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x4f, 0x6d,
366 0x73, 0x6b, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x4f, 0x72, 0x61, 0x6c, 0x0d, 0x0a, 0x41,
367 0x73, 0x69, 0x61, 0x2f, 0x50, 0x68, 0x6e, 0x6f, 0x6d, 0x5f, 0x50, 0x65, 0x6e, 0x68, 0x0d, 0x0a,
368 0x41, 0x73, 0x69, 0x61, 0x2f, 0x50, 0x6f, 0x6e, 0x74, 0x69, 0x61, 0x6e, 0x61, 0x6b, 0x0d, 0x0a,
369 0x41, 0x73, 0x69, 0x61, 0x2f, 0x50, 0x79, 0x6f, 0x6e, 0x67, 0x79, 0x61, 0x6e, 0x67, 0x0d, 0x0a,
370 0x41, 0x73, 0x69, 0x61, 0x2f, 0x51, 0x61, 0x74, 0x61, 0x72, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61,
371 0x2f, 0x51, 0x79, 0x7a, 0x79, 0x6c, 0x6f, 0x72, 0x64, 0x61, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61,
372 0x2f, 0x52, 0x61, 0x6e, 0x67, 0x6f, 0x6f, 0x6e, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x52,
373 0x69, 0x79, 0x61, 0x64, 0x68, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x53, 0x61, 0x69, 0x67,
374 0x6f, 0x6e, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x53, 0x61, 0x6b, 0x68, 0x61, 0x6c, 0x69,
375 0x6e, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x53, 0x61, 0x6d, 0x61, 0x72, 0x6b, 0x61, 0x6e,
376 0x64, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x53, 0x65, 0x6f, 0x75, 0x6c, 0x0d, 0x0a, 0x41,
377 0x73, 0x69, 0x61, 0x2f, 0x53, 0x68, 0x61, 0x6e, 0x67, 0x68, 0x61, 0x69, 0x0d, 0x0a, 0x41, 0x73,
378 0x69, 0x61, 0x2f, 0x53, 0x69, 0x6e, 0x67, 0x61, 0x70, 0x6f, 0x72, 0x65, 0x0d, 0x0a, 0x41, 0x73,
379 0x69, 0x61, 0x2f, 0x53, 0x72, 0x65, 0x64, 0x6e, 0x65, 0x6b, 0x6f, 0x6c, 0x79, 0x6d, 0x73, 0x6b,
380 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x54, 0x61, 0x69, 0x70, 0x65, 0x69, 0x0d, 0x0a, 0x41,
381 0x73, 0x69, 0x61, 0x2f, 0x54, 0x61, 0x73, 0x68, 0x6b, 0x65, 0x6e, 0x74, 0x0d, 0x0a, 0x41, 0x73,
382 0x69, 0x61, 0x2f, 0x54, 0x62, 0x69, 0x6c, 0x69, 0x73, 0x69, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61,
383 0x2f, 0x54, 0x65, 0x68, 0x72, 0x61, 0x6e, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x54, 0x65,
384 0x6c, 0x5f, 0x41, 0x76, 0x69, 0x76, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x54, 0x68, 0x69,
385 0x6d, 0x62, 0x75, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x54, 0x68, 0x69, 0x6d, 0x70, 0x68,
386 0x75, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x54, 0x6f, 0x6b, 0x79, 0x6f, 0x0d, 0x0a, 0x41,
387 0x73, 0x69, 0x61, 0x2f, 0x54, 0x6f, 0x6d, 0x73, 0x6b, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f,
388 0x55, 0x6a, 0x75, 0x6e, 0x67, 0x5f, 0x50, 0x61, 0x6e, 0x64, 0x61, 0x6e, 0x67, 0x0d, 0x0a, 0x41,
389 0x73, 0x69, 0x61, 0x2f, 0x55, 0x6c, 0x61, 0x61, 0x6e, 0x62, 0x61, 0x61, 0x74, 0x61, 0x72, 0x0d,
390 0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x55, 0x6c, 0x61, 0x6e, 0x5f, 0x42, 0x61, 0x74, 0x6f, 0x72,
391 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x55, 0x72, 0x75, 0x6d, 0x71, 0x69, 0x0d, 0x0a, 0x41,
392 0x73, 0x69, 0x61, 0x2f, 0x55, 0x73, 0x74, 0x2d, 0x4e, 0x65, 0x72, 0x61, 0x0d, 0x0a, 0x41, 0x73,
393 0x69, 0x61, 0x2f, 0x56, 0x69, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6e, 0x65, 0x0d, 0x0a, 0x41, 0x73,
394 0x69, 0x61, 0x2f, 0x56, 0x6c, 0x61, 0x64, 0x69, 0x76, 0x6f, 0x73, 0x74, 0x6f, 0x6b, 0x0d, 0x0a,
395 0x41, 0x73, 0x69, 0x61, 0x2f, 0x59, 0x61, 0x6b, 0x75, 0x74, 0x73, 0x6b, 0x0d, 0x0a, 0x41, 0x73,
396 0x69, 0x61, 0x2f, 0x59, 0x61, 0x6e, 0x67, 0x6f, 0x6e, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f,
397 0x59, 0x65, 0x6b, 0x61, 0x74, 0x65, 0x72, 0x69, 0x6e, 0x62, 0x75, 0x72, 0x67, 0x0d, 0x0a, 0x41,
398 0x73, 0x69, 0x61, 0x2f, 0x59, 0x65, 0x72, 0x65, 0x76, 0x61, 0x6e, 0x0d, 0x0a, 0x41, 0x74, 0x6c,
399 0x61, 0x6e, 0x74, 0x69, 0x63, 0x2f, 0x41, 0x7a, 0x6f, 0x72, 0x65, 0x73, 0x0d, 0x0a, 0x41, 0x74,
400 0x6c, 0x61, 0x6e, 0x74, 0x69, 0x63, 0x2f, 0x42, 0x65, 0x72, 0x6d, 0x75, 0x64, 0x61, 0x0d, 0x0a,
401 0x41, 0x74, 0x6c, 0x61, 0x6e, 0x74, 0x69, 0x63, 0x2f, 0x43, 0x61, 0x6e, 0x61, 0x72, 0x79, 0x0d,
402 0x0a, 0x41, 0x74, 0x6c, 0x61, 0x6e, 0x74, 0x69, 0x63, 0x2f, 0x43, 0x61, 0x70, 0x65, 0x5f, 0x56,
403 0x65, 0x72, 0x64, 0x65, 0x0d, 0x0a, 0x41, 0x74, 0x6c, 0x61, 0x6e, 0x74, 0x69, 0x63, 0x2f, 0x46,
404 0x61, 0x65, 0x72, 0x6f, 0x65, 0x0d, 0x0a, 0x41, 0x74, 0x6c, 0x61, 0x6e, 0x74, 0x69, 0x63, 0x2f,
405 0x46, 0x61, 0x72, 0x6f, 0x65, 0x0d, 0x0a, 0x41, 0x74, 0x6c, 0x61, 0x6e, 0x74, 0x69, 0x63, 0x2f,
406 0x4a, 0x61, 0x6e, 0x5f, 0x4d, 0x61, 0x79, 0x65, 0x6e, 0x0d, 0x0a, 0x41, 0x74, 0x6c, 0x61, 0x6e,
407 0x74, 0x69, 0x63, 0x2f, 0x4d, 0x61, 0x64, 0x65, 0x69, 0x72, 0x61, 0x0d, 0x0a, 0x41, 0x74, 0x6c,
408 0x61, 0x6e, 0x74, 0x69, 0x63, 0x2f, 0x52, 0x65, 0x79, 0x6b, 0x6a, 0x61, 0x76, 0x69, 0x6b, 0x0d,
409 0x0a, 0x41, 0x74, 0x6c, 0x61, 0x6e, 0x74, 0x69, 0x63, 0x2f, 0x53, 0x6f, 0x75, 0x74, 0x68, 0x5f,
410 0x47, 0x65, 0x6f, 0x72, 0x67, 0x69, 0x61, 0x0d, 0x0a, 0x41, 0x74, 0x6c, 0x61, 0x6e, 0x74, 0x69,
411 0x63, 0x2f, 0x53, 0x74, 0x61, 0x6e, 0x6c, 0x65, 0x79, 0x0d, 0x0a, 0x41, 0x74, 0x6c, 0x61, 0x6e,
412 0x74, 0x69, 0x63, 0x2f, 0x53, 0x74, 0x5f, 0x48, 0x65, 0x6c, 0x65, 0x6e, 0x61, 0x0d, 0x0a, 0x41,
413 0x75, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x69, 0x61, 0x2f, 0x41, 0x43, 0x54, 0x0d, 0x0a, 0x41, 0x75,
414 0x73, 0x74, 0x72, 0x61, 0x6c, 0x69, 0x61, 0x2f, 0x41, 0x64, 0x65, 0x6c, 0x61, 0x69, 0x64, 0x65,
415 0x0d, 0x0a, 0x41, 0x75, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x69, 0x61, 0x2f, 0x42, 0x72, 0x69, 0x73,
416 0x62, 0x61, 0x6e, 0x65, 0x0d, 0x0a, 0x41, 0x75, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x69, 0x61, 0x2f,
417 0x42, 0x72, 0x6f, 0x6b, 0x65, 0x6e, 0x5f, 0x48, 0x69, 0x6c, 0x6c, 0x0d, 0x0a, 0x41, 0x75, 0x73,
418 0x74, 0x72, 0x61, 0x6c, 0x69, 0x61, 0x2f, 0x43, 0x61, 0x6e, 0x62, 0x65, 0x72, 0x72, 0x61, 0x0d,
419 0x0a, 0x41, 0x75, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x69, 0x61, 0x2f, 0x43, 0x75, 0x72, 0x72, 0x69,
420 0x65, 0x0d, 0x0a, 0x41, 0x75, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x69, 0x61, 0x2f, 0x44, 0x61, 0x72,
421 0x77, 0x69, 0x6e, 0x0d, 0x0a, 0x41, 0x75, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x69, 0x61, 0x2f, 0x45,
422 0x75, 0x63, 0x6c, 0x61, 0x0d, 0x0a, 0x41, 0x75, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x69, 0x61, 0x2f,
423 0x48, 0x6f, 0x62, 0x61, 0x72, 0x74, 0x0d, 0x0a, 0x41, 0x75, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x69,
424 0x61, 0x2f, 0x4c, 0x48, 0x49, 0x0d, 0x0a, 0x41, 0x75, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x69, 0x61,
425 0x2f, 0x4c, 0x69, 0x6e, 0x64, 0x65, 0x6d, 0x61, 0x6e, 0x0d, 0x0a, 0x41, 0x75, 0x73, 0x74, 0x72,
426 0x61, 0x6c, 0x69, 0x61, 0x2f, 0x4c, 0x6f, 0x72, 0x64, 0x5f, 0x48, 0x6f, 0x77, 0x65, 0x0d, 0x0a,
427 0x41, 0x75, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x69, 0x61, 0x2f, 0x4d, 0x65, 0x6c, 0x62, 0x6f, 0x75,
428 0x72, 0x6e, 0x65, 0x0d, 0x0a, 0x41, 0x75, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x69, 0x61, 0x2f, 0x4e,
429 0x6f, 0x72, 0x74, 0x68, 0x0d, 0x0a, 0x41, 0x75, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x69, 0x61, 0x2f,
430 0x4e, 0x53, 0x57, 0x0d, 0x0a, 0x41, 0x75, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x69, 0x61, 0x2f, 0x50,
431 0x65, 0x72, 0x74, 0x68, 0x0d, 0x0a, 0x41, 0x75, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x69, 0x61, 0x2f,
432 0x51, 0x75, 0x65, 0x65, 0x6e, 0x73, 0x6c, 0x61, 0x6e, 0x64, 0x0d, 0x0a, 0x41, 0x75, 0x73, 0x74,
433 0x72, 0x61, 0x6c, 0x69, 0x61, 0x2f, 0x53, 0x6f, 0x75, 0x74, 0x68, 0x0d, 0x0a, 0x41, 0x75, 0x73,
434 0x74, 0x72, 0x61, 0x6c, 0x69, 0x61, 0x2f, 0x53, 0x79, 0x64, 0x6e, 0x65, 0x79, 0x0d, 0x0a, 0x41,
435 0x75, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x69, 0x61, 0x2f, 0x54, 0x61, 0x73, 0x6d, 0x61, 0x6e, 0x69,
436 0x61, 0x0d, 0x0a, 0x41, 0x75, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x69, 0x61, 0x2f, 0x56, 0x69, 0x63,
437 0x74, 0x6f, 0x72, 0x69, 0x61, 0x0d, 0x0a, 0x41, 0x75, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x69, 0x61,
438 0x2f, 0x57, 0x65, 0x73, 0x74, 0x0d, 0x0a, 0x41, 0x75, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x69, 0x61,
439 0x2f, 0x59, 0x61, 0x6e, 0x63, 0x6f, 0x77, 0x69, 0x6e, 0x6e, 0x61, 0x0d, 0x0a, 0x42, 0x72, 0x61,
440 0x7a, 0x69, 0x6c, 0x2f, 0x41, 0x63, 0x72, 0x65, 0x0d, 0x0a, 0x42, 0x72, 0x61, 0x7a, 0x69, 0x6c,
441 0x2f, 0x44, 0x65, 0x4e, 0x6f, 0x72, 0x6f, 0x6e, 0x68, 0x61, 0x0d, 0x0a, 0x42, 0x72, 0x61, 0x7a,
442 0x69, 0x6c, 0x2f, 0x45, 0x61, 0x73, 0x74, 0x0d, 0x0a, 0x42, 0x72, 0x61, 0x7a, 0x69, 0x6c, 0x2f,
443 0x57, 0x65, 0x73, 0x74, 0x0d, 0x0a, 0x43, 0x61, 0x6e, 0x61, 0x64, 0x61, 0x2f, 0x41, 0x74, 0x6c,
444 0x61, 0x6e, 0x74, 0x69, 0x63, 0x0d, 0x0a, 0x43, 0x61, 0x6e, 0x61, 0x64, 0x61, 0x2f, 0x43, 0x65,
445 0x6e, 0x74, 0x72, 0x61, 0x6c, 0x0d, 0x0a, 0x43, 0x61, 0x6e, 0x61, 0x64, 0x61, 0x2f, 0x45, 0x61,
446 0x73, 0x74, 0x2d, 0x53, 0x61, 0x73, 0x6b, 0x61, 0x74, 0x63, 0x68, 0x65, 0x77, 0x61, 0x6e, 0x0d,
447 0x0a, 0x43, 0x61, 0x6e, 0x61, 0x64, 0x61, 0x2f, 0x45, 0x61, 0x73, 0x74, 0x65, 0x72, 0x6e, 0x0d,
448 0x0a, 0x43, 0x61, 0x6e, 0x61, 0x64, 0x61, 0x2f, 0x4d, 0x6f, 0x75, 0x6e, 0x74, 0x61, 0x69, 0x6e,
449 0x0d, 0x0a, 0x43, 0x61, 0x6e, 0x61, 0x64, 0x61, 0x2f, 0x4e, 0x65, 0x77, 0x66, 0x6f, 0x75, 0x6e,
450 0x64, 0x6c, 0x61, 0x6e, 0x64, 0x0d, 0x0a, 0x43, 0x61, 0x6e, 0x61, 0x64, 0x61, 0x2f, 0x50, 0x61,
451 0x63, 0x69, 0x66, 0x69, 0x63, 0x0d, 0x0a, 0x43, 0x61, 0x6e, 0x61, 0x64, 0x61, 0x2f, 0x53, 0x61,
452 0x73, 0x6b, 0x61, 0x74, 0x63, 0x68, 0x65, 0x77, 0x61, 0x6e, 0x0d, 0x0a, 0x43, 0x61, 0x6e, 0x61,
453 0x64, 0x61, 0x2f, 0x59, 0x75, 0x6b, 0x6f, 0x6e, 0x0d, 0x0a, 0x43, 0x68, 0x69, 0x6c, 0x65, 0x2f,
454 0x43, 0x6f, 0x6e, 0x74, 0x69, 0x6e, 0x65, 0x6e, 0x74, 0x61, 0x6c, 0x0d, 0x0a, 0x43, 0x68, 0x69,
455 0x6c, 0x65, 0x2f, 0x45, 0x61, 0x73, 0x74, 0x65, 0x72, 0x49, 0x73, 0x6c, 0x61, 0x6e, 0x64, 0x0d,
456 0x0a, 0x45, 0x74, 0x63, 0x2f, 0x47, 0x4d, 0x54, 0x0d, 0x0a, 0x45, 0x74, 0x63, 0x2f, 0x47, 0x4d,
457 0x54, 0x2b, 0x30, 0x0d, 0x0a, 0x45, 0x74, 0x63, 0x2f, 0x47, 0x4d, 0x54, 0x2b, 0x31, 0x0d, 0x0a,
458 0x45, 0x74, 0x63, 0x2f, 0x47, 0x4d, 0x54, 0x2b, 0x31, 0x30, 0x0d, 0x0a, 0x45, 0x74, 0x63, 0x2f,
459 0x47, 0x4d, 0x54, 0x2b, 0x31, 0x31, 0x0d, 0x0a, 0x45, 0x74, 0x63, 0x2f, 0x47, 0x4d, 0x54, 0x2b,
460 0x31, 0x32, 0x0d, 0x0a, 0x45, 0x74, 0x63, 0x2f, 0x47, 0x4d, 0x54, 0x2b, 0x32, 0x0d, 0x0a, 0x45,
461 0x74, 0x63, 0x2f, 0x47, 0x4d, 0x54, 0x2b, 0x33, 0x0d, 0x0a, 0x45, 0x74, 0x63, 0x2f, 0x47, 0x4d,
462 0x54, 0x2b, 0x34, 0x0d, 0x0a, 0x45, 0x74, 0x63, 0x2f, 0x47, 0x4d, 0x54, 0x2b, 0x35, 0x0d, 0x0a,
463 0x45, 0x74, 0x63, 0x2f, 0x47, 0x4d, 0x54, 0x2b, 0x36, 0x0d, 0x0a, 0x45, 0x74, 0x63, 0x2f, 0x47,
464 0x4d, 0x54, 0x2b, 0x37, 0x0d, 0x0a, 0x45, 0x74, 0x63, 0x2f, 0x47, 0x4d, 0x54, 0x2b, 0x38, 0x0d,
465 0x0a, 0x45, 0x74, 0x63, 0x2f, 0x47, 0x4d, 0x54, 0x2b, 0x39, 0x0d, 0x0a, 0x45, 0x74, 0x63, 0x2f,
466 0x47, 0x4d, 0x54, 0x2d, 0x30, 0x0d, 0x0a, 0x45, 0x74, 0x63, 0x2f, 0x47, 0x4d, 0x54, 0x2d, 0x31,
467 0x0d, 0x0a, 0x45, 0x74, 0x63, 0x2f, 0x47, 0x4d, 0x54, 0x2d, 0x31, 0x30, 0x0d, 0x0a, 0x45, 0x74,
468 0x63, 0x2f, 0x47, 0x4d, 0x54, 0x2d, 0x31, 0x31, 0x0d, 0x0a, 0x45, 0x74, 0x63, 0x2f, 0x47, 0x4d,
469 0x54, 0x2d, 0x31, 0x32, 0x0d, 0x0a, 0x45, 0x74, 0x63, 0x2f, 0x47, 0x4d, 0x54, 0x2d, 0x31, 0x33,
470 0x0d, 0x0a, 0x45, 0x74, 0x63, 0x2f, 0x47, 0x4d, 0x54, 0x2d, 0x31, 0x34, 0x0d, 0x0a, 0x45, 0x74,
471 0x63, 0x2f, 0x47, 0x4d, 0x54, 0x2d, 0x32, 0x0d, 0x0a, 0x45, 0x74, 0x63, 0x2f, 0x47, 0x4d, 0x54,
472 0x2d, 0x33, 0x0d, 0x0a, 0x45, 0x74, 0x63, 0x2f, 0x47, 0x4d, 0x54, 0x2d, 0x34, 0x0d, 0x0a, 0x45,
473 0x74, 0x63, 0x2f, 0x47, 0x4d, 0x54, 0x2d, 0x35, 0x0d, 0x0a, 0x45, 0x74, 0x63, 0x2f, 0x47, 0x4d,
474 0x54, 0x2d, 0x36, 0x0d, 0x0a, 0x45, 0x74, 0x63, 0x2f, 0x47, 0x4d, 0x54, 0x2d, 0x37, 0x0d, 0x0a,
475 0x45, 0x74, 0x63, 0x2f, 0x47, 0x4d, 0x54, 0x2d, 0x38, 0x0d, 0x0a, 0x45, 0x74, 0x63, 0x2f, 0x47,
476 0x4d, 0x54, 0x2d, 0x39, 0x0d, 0x0a, 0x45, 0x74, 0x63, 0x2f, 0x47, 0x4d, 0x54, 0x30, 0x0d, 0x0a,
477 0x45, 0x74, 0x63, 0x2f, 0x47, 0x72, 0x65, 0x65, 0x6e, 0x77, 0x69, 0x63, 0x68, 0x0d, 0x0a, 0x45,
478 0x74, 0x63, 0x2f, 0x55, 0x43, 0x54, 0x0d, 0x0a, 0x45, 0x74, 0x63, 0x2f, 0x55, 0x6e, 0x69, 0x76,
479 0x65, 0x72, 0x73, 0x61, 0x6c, 0x0d, 0x0a, 0x45, 0x74, 0x63, 0x2f, 0x55, 0x54, 0x43, 0x0d, 0x0a,
480 0x45, 0x74, 0x63, 0x2f, 0x5a, 0x75, 0x6c, 0x75, 0x0d, 0x0a, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65,
481 0x2f, 0x41, 0x6d, 0x73, 0x74, 0x65, 0x72, 0x64, 0x61, 0x6d, 0x0d, 0x0a, 0x45, 0x75, 0x72, 0x6f,
482 0x70, 0x65, 0x2f, 0x41, 0x6e, 0x64, 0x6f, 0x72, 0x72, 0x61, 0x0d, 0x0a, 0x45, 0x75, 0x72, 0x6f,
483 0x70, 0x65, 0x2f, 0x41, 0x73, 0x74, 0x72, 0x61, 0x6b, 0x68, 0x61, 0x6e, 0x0d, 0x0a, 0x45, 0x75,
484 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x41, 0x74, 0x68, 0x65, 0x6e, 0x73, 0x0d, 0x0a, 0x45, 0x75, 0x72,
485 0x6f, 0x70, 0x65, 0x2f, 0x42, 0x65, 0x6c, 0x66, 0x61, 0x73, 0x74, 0x0d, 0x0a, 0x45, 0x75, 0x72,
486 0x6f, 0x70, 0x65, 0x2f, 0x42, 0x65, 0x6c, 0x67, 0x72, 0x61, 0x64, 0x65, 0x0d, 0x0a, 0x45, 0x75,
487 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x42, 0x65, 0x72, 0x6c, 0x69, 0x6e, 0x0d, 0x0a, 0x45, 0x75, 0x72,
488 0x6f, 0x70, 0x65, 0x2f, 0x42, 0x72, 0x61, 0x74, 0x69, 0x73, 0x6c, 0x61, 0x76, 0x61, 0x0d, 0x0a,
489 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x42, 0x72, 0x75, 0x73, 0x73, 0x65, 0x6c, 0x73, 0x0d,
490 0x0a, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x42, 0x75, 0x63, 0x68, 0x61, 0x72, 0x65, 0x73,
491 0x74, 0x0d, 0x0a, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x42, 0x75, 0x64, 0x61, 0x70, 0x65,
492 0x73, 0x74, 0x0d, 0x0a, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x42, 0x75, 0x73, 0x69, 0x6e,
493 0x67, 0x65, 0x6e, 0x0d, 0x0a, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x43, 0x68, 0x69, 0x73,
494 0x69, 0x6e, 0x61, 0x75, 0x0d, 0x0a, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x43, 0x6f, 0x70,
495 0x65, 0x6e, 0x68, 0x61, 0x67, 0x65, 0x6e, 0x0d, 0x0a, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f,
496 0x44, 0x75, 0x62, 0x6c, 0x69, 0x6e, 0x0d, 0x0a, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x47,
497 0x69, 0x62, 0x72, 0x61, 0x6c, 0x74, 0x61, 0x72, 0x0d, 0x0a, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65,
498 0x2f, 0x47, 0x75, 0x65, 0x72, 0x6e, 0x73, 0x65, 0x79, 0x0d, 0x0a, 0x45, 0x75, 0x72, 0x6f, 0x70,
499 0x65, 0x2f, 0x48, 0x65, 0x6c, 0x73, 0x69, 0x6e, 0x6b, 0x69, 0x0d, 0x0a, 0x45, 0x75, 0x72, 0x6f,
500 0x70, 0x65, 0x2f, 0x49, 0x73, 0x6c, 0x65, 0x5f, 0x6f, 0x66, 0x5f, 0x4d, 0x61, 0x6e, 0x0d, 0x0a,
501 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x49, 0x73, 0x74, 0x61, 0x6e, 0x62, 0x75, 0x6c, 0x0d,
502 0x0a, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x4a, 0x65, 0x72, 0x73, 0x65, 0x79, 0x0d, 0x0a,
503 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x4b, 0x61, 0x6c, 0x69, 0x6e, 0x69, 0x6e, 0x67, 0x72,
504 0x61, 0x64, 0x0d, 0x0a, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x4b, 0x69, 0x65, 0x76, 0x0d,
505 0x0a, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x4b, 0x69, 0x72, 0x6f, 0x76, 0x0d, 0x0a, 0x45,
506 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x4c, 0x69, 0x73, 0x62, 0x6f, 0x6e, 0x0d, 0x0a, 0x45, 0x75,
507 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x4c, 0x6a, 0x75, 0x62, 0x6c, 0x6a, 0x61, 0x6e, 0x61, 0x0d, 0x0a,
508 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x4c, 0x6f, 0x6e, 0x64, 0x6f, 0x6e, 0x0d, 0x0a, 0x45,
509 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x4c, 0x75, 0x78, 0x65, 0x6d, 0x62, 0x6f, 0x75, 0x72, 0x67,
510 0x0d, 0x0a, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x4d, 0x61, 0x64, 0x72, 0x69, 0x64, 0x0d,
511 0x0a, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x4d, 0x61, 0x6c, 0x74, 0x61, 0x0d, 0x0a, 0x45,
512 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x4d, 0x61, 0x72, 0x69, 0x65, 0x68, 0x61, 0x6d, 0x6e, 0x0d,
513 0x0a, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x4d, 0x69, 0x6e, 0x73, 0x6b, 0x0d, 0x0a, 0x45,
514 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x4d, 0x6f, 0x6e, 0x61, 0x63, 0x6f, 0x0d, 0x0a, 0x45, 0x75,
515 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x4d, 0x6f, 0x73, 0x63, 0x6f, 0x77, 0x0d, 0x0a, 0x45, 0x75, 0x72,
516 0x6f, 0x70, 0x65, 0x2f, 0x4e, 0x69, 0x63, 0x6f, 0x73, 0x69, 0x61, 0x0d, 0x0a, 0x45, 0x75, 0x72,
517 0x6f, 0x70, 0x65, 0x2f, 0x4f, 0x73, 0x6c, 0x6f, 0x0d, 0x0a, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65,
518 0x2f, 0x50, 0x61, 0x72, 0x69, 0x73, 0x0d, 0x0a, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x50,
519 0x6f, 0x64, 0x67, 0x6f, 0x72, 0x69, 0x63, 0x61, 0x0d, 0x0a, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65,
520 0x2f, 0x50, 0x72, 0x61, 0x67, 0x75, 0x65, 0x0d, 0x0a, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f,
521 0x52, 0x69, 0x67, 0x61, 0x0d, 0x0a, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x52, 0x6f, 0x6d,
522 0x65, 0x0d, 0x0a, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x53, 0x61, 0x6d, 0x61, 0x72, 0x61,
523 0x0d, 0x0a, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x53, 0x61, 0x6e, 0x5f, 0x4d, 0x61, 0x72,
524 0x69, 0x6e, 0x6f, 0x0d, 0x0a, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x53, 0x61, 0x72, 0x61,
525 0x6a, 0x65, 0x76, 0x6f, 0x0d, 0x0a, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x53, 0x61, 0x72,
526 0x61, 0x74, 0x6f, 0x76, 0x0d, 0x0a, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x53, 0x69, 0x6d,
527 0x66, 0x65, 0x72, 0x6f, 0x70, 0x6f, 0x6c, 0x0d, 0x0a, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f,
528 0x53, 0x6b, 0x6f, 0x70, 0x6a, 0x65, 0x0d, 0x0a, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x53,
529 0x6f, 0x66, 0x69, 0x61, 0x0d, 0x0a, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x53, 0x74, 0x6f,
530 0x63, 0x6b, 0x68, 0x6f, 0x6c, 0x6d, 0x0d, 0x0a, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x54,
531 0x61, 0x6c, 0x6c, 0x69, 0x6e, 0x6e, 0x0d, 0x0a, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x54,
532 0x69, 0x72, 0x61, 0x6e, 0x65, 0x0d, 0x0a, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x54, 0x69,
533 0x72, 0x61, 0x73, 0x70, 0x6f, 0x6c, 0x0d, 0x0a, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x55,
534 0x6c, 0x79, 0x61, 0x6e, 0x6f, 0x76, 0x73, 0x6b, 0x0d, 0x0a, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65,
535 0x2f, 0x55, 0x7a, 0x68, 0x67, 0x6f, 0x72, 0x6f, 0x64, 0x0d, 0x0a, 0x45, 0x75, 0x72, 0x6f, 0x70,
536 0x65, 0x2f, 0x56, 0x61, 0x64, 0x75, 0x7a, 0x0d, 0x0a, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f,
537 0x56, 0x61, 0x74, 0x69, 0x63, 0x61, 0x6e, 0x0d, 0x0a, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f,
538 0x56, 0x69, 0x65, 0x6e, 0x6e, 0x61, 0x0d, 0x0a, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x56,
539 0x69, 0x6c, 0x6e, 0x69, 0x75, 0x73, 0x0d, 0x0a, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x56,
540 0x6f, 0x6c, 0x67, 0x6f, 0x67, 0x72, 0x61, 0x64, 0x0d, 0x0a, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65,
541 0x2f, 0x57, 0x61, 0x72, 0x73, 0x61, 0x77, 0x0d, 0x0a, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f,
542 0x5a, 0x61, 0x67, 0x72, 0x65, 0x62, 0x0d, 0x0a, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x5a,
543 0x61, 0x70, 0x6f, 0x72, 0x6f, 0x7a, 0x68, 0x79, 0x65, 0x0d, 0x0a, 0x45, 0x75, 0x72, 0x6f, 0x70,
544 0x65, 0x2f, 0x5a, 0x75, 0x72, 0x69, 0x63, 0x68, 0x0d, 0x0a, 0x49, 0x6e, 0x64, 0x69, 0x61, 0x6e,
545 0x2f, 0x41, 0x6e, 0x74, 0x61, 0x6e, 0x61, 0x6e, 0x61, 0x72, 0x69, 0x76, 0x6f, 0x0d, 0x0a, 0x49,
546 0x6e, 0x64, 0x69, 0x61, 0x6e, 0x2f, 0x43, 0x68, 0x61, 0x67, 0x6f, 0x73, 0x0d, 0x0a, 0x49, 0x6e,
547 0x64, 0x69, 0x61, 0x6e, 0x2f, 0x43, 0x68, 0x72, 0x69, 0x73, 0x74, 0x6d, 0x61, 0x73, 0x0d, 0x0a,
548 0x49, 0x6e, 0x64, 0x69, 0x61, 0x6e, 0x2f, 0x43, 0x6f, 0x63, 0x6f, 0x73, 0x0d, 0x0a, 0x49, 0x6e,
549 0x64, 0x69, 0x61, 0x6e, 0x2f, 0x43, 0x6f, 0x6d, 0x6f, 0x72, 0x6f, 0x0d, 0x0a, 0x49, 0x6e, 0x64,
550 0x69, 0x61, 0x6e, 0x2f, 0x4b, 0x65, 0x72, 0x67, 0x75, 0x65, 0x6c, 0x65, 0x6e, 0x0d, 0x0a, 0x49,
551 0x6e, 0x64, 0x69, 0x61, 0x6e, 0x2f, 0x4d, 0x61, 0x68, 0x65, 0x0d, 0x0a, 0x49, 0x6e, 0x64, 0x69,
552 0x61, 0x6e, 0x2f, 0x4d, 0x61, 0x6c, 0x64, 0x69, 0x76, 0x65, 0x73, 0x0d, 0x0a, 0x49, 0x6e, 0x64,
553 0x69, 0x61, 0x6e, 0x2f, 0x4d, 0x61, 0x75, 0x72, 0x69, 0x74, 0x69, 0x75, 0x73, 0x0d, 0x0a, 0x49,
554 0x6e, 0x64, 0x69, 0x61, 0x6e, 0x2f, 0x4d, 0x61, 0x79, 0x6f, 0x74, 0x74, 0x65, 0x0d, 0x0a, 0x49,
555 0x6e, 0x64, 0x69, 0x61, 0x6e, 0x2f, 0x52, 0x65, 0x75, 0x6e, 0x69, 0x6f, 0x6e, 0x0d, 0x0a, 0x4d,
556 0x65, 0x78, 0x69, 0x63, 0x6f, 0x2f, 0x42, 0x61, 0x6a, 0x61, 0x4e, 0x6f, 0x72, 0x74, 0x65, 0x0d,
557 0x0a, 0x4d, 0x65, 0x78, 0x69, 0x63, 0x6f, 0x2f, 0x42, 0x61, 0x6a, 0x61, 0x53, 0x75, 0x72, 0x0d,
558 0x0a, 0x4d, 0x65, 0x78, 0x69, 0x63, 0x6f, 0x2f, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x6c, 0x0d,
559 0x0a, 0x50, 0x61, 0x63, 0x69, 0x66, 0x69, 0x63, 0x2f, 0x41, 0x70, 0x69, 0x61, 0x0d, 0x0a, 0x50,
560 0x61, 0x63, 0x69, 0x66, 0x69, 0x63, 0x2f, 0x41, 0x75, 0x63, 0x6b, 0x6c, 0x61, 0x6e, 0x64, 0x0d,
561 0x0a, 0x50, 0x61, 0x63, 0x69, 0x66, 0x69, 0x63, 0x2f, 0x42, 0x6f, 0x75, 0x67, 0x61, 0x69, 0x6e,
562 0x76, 0x69, 0x6c, 0x6c, 0x65, 0x0d, 0x0a, 0x50, 0x61, 0x63, 0x69, 0x66, 0x69, 0x63, 0x2f, 0x43,
563 0x68, 0x61, 0x74, 0x68, 0x61, 0x6d, 0x0d, 0x0a, 0x50, 0x61, 0x63, 0x69, 0x66, 0x69, 0x63, 0x2f,
564 0x43, 0x68, 0x75, 0x75, 0x6b, 0x0d, 0x0a, 0x50, 0x61, 0x63, 0x69, 0x66, 0x69, 0x63, 0x2f, 0x45,
565 0x61, 0x73, 0x74, 0x65, 0x72, 0x0d, 0x0a, 0x50, 0x61, 0x63, 0x69, 0x66, 0x69, 0x63, 0x2f, 0x45,
566 0x66, 0x61, 0x74, 0x65, 0x0d, 0x0a, 0x50, 0x61, 0x63, 0x69, 0x66, 0x69, 0x63, 0x2f, 0x45, 0x6e,
567 0x64, 0x65, 0x72, 0x62, 0x75, 0x72, 0x79, 0x0d, 0x0a, 0x50, 0x61, 0x63, 0x69, 0x66, 0x69, 0x63,
568 0x2f, 0x46, 0x61, 0x6b, 0x61, 0x6f, 0x66, 0x6f, 0x0d, 0x0a, 0x50, 0x61, 0x63, 0x69, 0x66, 0x69,
569 0x63, 0x2f, 0x46, 0x69, 0x6a, 0x69, 0x0d, 0x0a, 0x50, 0x61, 0x63, 0x69, 0x66, 0x69, 0x63, 0x2f,
570 0x46, 0x75, 0x6e, 0x61, 0x66, 0x75, 0x74, 0x69, 0x0d, 0x0a, 0x50, 0x61, 0x63, 0x69, 0x66, 0x69,
571 0x63, 0x2f, 0x47, 0x61, 0x6c, 0x61, 0x70, 0x61, 0x67, 0x6f, 0x73, 0x0d, 0x0a, 0x50, 0x61, 0x63,
572 0x69, 0x66, 0x69, 0x63, 0x2f, 0x47, 0x61, 0x6d, 0x62, 0x69, 0x65, 0x72, 0x0d, 0x0a, 0x50, 0x61,
573 0x63, 0x69, 0x66, 0x69, 0x63, 0x2f, 0x47, 0x75, 0x61, 0x64, 0x61, 0x6c, 0x63, 0x61, 0x6e, 0x61,
574 0x6c, 0x0d, 0x0a, 0x50, 0x61, 0x63, 0x69, 0x66, 0x69, 0x63, 0x2f, 0x47, 0x75, 0x61, 0x6d, 0x0d,
575 0x0a, 0x50, 0x61, 0x63, 0x69, 0x66, 0x69, 0x63, 0x2f, 0x48, 0x6f, 0x6e, 0x6f, 0x6c, 0x75, 0x6c,
576 0x75, 0x0d, 0x0a, 0x50, 0x61, 0x63, 0x69, 0x66, 0x69, 0x63, 0x2f, 0x4a, 0x6f, 0x68, 0x6e, 0x73,
577 0x74, 0x6f, 0x6e, 0x0d, 0x0a, 0x50, 0x61, 0x63, 0x69, 0x66, 0x69, 0x63, 0x2f, 0x4b, 0x69, 0x72,
578 0x69, 0x74, 0x69, 0x6d, 0x61, 0x74, 0x69, 0x0d, 0x0a, 0x50, 0x61, 0x63, 0x69, 0x66, 0x69, 0x63,
579 0x2f, 0x4b, 0x6f, 0x73, 0x72, 0x61, 0x65, 0x0d, 0x0a, 0x50, 0x61, 0x63, 0x69, 0x66, 0x69, 0x63,
580 0x2f, 0x4b, 0x77, 0x61, 0x6a, 0x61, 0x6c, 0x65, 0x69, 0x6e, 0x0d, 0x0a, 0x50, 0x61, 0x63, 0x69,
581 0x66, 0x69, 0x63, 0x2f, 0x4d, 0x61, 0x6a, 0x75, 0x72, 0x6f, 0x0d, 0x0a, 0x50, 0x61, 0x63, 0x69,
582 0x66, 0x69, 0x63, 0x2f, 0x4d, 0x61, 0x72, 0x71, 0x75, 0x65, 0x73, 0x61, 0x73, 0x0d, 0x0a, 0x50,
583 0x61, 0x63, 0x69, 0x66, 0x69, 0x63, 0x2f, 0x4d, 0x69, 0x64, 0x77, 0x61, 0x79, 0x0d, 0x0a, 0x50,
584 0x61, 0x63, 0x69, 0x66, 0x69, 0x63, 0x2f, 0x4e, 0x61, 0x75, 0x72, 0x75, 0x0d, 0x0a, 0x50, 0x61,
585 0x63, 0x69, 0x66, 0x69, 0x63, 0x2f, 0x4e, 0x69, 0x75, 0x65, 0x0d, 0x0a, 0x50, 0x61, 0x63, 0x69,
586 0x66, 0x69, 0x63, 0x2f, 0x4e, 0x6f, 0x72, 0x66, 0x6f, 0x6c, 0x6b, 0x0d, 0x0a, 0x50, 0x61, 0x63,
587 0x69, 0x66, 0x69, 0x63, 0x2f, 0x4e, 0x6f, 0x75, 0x6d, 0x65, 0x61, 0x0d, 0x0a, 0x50, 0x61, 0x63,
588 0x69, 0x66, 0x69, 0x63, 0x2f, 0x50, 0x61, 0x67, 0x6f, 0x5f, 0x50, 0x61, 0x67, 0x6f, 0x0d, 0x0a,
589 0x50, 0x61, 0x63, 0x69, 0x66, 0x69, 0x63, 0x2f, 0x50, 0x61, 0x6c, 0x61, 0x75, 0x0d, 0x0a, 0x50,
590 0x61, 0x63, 0x69, 0x66, 0x69, 0x63, 0x2f, 0x50, 0x69, 0x74, 0x63, 0x61, 0x69, 0x72, 0x6e, 0x0d,
591 0x0a, 0x50, 0x61, 0x63, 0x69, 0x66, 0x69, 0x63, 0x2f, 0x50, 0x6f, 0x68, 0x6e, 0x70, 0x65, 0x69,
592 0x0d, 0x0a, 0x50, 0x61, 0x63, 0x69, 0x66, 0x69, 0x63, 0x2f, 0x50, 0x6f, 0x6e, 0x61, 0x70, 0x65,
593 0x0d, 0x0a, 0x50, 0x61, 0x63, 0x69, 0x66, 0x69, 0x63, 0x2f, 0x50, 0x6f, 0x72, 0x74, 0x5f, 0x4d,
594 0x6f, 0x72, 0x65, 0x73, 0x62, 0x79, 0x0d, 0x0a, 0x50, 0x61, 0x63, 0x69, 0x66, 0x69, 0x63, 0x2f,
595 0x52, 0x61, 0x72, 0x6f, 0x74, 0x6f, 0x6e, 0x67, 0x61, 0x0d, 0x0a, 0x50, 0x61, 0x63, 0x69, 0x66,
596 0x69, 0x63, 0x2f, 0x53, 0x61, 0x69, 0x70, 0x61, 0x6e, 0x0d, 0x0a, 0x50, 0x61, 0x63, 0x69, 0x66,
597 0x69, 0x63, 0x2f, 0x53, 0x61, 0x6d, 0x6f, 0x61, 0x0d, 0x0a, 0x50, 0x61, 0x63, 0x69, 0x66, 0x69,
598 0x63, 0x2f, 0x54, 0x61, 0x68, 0x69, 0x74, 0x69, 0x0d, 0x0a, 0x50, 0x61, 0x63, 0x69, 0x66, 0x69,
599 0x63, 0x2f, 0x54, 0x61, 0x72, 0x61, 0x77, 0x61, 0x0d, 0x0a, 0x50, 0x61, 0x63, 0x69, 0x66, 0x69,
600 0x63, 0x2f, 0x54, 0x6f, 0x6e, 0x67, 0x61, 0x74, 0x61, 0x70, 0x75, 0x0d, 0x0a, 0x50, 0x61, 0x63,
601 0x69, 0x66, 0x69, 0x63, 0x2f, 0x54, 0x72, 0x75, 0x6b, 0x0d, 0x0a, 0x50, 0x61, 0x63, 0x69, 0x66,
602 0x69, 0x63, 0x2f, 0x57, 0x61, 0x6b, 0x65, 0x0d, 0x0a, 0x50, 0x61, 0x63, 0x69, 0x66, 0x69, 0x63,
603 0x2f, 0x57, 0x61, 0x6c, 0x6c, 0x69, 0x73, 0x0d, 0x0a, 0x50, 0x61, 0x63, 0x69, 0x66, 0x69, 0x63,
604 0x2f, 0x59, 0x61, 0x70, 0x0d, 0x0a, 0x55, 0x53, 0x2f, 0x41, 0x6c, 0x61, 0x73, 0x6b, 0x61, 0x0d,
605 0x0a, 0x55, 0x53, 0x2f, 0x41, 0x6c, 0x65, 0x75, 0x74, 0x69, 0x61, 0x6e, 0x0d, 0x0a, 0x55, 0x53,
606 0x2f, 0x41, 0x72, 0x69, 0x7a, 0x6f, 0x6e, 0x61, 0x0d, 0x0a, 0x55, 0x53, 0x2f, 0x43, 0x65, 0x6e,
607 0x74, 0x72, 0x61, 0x6c, 0x0d, 0x0a, 0x55, 0x53, 0x2f, 0x45, 0x61, 0x73, 0x74, 0x2d, 0x49, 0x6e,
608 0x64, 0x69, 0x61, 0x6e, 0x61, 0x0d, 0x0a, 0x55, 0x53, 0x2f, 0x45, 0x61, 0x73, 0x74, 0x65, 0x72,
609 0x6e, 0x0d, 0x0a, 0x55, 0x53, 0x2f, 0x48, 0x61, 0x77, 0x61, 0x69, 0x69, 0x0d, 0x0a, 0x55, 0x53,
610 0x2f, 0x49, 0x6e, 0x64, 0x69, 0x61, 0x6e, 0x61, 0x2d, 0x53, 0x74, 0x61, 0x72, 0x6b, 0x65, 0x0d,
611 0x0a, 0x55, 0x53, 0x2f, 0x4d, 0x69, 0x63, 0x68, 0x69, 0x67, 0x61, 0x6e, 0x0d, 0x0a, 0x55, 0x53,
612 0x2f, 0x4d, 0x6f, 0x75, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x0d, 0x0a, 0x55, 0x53, 0x2f, 0x50, 0x61,
613 0x63, 0x69, 0x66, 0x69, 0x63, 0x0d, 0x0a, 0x55, 0x53, 0x2f, 0x50, 0x61, 0x63, 0x69, 0x66, 0x69,
614 0x63, 0x2d, 0x4e, 0x65, 0x77, 0x0d, 0x0a, 0x55, 0x53, 0x2f, 0x53, 0x61, 0x6d, 0x6f, 0x61, 0x0d,
615 0x0a};
616
617static VirtualFile GenerateDefaultTimeZoneFile() {
618 struct {
619 s64_be at;
620 INSERT_PADDING_BYTES(7);
621 std::array<char, 4> time_zone_chars;
622 INSERT_PADDING_BYTES(2);
623 std::array<char, 6> time_zone_name;
624 } time_zone_info{};
625
626 const VirtualFile file{std::make_shared<VectorVfsFile>(
627 std::vector<u8>(sizeof(Service::Time::TimeZone::TzifHeader) + sizeof(time_zone_info)),
628 "GMT")};
629
630 Service::Time::TimeZone::TzifHeader header{};
631 header.magic = 0x545a6966;
632 header.version = 0x32;
633 header.ttis_gmt_count = 0x1;
634 header.ttis_std_count = 0x1;
635 header.time_count = 0x1;
636 header.type_count = 0x1;
637 header.char_count = 0x4;
638 file->WriteObject(header, 0);
639
640 time_zone_info.at = 0xf8;
641 time_zone_info.time_zone_chars = {'G', 'M', 'T', '\0'};
642 time_zone_info.time_zone_name = {'\n', 'G', 'M', 'T', '0', '\n'};
643 file->WriteObject(time_zone_info, sizeof(Service::Time::TimeZone::TzifHeader));
644
645 return file;
646}
647
648VirtualDir TimeZoneBinary() {
649 const std::vector<VirtualDir> root_dirs{std::make_shared<VectorVfsDirectory>(
650 std::vector<VirtualFile>{GenerateDefaultTimeZoneFile()}, std::vector<VirtualDir>{},
651 "zoneinfo")};
652 const std::vector<VirtualFile> root_files{
653 std::make_shared<ArrayVfsFile<LOCATION_NAMES.size()>>(LOCATION_NAMES, "binaryList.txt")};
654 return std::make_shared<VectorVfsDirectory>(root_files, root_dirs, "data");
655}
656
657} // namespace FileSys::SystemArchive
diff --git a/src/core/file_sys/system_archive/time_zone_binary.h b/src/core/file_sys/system_archive/time_zone_binary.h
new file mode 100644
index 000000000..ed2b78227
--- /dev/null
+++ b/src/core/file_sys/system_archive/time_zone_binary.h
@@ -0,0 +1,14 @@
1// Copyright 2019 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 <string>
8#include "core/file_sys/vfs_types.h"
9
10namespace FileSys::SystemArchive {
11
12VirtualDir TimeZoneBinary();
13
14} // namespace FileSys::SystemArchive
diff --git a/src/core/hle/kernel/physical_memory.h b/src/core/hle/kernel/physical_memory.h
index 090565310..b689e8e8b 100644
--- a/src/core/hle/kernel/physical_memory.h
+++ b/src/core/hle/kernel/physical_memory.h
@@ -14,6 +14,9 @@ namespace Kernel {
14// - Second to ensure all host backing memory used is aligned to 256 bytes due 14// - Second to ensure all host backing memory used is aligned to 256 bytes due
15// to strict alignment restrictions on GPU memory. 15// to strict alignment restrictions on GPU memory.
16 16
17using PhysicalMemory = std::vector<u8, Common::AlignmentAllocator<u8, 256>>; 17using PhysicalMemoryVector = std::vector<u8, Common::AlignmentAllocator<u8, 256>>;
18class PhysicalMemory final : public PhysicalMemoryVector {
19 using PhysicalMemoryVector::PhysicalMemoryVector;
20};
18 21
19} // namespace Kernel 22} // namespace Kernel
diff --git a/src/core/hle/kernel/vm_manager.cpp b/src/core/hle/kernel/vm_manager.cpp
index a9a20ef76..0b3500fce 100644
--- a/src/core/hle/kernel/vm_manager.cpp
+++ b/src/core/hle/kernel/vm_manager.cpp
@@ -3,6 +3,7 @@
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <algorithm> 5#include <algorithm>
6#include <cstring>
6#include <iterator> 7#include <iterator>
7#include <utility> 8#include <utility>
8#include "common/alignment.h" 9#include "common/alignment.h"
@@ -269,18 +270,9 @@ ResultVal<VAddr> VMManager::SetHeapSize(u64 size) {
269 // If necessary, expand backing vector to cover new heap extents in 270 // If necessary, expand backing vector to cover new heap extents in
270 // the case of allocating. Otherwise, shrink the backing memory, 271 // the case of allocating. Otherwise, shrink the backing memory,
271 // if a smaller heap has been requested. 272 // if a smaller heap has been requested.
272 const u64 old_heap_size = GetCurrentHeapSize(); 273 heap_memory->resize(size);
273 if (size > old_heap_size) { 274 heap_memory->shrink_to_fit();
274 const u64 alloc_size = size - old_heap_size; 275 RefreshMemoryBlockMappings(heap_memory.get());
275
276 heap_memory->insert(heap_memory->end(), alloc_size, 0);
277 RefreshMemoryBlockMappings(heap_memory.get());
278 } else if (size < old_heap_size) {
279 heap_memory->resize(size);
280 heap_memory->shrink_to_fit();
281
282 RefreshMemoryBlockMappings(heap_memory.get());
283 }
284 276
285 heap_end = heap_region_base + size; 277 heap_end = heap_region_base + size;
286 ASSERT(GetCurrentHeapSize() == heap_memory->size()); 278 ASSERT(GetCurrentHeapSize() == heap_memory->size());
@@ -752,24 +744,20 @@ void VMManager::MergeAdjacentVMA(VirtualMemoryArea& left, const VirtualMemoryAre
752 // Always merge allocated memory blocks, even when they don't share the same backing block. 744 // Always merge allocated memory blocks, even when they don't share the same backing block.
753 if (left.type == VMAType::AllocatedMemoryBlock && 745 if (left.type == VMAType::AllocatedMemoryBlock &&
754 (left.backing_block != right.backing_block || left.offset + left.size != right.offset)) { 746 (left.backing_block != right.backing_block || left.offset + left.size != right.offset)) {
755 const auto right_begin = right.backing_block->begin() + right.offset;
756 const auto right_end = right_begin + right.size;
757 747
758 // Check if we can save work. 748 // Check if we can save work.
759 if (left.offset == 0 && left.size == left.backing_block->size()) { 749 if (left.offset == 0 && left.size == left.backing_block->size()) {
760 // Fast case: left is an entire backing block. 750 // Fast case: left is an entire backing block.
761 left.backing_block->insert(left.backing_block->end(), right_begin, right_end); 751 left.backing_block->resize(left.size + right.size);
752 std::memcpy(left.backing_block->data() + left.size,
753 right.backing_block->data() + right.offset, right.size);
762 } else { 754 } else {
763 // Slow case: make a new memory block for left and right. 755 // Slow case: make a new memory block for left and right.
764 const auto left_begin = left.backing_block->begin() + left.offset;
765 const auto left_end = left_begin + left.size;
766 const auto left_size = static_cast<std::size_t>(std::distance(left_begin, left_end));
767 const auto right_size = static_cast<std::size_t>(std::distance(right_begin, right_end));
768
769 auto new_memory = std::make_shared<PhysicalMemory>(); 756 auto new_memory = std::make_shared<PhysicalMemory>();
770 new_memory->reserve(left_size + right_size); 757 new_memory->resize(left.size + right.size);
771 new_memory->insert(new_memory->end(), left_begin, left_end); 758 std::memcpy(new_memory->data(), left.backing_block->data() + left.offset, left.size);
772 new_memory->insert(new_memory->end(), right_begin, right_end); 759 std::memcpy(new_memory->data() + left.size, right.backing_block->data() + right.offset,
760 right.size);
773 761
774 left.backing_block = std::move(new_memory); 762 left.backing_block = std::move(new_memory);
775 left.offset = 0; 763 left.offset = 0;
@@ -792,8 +780,7 @@ void VMManager::UpdatePageTableForVMA(const VirtualMemoryArea& vma) {
792 memory.UnmapRegion(page_table, vma.base, vma.size); 780 memory.UnmapRegion(page_table, vma.base, vma.size);
793 break; 781 break;
794 case VMAType::AllocatedMemoryBlock: 782 case VMAType::AllocatedMemoryBlock:
795 memory.MapMemoryRegion(page_table, vma.base, vma.size, 783 memory.MapMemoryRegion(page_table, vma.base, vma.size, *vma.backing_block, vma.offset);
796 vma.backing_block->data() + vma.offset);
797 break; 784 break;
798 case VMAType::BackingMemory: 785 case VMAType::BackingMemory:
799 memory.MapMemoryRegion(page_table, vma.base, vma.size, vma.backing_memory); 786 memory.MapMemoryRegion(page_table, vma.base, vma.size, vma.backing_memory);
diff --git a/src/core/hle/service/acc/acc.cpp b/src/core/hle/service/acc/acc.cpp
index 7e3e311fb..cfac8ca9a 100644
--- a/src/core/hle/service/acc/acc.cpp
+++ b/src/core/hle/service/acc/acc.cpp
@@ -211,7 +211,7 @@ protected:
211 } 211 }
212 212
213 ProfileManager& profile_manager; 213 ProfileManager& profile_manager;
214 Common::UUID user_id; ///< The user id this profile refers to. 214 Common::UUID user_id{Common::INVALID_UUID}; ///< The user id this profile refers to.
215}; 215};
216 216
217class IProfile final : public IProfileCommon { 217class IProfile final : public IProfileCommon {
diff --git a/src/core/hle/service/acc/profile_manager.cpp b/src/core/hle/service/acc/profile_manager.cpp
index 3e756e59e..eb8c81645 100644
--- a/src/core/hle/service/acc/profile_manager.cpp
+++ b/src/core/hle/service/acc/profile_manager.cpp
@@ -16,17 +16,17 @@ namespace Service::Account {
16using Common::UUID; 16using Common::UUID;
17 17
18struct UserRaw { 18struct UserRaw {
19 UUID uuid; 19 UUID uuid{Common::INVALID_UUID};
20 UUID uuid2; 20 UUID uuid2{Common::INVALID_UUID};
21 u64 timestamp; 21 u64 timestamp{};
22 ProfileUsername username; 22 ProfileUsername username{};
23 ProfileData extra_data; 23 ProfileData extra_data{};
24}; 24};
25static_assert(sizeof(UserRaw) == 0xC8, "UserRaw has incorrect size."); 25static_assert(sizeof(UserRaw) == 0xC8, "UserRaw has incorrect size.");
26 26
27struct ProfileDataRaw { 27struct ProfileDataRaw {
28 INSERT_PADDING_BYTES(0x10); 28 INSERT_PADDING_BYTES(0x10);
29 std::array<UserRaw, MAX_USERS> users; 29 std::array<UserRaw, MAX_USERS> users{};
30}; 30};
31static_assert(sizeof(ProfileDataRaw) == 0x650, "ProfileDataRaw has incorrect size."); 31static_assert(sizeof(ProfileDataRaw) == 0x650, "ProfileDataRaw has incorrect size.");
32 32
@@ -238,7 +238,7 @@ UserIDArray ProfileManager::GetOpenUsers() const {
238 std::transform(profiles.begin(), profiles.end(), output.begin(), [](const ProfileInfo& p) { 238 std::transform(profiles.begin(), profiles.end(), output.begin(), [](const ProfileInfo& p) {
239 if (p.is_open) 239 if (p.is_open)
240 return p.user_uuid; 240 return p.user_uuid;
241 return UUID{}; 241 return UUID{Common::INVALID_UUID};
242 }); 242 });
243 std::stable_partition(output.begin(), output.end(), [](const UUID& uuid) { return uuid; }); 243 std::stable_partition(output.begin(), output.end(), [](const UUID& uuid) { return uuid; });
244 return output; 244 return output;
diff --git a/src/core/hle/service/acc/profile_manager.h b/src/core/hle/service/acc/profile_manager.h
index 5a6d28925..5310637a6 100644
--- a/src/core/hle/service/acc/profile_manager.h
+++ b/src/core/hle/service/acc/profile_manager.h
@@ -13,9 +13,10 @@
13#include "core/hle/result.h" 13#include "core/hle/result.h"
14 14
15namespace Service::Account { 15namespace Service::Account {
16constexpr std::size_t MAX_USERS = 8;
17 16
18constexpr std::size_t profile_username_size = 32; 17constexpr std::size_t MAX_USERS{8};
18constexpr std::size_t profile_username_size{32};
19
19using ProfileUsername = std::array<u8, profile_username_size>; 20using ProfileUsername = std::array<u8, profile_username_size>;
20using UserIDArray = std::array<Common::UUID, MAX_USERS>; 21using UserIDArray = std::array<Common::UUID, MAX_USERS>;
21 22
@@ -23,8 +24,8 @@ using UserIDArray = std::array<Common::UUID, MAX_USERS>;
23/// TODO: RE this structure 24/// TODO: RE this structure
24struct ProfileData { 25struct ProfileData {
25 INSERT_PADDING_WORDS(1); 26 INSERT_PADDING_WORDS(1);
26 u32 icon_id; 27 u32 icon_id{};
27 u8 bg_color_id; 28 u8 bg_color_id{};
28 INSERT_PADDING_BYTES(0x7); 29 INSERT_PADDING_BYTES(0x7);
29 INSERT_PADDING_BYTES(0x10); 30 INSERT_PADDING_BYTES(0x10);
30 INSERT_PADDING_BYTES(0x60); 31 INSERT_PADDING_BYTES(0x60);
@@ -34,17 +35,17 @@ static_assert(sizeof(ProfileData) == 0x80, "ProfileData structure has incorrect
34/// This holds general information about a users profile. This is where we store all the information 35/// This holds general information about a users profile. This is where we store all the information
35/// based on a specific user 36/// based on a specific user
36struct ProfileInfo { 37struct ProfileInfo {
37 Common::UUID user_uuid; 38 Common::UUID user_uuid{Common::INVALID_UUID};
38 ProfileUsername username; 39 ProfileUsername username{};
39 u64 creation_time; 40 u64 creation_time{};
40 ProfileData data; // TODO(ognik): Work out what this is 41 ProfileData data{}; // TODO(ognik): Work out what this is
41 bool is_open; 42 bool is_open{};
42}; 43};
43 44
44struct ProfileBase { 45struct ProfileBase {
45 Common::UUID user_uuid; 46 Common::UUID user_uuid{Common::INVALID_UUID};
46 u64_le timestamp; 47 u64_le timestamp{};
47 ProfileUsername username; 48 ProfileUsername username{};
48 49
49 // Zero out all the fields to make the profile slot considered "Empty" 50 // Zero out all the fields to make the profile slot considered "Empty"
50 void Invalidate() { 51 void Invalidate() {
@@ -101,7 +102,7 @@ private:
101 bool RemoveProfileAtIndex(std::size_t index); 102 bool RemoveProfileAtIndex(std::size_t index);
102 103
103 std::array<ProfileInfo, MAX_USERS> profiles{}; 104 std::array<ProfileInfo, MAX_USERS> profiles{};
104 std::size_t user_count = 0; 105 std::size_t user_count{};
105 Common::UUID last_opened_user{Common::INVALID_UUID}; 106 Common::UUID last_opened_user{Common::INVALID_UUID};
106}; 107};
107 108
diff --git a/src/core/hle/service/friend/friend.cpp b/src/core/hle/service/friend/friend.cpp
index 219176c31..6aadb3ea8 100644
--- a/src/core/hle/service/friend/friend.cpp
+++ b/src/core/hle/service/friend/friend.cpp
@@ -241,7 +241,7 @@ private:
241 bool has_received_friend_request; 241 bool has_received_friend_request;
242 }; 242 };
243 243
244 Common::UUID uuid; 244 Common::UUID uuid{Common::INVALID_UUID};
245 Kernel::EventPair notification_event; 245 Kernel::EventPair notification_event;
246 std::queue<SizedNotificationInfo> notifications; 246 std::queue<SizedNotificationInfo> notifications;
247 States states{}; 247 States states{};
diff --git a/src/core/hle/service/mii/mii_manager.h b/src/core/hle/service/mii/mii_manager.h
index 38ad78a0d..fc742816a 100644
--- a/src/core/hle/service/mii/mii_manager.h
+++ b/src/core/hle/service/mii/mii_manager.h
@@ -10,13 +10,13 @@
10 10
11namespace Service::Mii { 11namespace Service::Mii {
12 12
13constexpr std::size_t MAX_MIIS = 100; 13constexpr std::size_t MAX_MIIS{100};
14constexpr u32 INVALID_INDEX = 0xFFFFFFFF; 14constexpr u32 INVALID_INDEX{0xFFFFFFFF};
15 15
16struct RandomParameters { 16struct RandomParameters {
17 u32 unknown_1; 17 u32 unknown_1{};
18 u32 unknown_2; 18 u32 unknown_2{};
19 u32 unknown_3; 19 u32 unknown_3{};
20}; 20};
21static_assert(sizeof(RandomParameters) == 0xC, "RandomParameters has incorrect size."); 21static_assert(sizeof(RandomParameters) == 0xC, "RandomParameters has incorrect size.");
22 22
@@ -30,57 +30,57 @@ enum class Source : u32 {
30std::ostream& operator<<(std::ostream& os, Source source); 30std::ostream& operator<<(std::ostream& os, Source source);
31 31
32struct MiiInfo { 32struct MiiInfo {
33 Common::UUID uuid; 33 Common::UUID uuid{Common::INVALID_UUID};
34 std::array<char16_t, 11> name; 34 std::array<char16_t, 11> name{};
35 u8 font_region; 35 u8 font_region{};
36 u8 favorite_color; 36 u8 favorite_color{};
37 u8 gender; 37 u8 gender{};
38 u8 height; 38 u8 height{};
39 u8 weight; 39 u8 weight{};
40 u8 mii_type; 40 u8 mii_type{};
41 u8 mii_region; 41 u8 mii_region{};
42 u8 face_type; 42 u8 face_type{};
43 u8 face_color; 43 u8 face_color{};
44 u8 face_wrinkle; 44 u8 face_wrinkle{};
45 u8 face_makeup; 45 u8 face_makeup{};
46 u8 hair_type; 46 u8 hair_type{};
47 u8 hair_color; 47 u8 hair_color{};
48 bool hair_flip; 48 bool hair_flip{};
49 u8 eye_type; 49 u8 eye_type{};
50 u8 eye_color; 50 u8 eye_color{};
51 u8 eye_scale; 51 u8 eye_scale{};
52 u8 eye_aspect_ratio; 52 u8 eye_aspect_ratio{};
53 u8 eye_rotate; 53 u8 eye_rotate{};
54 u8 eye_x; 54 u8 eye_x{};
55 u8 eye_y; 55 u8 eye_y{};
56 u8 eyebrow_type; 56 u8 eyebrow_type{};
57 u8 eyebrow_color; 57 u8 eyebrow_color{};
58 u8 eyebrow_scale; 58 u8 eyebrow_scale{};
59 u8 eyebrow_aspect_ratio; 59 u8 eyebrow_aspect_ratio{};
60 u8 eyebrow_rotate; 60 u8 eyebrow_rotate{};
61 u8 eyebrow_x; 61 u8 eyebrow_x{};
62 u8 eyebrow_y; 62 u8 eyebrow_y{};
63 u8 nose_type; 63 u8 nose_type{};
64 u8 nose_scale; 64 u8 nose_scale{};
65 u8 nose_y; 65 u8 nose_y{};
66 u8 mouth_type; 66 u8 mouth_type{};
67 u8 mouth_color; 67 u8 mouth_color{};
68 u8 mouth_scale; 68 u8 mouth_scale{};
69 u8 mouth_aspect_ratio; 69 u8 mouth_aspect_ratio{};
70 u8 mouth_y; 70 u8 mouth_y{};
71 u8 facial_hair_color; 71 u8 facial_hair_color{};
72 u8 beard_type; 72 u8 beard_type{};
73 u8 mustache_type; 73 u8 mustache_type{};
74 u8 mustache_scale; 74 u8 mustache_scale{};
75 u8 mustache_y; 75 u8 mustache_y{};
76 u8 glasses_type; 76 u8 glasses_type{};
77 u8 glasses_color; 77 u8 glasses_color{};
78 u8 glasses_scale; 78 u8 glasses_scale{};
79 u8 glasses_y; 79 u8 glasses_y{};
80 u8 mole_type; 80 u8 mole_type{};
81 u8 mole_scale; 81 u8 mole_scale{};
82 u8 mole_x; 82 u8 mole_x{};
83 u8 mole_y; 83 u8 mole_y{};
84 INSERT_PADDING_BYTES(1); 84 INSERT_PADDING_BYTES(1);
85 85
86 std::u16string Name() const; 86 std::u16string Name() const;
@@ -94,14 +94,14 @@ bool operator!=(const MiiInfo& lhs, const MiiInfo& rhs);
94 94
95#pragma pack(push, 4) 95#pragma pack(push, 4)
96struct MiiInfoElement { 96struct MiiInfoElement {
97 MiiInfo info; 97 MiiInfo info{};
98 Source source; 98 Source source{};
99}; 99};
100static_assert(sizeof(MiiInfoElement) == 0x5C, "MiiInfoElement has incorrect size."); 100static_assert(sizeof(MiiInfoElement) == 0x5C, "MiiInfoElement has incorrect size.");
101 101
102struct MiiStoreBitFields { 102struct MiiStoreBitFields {
103 union { 103 union {
104 u32 word_0; 104 u32 word_0{};
105 105
106 BitField<24, 8, u32> hair_type; 106 BitField<24, 8, u32> hair_type;
107 BitField<23, 1, u32> mole_type; 107 BitField<23, 1, u32> mole_type;
@@ -112,7 +112,7 @@ struct MiiStoreBitFields {
112 }; 112 };
113 113
114 union { 114 union {
115 u32 word_1; 115 u32 word_1{};
116 116
117 BitField<31, 1, u32> gender; 117 BitField<31, 1, u32> gender;
118 BitField<24, 7, u32> eye_color; 118 BitField<24, 7, u32> eye_color;
@@ -122,7 +122,7 @@ struct MiiStoreBitFields {
122 }; 122 };
123 123
124 union { 124 union {
125 u32 word_2; 125 u32 word_2{};
126 126
127 BitField<31, 1, u32> mii_type; 127 BitField<31, 1, u32> mii_type;
128 BitField<24, 7, u32> glasses_color; 128 BitField<24, 7, u32> glasses_color;
@@ -135,7 +135,7 @@ struct MiiStoreBitFields {
135 }; 135 };
136 136
137 union { 137 union {
138 u32 word_3; 138 u32 word_3{};
139 139
140 BitField<29, 3, u32> mustache_type; 140 BitField<29, 3, u32> mustache_type;
141 BitField<24, 5, u32> eyebrow_type; 141 BitField<24, 5, u32> eyebrow_type;
@@ -148,7 +148,7 @@ struct MiiStoreBitFields {
148 }; 148 };
149 149
150 union { 150 union {
151 u32 word_4; 151 u32 word_4{};
152 152
153 BitField<29, 3, u32> eye_rotate; 153 BitField<29, 3, u32> eye_rotate;
154 BitField<24, 5, u32> mustache_y; 154 BitField<24, 5, u32> mustache_y;
@@ -160,7 +160,7 @@ struct MiiStoreBitFields {
160 }; 160 };
161 161
162 union { 162 union {
163 u32 word_5; 163 u32 word_5{};
164 164
165 BitField<24, 5, u32> glasses_type; 165 BitField<24, 5, u32> glasses_type;
166 BitField<20, 4, u32> face_type; 166 BitField<20, 4, u32> face_type;
@@ -172,7 +172,7 @@ struct MiiStoreBitFields {
172 }; 172 };
173 173
174 union { 174 union {
175 u32 word_6; 175 u32 word_6{};
176 176
177 BitField<28, 4, u32> eyebrow_rotate; 177 BitField<28, 4, u32> eyebrow_rotate;
178 BitField<24, 4, u32> eyebrow_scale; 178 BitField<24, 4, u32> eyebrow_scale;
@@ -192,30 +192,30 @@ struct MiiStoreData {
192 // This corresponds to the above structure MiiStoreBitFields. I did it like this because the 192 // This corresponds to the above structure MiiStoreBitFields. I did it like this because the
193 // BitField<> type makes this (and any thing that contains it) not trivially copyable, which is 193 // BitField<> type makes this (and any thing that contains it) not trivially copyable, which is
194 // not suitable for our uses. 194 // not suitable for our uses.
195 std::array<u8, 0x1C> data; 195 std::array<u8, 0x1C> data{};
196 static_assert(sizeof(MiiStoreBitFields) == sizeof(data), "data field has incorrect size."); 196 static_assert(sizeof(MiiStoreBitFields) == sizeof(data), "data field has incorrect size.");
197 197
198 std::array<char16_t, 10> name; 198 std::array<char16_t, 10> name{};
199 Common::UUID uuid; 199 Common::UUID uuid{Common::INVALID_UUID};
200 u16 crc_1; 200 u16 crc_1{};
201 u16 crc_2; 201 u16 crc_2{};
202 202
203 std::u16string Name() const; 203 std::u16string Name() const;
204}; 204};
205static_assert(sizeof(MiiStoreData) == 0x44, "MiiStoreData has incorrect size."); 205static_assert(sizeof(MiiStoreData) == 0x44, "MiiStoreData has incorrect size.");
206 206
207struct MiiStoreDataElement { 207struct MiiStoreDataElement {
208 MiiStoreData data; 208 MiiStoreData data{};
209 Source source; 209 Source source{};
210}; 210};
211static_assert(sizeof(MiiStoreDataElement) == 0x48, "MiiStoreDataElement has incorrect size."); 211static_assert(sizeof(MiiStoreDataElement) == 0x48, "MiiStoreDataElement has incorrect size.");
212 212
213struct MiiDatabase { 213struct MiiDatabase {
214 u32 magic; // 'NFDB' 214 u32 magic{}; // 'NFDB'
215 std::array<MiiStoreData, MAX_MIIS> miis; 215 std::array<MiiStoreData, MAX_MIIS> miis{};
216 INSERT_PADDING_BYTES(1); 216 INSERT_PADDING_BYTES(1);
217 u8 count; 217 u8 count{};
218 u16 crc; 218 u16 crc{};
219}; 219};
220static_assert(sizeof(MiiDatabase) == 0x1A98, "MiiDatabase has incorrect size."); 220static_assert(sizeof(MiiDatabase) == 0x1A98, "MiiDatabase has incorrect size.");
221#pragma pack(pop) 221#pragma pack(pop)
@@ -266,8 +266,8 @@ private:
266 void EnsureDatabasePartition(); 266 void EnsureDatabasePartition();
267 267
268 MiiDatabase database; 268 MiiDatabase database;
269 bool updated_flag = false; 269 bool updated_flag{};
270 bool is_test_mode_enabled = false; 270 bool is_test_mode_enabled{};
271}; 271};
272 272
273}; // namespace Service::Mii 273}; // namespace Service::Mii
diff --git a/src/core/hle/service/time/clock_types.h b/src/core/hle/service/time/clock_types.h
new file mode 100644
index 000000000..72e1921ec
--- /dev/null
+++ b/src/core/hle/service/time/clock_types.h
@@ -0,0 +1,103 @@
1// Copyright 2019 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 "common/common_funcs.h"
8#include "common/common_types.h"
9#include "common/uuid.h"
10#include "core/hle/service/time/errors.h"
11#include "core/hle/service/time/time_zone_types.h"
12
13namespace Service::Time::Clock {
14
15/// https://switchbrew.org/wiki/Glue_services#SteadyClockTimePoint
16struct SteadyClockTimePoint {
17 s64 time_point;
18 Common::UUID clock_source_id;
19
20 ResultCode GetSpanBetween(SteadyClockTimePoint other, s64& span) const {
21 span = 0;
22
23 if (clock_source_id != other.clock_source_id) {
24 return ERROR_TIME_MISMATCH;
25 }
26
27 span = other.time_point - time_point;
28
29 return RESULT_SUCCESS;
30 }
31
32 static SteadyClockTimePoint GetRandom() {
33 return {0, Common::UUID::Generate()};
34 }
35};
36static_assert(sizeof(SteadyClockTimePoint) == 0x18, "SteadyClockTimePoint is incorrect size");
37static_assert(std::is_trivially_copyable_v<SteadyClockTimePoint>,
38 "SteadyClockTimePoint must be trivially copyable");
39
40struct SteadyClockContext {
41 u64 internal_offset;
42 Common::UUID steady_time_point;
43};
44static_assert(sizeof(SteadyClockContext) == 0x18, "SteadyClockContext is incorrect size");
45static_assert(std::is_trivially_copyable_v<SteadyClockContext>,
46 "SteadyClockContext must be trivially copyable");
47
48struct SystemClockContext {
49 s64 offset;
50 SteadyClockTimePoint steady_time_point;
51};
52static_assert(sizeof(SystemClockContext) == 0x20, "SystemClockContext is incorrect size");
53static_assert(std::is_trivially_copyable_v<SystemClockContext>,
54 "SystemClockContext must be trivially copyable");
55
56/// https://switchbrew.org/wiki/Glue_services#TimeSpanType
57struct TimeSpanType {
58 s64 nanoseconds{};
59 static constexpr s64 ns_per_second{1000000000ULL};
60
61 s64 ToSeconds() const {
62 return nanoseconds / ns_per_second;
63 }
64
65 static TimeSpanType FromSeconds(s64 seconds) {
66 return {seconds * ns_per_second};
67 }
68
69 static TimeSpanType FromTicks(u64 ticks, u64 frequency) {
70 return FromSeconds(static_cast<s64>(ticks) / static_cast<s64>(frequency));
71 }
72};
73static_assert(sizeof(TimeSpanType) == 8, "TimeSpanType is incorrect size");
74
75struct ClockSnapshot {
76 SystemClockContext user_context{};
77 SystemClockContext network_context{};
78 s64 user_time{};
79 s64 network_time{};
80 TimeZone::CalendarTime user_calendar_time{};
81 TimeZone::CalendarTime network_calendar_time{};
82 TimeZone::CalendarAdditionalInfo user_calendar_additional_time{};
83 TimeZone::CalendarAdditionalInfo network_calendar_additional_time{};
84 SteadyClockTimePoint steady_clock_time_point{};
85 TimeZone::LocationName location_name{};
86 u8 is_automatic_correction_enabled{};
87 u8 type{};
88 INSERT_PADDING_BYTES(0x2);
89
90 static ResultCode GetCurrentTime(s64& current_time,
91 const SteadyClockTimePoint& steady_clock_time_point,
92 const SystemClockContext& context) {
93 if (steady_clock_time_point.clock_source_id != context.steady_time_point.clock_source_id) {
94 current_time = 0;
95 return ERROR_TIME_MISMATCH;
96 }
97 current_time = steady_clock_time_point.time_point + context.offset;
98 return RESULT_SUCCESS;
99 }
100};
101static_assert(sizeof(ClockSnapshot) == 0xD0, "ClockSnapshot is incorrect size");
102
103} // namespace Service::Time::Clock
diff --git a/src/core/hle/service/time/ephemeral_network_system_clock_context_writer.h b/src/core/hle/service/time/ephemeral_network_system_clock_context_writer.h
new file mode 100644
index 000000000..42893e3f6
--- /dev/null
+++ b/src/core/hle/service/time/ephemeral_network_system_clock_context_writer.h
@@ -0,0 +1,16 @@
1// Copyright 2019 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 "core/hle/service/time/system_clock_context_update_callback.h"
8
9namespace Service::Time::Clock {
10
11class EphemeralNetworkSystemClockContextWriter final : public SystemClockContextUpdateCallback {
12public:
13 EphemeralNetworkSystemClockContextWriter() : SystemClockContextUpdateCallback{} {}
14};
15
16} // namespace Service::Time::Clock
diff --git a/src/core/hle/service/time/ephemeral_network_system_clock_core.h b/src/core/hle/service/time/ephemeral_network_system_clock_core.h
new file mode 100644
index 000000000..4c6cdef86
--- /dev/null
+++ b/src/core/hle/service/time/ephemeral_network_system_clock_core.h
@@ -0,0 +1,17 @@
1// Copyright 2019 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 "core/hle/service/time/system_clock_core.h"
8
9namespace Service::Time::Clock {
10
11class EphemeralNetworkSystemClockCore final : public SystemClockCore {
12public:
13 explicit EphemeralNetworkSystemClockCore(SteadyClockCore& steady_clock_core)
14 : SystemClockCore{steady_clock_core} {}
15};
16
17} // namespace Service::Time::Clock
diff --git a/src/core/hle/service/time/errors.h b/src/core/hle/service/time/errors.h
new file mode 100644
index 000000000..8501a3e8c
--- /dev/null
+++ b/src/core/hle/service/time/errors.h
@@ -0,0 +1,22 @@
1// Copyright 2019 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 "core/hle/result.h"
8
9namespace Service::Time {
10
11constexpr ResultCode ERROR_PERMISSION_DENIED{ErrorModule::Time, 1};
12constexpr ResultCode ERROR_TIME_MISMATCH{ErrorModule::Time, 102};
13constexpr ResultCode ERROR_UNINITIALIZED_CLOCK{ErrorModule::Time, 103};
14constexpr ResultCode ERROR_TIME_NOT_FOUND{ErrorModule::Time, 200};
15constexpr ResultCode ERROR_OVERFLOW{ErrorModule::Time, 201};
16constexpr ResultCode ERROR_LOCATION_NAME_TOO_LONG{ErrorModule::Time, 801};
17constexpr ResultCode ERROR_OUT_OF_RANGE{ErrorModule::Time, 902};
18constexpr ResultCode ERROR_TIME_ZONE_CONVERSION_FAILED{ErrorModule::Time, 903};
19constexpr ResultCode ERROR_TIME_ZONE_NOT_FOUND{ErrorModule::Time, 989};
20constexpr ResultCode ERROR_NOT_IMPLEMENTED{ErrorModule::Time, 990};
21
22} // namespace Service::Time
diff --git a/src/core/hle/service/time/interface.cpp b/src/core/hle/service/time/interface.cpp
index bc74f1e1d..1660bbdb8 100644
--- a/src/core/hle/service/time/interface.cpp
+++ b/src/core/hle/service/time/interface.cpp
@@ -1,4 +1,4 @@
1// Copyright 2018 yuzu emulator team 1// Copyright 2019 yuzu emulator team
2// Licensed under GPLv2 or any later version 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
@@ -6,9 +6,8 @@
6 6
7namespace Service::Time { 7namespace Service::Time {
8 8
9Time::Time(std::shared_ptr<Module> time, std::shared_ptr<SharedMemory> shared_memory, 9Time::Time(std::shared_ptr<Module> module, Core::System& system, const char* name)
10 Core::System& system, const char* name) 10 : Module::Interface(std::move(module), system, name) {
11 : Module::Interface(std::move(time), std::move(shared_memory), system, name) {
12 // clang-format off 11 // clang-format off
13 static const FunctionInfo functions[] = { 12 static const FunctionInfo functions[] = {
14 {0, &Time::GetStandardUserSystemClock, "GetStandardUserSystemClock"}, 13 {0, &Time::GetStandardUserSystemClock, "GetStandardUserSystemClock"},
@@ -22,15 +21,15 @@ Time::Time(std::shared_ptr<Module> time, std::shared_ptr<SharedMemory> shared_me
22 {31, nullptr, "GetEphemeralNetworkClockOperationEventReadableHandle"}, 21 {31, nullptr, "GetEphemeralNetworkClockOperationEventReadableHandle"},
23 {50, nullptr, "SetStandardSteadyClockInternalOffset"}, 22 {50, nullptr, "SetStandardSteadyClockInternalOffset"},
24 {51, nullptr, "GetStandardSteadyClockRtcValue"}, 23 {51, nullptr, "GetStandardSteadyClockRtcValue"},
25 {100, &Time::IsStandardUserSystemClockAutomaticCorrectionEnabled, "IsStandardUserSystemClockAutomaticCorrectionEnabled"}, 24 {100, nullptr, "IsStandardUserSystemClockAutomaticCorrectionEnabled"},
26 {101, &Time::SetStandardUserSystemClockAutomaticCorrectionEnabled, "SetStandardUserSystemClockAutomaticCorrectionEnabled"}, 25 {101, nullptr, "SetStandardUserSystemClockAutomaticCorrectionEnabled"},
27 {102, nullptr, "GetStandardUserSystemClockInitialYear"}, 26 {102, nullptr, "GetStandardUserSystemClockInitialYear"},
28 {200, nullptr, "IsStandardNetworkSystemClockAccuracySufficient"}, 27 {200, &Time::IsStandardNetworkSystemClockAccuracySufficient, "IsStandardNetworkSystemClockAccuracySufficient"},
29 {201, nullptr, "GetStandardUserSystemClockAutomaticCorrectionUpdatedTime"}, 28 {201, nullptr, "GetStandardUserSystemClockAutomaticCorrectionUpdatedTime"},
30 {300, nullptr, "CalculateMonotonicSystemClockBaseTimePoint"}, 29 {300, &Time::CalculateMonotonicSystemClockBaseTimePoint, "CalculateMonotonicSystemClockBaseTimePoint"},
31 {400, &Time::GetClockSnapshot, "GetClockSnapshot"}, 30 {400, &Time::GetClockSnapshot, "GetClockSnapshot"},
32 {401, nullptr, "GetClockSnapshotFromSystemClockContext"}, 31 {401, &Time::GetClockSnapshotFromSystemClockContext, "GetClockSnapshotFromSystemClockContext"},
33 {500, &Time::CalculateStandardUserSystemClockDifferenceByUser, "CalculateStandardUserSystemClockDifferenceByUser"}, 32 {500, nullptr, "CalculateStandardUserSystemClockDifferenceByUser"},
34 {501, nullptr, "CalculateSpanBetween"}, 33 {501, nullptr, "CalculateSpanBetween"},
35 }; 34 };
36 // clang-format on 35 // clang-format on
diff --git a/src/core/hle/service/time/interface.h b/src/core/hle/service/time/interface.h
index 5c63a07f4..4f49e1f07 100644
--- a/src/core/hle/service/time/interface.h
+++ b/src/core/hle/service/time/interface.h
@@ -1,4 +1,4 @@
1// Copyright 2018 yuzu emulator team 1// Copyright 2019 yuzu emulator team
2// Licensed under GPLv2 or any later version 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
@@ -6,14 +6,15 @@
6 6
7#include "core/hle/service/time/time.h" 7#include "core/hle/service/time/time.h"
8 8
9namespace Service::Time { 9namespace Core {
10class System;
11}
10 12
11class SharedMemory; 13namespace Service::Time {
12 14
13class Time final : public Module::Interface { 15class Time final : public Module::Interface {
14public: 16public:
15 explicit Time(std::shared_ptr<Module> time, std::shared_ptr<SharedMemory> shared_memory, 17 explicit Time(std::shared_ptr<Module> time, Core::System& system, const char* name);
16 Core::System& system, const char* name);
17 ~Time() override; 18 ~Time() override;
18}; 19};
19 20
diff --git a/src/core/hle/service/time/local_system_clock_context_writer.h b/src/core/hle/service/time/local_system_clock_context_writer.h
new file mode 100644
index 000000000..7050844c6
--- /dev/null
+++ b/src/core/hle/service/time/local_system_clock_context_writer.h
@@ -0,0 +1,28 @@
1// Copyright 2019 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 "core/hle/service/time/errors.h"
8#include "core/hle/service/time/system_clock_context_update_callback.h"
9#include "core/hle/service/time/time_sharedmemory.h"
10
11namespace Service::Time::Clock {
12
13class LocalSystemClockContextWriter final : public SystemClockContextUpdateCallback {
14public:
15 explicit LocalSystemClockContextWriter(SharedMemory& shared_memory)
16 : SystemClockContextUpdateCallback{}, shared_memory{shared_memory} {}
17
18protected:
19 ResultCode Update() override {
20 shared_memory.UpdateLocalSystemClockContext(context);
21 return RESULT_SUCCESS;
22 }
23
24private:
25 SharedMemory& shared_memory;
26};
27
28} // namespace Service::Time::Clock
diff --git a/src/core/hle/service/time/network_system_clock_context_writer.h b/src/core/hle/service/time/network_system_clock_context_writer.h
new file mode 100644
index 000000000..94d8788ff
--- /dev/null
+++ b/src/core/hle/service/time/network_system_clock_context_writer.h
@@ -0,0 +1,28 @@
1// Copyright 2019 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 "core/hle/service/time/errors.h"
8#include "core/hle/service/time/system_clock_context_update_callback.h"
9#include "core/hle/service/time/time_sharedmemory.h"
10
11namespace Service::Time::Clock {
12
13class NetworkSystemClockContextWriter final : public SystemClockContextUpdateCallback {
14public:
15 explicit NetworkSystemClockContextWriter(SharedMemory& shared_memory)
16 : SystemClockContextUpdateCallback{}, shared_memory{shared_memory} {}
17
18protected:
19 ResultCode Update() override {
20 shared_memory.UpdateNetworkSystemClockContext(context);
21 return RESULT_SUCCESS;
22 }
23
24private:
25 SharedMemory& shared_memory;
26};
27
28} // namespace Service::Time::Clock
diff --git a/src/core/hle/service/time/standard_local_system_clock_core.h b/src/core/hle/service/time/standard_local_system_clock_core.h
new file mode 100644
index 000000000..8c1882eb1
--- /dev/null
+++ b/src/core/hle/service/time/standard_local_system_clock_core.h
@@ -0,0 +1,17 @@
1// Copyright 2019 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 "core/hle/service/time/system_clock_core.h"
8
9namespace Service::Time::Clock {
10
11class StandardLocalSystemClockCore final : public SystemClockCore {
12public:
13 explicit StandardLocalSystemClockCore(SteadyClockCore& steady_clock_core)
14 : SystemClockCore{steady_clock_core} {}
15};
16
17} // namespace Service::Time::Clock
diff --git a/src/core/hle/service/time/standard_network_system_clock_core.h b/src/core/hle/service/time/standard_network_system_clock_core.h
new file mode 100644
index 000000000..3f505c37c
--- /dev/null
+++ b/src/core/hle/service/time/standard_network_system_clock_core.h
@@ -0,0 +1,46 @@
1// Copyright 2019 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 "core/hle/service/time/clock_types.h"
8#include "core/hle/service/time/steady_clock_core.h"
9#include "core/hle/service/time/system_clock_core.h"
10
11namespace Core {
12class System;
13}
14
15namespace Service::Time::Clock {
16
17class StandardNetworkSystemClockCore final : public SystemClockCore {
18public:
19 explicit StandardNetworkSystemClockCore(SteadyClockCore& steady_clock_core)
20 : SystemClockCore{steady_clock_core} {}
21
22 void SetStandardNetworkClockSufficientAccuracy(TimeSpanType value) {
23 standard_network_clock_sufficient_accuracy = value;
24 }
25
26 bool IsStandardNetworkSystemClockAccuracySufficient(Core::System& system) {
27 SystemClockContext context{};
28 if (GetClockContext(system, context) != RESULT_SUCCESS) {
29 return {};
30 }
31
32 s64 span{};
33 if (context.steady_time_point.GetSpanBetween(
34 GetSteadyClockCore().GetCurrentTimePoint(system), span) != RESULT_SUCCESS) {
35 return {};
36 }
37
38 return TimeSpanType{span}.nanoseconds <
39 standard_network_clock_sufficient_accuracy.nanoseconds;
40 }
41
42private:
43 TimeSpanType standard_network_clock_sufficient_accuracy{};
44};
45
46} // namespace Service::Time::Clock
diff --git a/src/core/hle/service/time/standard_steady_clock_core.cpp b/src/core/hle/service/time/standard_steady_clock_core.cpp
new file mode 100644
index 000000000..ca1a783fc
--- /dev/null
+++ b/src/core/hle/service/time/standard_steady_clock_core.cpp
@@ -0,0 +1,26 @@
1// Copyright 2019 yuzu emulator team
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include "core/core.h"
6#include "core/core_timing.h"
7#include "core/core_timing_util.h"
8#include "core/hle/service/time/standard_steady_clock_core.h"
9
10namespace Service::Time::Clock {
11
12TimeSpanType StandardSteadyClockCore::GetCurrentRawTimePoint(Core::System& system) {
13 const TimeSpanType ticks_time_span{TimeSpanType::FromTicks(
14 Core::Timing::CpuCyclesToClockCycles(system.CoreTiming().GetTicks()),
15 Core::Timing::CNTFREQ)};
16 TimeSpanType raw_time_point{setup_value.nanoseconds + ticks_time_span.nanoseconds};
17
18 if (raw_time_point.nanoseconds < cached_raw_time_point.nanoseconds) {
19 raw_time_point.nanoseconds = cached_raw_time_point.nanoseconds;
20 }
21
22 cached_raw_time_point = raw_time_point;
23 return raw_time_point;
24}
25
26} // namespace Service::Time::Clock
diff --git a/src/core/hle/service/time/standard_steady_clock_core.h b/src/core/hle/service/time/standard_steady_clock_core.h
new file mode 100644
index 000000000..f56f3fd95
--- /dev/null
+++ b/src/core/hle/service/time/standard_steady_clock_core.h
@@ -0,0 +1,42 @@
1// Copyright 2019 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 "core/hle/service/time/clock_types.h"
8#include "core/hle/service/time/steady_clock_core.h"
9
10namespace Core {
11class System;
12}
13
14namespace Service::Time::Clock {
15
16class StandardSteadyClockCore final : public SteadyClockCore {
17public:
18 SteadyClockTimePoint GetTimePoint(Core::System& system) override {
19 return {GetCurrentRawTimePoint(system).ToSeconds(), GetClockSourceId()};
20 }
21
22 TimeSpanType GetInternalOffset() const override {
23 return internal_offset;
24 }
25
26 void SetInternalOffset(TimeSpanType value) override {
27 internal_offset = value;
28 }
29
30 TimeSpanType GetCurrentRawTimePoint(Core::System& system) override;
31
32 void SetSetupValue(TimeSpanType value) {
33 setup_value = value;
34 }
35
36private:
37 TimeSpanType setup_value{};
38 TimeSpanType internal_offset{};
39 TimeSpanType cached_raw_time_point{};
40};
41
42} // namespace Service::Time::Clock
diff --git a/src/core/hle/service/time/standard_user_system_clock_core.cpp b/src/core/hle/service/time/standard_user_system_clock_core.cpp
new file mode 100644
index 000000000..8af17091c
--- /dev/null
+++ b/src/core/hle/service/time/standard_user_system_clock_core.cpp
@@ -0,0 +1,77 @@
1// Copyright 2019 yuzu emulator team
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include "common/assert.h"
6#include "core/core.h"
7#include "core/hle/kernel/writable_event.h"
8#include "core/hle/service/time/standard_local_system_clock_core.h"
9#include "core/hle/service/time/standard_network_system_clock_core.h"
10#include "core/hle/service/time/standard_user_system_clock_core.h"
11
12namespace Service::Time::Clock {
13
14StandardUserSystemClockCore::StandardUserSystemClockCore(
15 StandardLocalSystemClockCore& local_system_clock_core,
16 StandardNetworkSystemClockCore& network_system_clock_core, Core::System& system)
17 : SystemClockCore(local_system_clock_core.GetSteadyClockCore()),
18 local_system_clock_core{local_system_clock_core},
19 network_system_clock_core{network_system_clock_core}, auto_correction_enabled{},
20 auto_correction_time{SteadyClockTimePoint::GetRandom()},
21 auto_correction_event{Kernel::WritableEvent::CreateEventPair(
22 system.Kernel(), "StandardUserSystemClockCore:AutoCorrectionEvent")} {}
23
24ResultCode StandardUserSystemClockCore::SetAutomaticCorrectionEnabled(Core::System& system,
25 bool value) {
26 if (const ResultCode result{ApplyAutomaticCorrection(system, value)};
27 result != RESULT_SUCCESS) {
28 return result;
29 }
30
31 auto_correction_enabled = value;
32
33 return RESULT_SUCCESS;
34}
35
36ResultCode StandardUserSystemClockCore::GetClockContext(Core::System& system,
37 SystemClockContext& context) const {
38 if (const ResultCode result{ApplyAutomaticCorrection(system, false)};
39 result != RESULT_SUCCESS) {
40 return result;
41 }
42
43 return local_system_clock_core.GetClockContext(system, context);
44}
45
46ResultCode StandardUserSystemClockCore::Flush(const SystemClockContext& context) {
47 UNREACHABLE();
48 return ERROR_NOT_IMPLEMENTED;
49}
50
51ResultCode StandardUserSystemClockCore::SetClockContext(const SystemClockContext& context) {
52 UNREACHABLE();
53 return ERROR_NOT_IMPLEMENTED;
54}
55
56ResultCode StandardUserSystemClockCore::ApplyAutomaticCorrection(Core::System& system,
57 bool value) const {
58 if (auto_correction_enabled == value) {
59 return RESULT_SUCCESS;
60 }
61
62 if (!network_system_clock_core.IsClockSetup(system)) {
63 return ERROR_UNINITIALIZED_CLOCK;
64 }
65
66 SystemClockContext context{};
67 if (const ResultCode result{network_system_clock_core.GetClockContext(system, context)};
68 result != RESULT_SUCCESS) {
69 return result;
70 }
71
72 local_system_clock_core.SetClockContext(context);
73
74 return RESULT_SUCCESS;
75}
76
77} // namespace Service::Time::Clock
diff --git a/src/core/hle/service/time/standard_user_system_clock_core.h b/src/core/hle/service/time/standard_user_system_clock_core.h
new file mode 100644
index 000000000..ef3d468b7
--- /dev/null
+++ b/src/core/hle/service/time/standard_user_system_clock_core.h
@@ -0,0 +1,57 @@
1// Copyright 2019 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 "core/hle/kernel/writable_event.h"
8#include "core/hle/service/time/clock_types.h"
9#include "core/hle/service/time/system_clock_core.h"
10
11namespace Core {
12class System;
13}
14
15namespace Service::Time::Clock {
16
17class StandardLocalSystemClockCore;
18class StandardNetworkSystemClockCore;
19
20class StandardUserSystemClockCore final : public SystemClockCore {
21public:
22 StandardUserSystemClockCore(StandardLocalSystemClockCore& local_system_clock_core,
23 StandardNetworkSystemClockCore& network_system_clock_core,
24 Core::System& system);
25
26 ResultCode SetAutomaticCorrectionEnabled(Core::System& system, bool value);
27
28 ResultCode GetClockContext(Core::System& system, SystemClockContext& context) const override;
29
30 bool IsAutomaticCorrectionEnabled() const {
31 return auto_correction_enabled;
32 }
33
34 void SetAutomaticCorrectionUpdatedTime(SteadyClockTimePoint steady_clock_time_point) {
35 auto_correction_time = steady_clock_time_point;
36 }
37
38protected:
39 ResultCode Flush(const SystemClockContext& context) override;
40
41 ResultCode SetClockContext(const SystemClockContext&) override;
42
43 ResultCode ApplyAutomaticCorrection(Core::System& system, bool value) const;
44
45 const SteadyClockTimePoint& GetAutomaticCorrectionUpdatedTime() const {
46 return auto_correction_time;
47 }
48
49private:
50 StandardLocalSystemClockCore& local_system_clock_core;
51 StandardNetworkSystemClockCore& network_system_clock_core;
52 bool auto_correction_enabled{};
53 SteadyClockTimePoint auto_correction_time;
54 Kernel::EventPair auto_correction_event;
55};
56
57} // namespace Service::Time::Clock
diff --git a/src/core/hle/service/time/steady_clock_core.h b/src/core/hle/service/time/steady_clock_core.h
new file mode 100644
index 000000000..84af3d105
--- /dev/null
+++ b/src/core/hle/service/time/steady_clock_core.h
@@ -0,0 +1,55 @@
1// Copyright 2019 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 "common/uuid.h"
8#include "core/hle/service/time/clock_types.h"
9
10namespace Core {
11class System;
12}
13
14namespace Service::Time::Clock {
15
16class SteadyClockCore {
17public:
18 SteadyClockCore() = default;
19
20 const Common::UUID& GetClockSourceId() const {
21 return clock_source_id;
22 }
23
24 void SetClockSourceId(const Common::UUID& value) {
25 clock_source_id = value;
26 }
27
28 virtual TimeSpanType GetInternalOffset() const = 0;
29
30 virtual void SetInternalOffset(TimeSpanType internal_offset) = 0;
31
32 virtual SteadyClockTimePoint GetTimePoint(Core::System& system) = 0;
33
34 virtual TimeSpanType GetCurrentRawTimePoint(Core::System& system) = 0;
35
36 SteadyClockTimePoint GetCurrentTimePoint(Core::System& system) {
37 SteadyClockTimePoint result{GetTimePoint(system)};
38 result.time_point += GetInternalOffset().ToSeconds();
39 return result;
40 }
41
42 bool IsInitialized() const {
43 return is_initialized;
44 }
45
46 void MarkAsInitialized() {
47 is_initialized = true;
48 }
49
50private:
51 Common::UUID clock_source_id{Common::UUID::Generate()};
52 bool is_initialized{};
53};
54
55} // namespace Service::Time::Clock
diff --git a/src/core/hle/service/time/system_clock_context_update_callback.cpp b/src/core/hle/service/time/system_clock_context_update_callback.cpp
new file mode 100644
index 000000000..5cdb80703
--- /dev/null
+++ b/src/core/hle/service/time/system_clock_context_update_callback.cpp
@@ -0,0 +1,55 @@
1// Copyright 2019 yuzu emulator team
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include "core/hle/kernel/writable_event.h"
6#include "core/hle/service/time/errors.h"
7#include "core/hle/service/time/system_clock_context_update_callback.h"
8
9namespace Service::Time::Clock {
10
11SystemClockContextUpdateCallback::SystemClockContextUpdateCallback() = default;
12SystemClockContextUpdateCallback::~SystemClockContextUpdateCallback() = default;
13
14bool SystemClockContextUpdateCallback::NeedUpdate(const SystemClockContext& value) const {
15 if (has_context) {
16 return context.offset != value.offset ||
17 context.steady_time_point.clock_source_id != value.steady_time_point.clock_source_id;
18 }
19
20 return true;
21}
22
23void SystemClockContextUpdateCallback::RegisterOperationEvent(
24 std::shared_ptr<Kernel::WritableEvent>&& writable_event) {
25 operation_event_list.emplace_back(std::move(writable_event));
26}
27
28void SystemClockContextUpdateCallback::BroadcastOperationEvent() {
29 for (const auto& writable_event : operation_event_list) {
30 writable_event->Signal();
31 }
32}
33
34ResultCode SystemClockContextUpdateCallback::Update(const SystemClockContext& value) {
35 ResultCode result{RESULT_SUCCESS};
36
37 if (NeedUpdate(value)) {
38 context = value;
39 has_context = true;
40
41 result = Update();
42
43 if (result == RESULT_SUCCESS) {
44 BroadcastOperationEvent();
45 }
46 }
47
48 return result;
49}
50
51ResultCode SystemClockContextUpdateCallback::Update() {
52 return RESULT_SUCCESS;
53}
54
55} // namespace Service::Time::Clock
diff --git a/src/core/hle/service/time/system_clock_context_update_callback.h b/src/core/hle/service/time/system_clock_context_update_callback.h
new file mode 100644
index 000000000..6260de6c3
--- /dev/null
+++ b/src/core/hle/service/time/system_clock_context_update_callback.h
@@ -0,0 +1,43 @@
1// Copyright 2019 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 <vector>
8
9#include "core/hle/service/time/clock_types.h"
10
11namespace Kernel {
12class WritableEvent;
13}
14
15namespace Service::Time::Clock {
16
17// Parts of this implementation were based on Ryujinx (https://github.com/Ryujinx/Ryujinx/pull/783).
18// This code was released under public domain.
19
20class SystemClockContextUpdateCallback {
21public:
22 SystemClockContextUpdateCallback();
23 ~SystemClockContextUpdateCallback();
24
25 bool NeedUpdate(const SystemClockContext& value) const;
26
27 void RegisterOperationEvent(std::shared_ptr<Kernel::WritableEvent>&& writable_event);
28
29 void BroadcastOperationEvent();
30
31 ResultCode Update(const SystemClockContext& value);
32
33protected:
34 virtual ResultCode Update();
35
36 SystemClockContext context{};
37
38private:
39 bool has_context{};
40 std::vector<std::shared_ptr<Kernel::WritableEvent>> operation_event_list;
41};
42
43} // namespace Service::Time::Clock
diff --git a/src/core/hle/service/time/system_clock_core.cpp b/src/core/hle/service/time/system_clock_core.cpp
new file mode 100644
index 000000000..1a3ab8cfa
--- /dev/null
+++ b/src/core/hle/service/time/system_clock_core.cpp
@@ -0,0 +1,72 @@
1// Copyright 2019 yuzu emulator team
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include "core/hle/service/time/steady_clock_core.h"
6#include "core/hle/service/time/system_clock_context_update_callback.h"
7#include "core/hle/service/time/system_clock_core.h"
8
9namespace Service::Time::Clock {
10
11SystemClockCore::SystemClockCore(SteadyClockCore& steady_clock_core)
12 : steady_clock_core{steady_clock_core}, is_initialized{} {
13 context.steady_time_point.clock_source_id = steady_clock_core.GetClockSourceId();
14}
15
16SystemClockCore ::~SystemClockCore() = default;
17
18ResultCode SystemClockCore::GetCurrentTime(Core::System& system, s64& posix_time) const {
19 posix_time = 0;
20
21 const SteadyClockTimePoint current_time_point{steady_clock_core.GetCurrentTimePoint(system)};
22
23 SystemClockContext clock_context{};
24 if (const ResultCode result{GetClockContext(system, clock_context)}; result != RESULT_SUCCESS) {
25 return result;
26 }
27
28 if (current_time_point.clock_source_id != clock_context.steady_time_point.clock_source_id) {
29 return ERROR_TIME_MISMATCH;
30 }
31
32 posix_time = clock_context.offset + current_time_point.time_point;
33
34 return RESULT_SUCCESS;
35}
36
37ResultCode SystemClockCore::SetCurrentTime(Core::System& system, s64 posix_time) {
38 const SteadyClockTimePoint current_time_point{steady_clock_core.GetCurrentTimePoint(system)};
39 const SystemClockContext clock_context{posix_time - current_time_point.time_point,
40 current_time_point};
41
42 if (const ResultCode result{SetClockContext(clock_context)}; result != RESULT_SUCCESS) {
43 return result;
44 }
45 return Flush(clock_context);
46}
47
48ResultCode SystemClockCore::Flush(const SystemClockContext& context) {
49 if (!system_clock_context_update_callback) {
50 return RESULT_SUCCESS;
51 }
52 return system_clock_context_update_callback->Update(context);
53}
54
55ResultCode SystemClockCore::SetSystemClockContext(const SystemClockContext& context) {
56 if (const ResultCode result{SetClockContext(context)}; result != RESULT_SUCCESS) {
57 return result;
58 }
59 return Flush(context);
60}
61
62bool SystemClockCore::IsClockSetup(Core::System& system) const {
63 SystemClockContext value{};
64 if (GetClockContext(system, value) == RESULT_SUCCESS) {
65 const SteadyClockTimePoint steady_clock_time_point{
66 steady_clock_core.GetCurrentTimePoint(system)};
67 return steady_clock_time_point.clock_source_id == value.steady_time_point.clock_source_id;
68 }
69 return {};
70}
71
72} // namespace Service::Time::Clock
diff --git a/src/core/hle/service/time/system_clock_core.h b/src/core/hle/service/time/system_clock_core.h
new file mode 100644
index 000000000..54407a6c5
--- /dev/null
+++ b/src/core/hle/service/time/system_clock_core.h
@@ -0,0 +1,71 @@
1// Copyright 2019 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 "common/common_types.h"
8#include "core/hle/service/time/clock_types.h"
9
10namespace Core {
11class System;
12}
13
14namespace Service::Time::Clock {
15
16class SteadyClockCore;
17class SystemClockContextUpdateCallback;
18
19// Parts of this implementation were based on Ryujinx (https://github.com/Ryujinx/Ryujinx/pull/783).
20// This code was released under public domain.
21
22class SystemClockCore {
23public:
24 explicit SystemClockCore(SteadyClockCore& steady_clock_core);
25 ~SystemClockCore();
26
27 SteadyClockCore& GetSteadyClockCore() const {
28 return steady_clock_core;
29 }
30
31 ResultCode GetCurrentTime(Core::System& system, s64& posix_time) const;
32
33 ResultCode SetCurrentTime(Core::System& system, s64 posix_time);
34
35 virtual ResultCode GetClockContext([[maybe_unused]] Core::System& system,
36 SystemClockContext& value) const {
37 value = context;
38 return RESULT_SUCCESS;
39 }
40
41 virtual ResultCode SetClockContext(const SystemClockContext& value) {
42 context = value;
43 return RESULT_SUCCESS;
44 }
45
46 virtual ResultCode Flush(const SystemClockContext& context);
47
48 void SetUpdateCallbackInstance(std::shared_ptr<SystemClockContextUpdateCallback> callback) {
49 system_clock_context_update_callback = std::move(callback);
50 }
51
52 ResultCode SetSystemClockContext(const SystemClockContext& context);
53
54 bool IsInitialized() const {
55 return is_initialized;
56 }
57
58 void MarkAsInitialized() {
59 is_initialized = true;
60 }
61
62 bool IsClockSetup(Core::System& system) const;
63
64private:
65 SteadyClockCore& steady_clock_core;
66 SystemClockContext context{};
67 bool is_initialized{};
68 std::shared_ptr<SystemClockContextUpdateCallback> system_clock_context_update_callback;
69};
70
71} // namespace Service::Time::Clock
diff --git a/src/core/hle/service/time/tick_based_steady_clock_core.cpp b/src/core/hle/service/time/tick_based_steady_clock_core.cpp
new file mode 100644
index 000000000..c77b98189
--- /dev/null
+++ b/src/core/hle/service/time/tick_based_steady_clock_core.cpp
@@ -0,0 +1,24 @@
1// Copyright 2020 yuzu emulator team
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include "core/core.h"
6#include "core/core_timing.h"
7#include "core/core_timing_util.h"
8#include "core/hle/service/time/tick_based_steady_clock_core.h"
9
10namespace Service::Time::Clock {
11
12SteadyClockTimePoint TickBasedSteadyClockCore::GetTimePoint(Core::System& system) {
13 const TimeSpanType ticks_time_span{TimeSpanType::FromTicks(
14 Core::Timing::CpuCyclesToClockCycles(system.CoreTiming().GetTicks()),
15 Core::Timing::CNTFREQ)};
16
17 return {ticks_time_span.ToSeconds(), GetClockSourceId()};
18}
19
20TimeSpanType TickBasedSteadyClockCore::GetCurrentRawTimePoint(Core::System& system) {
21 return TimeSpanType::FromSeconds(GetTimePoint(system).time_point);
22}
23
24} // namespace Service::Time::Clock
diff --git a/src/core/hle/service/time/tick_based_steady_clock_core.h b/src/core/hle/service/time/tick_based_steady_clock_core.h
new file mode 100644
index 000000000..1a5a53fd7
--- /dev/null
+++ b/src/core/hle/service/time/tick_based_steady_clock_core.h
@@ -0,0 +1,29 @@
1// Copyright 2020 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 "core/hle/service/time/clock_types.h"
8#include "core/hle/service/time/steady_clock_core.h"
9
10namespace Core {
11class System;
12}
13
14namespace Service::Time::Clock {
15
16class TickBasedSteadyClockCore final : public SteadyClockCore {
17public:
18 TimeSpanType GetInternalOffset() const override {
19 return {};
20 }
21
22 void SetInternalOffset(TimeSpanType internal_offset) override {}
23
24 SteadyClockTimePoint GetTimePoint(Core::System& system) override;
25
26 TimeSpanType GetCurrentRawTimePoint(Core::System& system) override;
27};
28
29} // namespace Service::Time::Clock
diff --git a/src/core/hle/service/time/time.cpp b/src/core/hle/service/time/time.cpp
index 6ee77c5f9..8ef4efcef 100644
--- a/src/core/hle/service/time/time.cpp
+++ b/src/core/hle/service/time/time.cpp
@@ -1,9 +1,7 @@
1// Copyright 2018 yuzu emulator team 1// Copyright 2019 yuzu emulator team
2// Licensed under GPLv2 or any later version 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <chrono>
6#include <ctime>
7#include "common/logging/log.h" 5#include "common/logging/log.h"
8#include "core/core.h" 6#include "core/core.h"
9#include "core/core_timing.h" 7#include "core/core_timing.h"
@@ -11,429 +9,321 @@
11#include "core/hle/ipc_helpers.h" 9#include "core/hle/ipc_helpers.h"
12#include "core/hle/kernel/client_port.h" 10#include "core/hle/kernel/client_port.h"
13#include "core/hle/kernel/client_session.h" 11#include "core/hle/kernel/client_session.h"
12#include "core/hle/kernel/scheduler.h"
14#include "core/hle/service/time/interface.h" 13#include "core/hle/service/time/interface.h"
15#include "core/hle/service/time/time.h" 14#include "core/hle/service/time/time.h"
16#include "core/hle/service/time/time_sharedmemory.h" 15#include "core/hle/service/time/time_sharedmemory.h"
17#include "core/settings.h" 16#include "core/hle/service/time/time_zone_service.h"
18 17
19namespace Service::Time { 18namespace Service::Time {
20 19
21static std::chrono::seconds GetSecondsSinceEpoch() {
22 return std::chrono::duration_cast<std::chrono::seconds>(
23 std::chrono::system_clock::now().time_since_epoch()) +
24 Settings::values.custom_rtc_differential;
25}
26
27static void PosixToCalendar(u64 posix_time, CalendarTime& calendar_time,
28 CalendarAdditionalInfo& additional_info,
29 [[maybe_unused]] const TimeZoneRule& /*rule*/) {
30 const std::time_t time(posix_time);
31 const std::tm* tm = std::localtime(&time);
32 if (tm == nullptr) {
33 calendar_time = {};
34 additional_info = {};
35 return;
36 }
37 calendar_time.year = static_cast<u16_le>(tm->tm_year + 1900);
38 calendar_time.month = static_cast<u8>(tm->tm_mon + 1);
39 calendar_time.day = static_cast<u8>(tm->tm_mday);
40 calendar_time.hour = static_cast<u8>(tm->tm_hour);
41 calendar_time.minute = static_cast<u8>(tm->tm_min);
42 calendar_time.second = static_cast<u8>(tm->tm_sec);
43
44 additional_info.day_of_week = tm->tm_wday;
45 additional_info.day_of_year = tm->tm_yday;
46 std::memcpy(additional_info.name.data(), "UTC", sizeof("UTC"));
47 additional_info.utc_offset = 0;
48}
49
50static u64 CalendarToPosix(const CalendarTime& calendar_time,
51 [[maybe_unused]] const TimeZoneRule& /*rule*/) {
52 std::tm time{};
53 time.tm_year = calendar_time.year - 1900;
54 time.tm_mon = calendar_time.month - 1;
55 time.tm_mday = calendar_time.day;
56
57 time.tm_hour = calendar_time.hour;
58 time.tm_min = calendar_time.minute;
59 time.tm_sec = calendar_time.second;
60
61 std::time_t epoch_time = std::mktime(&time);
62 return static_cast<u64>(epoch_time);
63}
64
65enum class ClockContextType {
66 StandardSteady,
67 StandardUserSystem,
68 StandardNetworkSystem,
69 StandardLocalSystem,
70};
71
72class ISystemClock final : public ServiceFramework<ISystemClock> { 20class ISystemClock final : public ServiceFramework<ISystemClock> {
73public: 21public:
74 ISystemClock(std::shared_ptr<Service::Time::SharedMemory> shared_memory, 22 ISystemClock(Clock::SystemClockCore& clock_core)
75 ClockContextType clock_type) 23 : ServiceFramework("ISystemClock"), clock_core{clock_core} {
76 : ServiceFramework("ISystemClock"), shared_memory(shared_memory), clock_type(clock_type) {
77 // clang-format off 24 // clang-format off
78 static const FunctionInfo functions[] = { 25 static const FunctionInfo functions[] = {
79 {0, &ISystemClock::GetCurrentTime, "GetCurrentTime"}, 26 {0, &ISystemClock::GetCurrentTime, "GetCurrentTime"},
80 {1, nullptr, "SetCurrentTime"}, 27 {1, nullptr, "SetCurrentTime"},
81 {2, &ISystemClock::GetSystemClockContext, "GetSystemClockContext"}, 28 {2, &ISystemClock::GetSystemClockContext, "GetSystemClockContext"},
82 {3, nullptr, "SetSystemClockContext"}, 29 {3, nullptr, "SetSystemClockContext"},
83 {4, nullptr, "GetOperationEventReadableHandle"}, 30 {4, nullptr, "GetOperationEventReadableHandle"},
84 }; 31 };
85 // clang-format on 32 // clang-format on
86 33
87 RegisterHandlers(functions); 34 RegisterHandlers(functions);
88 UpdateSharedMemoryContext(system_clock_context);
89 } 35 }
90 36
91private: 37private:
92 void GetCurrentTime(Kernel::HLERequestContext& ctx) { 38 void GetCurrentTime(Kernel::HLERequestContext& ctx) {
93 const s64 time_since_epoch{GetSecondsSinceEpoch().count()};
94 LOG_DEBUG(Service_Time, "called"); 39 LOG_DEBUG(Service_Time, "called");
95 40
41 if (!clock_core.IsInitialized()) {
42 IPC::ResponseBuilder rb{ctx, 2};
43 rb.Push(ERROR_UNINITIALIZED_CLOCK);
44 return;
45 }
46
47 s64 posix_time{};
48 if (const ResultCode result{
49 clock_core.GetCurrentTime(Core::System::GetInstance(), posix_time)};
50 result != RESULT_SUCCESS) {
51 IPC::ResponseBuilder rb{ctx, 2};
52 rb.Push(result);
53 return;
54 }
55
96 IPC::ResponseBuilder rb{ctx, 4}; 56 IPC::ResponseBuilder rb{ctx, 4};
97 rb.Push(RESULT_SUCCESS); 57 rb.Push(RESULT_SUCCESS);
98 rb.Push<u64>(time_since_epoch); 58 rb.Push<s64>(posix_time);
99 } 59 }
100 60
101 void GetSystemClockContext(Kernel::HLERequestContext& ctx) { 61 void GetSystemClockContext(Kernel::HLERequestContext& ctx) {
102 LOG_WARNING(Service_Time, "(STUBBED) called"); 62 LOG_DEBUG(Service_Time, "called");
63
64 if (!clock_core.IsInitialized()) {
65 IPC::ResponseBuilder rb{ctx, 2};
66 rb.Push(ERROR_UNINITIALIZED_CLOCK);
67 return;
68 }
103 69
104 // TODO(ogniK): This should be updated periodically however since we have it stubbed we'll 70 Clock::SystemClockContext system_clock_context{};
105 // only update when we get a new context 71 if (const ResultCode result{
106 UpdateSharedMemoryContext(system_clock_context); 72 clock_core.GetClockContext(Core::System::GetInstance(), system_clock_context)};
73 result != RESULT_SUCCESS) {
74 IPC::ResponseBuilder rb{ctx, 2};
75 rb.Push(result);
76 return;
77 }
107 78
108 IPC::ResponseBuilder rb{ctx, (sizeof(SystemClockContext) / 4) + 2}; 79 IPC::ResponseBuilder rb{ctx, sizeof(Clock::SystemClockContext) / 4 + 2};
109 rb.Push(RESULT_SUCCESS); 80 rb.Push(RESULT_SUCCESS);
110 rb.PushRaw(system_clock_context); 81 rb.PushRaw(system_clock_context);
111 } 82 }
112 83
113 void UpdateSharedMemoryContext(const SystemClockContext& clock_context) { 84 Clock::SystemClockCore& clock_core;
114 switch (clock_type) {
115 case ClockContextType::StandardLocalSystem:
116 shared_memory->SetStandardLocalSystemClockContext(clock_context);
117 break;
118 case ClockContextType::StandardNetworkSystem:
119 shared_memory->SetStandardNetworkSystemClockContext(clock_context);
120 break;
121 }
122 }
123
124 SystemClockContext system_clock_context{};
125 std::shared_ptr<Service::Time::SharedMemory> shared_memory;
126 ClockContextType clock_type;
127}; 85};
128 86
129class ISteadyClock final : public ServiceFramework<ISteadyClock> { 87class ISteadyClock final : public ServiceFramework<ISteadyClock> {
130public: 88public:
131 ISteadyClock(std::shared_ptr<SharedMemory> shared_memory, Core::System& system) 89 ISteadyClock(Clock::SteadyClockCore& clock_core)
132 : ServiceFramework("ISteadyClock"), shared_memory(shared_memory), system(system) { 90 : ServiceFramework("ISteadyClock"), clock_core{clock_core} {
133 static const FunctionInfo functions[] = { 91 static const FunctionInfo functions[] = {
134 {0, &ISteadyClock::GetCurrentTimePoint, "GetCurrentTimePoint"}, 92 {0, &ISteadyClock::GetCurrentTimePoint, "GetCurrentTimePoint"},
135 }; 93 };
136 RegisterHandlers(functions); 94 RegisterHandlers(functions);
137
138 shared_memory->SetStandardSteadyClockTimepoint(GetCurrentTimePoint());
139 } 95 }
140 96
141private: 97private:
142 void GetCurrentTimePoint(Kernel::HLERequestContext& ctx) { 98 void GetCurrentTimePoint(Kernel::HLERequestContext& ctx) {
143 LOG_DEBUG(Service_Time, "called"); 99 LOG_DEBUG(Service_Time, "called");
144 100
145 const auto time_point = GetCurrentTimePoint(); 101 if (!clock_core.IsInitialized()) {
146 // TODO(ogniK): This should be updated periodically 102 IPC::ResponseBuilder rb{ctx, 2};
147 shared_memory->SetStandardSteadyClockTimepoint(time_point); 103 rb.Push(ERROR_UNINITIALIZED_CLOCK);
104 return;
105 }
148 106
149 IPC::ResponseBuilder rb{ctx, (sizeof(SteadyClockTimePoint) / 4) + 2}; 107 const Clock::SteadyClockTimePoint time_point{
108 clock_core.GetCurrentTimePoint(Core::System::GetInstance())};
109 IPC::ResponseBuilder rb{ctx, (sizeof(Clock::SteadyClockTimePoint) / 4) + 2};
150 rb.Push(RESULT_SUCCESS); 110 rb.Push(RESULT_SUCCESS);
151 rb.PushRaw(time_point); 111 rb.PushRaw(time_point);
152 } 112 }
153 113
154 SteadyClockTimePoint GetCurrentTimePoint() const { 114 Clock::SteadyClockCore& clock_core;
155 const auto& core_timing = system.CoreTiming();
156 const auto ms = Core::Timing::CyclesToMs(core_timing.GetTicks());
157 return {static_cast<u64_le>(ms.count() / 1000), {}};
158 }
159
160 std::shared_ptr<SharedMemory> shared_memory;
161 Core::System& system;
162}; 115};
163 116
164class ITimeZoneService final : public ServiceFramework<ITimeZoneService> { 117ResultCode Module::Interface::GetClockSnapshotFromSystemClockContextInternal(
165public: 118 Kernel::Thread* thread, Clock::SystemClockContext user_context,
166 ITimeZoneService() : ServiceFramework("ITimeZoneService") { 119 Clock::SystemClockContext network_context, u8 type, Clock::ClockSnapshot& clock_snapshot) {
167 // clang-format off
168 static const FunctionInfo functions[] = {
169 {0, &ITimeZoneService::GetDeviceLocationName, "GetDeviceLocationName"},
170 {1, nullptr, "SetDeviceLocationName"},
171 {2, &ITimeZoneService::GetTotalLocationNameCount, "GetTotalLocationNameCount"},
172 {3, nullptr, "LoadLocationNameList"},
173 {4, &ITimeZoneService::LoadTimeZoneRule, "LoadTimeZoneRule"},
174 {5, nullptr, "GetTimeZoneRuleVersion"},
175 {6, nullptr, "GetDeviceLocationNameAndUpdatedTime"},
176 {7, nullptr, "SetDeviceLocationNameWithTimeZoneRule"},
177 {8, nullptr, "ParseTimeZoneBinary"},
178 {20, nullptr, "GetDeviceLocationNameOperationEventReadableHandle"},
179 {100, &ITimeZoneService::ToCalendarTime, "ToCalendarTime"},
180 {101, &ITimeZoneService::ToCalendarTimeWithMyRule, "ToCalendarTimeWithMyRule"},
181 {201, &ITimeZoneService::ToPosixTime, "ToPosixTime"},
182 {202, &ITimeZoneService::ToPosixTimeWithMyRule, "ToPosixTimeWithMyRule"},
183 };
184 // clang-format on
185
186 RegisterHandlers(functions);
187 }
188 120
189private: 121 auto& time_manager{module->GetTimeManager()};
190 LocationName location_name{"UTC"};
191 TimeZoneRule my_time_zone_rule{};
192 122
193 void GetDeviceLocationName(Kernel::HLERequestContext& ctx) { 123 clock_snapshot.is_automatic_correction_enabled =
194 LOG_DEBUG(Service_Time, "called"); 124 time_manager.GetStandardUserSystemClockCore().IsAutomaticCorrectionEnabled();
125 clock_snapshot.user_context = user_context;
126 clock_snapshot.network_context = network_context;
195 127
196 IPC::ResponseBuilder rb{ctx, (sizeof(LocationName) / 4) + 2}; 128 if (const ResultCode result{
197 rb.Push(RESULT_SUCCESS); 129 time_manager.GetTimeZoneContentManager().GetTimeZoneManager().GetDeviceLocationName(
198 rb.PushRaw(location_name); 130 clock_snapshot.location_name)};
131 result != RESULT_SUCCESS) {
132 return result;
199 } 133 }
200 134
201 void GetTotalLocationNameCount(Kernel::HLERequestContext& ctx) { 135 const auto current_time_point{
202 LOG_WARNING(Service_Time, "(STUBBED) called"); 136 time_manager.GetStandardSteadyClockCore().GetCurrentTimePoint(Core::System::GetInstance())};
203 137 if (const ResultCode result{Clock::ClockSnapshot::GetCurrentTime(
204 IPC::ResponseBuilder rb{ctx, 3}; 138 clock_snapshot.user_time, current_time_point, clock_snapshot.user_context)};
205 rb.Push(RESULT_SUCCESS); 139 result != RESULT_SUCCESS) {
206 rb.Push<u32>(0); 140 return result;
207 } 141 }
208 142
209 void LoadTimeZoneRule(Kernel::HLERequestContext& ctx) { 143 TimeZone::CalendarInfo userCalendarInfo{};
210 LOG_WARNING(Service_Time, "(STUBBED) called"); 144 if (const ResultCode result{
211 145 time_manager.GetTimeZoneContentManager().GetTimeZoneManager().ToCalendarTimeWithMyRules(
212 ctx.WriteBuffer(&my_time_zone_rule, sizeof(TimeZoneRule)); 146 clock_snapshot.user_time, userCalendarInfo)};
213 147 result != RESULT_SUCCESS) {
214 IPC::ResponseBuilder rb{ctx, 2}; 148 return result;
215 rb.Push(RESULT_SUCCESS);
216 } 149 }
217 150
218 void ToCalendarTime(Kernel::HLERequestContext& ctx) { 151 clock_snapshot.user_calendar_time = userCalendarInfo.time;
219 IPC::RequestParser rp{ctx}; 152 clock_snapshot.user_calendar_additional_time = userCalendarInfo.additiona_info;
220 const u64 posix_time = rp.Pop<u64>();
221 LOG_WARNING(Service_Time, "(STUBBED) called, posix_time=0x{:016X}", posix_time);
222
223 TimeZoneRule time_zone_rule{};
224 auto buffer = ctx.ReadBuffer();
225 std::memcpy(&time_zone_rule, buffer.data(), buffer.size());
226 153
227 CalendarTime calendar_time{2018, 1, 1, 0, 0, 0}; 154 if (Clock::ClockSnapshot::GetCurrentTime(clock_snapshot.network_time, current_time_point,
228 CalendarAdditionalInfo additional_info{}; 155 clock_snapshot.network_context) != RESULT_SUCCESS) {
229 156 clock_snapshot.network_time = 0;
230 PosixToCalendar(posix_time, calendar_time, additional_info, time_zone_rule);
231
232 IPC::ResponseBuilder rb{ctx, 10};
233 rb.Push(RESULT_SUCCESS);
234 rb.PushRaw(calendar_time);
235 rb.PushRaw(additional_info);
236 }
237
238 void ToCalendarTimeWithMyRule(Kernel::HLERequestContext& ctx) {
239 IPC::RequestParser rp{ctx};
240 const u64 posix_time = rp.Pop<u64>();
241 LOG_WARNING(Service_Time, "(STUBBED) called, posix_time=0x{:016X}", posix_time);
242
243 CalendarTime calendar_time{2018, 1, 1, 0, 0, 0};
244 CalendarAdditionalInfo additional_info{};
245
246 PosixToCalendar(posix_time, calendar_time, additional_info, my_time_zone_rule);
247
248 IPC::ResponseBuilder rb{ctx, 10};
249 rb.Push(RESULT_SUCCESS);
250 rb.PushRaw(calendar_time);
251 rb.PushRaw(additional_info);
252 } 157 }
253 158
254 void ToPosixTime(Kernel::HLERequestContext& ctx) { 159 TimeZone::CalendarInfo networkCalendarInfo{};
255 // TODO(ogniK): Figure out how to handle multiple times 160 if (const ResultCode result{
256 LOG_WARNING(Service_Time, "(STUBBED) called"); 161 time_manager.GetTimeZoneContentManager().GetTimeZoneManager().ToCalendarTimeWithMyRules(
257 162 clock_snapshot.network_time, networkCalendarInfo)};
258 IPC::RequestParser rp{ctx}; 163 result != RESULT_SUCCESS) {
259 auto calendar_time = rp.PopRaw<CalendarTime>(); 164 return result;
260 auto posix_time = CalendarToPosix(calendar_time, {});
261
262 IPC::ResponseBuilder rb{ctx, 3};
263 rb.Push(RESULT_SUCCESS);
264 rb.PushRaw<u32>(1); // Amount of times we're returning
265 ctx.WriteBuffer(&posix_time, sizeof(u64));
266 } 165 }
267 166
268 void ToPosixTimeWithMyRule(Kernel::HLERequestContext& ctx) { 167 clock_snapshot.network_calendar_time = networkCalendarInfo.time;
269 LOG_WARNING(Service_Time, "(STUBBED) called"); 168 clock_snapshot.network_calendar_additional_time = networkCalendarInfo.additiona_info;
270 169 clock_snapshot.type = type;
271 IPC::RequestParser rp{ctx};
272 auto calendar_time = rp.PopRaw<CalendarTime>();
273 auto posix_time = CalendarToPosix(calendar_time, {});
274 170
275 IPC::ResponseBuilder rb{ctx, 3}; 171 return RESULT_SUCCESS;
276 rb.Push(RESULT_SUCCESS); 172}
277 rb.PushRaw<u32>(1); // Amount of times we're returning
278 ctx.WriteBuffer(&posix_time, sizeof(u64));
279 }
280};
281 173
282void Module::Interface::GetStandardUserSystemClock(Kernel::HLERequestContext& ctx) { 174void Module::Interface::GetStandardUserSystemClock(Kernel::HLERequestContext& ctx) {
283 LOG_DEBUG(Service_Time, "called"); 175 LOG_DEBUG(Service_Time, "called");
284
285 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 176 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
286 rb.Push(RESULT_SUCCESS); 177 rb.Push(RESULT_SUCCESS);
287 rb.PushIpcInterface<ISystemClock>(shared_memory, ClockContextType::StandardUserSystem); 178 rb.PushIpcInterface<ISystemClock>(module->GetTimeManager().GetStandardUserSystemClockCore());
288} 179}
289 180
290void Module::Interface::GetStandardNetworkSystemClock(Kernel::HLERequestContext& ctx) { 181void Module::Interface::GetStandardNetworkSystemClock(Kernel::HLERequestContext& ctx) {
291 LOG_DEBUG(Service_Time, "called"); 182 LOG_DEBUG(Service_Time, "called");
292
293 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 183 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
294 rb.Push(RESULT_SUCCESS); 184 rb.Push(RESULT_SUCCESS);
295 rb.PushIpcInterface<ISystemClock>(shared_memory, ClockContextType::StandardNetworkSystem); 185 rb.PushIpcInterface<ISystemClock>(module->GetTimeManager().GetStandardNetworkSystemClockCore());
296} 186}
297 187
298void Module::Interface::GetStandardSteadyClock(Kernel::HLERequestContext& ctx) { 188void Module::Interface::GetStandardSteadyClock(Kernel::HLERequestContext& ctx) {
299 LOG_DEBUG(Service_Time, "called"); 189 LOG_DEBUG(Service_Time, "called");
300
301 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 190 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
302 rb.Push(RESULT_SUCCESS); 191 rb.Push(RESULT_SUCCESS);
303 rb.PushIpcInterface<ISteadyClock>(shared_memory, system); 192 rb.PushIpcInterface<ISteadyClock>(module->GetTimeManager().GetStandardSteadyClockCore());
304} 193}
305 194
306void Module::Interface::GetTimeZoneService(Kernel::HLERequestContext& ctx) { 195void Module::Interface::GetTimeZoneService(Kernel::HLERequestContext& ctx) {
307 LOG_DEBUG(Service_Time, "called"); 196 LOG_DEBUG(Service_Time, "called");
308
309 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 197 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
310 rb.Push(RESULT_SUCCESS); 198 rb.Push(RESULT_SUCCESS);
311 rb.PushIpcInterface<ITimeZoneService>(); 199 rb.PushIpcInterface<ITimeZoneService>(module->GetTimeManager().GetTimeZoneContentManager());
312} 200}
313 201
314void Module::Interface::GetStandardLocalSystemClock(Kernel::HLERequestContext& ctx) { 202void Module::Interface::GetStandardLocalSystemClock(Kernel::HLERequestContext& ctx) {
315 LOG_DEBUG(Service_Time, "called"); 203 LOG_DEBUG(Service_Time, "called");
316
317 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 204 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
318 rb.Push(RESULT_SUCCESS); 205 rb.Push(RESULT_SUCCESS);
319 rb.PushIpcInterface<ISystemClock>(shared_memory, ClockContextType::StandardLocalSystem); 206 rb.PushIpcInterface<ISystemClock>(module->GetTimeManager().GetStandardLocalSystemClockCore());
320} 207}
321 208
322void Module::Interface::GetClockSnapshot(Kernel::HLERequestContext& ctx) { 209void Module::Interface::IsStandardNetworkSystemClockAccuracySufficient(
210 Kernel::HLERequestContext& ctx) {
323 LOG_DEBUG(Service_Time, "called"); 211 LOG_DEBUG(Service_Time, "called");
212 auto& clock_core{module->GetTimeManager().GetStandardNetworkSystemClockCore()};
213 IPC::ResponseBuilder rb{ctx, 3};
214 rb.Push(RESULT_SUCCESS);
215 rb.Push<u32>(clock_core.IsStandardNetworkSystemClockAccuracySufficient(system));
216}
324 217
325 IPC::RequestParser rp{ctx}; 218void Module::Interface::CalculateMonotonicSystemClockBaseTimePoint(Kernel::HLERequestContext& ctx) {
326 const auto initial_type = rp.PopRaw<u8>(); 219 LOG_DEBUG(Service_Time, "called");
327 220
328 const s64 time_since_epoch{GetSecondsSinceEpoch().count()}; 221 auto& steady_clock_core{module->GetTimeManager().GetStandardSteadyClockCore()};
329 const std::time_t time(time_since_epoch); 222 if (!steady_clock_core.IsInitialized()) {
330 const std::tm* tm = std::localtime(&time);
331 if (tm == nullptr) {
332 LOG_ERROR(Service_Time, "tm is a nullptr");
333 IPC::ResponseBuilder rb{ctx, 2}; 223 IPC::ResponseBuilder rb{ctx, 2};
334 rb.Push(RESULT_UNKNOWN); // TODO(ogniK): Find appropriate error code 224 rb.Push(ERROR_UNINITIALIZED_CLOCK);
335 return; 225 return;
336 } 226 }
337 227
338 const auto& core_timing = system.CoreTiming(); 228 IPC::RequestParser rp{ctx};
339 const auto ms = Core::Timing::CyclesToMs(core_timing.GetTicks()); 229 const auto context{rp.PopRaw<Clock::SystemClockContext>()};
340 const SteadyClockTimePoint steady_clock_time_point{static_cast<u64_le>(ms.count() / 1000), {}}; 230 const auto current_time_point{
341 231 steady_clock_core.GetCurrentTimePoint(Core::System::GetInstance())};
342 CalendarTime calendar_time{}; 232
343 calendar_time.year = static_cast<u16_le>(tm->tm_year + 1900); 233 if (current_time_point.clock_source_id == context.steady_time_point.clock_source_id) {
344 calendar_time.month = static_cast<u8>(tm->tm_mon + 1); 234 const auto ticks{Clock::TimeSpanType::FromTicks(
345 calendar_time.day = static_cast<u8>(tm->tm_mday); 235 Core::Timing::CpuCyclesToClockCycles(system.CoreTiming().GetTicks()),
346 calendar_time.hour = static_cast<u8>(tm->tm_hour); 236 Core::Timing::CNTFREQ)};
347 calendar_time.minute = static_cast<u8>(tm->tm_min); 237 const s64 base_time_point{context.offset + current_time_point.time_point -
348 calendar_time.second = static_cast<u8>(tm->tm_sec); 238 ticks.ToSeconds()};
239 IPC::ResponseBuilder rb{ctx, (sizeof(s64) / 4) + 2};
240 rb.Push(RESULT_SUCCESS);
241 rb.PushRaw(base_time_point);
242 return;
243 }
349 244
350 ClockSnapshot clock_snapshot{}; 245 IPC::ResponseBuilder rb{ctx, 2};
351 clock_snapshot.system_posix_time = time_since_epoch; 246 rb.Push(ERROR_TIME_MISMATCH);
352 clock_snapshot.network_posix_time = time_since_epoch; 247}
353 clock_snapshot.system_calendar_time = calendar_time;
354 clock_snapshot.network_calendar_time = calendar_time;
355 248
356 CalendarAdditionalInfo additional_info{}; 249void Module::Interface::GetClockSnapshot(Kernel::HLERequestContext& ctx) {
357 PosixToCalendar(time_since_epoch, calendar_time, additional_info, {}); 250 LOG_DEBUG(Service_Time, "called");
251 IPC::RequestParser rp{ctx};
252 const auto type{rp.PopRaw<u8>()};
358 253
359 clock_snapshot.system_calendar_info = additional_info; 254 Clock::SystemClockContext user_context{};
360 clock_snapshot.network_calendar_info = additional_info; 255 if (const ResultCode result{
256 module->GetTimeManager().GetStandardUserSystemClockCore().GetClockContext(
257 Core::System::GetInstance(), user_context)};
258 result != RESULT_SUCCESS) {
259 IPC::ResponseBuilder rb{ctx, 2};
260 rb.Push(result);
261 return;
262 }
263 Clock::SystemClockContext network_context{};
264 if (const ResultCode result{
265 module->GetTimeManager().GetStandardNetworkSystemClockCore().GetClockContext(
266 Core::System::GetInstance(), network_context)};
267 result != RESULT_SUCCESS) {
268 IPC::ResponseBuilder rb{ctx, 2};
269 rb.Push(result);
270 return;
271 }
361 272
362 clock_snapshot.steady_clock_timepoint = steady_clock_time_point; 273 Clock::ClockSnapshot clock_snapshot{};
363 clock_snapshot.location_name = LocationName{"UTC"}; 274 if (const ResultCode result{GetClockSnapshotFromSystemClockContextInternal(
364 clock_snapshot.clock_auto_adjustment_enabled = 1; 275 &ctx.GetThread(), user_context, network_context, type, clock_snapshot)};
365 clock_snapshot.type = initial_type; 276 result != RESULT_SUCCESS) {
277 IPC::ResponseBuilder rb{ctx, 2};
278 rb.Push(result);
279 return;
280 }
366 281
367 IPC::ResponseBuilder rb{ctx, 2}; 282 IPC::ResponseBuilder rb{ctx, 2};
368 rb.Push(RESULT_SUCCESS); 283 rb.Push(RESULT_SUCCESS);
369 ctx.WriteBuffer(&clock_snapshot, sizeof(ClockSnapshot)); 284 ctx.WriteBuffer(&clock_snapshot, sizeof(Clock::ClockSnapshot));
370} 285}
371 286
372void Module::Interface::CalculateStandardUserSystemClockDifferenceByUser( 287void Module::Interface::GetClockSnapshotFromSystemClockContext(Kernel::HLERequestContext& ctx) {
373 Kernel::HLERequestContext& ctx) {
374 LOG_DEBUG(Service_Time, "called"); 288 LOG_DEBUG(Service_Time, "called");
375
376 IPC::RequestParser rp{ctx}; 289 IPC::RequestParser rp{ctx};
377 const auto snapshot_a = rp.PopRaw<ClockSnapshot>(); 290 const auto type{rp.PopRaw<u8>()};
378 const auto snapshot_b = rp.PopRaw<ClockSnapshot>(); 291 rp.AlignWithPadding();
379 const u64 difference = 292
380 snapshot_b.user_clock_context.offset - snapshot_a.user_clock_context.offset; 293 const Clock::SystemClockContext user_context{rp.PopRaw<Clock::SystemClockContext>()};
294 const Clock::SystemClockContext network_context{rp.PopRaw<Clock::SystemClockContext>()};
381 295
382 IPC::ResponseBuilder rb{ctx, 4}; 296 Clock::ClockSnapshot clock_snapshot{};
297 if (const ResultCode result{GetClockSnapshotFromSystemClockContextInternal(
298 &ctx.GetThread(), user_context, network_context, type, clock_snapshot)};
299 result != RESULT_SUCCESS) {
300 IPC::ResponseBuilder rb{ctx, 2};
301 rb.Push(result);
302 return;
303 }
304
305 IPC::ResponseBuilder rb{ctx, 2};
383 rb.Push(RESULT_SUCCESS); 306 rb.Push(RESULT_SUCCESS);
384 rb.PushRaw<u64>(difference); 307 ctx.WriteBuffer(&clock_snapshot, sizeof(Clock::ClockSnapshot));
385} 308}
386 309
387void Module::Interface::GetSharedMemoryNativeHandle(Kernel::HLERequestContext& ctx) { 310void Module::Interface::GetSharedMemoryNativeHandle(Kernel::HLERequestContext& ctx) {
388 LOG_DEBUG(Service_Time, "called"); 311 LOG_DEBUG(Service_Time, "called");
389 IPC::ResponseBuilder rb{ctx, 2, 1}; 312 IPC::ResponseBuilder rb{ctx, 2, 1};
390 rb.Push(RESULT_SUCCESS); 313 rb.Push(RESULT_SUCCESS);
391 rb.PushCopyObjects(shared_memory->GetSharedMemoryHolder()); 314 rb.PushCopyObjects(module->GetTimeManager().GetSharedMemory().GetSharedMemoryHolder());
392}
393
394void Module::Interface::IsStandardUserSystemClockAutomaticCorrectionEnabled(
395 Kernel::HLERequestContext& ctx) {
396 // ogniK(TODO): When clock contexts are implemented, the value should be read from the context
397 // instead of our shared memory holder
398 LOG_DEBUG(Service_Time, "called");
399
400 IPC::ResponseBuilder rb{ctx, 3};
401 rb.Push(RESULT_SUCCESS);
402 rb.Push<u8>(shared_memory->GetStandardUserSystemClockAutomaticCorrectionEnabled());
403}
404
405void Module::Interface::SetStandardUserSystemClockAutomaticCorrectionEnabled(
406 Kernel::HLERequestContext& ctx) {
407 IPC::RequestParser rp{ctx};
408 const auto enabled = rp.Pop<u8>();
409
410 LOG_WARNING(Service_Time, "(PARTIAL IMPLEMENTATION) called");
411
412 // TODO(ogniK): Update clock contexts and correct timespans
413
414 shared_memory->SetStandardUserSystemClockAutomaticCorrectionEnabled(enabled > 0);
415 IPC::ResponseBuilder rb{ctx, 2};
416 rb.Push(RESULT_SUCCESS);
417} 315}
418 316
419Module::Interface::Interface(std::shared_ptr<Module> time, 317Module::Interface::Interface(std::shared_ptr<Module> module, Core::System& system, const char* name)
420 std::shared_ptr<SharedMemory> shared_memory, Core::System& system, 318 : ServiceFramework(name), module{std::move(module)}, system{system} {}
421 const char* name)
422 : ServiceFramework(name), time(std::move(time)), shared_memory(std::move(shared_memory)),
423 system(system) {}
424 319
425Module::Interface::~Interface() = default; 320Module::Interface::~Interface() = default;
426 321
427void InstallInterfaces(Core::System& system) { 322void InstallInterfaces(Core::System& system) {
428 auto time = std::make_shared<Module>(); 323 auto module{std::make_shared<Module>(system)};
429 auto shared_mem = std::make_shared<SharedMemory>(system); 324 std::make_shared<Time>(module, system, "time:a")->InstallAsService(system.ServiceManager());
430 325 std::make_shared<Time>(module, system, "time:s")->InstallAsService(system.ServiceManager());
431 std::make_shared<Time>(time, shared_mem, system, "time:a") 326 std::make_shared<Time>(module, system, "time:u")->InstallAsService(system.ServiceManager());
432 ->InstallAsService(system.ServiceManager());
433 std::make_shared<Time>(time, shared_mem, system, "time:s")
434 ->InstallAsService(system.ServiceManager());
435 std::make_shared<Time>(std::move(time), shared_mem, system, "time:u")
436 ->InstallAsService(system.ServiceManager());
437} 327}
438 328
439} // namespace Service::Time 329} // namespace Service::Time
diff --git a/src/core/hle/service/time/time.h b/src/core/hle/service/time/time.h
index c32d32860..aadc2df60 100644
--- a/src/core/hle/service/time/time.h
+++ b/src/core/hle/service/time/time.h
@@ -4,84 +4,23 @@
4 4
5#pragma once 5#pragma once
6 6
7#include <array>
8#include "common/common_funcs.h"
9#include "core/hle/service/service.h" 7#include "core/hle/service/service.h"
8#include "core/hle/service/time/clock_types.h"
9#include "core/hle/service/time/time_manager.h"
10 10
11namespace Service::Time { 11namespace Core {
12 12class System;
13class SharedMemory; 13}
14
15struct LocationName {
16 std::array<u8, 0x24> name;
17};
18static_assert(sizeof(LocationName) == 0x24, "LocationName is incorrect size");
19
20struct CalendarTime {
21 u16_le year;
22 u8 month; // Starts at 1
23 u8 day; // Starts at 1
24 u8 hour;
25 u8 minute;
26 u8 second;
27};
28static_assert(sizeof(CalendarTime) == 0x8, "CalendarTime structure has incorrect size");
29
30struct CalendarAdditionalInfo {
31 u32_le day_of_week;
32 u32_le day_of_year;
33 std::array<u8, 8> name;
34 u8 is_dst;
35 s32_le utc_offset;
36};
37static_assert(sizeof(CalendarAdditionalInfo) == 0x18,
38 "CalendarAdditionalInfo structure has incorrect size");
39
40// TODO(mailwl) RE this structure
41struct TimeZoneRule {
42 INSERT_PADDING_BYTES(0x4000);
43};
44
45struct SteadyClockTimePoint {
46 using SourceID = std::array<u8, 16>;
47 14
48 u64_le value; 15namespace Service::Time {
49 SourceID source_id;
50};
51static_assert(sizeof(SteadyClockTimePoint) == 0x18, "SteadyClockTimePoint is incorrect size");
52
53struct SystemClockContext {
54 u64_le offset;
55 SteadyClockTimePoint time_point;
56};
57static_assert(sizeof(SystemClockContext) == 0x20,
58 "SystemClockContext structure has incorrect size");
59
60struct ClockSnapshot {
61 SystemClockContext user_clock_context;
62 SystemClockContext network_clock_context;
63 s64_le system_posix_time;
64 s64_le network_posix_time;
65 CalendarTime system_calendar_time;
66 CalendarTime network_calendar_time;
67 CalendarAdditionalInfo system_calendar_info;
68 CalendarAdditionalInfo network_calendar_info;
69 SteadyClockTimePoint steady_clock_timepoint;
70 LocationName location_name;
71 u8 clock_auto_adjustment_enabled;
72 u8 type;
73 u8 version;
74 INSERT_PADDING_BYTES(1);
75};
76static_assert(sizeof(ClockSnapshot) == 0xd0, "ClockSnapshot is an invalid size");
77 16
78class Module final { 17class Module final {
79public: 18public:
19 Module(Core::System& system) : time_manager{system} {}
20
80 class Interface : public ServiceFramework<Interface> { 21 class Interface : public ServiceFramework<Interface> {
81 public: 22 public:
82 explicit Interface(std::shared_ptr<Module> time, 23 explicit Interface(std::shared_ptr<Module> module, Core::System& system, const char* name);
83 std::shared_ptr<SharedMemory> shared_memory, Core::System& system,
84 const char* name);
85 ~Interface() override; 24 ~Interface() override;
86 25
87 void GetStandardUserSystemClock(Kernel::HLERequestContext& ctx); 26 void GetStandardUserSystemClock(Kernel::HLERequestContext& ctx);
@@ -89,17 +28,29 @@ public:
89 void GetStandardSteadyClock(Kernel::HLERequestContext& ctx); 28 void GetStandardSteadyClock(Kernel::HLERequestContext& ctx);
90 void GetTimeZoneService(Kernel::HLERequestContext& ctx); 29 void GetTimeZoneService(Kernel::HLERequestContext& ctx);
91 void GetStandardLocalSystemClock(Kernel::HLERequestContext& ctx); 30 void GetStandardLocalSystemClock(Kernel::HLERequestContext& ctx);
31 void IsStandardNetworkSystemClockAccuracySufficient(Kernel::HLERequestContext& ctx);
32 void CalculateMonotonicSystemClockBaseTimePoint(Kernel::HLERequestContext& ctx);
92 void GetClockSnapshot(Kernel::HLERequestContext& ctx); 33 void GetClockSnapshot(Kernel::HLERequestContext& ctx);
93 void CalculateStandardUserSystemClockDifferenceByUser(Kernel::HLERequestContext& ctx); 34 void GetClockSnapshotFromSystemClockContext(Kernel::HLERequestContext& ctx);
94 void GetSharedMemoryNativeHandle(Kernel::HLERequestContext& ctx); 35 void GetSharedMemoryNativeHandle(Kernel::HLERequestContext& ctx);
95 void IsStandardUserSystemClockAutomaticCorrectionEnabled(Kernel::HLERequestContext& ctx); 36
96 void SetStandardUserSystemClockAutomaticCorrectionEnabled(Kernel::HLERequestContext& ctx); 37 private:
38 ResultCode GetClockSnapshotFromSystemClockContextInternal(
39 Kernel::Thread* thread, Clock::SystemClockContext user_context,
40 Clock::SystemClockContext network_context, u8 type,
41 Clock::ClockSnapshot& cloc_snapshot);
97 42
98 protected: 43 protected:
99 std::shared_ptr<Module> time; 44 std::shared_ptr<Module> module;
100 std::shared_ptr<SharedMemory> shared_memory;
101 Core::System& system; 45 Core::System& system;
102 }; 46 };
47
48 TimeManager& GetTimeManager() {
49 return time_manager;
50 }
51
52private:
53 TimeManager time_manager;
103}; 54};
104 55
105/// Registers all Time services with the specified service manager. 56/// Registers all Time services with the specified service manager.
diff --git a/src/core/hle/service/time/time_manager.cpp b/src/core/hle/service/time/time_manager.cpp
new file mode 100644
index 000000000..9d6c55865
--- /dev/null
+++ b/src/core/hle/service/time/time_manager.cpp
@@ -0,0 +1,137 @@
1// Copyright 2019 yuzu emulator team
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include <chrono>
6#include <ctime>
7
8#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/network_system_clock_context_writer.h"
11#include "core/hle/service/time/time_manager.h"
12#include "core/settings.h"
13
14namespace Service::Time {
15
16constexpr Clock::TimeSpanType standard_network_clock_accuracy{0x0009356907420000ULL};
17
18static std::chrono::seconds GetSecondsSinceEpoch() {
19 return std::chrono::duration_cast<std::chrono::seconds>(
20 std::chrono::system_clock::now().time_since_epoch()) +
21 Settings::values.custom_rtc_differential;
22}
23
24static s64 GetExternalRtcValue() {
25 return GetSecondsSinceEpoch().count();
26}
27
28TimeManager::TimeManager(Core::System& system)
29 : shared_memory{system}, standard_local_system_clock_core{standard_steady_clock_core},
30 standard_network_system_clock_core{standard_steady_clock_core},
31 standard_user_system_clock_core{standard_local_system_clock_core,
32 standard_network_system_clock_core, system},
33 ephemeral_network_system_clock_core{tick_based_steady_clock_core},
34 local_system_clock_context_writer{
35 std::make_shared<Clock::LocalSystemClockContextWriter>(shared_memory)},
36 network_system_clock_context_writer{
37 std::make_shared<Clock::NetworkSystemClockContextWriter>(shared_memory)},
38 ephemeral_network_system_clock_context_writer{
39 std::make_shared<Clock::EphemeralNetworkSystemClockContextWriter>()},
40 time_zone_content_manager{*this, system} {
41
42 const auto system_time{Clock::TimeSpanType::FromSeconds(GetExternalRtcValue())};
43 SetupStandardSteadyClock(system, Common::UUID::Generate(), system_time, {}, {});
44 SetupStandardLocalSystemClock(system, {}, system_time.ToSeconds());
45 SetupStandardNetworkSystemClock({}, standard_network_clock_accuracy);
46 SetupStandardUserSystemClock(system, {}, Clock::SteadyClockTimePoint::GetRandom());
47 SetupEphemeralNetworkSystemClock();
48}
49
50TimeManager::~TimeManager() = default;
51
52void TimeManager::SetupTimeZoneManager(std::string location_name,
53 Clock::SteadyClockTimePoint time_zone_updated_time_point,
54 std::size_t total_location_name_count,
55 u128 time_zone_rule_version,
56 FileSys::VirtualFile& vfs_file) {
57 if (time_zone_content_manager.GetTimeZoneManager().SetDeviceLocationNameWithTimeZoneRule(
58 location_name, vfs_file) != RESULT_SUCCESS) {
59 UNREACHABLE();
60 return;
61 }
62
63 time_zone_content_manager.GetTimeZoneManager().SetUpdatedTime(time_zone_updated_time_point);
64 time_zone_content_manager.GetTimeZoneManager().SetTotalLocationNameCount(
65 total_location_name_count);
66 time_zone_content_manager.GetTimeZoneManager().SetTimeZoneRuleVersion(time_zone_rule_version);
67 time_zone_content_manager.GetTimeZoneManager().MarkAsInitialized();
68}
69
70void TimeManager::SetupStandardSteadyClock(Core::System& system, Common::UUID clock_source_id,
71 Clock::TimeSpanType setup_value,
72 Clock::TimeSpanType internal_offset,
73 bool is_rtc_reset_detected) {
74 standard_steady_clock_core.SetClockSourceId(clock_source_id);
75 standard_steady_clock_core.SetSetupValue(setup_value);
76 standard_steady_clock_core.SetInternalOffset(internal_offset);
77 standard_steady_clock_core.MarkAsInitialized();
78
79 const auto current_time_point{standard_steady_clock_core.GetCurrentRawTimePoint(system)};
80 shared_memory.SetupStandardSteadyClock(system, clock_source_id, current_time_point);
81}
82
83void TimeManager::SetupStandardLocalSystemClock(Core::System& system,
84 Clock::SystemClockContext clock_context,
85 s64 posix_time) {
86 standard_local_system_clock_core.SetUpdateCallbackInstance(local_system_clock_context_writer);
87
88 const auto current_time_point{
89 standard_local_system_clock_core.GetSteadyClockCore().GetCurrentTimePoint(system)};
90 if (current_time_point.clock_source_id == clock_context.steady_time_point.clock_source_id) {
91 standard_local_system_clock_core.SetSystemClockContext(clock_context);
92 } else {
93 if (standard_local_system_clock_core.SetCurrentTime(system, posix_time) != RESULT_SUCCESS) {
94 UNREACHABLE();
95 return;
96 }
97 }
98
99 standard_local_system_clock_core.MarkAsInitialized();
100}
101
102void TimeManager::SetupStandardNetworkSystemClock(Clock::SystemClockContext clock_context,
103 Clock::TimeSpanType sufficient_accuracy) {
104 standard_network_system_clock_core.SetUpdateCallbackInstance(
105 network_system_clock_context_writer);
106
107 if (standard_network_system_clock_core.SetSystemClockContext(clock_context) != RESULT_SUCCESS) {
108 UNREACHABLE();
109 return;
110 }
111
112 standard_network_system_clock_core.SetStandardNetworkClockSufficientAccuracy(
113 sufficient_accuracy);
114 standard_network_system_clock_core.MarkAsInitialized();
115}
116
117void TimeManager::SetupStandardUserSystemClock(
118 Core::System& system, bool is_automatic_correction_enabled,
119 Clock::SteadyClockTimePoint steady_clock_time_point) {
120 if (standard_user_system_clock_core.SetAutomaticCorrectionEnabled(
121 system, is_automatic_correction_enabled) != RESULT_SUCCESS) {
122 UNREACHABLE();
123 return;
124 }
125
126 standard_user_system_clock_core.SetAutomaticCorrectionUpdatedTime(steady_clock_time_point);
127 standard_user_system_clock_core.MarkAsInitialized();
128 shared_memory.SetAutomaticCorrectionEnabled(is_automatic_correction_enabled);
129}
130
131void TimeManager::SetupEphemeralNetworkSystemClock() {
132 ephemeral_network_system_clock_core.SetUpdateCallbackInstance(
133 ephemeral_network_system_clock_context_writer);
134 ephemeral_network_system_clock_core.MarkAsInitialized();
135}
136
137} // namespace Service::Time
diff --git a/src/core/hle/service/time/time_manager.h b/src/core/hle/service/time/time_manager.h
new file mode 100644
index 000000000..8e65f0d22
--- /dev/null
+++ b/src/core/hle/service/time/time_manager.h
@@ -0,0 +1,117 @@
1// Copyright 2019 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 "common/common_types.h"
8#include "core/file_sys/vfs_types.h"
9#include "core/hle/service/time/clock_types.h"
10#include "core/hle/service/time/ephemeral_network_system_clock_core.h"
11#include "core/hle/service/time/standard_local_system_clock_core.h"
12#include "core/hle/service/time/standard_network_system_clock_core.h"
13#include "core/hle/service/time/standard_steady_clock_core.h"
14#include "core/hle/service/time/standard_user_system_clock_core.h"
15#include "core/hle/service/time/tick_based_steady_clock_core.h"
16#include "core/hle/service/time/time_sharedmemory.h"
17#include "core/hle/service/time/time_zone_content_manager.h"
18
19namespace Service::Time {
20
21namespace Clock {
22class EphemeralNetworkSystemClockContextWriter;
23class LocalSystemClockContextWriter;
24class NetworkSystemClockContextWriter;
25} // namespace Clock
26
27// Parts of this implementation were based on Ryujinx (https://github.com/Ryujinx/Ryujinx/pull/783).
28// This code was released under public domain.
29
30class TimeManager final {
31public:
32 explicit TimeManager(Core::System& system);
33 ~TimeManager();
34
35 Clock::StandardSteadyClockCore& GetStandardSteadyClockCore() {
36 return standard_steady_clock_core;
37 }
38
39 const Clock::StandardSteadyClockCore& GetStandardSteadyClockCore() const {
40 return standard_steady_clock_core;
41 }
42
43 Clock::StandardLocalSystemClockCore& GetStandardLocalSystemClockCore() {
44 return standard_local_system_clock_core;
45 }
46
47 const Clock::StandardLocalSystemClockCore& GetStandardLocalSystemClockCore() const {
48 return standard_local_system_clock_core;
49 }
50
51 Clock::StandardNetworkSystemClockCore& GetStandardNetworkSystemClockCore() {
52 return standard_network_system_clock_core;
53 }
54
55 const Clock::StandardNetworkSystemClockCore& GetStandardNetworkSystemClockCore() const {
56 return standard_network_system_clock_core;
57 }
58
59 Clock::StandardUserSystemClockCore& GetStandardUserSystemClockCore() {
60 return standard_user_system_clock_core;
61 }
62
63 const Clock::StandardUserSystemClockCore& GetStandardUserSystemClockCore() const {
64 return standard_user_system_clock_core;
65 }
66
67 TimeZone::TimeZoneContentManager& GetTimeZoneContentManager() {
68 return time_zone_content_manager;
69 }
70
71 const TimeZone::TimeZoneContentManager& GetTimeZoneContentManager() const {
72 return time_zone_content_manager;
73 }
74
75 SharedMemory& GetSharedMemory() {
76 return shared_memory;
77 }
78
79 const SharedMemory& GetSharedMemory() const {
80 return shared_memory;
81 }
82
83 void SetupTimeZoneManager(std::string location_name,
84 Clock::SteadyClockTimePoint time_zone_updated_time_point,
85 std::size_t total_location_name_count, u128 time_zone_rule_version,
86 FileSys::VirtualFile& vfs_file);
87
88private:
89 void SetupStandardSteadyClock(Core::System& system, Common::UUID clock_source_id,
90 Clock::TimeSpanType setup_value,
91 Clock::TimeSpanType internal_offset, bool is_rtc_reset_detected);
92 void SetupStandardLocalSystemClock(Core::System& system,
93 Clock::SystemClockContext clock_context, s64 posix_time);
94 void SetupStandardNetworkSystemClock(Clock::SystemClockContext clock_context,
95 Clock::TimeSpanType sufficient_accuracy);
96 void SetupStandardUserSystemClock(Core::System& system, bool is_automatic_correction_enabled,
97 Clock::SteadyClockTimePoint steady_clock_time_point);
98 void SetupEphemeralNetworkSystemClock();
99
100 SharedMemory shared_memory;
101
102 Clock::StandardSteadyClockCore standard_steady_clock_core;
103 Clock::TickBasedSteadyClockCore tick_based_steady_clock_core;
104 Clock::StandardLocalSystemClockCore standard_local_system_clock_core;
105 Clock::StandardNetworkSystemClockCore standard_network_system_clock_core;
106 Clock::StandardUserSystemClockCore standard_user_system_clock_core;
107 Clock::EphemeralNetworkSystemClockCore ephemeral_network_system_clock_core;
108
109 std::shared_ptr<Clock::LocalSystemClockContextWriter> local_system_clock_context_writer;
110 std::shared_ptr<Clock::NetworkSystemClockContextWriter> network_system_clock_context_writer;
111 std::shared_ptr<Clock::EphemeralNetworkSystemClockContextWriter>
112 ephemeral_network_system_clock_context_writer;
113
114 TimeZone::TimeZoneContentManager time_zone_content_manager;
115};
116
117} // namespace Service::Time
diff --git a/src/core/hle/service/time/time_sharedmemory.cpp b/src/core/hle/service/time/time_sharedmemory.cpp
index 4035f5072..9b03191bf 100644
--- a/src/core/hle/service/time/time_sharedmemory.cpp
+++ b/src/core/hle/service/time/time_sharedmemory.cpp
@@ -3,20 +3,21 @@
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include "core/core.h" 5#include "core/core.h"
6#include "core/core_timing.h"
7#include "core/core_timing_util.h"
8#include "core/hle/service/time/clock_types.h"
9#include "core/hle/service/time/steady_clock_core.h"
6#include "core/hle/service/time/time_sharedmemory.h" 10#include "core/hle/service/time/time_sharedmemory.h"
7 11
8namespace Service::Time { 12namespace Service::Time {
9const std::size_t SHARED_MEMORY_SIZE = 0x1000; 13
14static constexpr std::size_t SHARED_MEMORY_SIZE{0x1000};
10 15
11SharedMemory::SharedMemory(Core::System& system) : system(system) { 16SharedMemory::SharedMemory(Core::System& system) : system(system) {
12 shared_memory_holder = Kernel::SharedMemory::Create( 17 shared_memory_holder = Kernel::SharedMemory::Create(
13 system.Kernel(), nullptr, SHARED_MEMORY_SIZE, Kernel::MemoryPermission::ReadWrite, 18 system.Kernel(), nullptr, SHARED_MEMORY_SIZE, Kernel::MemoryPermission::ReadWrite,
14 Kernel::MemoryPermission::Read, 0, Kernel::MemoryRegion::BASE, "Time:SharedMemory"); 19 Kernel::MemoryPermission::Read, 0, Kernel::MemoryRegion::BASE, "Time:SharedMemory");
15 20 std::memset(shared_memory_holder->GetPointer(), 0, SHARED_MEMORY_SIZE);
16 // Seems static from 1.0.0 -> 8.1.0. Specific games seem to check this value and crash
17 // if it's set to anything else
18 shared_memory_format.format_version = 14;
19 std::memcpy(shared_memory_holder->GetPointer(), &shared_memory_format, sizeof(Format));
20} 21}
21 22
22SharedMemory::~SharedMemory() = default; 23SharedMemory::~SharedMemory() = default;
@@ -25,44 +26,32 @@ std::shared_ptr<Kernel::SharedMemory> SharedMemory::GetSharedMemoryHolder() cons
25 return shared_memory_holder; 26 return shared_memory_holder;
26} 27}
27 28
28void SharedMemory::SetStandardSteadyClockTimepoint(const SteadyClockTimePoint& timepoint) { 29void SharedMemory::SetupStandardSteadyClock(Core::System& system,
30 const Common::UUID& clock_source_id,
31 Clock::TimeSpanType current_time_point) {
32 const Clock::TimeSpanType ticks_time_span{Clock::TimeSpanType::FromTicks(
33 Core::Timing::CpuCyclesToClockCycles(system.CoreTiming().GetTicks()),
34 Core::Timing::CNTFREQ)};
35 const Clock::SteadyClockContext context{
36 static_cast<u64>(current_time_point.nanoseconds - ticks_time_span.nanoseconds),
37 clock_source_id};
29 shared_memory_format.standard_steady_clock_timepoint.StoreData( 38 shared_memory_format.standard_steady_clock_timepoint.StoreData(
30 shared_memory_holder->GetPointer(), timepoint); 39 shared_memory_holder->GetPointer(), context);
31} 40}
32 41
33void SharedMemory::SetStandardLocalSystemClockContext(const SystemClockContext& context) { 42void SharedMemory::UpdateLocalSystemClockContext(const Clock::SystemClockContext& context) {
34 shared_memory_format.standard_local_system_clock_context.StoreData( 43 shared_memory_format.standard_local_system_clock_context.StoreData(
35 shared_memory_holder->GetPointer(), context); 44 shared_memory_holder->GetPointer(), context);
36} 45}
37 46
38void SharedMemory::SetStandardNetworkSystemClockContext(const SystemClockContext& context) { 47void SharedMemory::UpdateNetworkSystemClockContext(const Clock::SystemClockContext& context) {
39 shared_memory_format.standard_network_system_clock_context.StoreData( 48 shared_memory_format.standard_network_system_clock_context.StoreData(
40 shared_memory_holder->GetPointer(), context); 49 shared_memory_holder->GetPointer(), context);
41} 50}
42 51
43void SharedMemory::SetStandardUserSystemClockAutomaticCorrectionEnabled(bool enabled) { 52void SharedMemory::SetAutomaticCorrectionEnabled(bool is_enabled) {
44 shared_memory_format.standard_user_system_clock_automatic_correction.StoreData( 53 shared_memory_format.standard_user_system_clock_automatic_correction.StoreData(
45 shared_memory_holder->GetPointer(), enabled); 54 shared_memory_holder->GetPointer(), is_enabled);
46}
47
48SteadyClockTimePoint SharedMemory::GetStandardSteadyClockTimepoint() {
49 return shared_memory_format.standard_steady_clock_timepoint.ReadData(
50 shared_memory_holder->GetPointer());
51}
52
53SystemClockContext SharedMemory::GetStandardLocalSystemClockContext() {
54 return shared_memory_format.standard_local_system_clock_context.ReadData(
55 shared_memory_holder->GetPointer());
56}
57
58SystemClockContext SharedMemory::GetStandardNetworkSystemClockContext() {
59 return shared_memory_format.standard_network_system_clock_context.ReadData(
60 shared_memory_holder->GetPointer());
61}
62
63bool SharedMemory::GetStandardUserSystemClockAutomaticCorrectionEnabled() {
64 return shared_memory_format.standard_user_system_clock_automatic_correction.ReadData(
65 shared_memory_holder->GetPointer());
66} 55}
67 56
68} // namespace Service::Time 57} // namespace Service::Time
diff --git a/src/core/hle/service/time/time_sharedmemory.h b/src/core/hle/service/time/time_sharedmemory.h
index 904a96430..5976b2046 100644
--- a/src/core/hle/service/time/time_sharedmemory.h
+++ b/src/core/hle/service/time/time_sharedmemory.h
@@ -5,11 +5,14 @@
5#pragma once 5#pragma once
6 6
7#include "common/common_types.h" 7#include "common/common_types.h"
8#include "common/uuid.h"
8#include "core/hle/kernel/shared_memory.h" 9#include "core/hle/kernel/shared_memory.h"
9#include "core/hle/service/time/time.h" 10#include "core/hle/kernel/thread.h"
11#include "core/hle/service/time/clock_types.h"
10 12
11namespace Service::Time { 13namespace Service::Time {
12class SharedMemory { 14
15class SharedMemory final {
13public: 16public:
14 explicit SharedMemory(Core::System& system); 17 explicit SharedMemory(Core::System& system);
15 ~SharedMemory(); 18 ~SharedMemory();
@@ -17,22 +20,10 @@ public:
17 // Return the shared memory handle 20 // Return the shared memory handle
18 std::shared_ptr<Kernel::SharedMemory> GetSharedMemoryHolder() const; 21 std::shared_ptr<Kernel::SharedMemory> GetSharedMemoryHolder() const;
19 22
20 // Set memory barriers in shared memory and update them
21 void SetStandardSteadyClockTimepoint(const SteadyClockTimePoint& timepoint);
22 void SetStandardLocalSystemClockContext(const SystemClockContext& context);
23 void SetStandardNetworkSystemClockContext(const SystemClockContext& context);
24 void SetStandardUserSystemClockAutomaticCorrectionEnabled(bool enabled);
25
26 // Pull from memory barriers in the shared memory
27 SteadyClockTimePoint GetStandardSteadyClockTimepoint();
28 SystemClockContext GetStandardLocalSystemClockContext();
29 SystemClockContext GetStandardNetworkSystemClockContext();
30 bool GetStandardUserSystemClockAutomaticCorrectionEnabled();
31
32 // TODO(ogniK): We have to properly simulate memory barriers, how are we going to do this? 23 // TODO(ogniK): We have to properly simulate memory barriers, how are we going to do this?
33 template <typename T, std::size_t Offset> 24 template <typename T, std::size_t Offset>
34 struct MemoryBarrier { 25 struct MemoryBarrier {
35 static_assert(std::is_trivially_constructible_v<T>, "T must be trivially constructable"); 26 static_assert(std::is_trivially_copyable_v<T>, "T must be trivially copyable");
36 u32_le read_attempt{}; 27 u32_le read_attempt{};
37 std::array<T, 2> data{}; 28 std::array<T, 2> data{};
38 29
@@ -57,16 +48,22 @@ public:
57 48
58 // Shared memory format 49 // Shared memory format
59 struct Format { 50 struct Format {
60 MemoryBarrier<SteadyClockTimePoint, 0x0> standard_steady_clock_timepoint; 51 MemoryBarrier<Clock::SteadyClockContext, 0x0> standard_steady_clock_timepoint;
61 MemoryBarrier<SystemClockContext, 0x38> standard_local_system_clock_context; 52 MemoryBarrier<Clock::SystemClockContext, 0x38> standard_local_system_clock_context;
62 MemoryBarrier<SystemClockContext, 0x80> standard_network_system_clock_context; 53 MemoryBarrier<Clock::SystemClockContext, 0x80> standard_network_system_clock_context;
63 MemoryBarrier<bool, 0xc8> standard_user_system_clock_automatic_correction; 54 MemoryBarrier<bool, 0xc8> standard_user_system_clock_automatic_correction;
64 u32_le format_version; 55 u32_le format_version;
65 }; 56 };
66 static_assert(sizeof(Format) == 0xd8, "Format is an invalid size"); 57 static_assert(sizeof(Format) == 0xd8, "Format is an invalid size");
67 58
59 void SetupStandardSteadyClock(Core::System& system, const Common::UUID& clock_source_id,
60 Clock::TimeSpanType currentTimePoint);
61 void UpdateLocalSystemClockContext(const Clock::SystemClockContext& context);
62 void UpdateNetworkSystemClockContext(const Clock::SystemClockContext& context);
63 void SetAutomaticCorrectionEnabled(bool is_enabled);
64
68private: 65private:
69 std::shared_ptr<Kernel::SharedMemory> shared_memory_holder{}; 66 std::shared_ptr<Kernel::SharedMemory> shared_memory_holder;
70 Core::System& system; 67 Core::System& system;
71 Format shared_memory_format{}; 68 Format shared_memory_format{};
72}; 69};
diff --git a/src/core/hle/service/time/time_zone_content_manager.cpp b/src/core/hle/service/time/time_zone_content_manager.cpp
new file mode 100644
index 000000000..57b1a2bca
--- /dev/null
+++ b/src/core/hle/service/time/time_zone_content_manager.cpp
@@ -0,0 +1,125 @@
1// Copyright 2019 yuzu emulator team
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include <sstream>
6
7#include "common/logging/log.h"
8#include "core/core.h"
9#include "core/file_sys/content_archive.h"
10#include "core/file_sys/nca_metadata.h"
11#include "core/file_sys/registered_cache.h"
12#include "core/file_sys/romfs.h"
13#include "core/file_sys/system_archive/system_archive.h"
14#include "core/hle/service/filesystem/filesystem.h"
15#include "core/hle/service/time/time_manager.h"
16#include "core/hle/service/time/time_zone_content_manager.h"
17
18namespace Service::Time::TimeZone {
19
20constexpr u64 time_zone_binary_titleid{0x010000000000080E};
21
22static FileSys::VirtualDir GetTimeZoneBinary(Core::System& system) {
23 const auto* nand{system.GetFileSystemController().GetSystemNANDContents()};
24 const auto nca{nand->GetEntry(time_zone_binary_titleid, FileSys::ContentRecordType::Data)};
25
26 FileSys::VirtualFile romfs;
27 if (nca) {
28 romfs = nca->GetRomFS();
29 }
30
31 if (!romfs) {
32 romfs = FileSys::SystemArchive::SynthesizeSystemArchive(time_zone_binary_titleid);
33 }
34
35 if (!romfs) {
36 LOG_ERROR(Service_Time, "Failed to find or synthesize {:016X!}", time_zone_binary_titleid);
37 return {};
38 }
39
40 return FileSys::ExtractRomFS(romfs);
41}
42
43static std::vector<std::string> BuildLocationNameCache(Core::System& system) {
44 const FileSys::VirtualDir extracted_romfs{GetTimeZoneBinary(system)};
45 if (!extracted_romfs) {
46 LOG_ERROR(Service_Time, "Failed to extract RomFS for {:016X}!", time_zone_binary_titleid);
47 return {};
48 }
49
50 const FileSys::VirtualFile binary_list{extracted_romfs->GetFile("binaryList.txt")};
51 if (!binary_list) {
52 LOG_ERROR(Service_Time, "{:016X} has no file binaryList.txt!", time_zone_binary_titleid);
53 return {};
54 }
55
56 std::vector<char> raw_data(binary_list->GetSize());
57 binary_list->ReadBytes<char>(raw_data.data(), binary_list->GetSize());
58
59 std::stringstream data_stream{raw_data.data()};
60 std::string name;
61 std::vector<std::string> location_name_cache;
62 while (std::getline(data_stream, name)) {
63 name.pop_back(); // Remove carriage return
64 location_name_cache.emplace_back(std::move(name));
65 }
66 return location_name_cache;
67}
68
69TimeZoneContentManager::TimeZoneContentManager(TimeManager& time_manager, Core::System& system)
70 : system{system}, location_name_cache{BuildLocationNameCache(system)} {
71 if (FileSys::VirtualFile vfs_file; GetTimeZoneInfoFile("GMT", vfs_file) == RESULT_SUCCESS) {
72 const auto time_point{
73 time_manager.GetStandardSteadyClockCore().GetCurrentTimePoint(system)};
74 time_manager.SetupTimeZoneManager("GMT", time_point, location_name_cache.size(), {},
75 vfs_file);
76 } else {
77 time_zone_manager.MarkAsInitialized();
78 }
79}
80
81ResultCode TimeZoneContentManager::LoadTimeZoneRule(TimeZoneRule& rules,
82 const std::string& location_name) const {
83 FileSys::VirtualFile vfs_file;
84 if (const ResultCode result{GetTimeZoneInfoFile(location_name, vfs_file)};
85 result != RESULT_SUCCESS) {
86 return result;
87 }
88
89 return time_zone_manager.ParseTimeZoneRuleBinary(rules, vfs_file);
90}
91
92bool TimeZoneContentManager::IsLocationNameValid(const std::string& location_name) const {
93 return std::find(location_name_cache.begin(), location_name_cache.end(), location_name) !=
94 location_name_cache.end();
95}
96
97ResultCode TimeZoneContentManager::GetTimeZoneInfoFile(const std::string& location_name,
98 FileSys::VirtualFile& vfs_file) const {
99 if (!IsLocationNameValid(location_name)) {
100 return ERROR_TIME_NOT_FOUND;
101 }
102
103 const FileSys::VirtualDir extracted_romfs{GetTimeZoneBinary(system)};
104 if (!extracted_romfs) {
105 LOG_ERROR(Service_Time, "Failed to extract RomFS for {:016X}!", time_zone_binary_titleid);
106 return ERROR_TIME_NOT_FOUND;
107 }
108
109 const FileSys::VirtualDir zoneinfo_dir{extracted_romfs->GetSubdirectory("zoneinfo")};
110 if (!zoneinfo_dir) {
111 LOG_ERROR(Service_Time, "{:016X} has no directory zoneinfo!", time_zone_binary_titleid);
112 return ERROR_TIME_NOT_FOUND;
113 }
114
115 vfs_file = zoneinfo_dir->GetFile(location_name);
116 if (!vfs_file) {
117 LOG_ERROR(Service_Time, "{:016X} has no file \"{}\"!", time_zone_binary_titleid,
118 location_name);
119 return ERROR_TIME_NOT_FOUND;
120 }
121
122 return RESULT_SUCCESS;
123}
124
125} // namespace Service::Time::TimeZone
diff --git a/src/core/hle/service/time/time_zone_content_manager.h b/src/core/hle/service/time/time_zone_content_manager.h
new file mode 100644
index 000000000..4f302c3b9
--- /dev/null
+++ b/src/core/hle/service/time/time_zone_content_manager.h
@@ -0,0 +1,46 @@
1// Copyright 2019 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 <string>
8#include <vector>
9
10#include "core/hle/service/time/time_zone_manager.h"
11
12namespace Core {
13class System;
14}
15
16namespace Service::Time {
17class TimeManager;
18}
19
20namespace Service::Time::TimeZone {
21
22class TimeZoneContentManager final {
23public:
24 TimeZoneContentManager(TimeManager& time_manager, Core::System& system);
25
26 TimeZoneManager& GetTimeZoneManager() {
27 return time_zone_manager;
28 }
29
30 const TimeZoneManager& GetTimeZoneManager() const {
31 return time_zone_manager;
32 }
33
34 ResultCode LoadTimeZoneRule(TimeZoneRule& rules, const std::string& location_name) const;
35
36private:
37 bool IsLocationNameValid(const std::string& location_name) const;
38 ResultCode GetTimeZoneInfoFile(const std::string& location_name,
39 FileSys::VirtualFile& vfs_file) const;
40
41 Core::System& system;
42 TimeZoneManager time_zone_manager;
43 const std::vector<std::string> location_name_cache;
44};
45
46} // namespace Service::Time::TimeZone
diff --git a/src/core/hle/service/time/time_zone_manager.cpp b/src/core/hle/service/time/time_zone_manager.cpp
new file mode 100644
index 000000000..4db6d7ad3
--- /dev/null
+++ b/src/core/hle/service/time/time_zone_manager.cpp
@@ -0,0 +1,1030 @@
1// Copyright 2019 yuzu emulator team
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include <climits>
6
7#include "common/assert.h"
8#include "common/logging/log.h"
9#include "core/file_sys/content_archive.h"
10#include "core/file_sys/nca_metadata.h"
11#include "core/file_sys/registered_cache.h"
12#include "core/file_sys/romfs.h"
13#include "core/file_sys/system_archive/system_archive.h"
14#include "core/hle/service/time/time_zone_manager.h"
15
16namespace Service::Time::TimeZone {
17
18static constexpr s32 epoch_year{1970};
19static constexpr s32 year_base{1900};
20static constexpr s32 epoch_week_day{4};
21static constexpr s32 seconds_per_minute{60};
22static constexpr s32 minutes_per_hour{60};
23static constexpr s32 hours_per_day{24};
24static constexpr s32 days_per_week{7};
25static constexpr s32 days_per_normal_year{365};
26static constexpr s32 days_per_leap_year{366};
27static constexpr s32 months_per_year{12};
28static constexpr s32 seconds_per_hour{seconds_per_minute * minutes_per_hour};
29static constexpr s32 seconds_per_day{seconds_per_hour * hours_per_day};
30static constexpr s32 years_per_repeat{400};
31static constexpr s64 average_seconds_per_year{31556952};
32static constexpr s64 seconds_per_repeat{years_per_repeat * average_seconds_per_year};
33
34struct Rule {
35 enum class Type : u32 { JulianDay, DayOfYear, MonthNthDayOfWeek };
36 Type rule_type{};
37 s32 day{};
38 s32 week{};
39 s32 month{};
40 s32 transition_time{};
41};
42
43struct CalendarTimeInternal {
44 s64 year{};
45 s8 month{};
46 s8 day{};
47 s8 hour{};
48 s8 minute{};
49 s8 second{};
50 int Compare(const CalendarTimeInternal& other) const {
51 if (year != other.year) {
52 if (year < other.year) {
53 return -1;
54 }
55 return 1;
56 }
57 if (month != other.month) {
58 return month - other.month;
59 }
60 if (day != other.day) {
61 return day - other.day;
62 }
63 if (hour != other.hour) {
64 return hour - other.hour;
65 }
66 if (minute != other.minute) {
67 return minute - other.minute;
68 }
69 if (second != other.second) {
70 return second - other.second;
71 }
72 return {};
73 }
74};
75
76template <typename TResult, typename TOperand>
77static bool SafeAdd(TResult& result, TOperand op) {
78 result = result + op;
79 return true;
80}
81
82template <typename TResult, typename TUnit, typename TBase>
83static bool SafeNormalize(TResult& result, TUnit& unit, TBase base) {
84 TUnit delta{};
85 if (unit >= 0) {
86 delta = unit / base;
87 } else {
88 delta = -1 - (-1 - unit) / base;
89 }
90 unit -= delta * base;
91 return SafeAdd(result, delta);
92}
93
94template <typename T>
95static constexpr bool IsLeapYear(T year) {
96 return ((year) % 4) == 0 && (((year) % 100) != 0 || ((year) % 400) == 0);
97}
98
99template <typename T>
100static constexpr T GetYearLengthInDays(T year) {
101 return IsLeapYear(year) ? days_per_leap_year : days_per_normal_year;
102}
103
104static constexpr s64 GetLeapDaysFromYearPositive(s64 year) {
105 return year / 4 - year / 100 + year / years_per_repeat;
106}
107
108static constexpr s64 GetLeapDaysFromYear(s64 year) {
109 if (year < 0) {
110 return -1 - GetLeapDaysFromYearPositive(-1 - year);
111 } else {
112 return GetLeapDaysFromYearPositive(year);
113 }
114}
115
116static constexpr int GetMonthLength(bool is_leap_year, int month) {
117 constexpr std::array<int, 12> month_lengths{31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
118 constexpr std::array<int, 12> month_lengths_leap{31, 29, 31, 30, 31, 30,
119 31, 31, 30, 31, 30, 31};
120 return is_leap_year ? month_lengths_leap[month] : month_lengths[month];
121}
122
123static constexpr bool IsDigit(char value) {
124 return value >= '0' && value <= '9';
125}
126
127static constexpr int GetQZName(const char* name, int offset, char delimiter) {
128 while (name[offset] != '\0' && name[offset] != delimiter) {
129 offset++;
130 }
131 return offset;
132}
133
134static constexpr int GetTZName(const char* name, int offset) {
135 for (char value{name[offset]};
136 value != '\0' && !IsDigit(value) && value != ',' && value != '-' && value != '+';
137 offset++) {
138 value = name[offset];
139 }
140 return offset;
141}
142
143static constexpr bool GetInteger(const char* name, int& offset, int& value, int min, int max) {
144 value = 0;
145 char temp{name[offset]};
146 if (!IsDigit(temp)) {
147 return {};
148 }
149 do {
150 value = value * 10 + (temp - '0');
151 if (value > max) {
152 return {};
153 }
154 temp = name[offset];
155 } while (IsDigit(temp));
156
157 return value >= min;
158}
159
160static constexpr bool GetSeconds(const char* name, int& offset, int& seconds) {
161 seconds = 0;
162 int value{};
163 if (!GetInteger(name, offset, value, 0, hours_per_day * days_per_week - 1)) {
164 return {};
165 }
166 seconds = value * seconds_per_hour;
167
168 if (name[offset] == ':') {
169 offset++;
170 if (!GetInteger(name, offset, value, 0, minutes_per_hour - 1)) {
171 return {};
172 }
173 seconds += value * seconds_per_minute;
174 if (name[offset] == ':') {
175 offset++;
176 if (!GetInteger(name, offset, value, 0, seconds_per_minute)) {
177 return {};
178 }
179 seconds += value;
180 }
181 }
182 return true;
183}
184
185static constexpr bool GetOffset(const char* name, int& offset, int& value) {
186 bool is_negative{};
187 if (name[offset] == '-') {
188 is_negative = true;
189 offset++;
190 } else if (name[offset] == '+') {
191 offset++;
192 }
193 if (!GetSeconds(name, offset, value)) {
194 return {};
195 }
196 if (is_negative) {
197 value = -value;
198 }
199 return true;
200}
201
202static constexpr bool GetRule(const char* name, int& position, Rule& rule) {
203 bool is_valid{};
204 if (name[position] == 'J') {
205 position++;
206 rule.rule_type = Rule::Type::JulianDay;
207 is_valid = GetInteger(name, position, rule.day, 1, days_per_normal_year);
208 } else if (name[position] == 'M') {
209 position++;
210 rule.rule_type = Rule::Type::MonthNthDayOfWeek;
211 is_valid = GetInteger(name, position, rule.month, 1, months_per_year);
212 if (!is_valid) {
213 return {};
214 }
215 if (name[position++] != '.') {
216 return {};
217 }
218 is_valid = GetInteger(name, position, rule.week, 1, 5);
219 if (!is_valid) {
220 return {};
221 }
222 if (name[position++] != '.') {
223 return {};
224 }
225 is_valid = GetInteger(name, position, rule.day, 0, days_per_week - 1);
226 } else if (isdigit(name[position])) {
227 rule.rule_type = Rule::Type::DayOfYear;
228 is_valid = GetInteger(name, position, rule.day, 0, days_per_leap_year - 1);
229 } else {
230 return {};
231 }
232 if (!is_valid) {
233 return {};
234 }
235 if (name[position] == '/') {
236 position++;
237 return GetOffset(name, position, rule.transition_time);
238 } else {
239 rule.transition_time = 2 * seconds_per_hour;
240 }
241 return true;
242}
243
244static constexpr int TransitionTime(int year, Rule rule, int offset) {
245 int value{};
246 switch (rule.rule_type) {
247 case Rule::Type::JulianDay:
248 value = (rule.day - 1) * seconds_per_day;
249 if (IsLeapYear(year) && rule.day >= 60) {
250 value += seconds_per_day;
251 }
252 break;
253 case Rule::Type::DayOfYear:
254 value = rule.day * seconds_per_day;
255 break;
256 case Rule::Type::MonthNthDayOfWeek: {
257 // Use Zeller's Congruence (https://en.wikipedia.org/wiki/Zeller%27s_congruence) to
258 // calculate the day of the week for any Julian or Gregorian calendar date.
259 const int m1{(rule.month + 9) % 12 + 1};
260 const int yy0{(rule.month <= 2) ? (year - 1) : year};
261 const int yy1{yy0 / 100};
262 const int yy2{yy0 % 100};
263 int day_of_week{((26 * m1 - 2) / 10 + 1 + yy2 + yy2 / 4 + yy1 / 4 - 2 * yy1) % 7};
264
265 if (day_of_week < 0) {
266 day_of_week += days_per_week;
267 }
268 int day{rule.day - day_of_week};
269 if (day < 0) {
270 day += days_per_week;
271 }
272 for (int i{1}; i < rule.week; i++) {
273 if (day + days_per_week >= GetMonthLength(IsLeapYear(year), rule.month - 1)) {
274 break;
275 }
276 day += days_per_week;
277 }
278
279 value = day * seconds_per_day;
280 for (int index{}; index < rule.month - 1; ++index) {
281 value += GetMonthLength(IsLeapYear(year), index) * seconds_per_day;
282 }
283 break;
284 }
285 default:
286 UNREACHABLE();
287 }
288 return value + rule.transition_time + offset;
289}
290
291static bool ParsePosixName(const char* name, TimeZoneRule& rule) {
292 constexpr char default_rule[]{",M4.1.0,M10.5.0"};
293 const char* std_name{name};
294 int std_len{};
295 int offset{};
296 int std_offset{};
297
298 if (name[offset] == '<') {
299 offset++;
300 std_name = name + offset;
301 const int std_name_offset{offset};
302 offset = GetQZName(name, offset, '>');
303 if (name[offset] != '>') {
304 return {};
305 }
306 std_len = offset - std_name_offset;
307 offset++;
308 } else {
309 offset = GetTZName(name, offset);
310 std_len = offset;
311 }
312 if (!std_len) {
313 return {};
314 }
315 if (!GetOffset(name, offset, std_offset)) {
316 return {};
317 }
318
319 int char_count{std_len + 1};
320 int dest_len{};
321 int dest_offset{};
322 const char* dest_name{name + offset};
323 if (rule.chars.size() < char_count) {
324 return {};
325 }
326
327 if (name[offset] != '\0') {
328 if (name[offset] == '<') {
329 dest_name = name + (++offset);
330 const int dest_name_offset{offset};
331 offset = GetQZName(name, offset, '>');
332 if (name[offset] != '>') {
333 return {};
334 }
335 dest_len = offset - dest_name_offset;
336 offset++;
337 } else {
338 dest_name = name + (offset);
339 offset = GetTZName(name, offset);
340 dest_len = offset;
341 }
342 if (dest_len == 0) {
343 return {};
344 }
345 char_count += dest_len + 1;
346 if (rule.chars.size() < char_count) {
347 return {};
348 }
349 if (name[offset] != '\0' && name[offset] != ',' && name[offset] != ';') {
350 if (!GetOffset(name, offset, dest_offset)) {
351 return {};
352 }
353 } else {
354 dest_offset = std_offset - seconds_per_hour;
355 }
356 if (name[offset] == '\0') {
357 name = default_rule;
358 offset = 0;
359 }
360 if (name[offset] == ',' || name[offset] == ';') {
361 offset++;
362
363 Rule start{};
364 if (!GetRule(name, offset, start)) {
365 return {};
366 }
367 if (name[offset++] != ',') {
368 return {};
369 }
370
371 Rule end{};
372 if (!GetRule(name, offset, end)) {
373 return {};
374 }
375 if (name[offset] != '\0') {
376 return {};
377 }
378
379 rule.type_count = 2;
380 rule.ttis[0].gmt_offset = -dest_offset;
381 rule.ttis[0].is_dst = true;
382 rule.ttis[0].abbreviation_list_index = std_len + 1;
383 rule.ttis[1].gmt_offset = -std_offset;
384 rule.ttis[1].is_dst = false;
385 rule.ttis[1].abbreviation_list_index = 0;
386 rule.default_type = 0;
387
388 s64 jan_first{};
389 int time_count{};
390 int jan_offset{};
391 int year_beginning{epoch_year};
392 do {
393 const int year_seconds{GetYearLengthInDays(year_beginning - 1) * seconds_per_day};
394 year_beginning--;
395 if (!SafeAdd(jan_first, -year_seconds)) {
396 jan_offset = -year_seconds;
397 break;
398 }
399 } while (epoch_year - years_per_repeat / 2 < year_beginning);
400
401 int year_limit{year_beginning + years_per_repeat + 1};
402 int year{};
403 for (year = year_beginning; year < year_limit; year++) {
404 int start_time{TransitionTime(year, start, std_offset)};
405 int end_time{TransitionTime(year, end, dest_offset)};
406 const int year_seconds{GetYearLengthInDays(year) * seconds_per_day};
407 const bool is_reversed{end_time < start_time};
408 if (is_reversed) {
409 int swap{start_time};
410 start_time = end_time;
411 end_time = swap;
412 }
413
414 if (is_reversed ||
415 (start_time < end_time &&
416 (end_time - start_time < (year_seconds + (std_offset - dest_offset))))) {
417 if (rule.ats.size() - 2 < time_count) {
418 break;
419 }
420
421 rule.ats[time_count] = jan_first;
422 if (SafeAdd(rule.ats[time_count], jan_offset + start_time)) {
423 rule.types[time_count++] = is_reversed ? 1 : 0;
424 } else if (jan_offset != 0) {
425 rule.default_type = is_reversed ? 1 : 0;
426 }
427
428 rule.ats[time_count] = jan_first;
429 if (SafeAdd(rule.ats[time_count], jan_offset + end_time)) {
430 rule.types[time_count++] = is_reversed ? 0 : 1;
431 year_limit = year + years_per_repeat + 1;
432 } else if (jan_offset != 0) {
433 rule.default_type = is_reversed ? 0 : 1;
434 }
435 }
436 if (!SafeAdd(jan_first, jan_offset + year_seconds)) {
437 break;
438 }
439 jan_offset = 0;
440 }
441 rule.time_count = time_count;
442 if (time_count == 0) {
443 rule.type_count = 1;
444 } else if (years_per_repeat < year - year_beginning) {
445 rule.go_back = true;
446 rule.go_ahead = true;
447 }
448 } else {
449 if (name[offset] == '\0') {
450 return {};
451 }
452
453 s64 their_std_offset{};
454 for (int index{}; index < rule.time_count; ++index) {
455 const s8 type{rule.types[index]};
456 if (rule.ttis[type].is_standard_time_daylight) {
457 their_std_offset = -rule.ttis[type].gmt_offset;
458 }
459 }
460
461 s64 their_offset{their_std_offset};
462 for (int index{}; index < rule.time_count; ++index) {
463 const s8 type{rule.types[index]};
464 rule.types[index] = rule.ttis[type].is_dst ? 1 : 0;
465 if (!rule.ttis[type].is_gmt) {
466 if (!rule.ttis[type].is_standard_time_daylight) {
467 rule.ats[index] += dest_offset - their_std_offset;
468 } else {
469 rule.ats[index] += std_offset - their_std_offset;
470 }
471 }
472 their_offset = -rule.ttis[type].gmt_offset;
473 if (!rule.ttis[type].is_dst) {
474 their_std_offset = their_offset;
475 }
476 }
477 rule.ttis[0].gmt_offset = -std_offset;
478 rule.ttis[0].is_dst = false;
479 rule.ttis[0].abbreviation_list_index = 0;
480 rule.ttis[1].gmt_offset = -dest_offset;
481 rule.ttis[1].is_dst = true;
482 rule.ttis[1].abbreviation_list_index = std_len + 1;
483 rule.type_count = 2;
484 rule.default_type = 0;
485 }
486 } else {
487 // Default is standard time
488 rule.type_count = 1;
489 rule.time_count = 0;
490 rule.default_type = 0;
491 rule.ttis[0].gmt_offset = -std_offset;
492 rule.ttis[0].is_dst = false;
493 rule.ttis[0].abbreviation_list_index = 0;
494 }
495
496 rule.char_count = char_count;
497 for (int index{}; index < std_len; ++index) {
498 rule.chars[index] = std_name[index];
499 }
500
501 rule.chars[std_len++] = '\0';
502 if (dest_len != 0) {
503 for (int index{}; index < dest_len; ++index) {
504 rule.chars[std_len + index] = dest_name[index];
505 }
506 rule.chars[std_len + dest_len] = '\0';
507 }
508
509 return true;
510}
511
512static bool ParseTimeZoneBinary(TimeZoneRule& time_zone_rule, FileSys::VirtualFile& vfs_file) {
513 TzifHeader header{};
514 if (vfs_file->ReadObject<TzifHeader>(&header) != sizeof(TzifHeader)) {
515 return {};
516 }
517
518 constexpr s32 time_zone_max_leaps{50};
519 constexpr s32 time_zone_max_chars{50};
520 if (!(0 <= header.leap_count && header.leap_count < time_zone_max_leaps &&
521 0 < header.type_count && header.type_count < time_zone_rule.ttis.size() &&
522 0 <= header.time_count && header.time_count < time_zone_rule.ats.size() &&
523 0 <= header.char_count && header.char_count < time_zone_max_chars &&
524 (header.ttis_std_count == header.type_count || header.ttis_std_count == 0) &&
525 (header.ttis_gmt_count == header.type_count || header.ttis_gmt_count == 0))) {
526 return {};
527 }
528 time_zone_rule.time_count = header.time_count;
529 time_zone_rule.type_count = header.type_count;
530 time_zone_rule.char_count = header.char_count;
531
532 int time_count{};
533 u64 read_offset = sizeof(TzifHeader);
534 for (int index{}; index < time_zone_rule.time_count; ++index) {
535 s64_be at{};
536 vfs_file->ReadObject<s64_be>(&at, read_offset);
537 time_zone_rule.types[index] = 1;
538 if (time_count != 0 && at <= time_zone_rule.ats[time_count - 1]) {
539 if (at < time_zone_rule.ats[time_count - 1]) {
540 return {};
541 }
542 time_zone_rule.types[index - 1] = 0;
543 time_count--;
544 }
545 time_zone_rule.ats[time_count++] = at;
546 read_offset += sizeof(s64_be);
547 }
548 time_count = 0;
549 for (int index{}; index < time_zone_rule.time_count; ++index) {
550 const u8 type{*vfs_file->ReadByte(read_offset)};
551 read_offset += sizeof(u8);
552 if (time_zone_rule.time_count <= type) {
553 return {};
554 }
555 if (time_zone_rule.types[index] != 0) {
556 time_zone_rule.types[time_count++] = type;
557 }
558 }
559 time_zone_rule.time_count = time_count;
560 for (int index{}; index < time_zone_rule.type_count; ++index) {
561 TimeTypeInfo& ttis{time_zone_rule.ttis[index]};
562 u32_be gmt_offset{};
563 vfs_file->ReadObject<u32_be>(&gmt_offset, read_offset);
564 read_offset += sizeof(u32_be);
565 ttis.gmt_offset = gmt_offset;
566
567 const u8 dst{*vfs_file->ReadByte(read_offset)};
568 read_offset += sizeof(u8);
569 if (dst >= 2) {
570 return {};
571 }
572 ttis.is_dst = dst != 0;
573
574 const s32 abbreviation_list_index{*vfs_file->ReadByte(read_offset)};
575 read_offset += sizeof(u8);
576 if (abbreviation_list_index >= time_zone_rule.char_count) {
577 return {};
578 }
579 ttis.abbreviation_list_index = abbreviation_list_index;
580 }
581
582 vfs_file->ReadArray(time_zone_rule.chars.data(), time_zone_rule.char_count, read_offset);
583 time_zone_rule.chars[time_zone_rule.char_count] = '\0';
584 read_offset += time_zone_rule.char_count;
585 for (int index{}; index < time_zone_rule.type_count; ++index) {
586 if (header.ttis_std_count == 0) {
587 time_zone_rule.ttis[index].is_standard_time_daylight = false;
588 } else {
589 const u8 dst{*vfs_file->ReadByte(read_offset)};
590 read_offset += sizeof(u8);
591 if (dst >= 2) {
592 return {};
593 }
594 time_zone_rule.ttis[index].is_standard_time_daylight = dst != 0;
595 }
596 }
597
598 for (int index{}; index < time_zone_rule.type_count; ++index) {
599 if (header.ttis_std_count == 0) {
600 time_zone_rule.ttis[index].is_gmt = false;
601 } else {
602 const u8 dst{*vfs_file->ReadByte(read_offset)};
603 read_offset += sizeof(u8);
604 if (dst >= 2) {
605 return {};
606 }
607 time_zone_rule.ttis[index].is_gmt = dst != 0;
608 }
609 }
610
611 const u64 position{(read_offset - sizeof(TzifHeader))};
612 const std::size_t bytes_read{vfs_file->GetSize() - sizeof(TzifHeader) - position};
613 if (bytes_read < 0) {
614 return {};
615 }
616 constexpr s32 time_zone_name_max{255};
617 if (bytes_read > (time_zone_name_max + 1)) {
618 return {};
619 }
620
621 std::array<char, time_zone_name_max + 1> temp_name{};
622 vfs_file->ReadArray(temp_name.data(), bytes_read, read_offset);
623 if (bytes_read > 2 && temp_name[0] == '\n' && temp_name[bytes_read - 1] == '\n' &&
624 time_zone_rule.type_count + 2 <= time_zone_rule.ttis.size()) {
625 temp_name[bytes_read - 1] = '\0';
626
627 std::array<char, time_zone_name_max> name{};
628 std::memcpy(name.data(), temp_name.data() + 1, bytes_read - 1);
629
630 TimeZoneRule temp_rule;
631 if (ParsePosixName(name.data(), temp_rule)) {
632 UNIMPLEMENTED();
633 }
634 }
635 if (time_zone_rule.type_count == 0) {
636 return {};
637 }
638 if (time_zone_rule.time_count > 1) {
639 UNIMPLEMENTED();
640 }
641
642 s32 default_type{};
643
644 for (default_type = 0; default_type < time_zone_rule.time_count; default_type++) {
645 if (time_zone_rule.types[default_type] == 0) {
646 break;
647 }
648 }
649
650 default_type = default_type < time_zone_rule.time_count ? -1 : 0;
651 if (default_type < 0 && time_zone_rule.time_count > 0 &&
652 time_zone_rule.ttis[time_zone_rule.types[0]].is_dst) {
653 default_type = time_zone_rule.types[0];
654 while (--default_type >= 0) {
655 if (!time_zone_rule.ttis[default_type].is_dst) {
656 break;
657 }
658 }
659 }
660 if (default_type < 0) {
661 default_type = 0;
662 while (time_zone_rule.ttis[default_type].is_dst) {
663 if (++default_type >= time_zone_rule.type_count) {
664 default_type = 0;
665 break;
666 }
667 }
668 }
669 time_zone_rule.default_type = default_type;
670 return true;
671}
672
673static ResultCode CreateCalendarTime(s64 time, int gmt_offset, CalendarTimeInternal& calendar_time,
674 CalendarAdditionalInfo& calendar_additional_info) {
675 s64 year{epoch_year};
676 s64 time_days{time / seconds_per_day};
677 s64 remaining_seconds{time % seconds_per_day};
678 while (time_days < 0 || time_days >= GetYearLengthInDays(year)) {
679 s64 delta = time_days / days_per_leap_year;
680 if (!delta) {
681 delta = time_days < 0 ? -1 : 1;
682 }
683 s64 new_year{year};
684 if (!SafeAdd(new_year, delta)) {
685 return ERROR_OUT_OF_RANGE;
686 }
687 time_days -= (new_year - year) * days_per_normal_year;
688 time_days -= GetLeapDaysFromYear(new_year - 1) - GetLeapDaysFromYear(year - 1);
689 year = new_year;
690 }
691
692 s64 day_of_year{time_days};
693 remaining_seconds += gmt_offset;
694 while (remaining_seconds < 0) {
695 remaining_seconds += seconds_per_day;
696 day_of_year--;
697 }
698
699 while (remaining_seconds >= seconds_per_day) {
700 remaining_seconds -= seconds_per_day;
701 day_of_year++;
702 }
703
704 while (day_of_year < 0) {
705 if (!SafeAdd(year, -1)) {
706 return ERROR_OUT_OF_RANGE;
707 }
708 day_of_year += GetYearLengthInDays(year);
709 }
710
711 while (day_of_year >= GetYearLengthInDays(year)) {
712 day_of_year -= GetYearLengthInDays(year);
713 if (!SafeAdd(year, 1)) {
714 return ERROR_OUT_OF_RANGE;
715 }
716 }
717
718 calendar_time.year = year;
719 calendar_additional_info.day_of_year = static_cast<u32>(day_of_year);
720 s64 day_of_week{
721 (epoch_week_day +
722 ((year - epoch_year) % days_per_week) * (days_per_normal_year % days_per_week) +
723 GetLeapDaysFromYear(year - 1) - GetLeapDaysFromYear(epoch_year - 1) + day_of_year) %
724 days_per_week};
725 if (day_of_week < 0) {
726 day_of_week += days_per_week;
727 }
728
729 calendar_additional_info.day_of_week = static_cast<u32>(day_of_week);
730 calendar_time.hour = static_cast<s8>((remaining_seconds / seconds_per_hour) % seconds_per_hour);
731 remaining_seconds %= seconds_per_hour;
732 calendar_time.minute = static_cast<s8>(remaining_seconds / seconds_per_minute);
733 calendar_time.second = static_cast<s8>(remaining_seconds % seconds_per_minute);
734
735 for (calendar_time.month = 0;
736 day_of_year >= GetMonthLength(IsLeapYear(year), calendar_time.month);
737 ++calendar_time.month) {
738 day_of_year -= GetMonthLength(IsLeapYear(year), calendar_time.month);
739 }
740
741 calendar_time.day = static_cast<s8>(day_of_year + 1);
742 calendar_additional_info.is_dst = false;
743 calendar_additional_info.gmt_offset = gmt_offset;
744
745 return RESULT_SUCCESS;
746}
747
748static ResultCode ToCalendarTimeInternal(const TimeZoneRule& rules, s64 time,
749 CalendarTimeInternal& calendar_time,
750 CalendarAdditionalInfo& calendar_additional_info) {
751 if ((rules.go_ahead && time < rules.ats[0]) ||
752 (rules.go_back && time > rules.ats[rules.time_count - 1])) {
753 s64 seconds{};
754 if (time < rules.ats[0]) {
755 seconds = rules.ats[0] - time;
756 } else {
757 seconds = time - rules.ats[rules.time_count - 1];
758 }
759 seconds--;
760
761 const s64 years{(seconds / seconds_per_repeat + 1) * years_per_repeat};
762 seconds = years * average_seconds_per_year;
763
764 s64 new_time{time};
765 if (time < rules.ats[0]) {
766 new_time += seconds;
767 } else {
768 new_time -= seconds;
769 }
770 if (new_time < rules.ats[0] && new_time > rules.ats[rules.time_count - 1]) {
771 return ERROR_TIME_NOT_FOUND;
772 }
773 if (const ResultCode result{
774 ToCalendarTimeInternal(rules, new_time, calendar_time, calendar_additional_info)};
775 result != RESULT_SUCCESS) {
776 return result;
777 }
778 if (time < rules.ats[0]) {
779 calendar_time.year -= years;
780 } else {
781 calendar_time.year += years;
782 }
783
784 return RESULT_SUCCESS;
785 }
786
787 s32 tti_index{};
788 if (rules.time_count == 0 || time < rules.ats[0]) {
789 tti_index = rules.default_type;
790 } else {
791 s32 low{1};
792 s32 high{rules.time_count};
793 while (low < high) {
794 s32 mid{(low + high) >> 1};
795 if (time < rules.ats[mid]) {
796 high = mid;
797 } else {
798 low = mid + 1;
799 }
800 }
801 tti_index = rules.types[low - 1];
802 }
803
804 if (const ResultCode result{CreateCalendarTime(time, rules.ttis[tti_index].gmt_offset,
805 calendar_time, calendar_additional_info)};
806 result != RESULT_SUCCESS) {
807 return result;
808 }
809
810 calendar_additional_info.is_dst = rules.ttis[tti_index].is_dst;
811 const char* time_zone{&rules.chars[rules.ttis[tti_index].abbreviation_list_index]};
812 for (int index{}; time_zone[index] != '\0'; ++index) {
813 calendar_additional_info.timezone_name[index] = time_zone[index];
814 }
815 return RESULT_SUCCESS;
816}
817
818static ResultCode ToCalendarTimeImpl(const TimeZoneRule& rules, s64 time, CalendarInfo& calendar) {
819 CalendarTimeInternal calendar_time{};
820 const ResultCode result{
821 ToCalendarTimeInternal(rules, time, calendar_time, calendar.additiona_info)};
822 calendar.time.year = static_cast<s16>(calendar_time.year);
823 calendar.time.month = calendar_time.month;
824 calendar.time.day = calendar_time.day;
825 calendar.time.hour = calendar_time.hour;
826 calendar.time.minute = calendar_time.minute;
827 calendar.time.second = calendar_time.second;
828 return result;
829}
830
831TimeZoneManager::TimeZoneManager() = default;
832TimeZoneManager::~TimeZoneManager() = default;
833
834ResultCode TimeZoneManager::ToCalendarTime(const TimeZoneRule& rules, s64 time,
835 CalendarInfo& calendar) const {
836 return ToCalendarTimeImpl(rules, time, calendar);
837}
838
839ResultCode TimeZoneManager::SetDeviceLocationNameWithTimeZoneRule(const std::string& location_name,
840 FileSys::VirtualFile& vfs_file) {
841 TimeZoneRule rule{};
842 if (ParseTimeZoneBinary(rule, vfs_file)) {
843 device_location_name = location_name;
844 time_zone_rule = rule;
845 return RESULT_SUCCESS;
846 }
847 return ERROR_TIME_ZONE_CONVERSION_FAILED;
848}
849
850ResultCode TimeZoneManager::SetUpdatedTime(const Clock::SteadyClockTimePoint& value) {
851 time_zone_update_time_point = value;
852 return RESULT_SUCCESS;
853}
854
855ResultCode TimeZoneManager::ToCalendarTimeWithMyRules(s64 time, CalendarInfo& calendar) const {
856 if (is_initialized) {
857 return ToCalendarTime(time_zone_rule, time, calendar);
858 } else {
859 return ERROR_UNINITIALIZED_CLOCK;
860 }
861}
862
863ResultCode TimeZoneManager::ParseTimeZoneRuleBinary(TimeZoneRule& rules,
864 FileSys::VirtualFile& vfs_file) const {
865 if (!ParseTimeZoneBinary(rules, vfs_file)) {
866 return ERROR_TIME_ZONE_CONVERSION_FAILED;
867 }
868 return RESULT_SUCCESS;
869}
870
871ResultCode TimeZoneManager::ToPosixTime(const TimeZoneRule& rules,
872 const CalendarTime& calendar_time, s64& posix_time) const {
873 posix_time = 0;
874
875 CalendarTimeInternal internal_time{};
876 internal_time.year = calendar_time.year;
877 internal_time.month = calendar_time.month;
878 internal_time.day = calendar_time.day;
879 internal_time.hour = calendar_time.hour;
880 internal_time.minute = calendar_time.minute;
881 internal_time.second = calendar_time.second;
882
883 s32 hour{internal_time.hour};
884 s32 minute{internal_time.minute};
885 if (!SafeNormalize(hour, minute, minutes_per_hour)) {
886 return ERROR_OVERFLOW;
887 }
888 internal_time.minute = static_cast<s8>(minute);
889
890 s32 day{internal_time.day};
891 if (!SafeNormalize(day, hour, hours_per_day)) {
892 return ERROR_OVERFLOW;
893 }
894 internal_time.day = static_cast<s8>(day);
895 internal_time.hour = static_cast<s8>(hour);
896
897 s64 year{internal_time.year};
898 s64 month{internal_time.month};
899 if (!SafeNormalize(year, month, months_per_year)) {
900 return ERROR_OVERFLOW;
901 }
902 internal_time.month = static_cast<s8>(month);
903
904 if (!SafeAdd(year, year_base)) {
905 return ERROR_OVERFLOW;
906 }
907
908 while (day <= 0) {
909 if (!SafeAdd(year, -1)) {
910 return ERROR_OVERFLOW;
911 }
912 s64 temp_year{year};
913 if (1 < internal_time.month) {
914 ++temp_year;
915 }
916 day += static_cast<s32>(GetYearLengthInDays(temp_year));
917 }
918
919 while (day > days_per_leap_year) {
920 s64 temp_year{year};
921 if (1 < internal_time.month) {
922 temp_year++;
923 }
924 day -= static_cast<s32>(GetYearLengthInDays(temp_year));
925 if (!SafeAdd(year, 1)) {
926 return ERROR_OVERFLOW;
927 }
928 }
929
930 while (true) {
931 const s32 month_length{GetMonthLength(IsLeapYear(year), internal_time.month)};
932 if (day <= month_length) {
933 break;
934 }
935 day -= month_length;
936 internal_time.month++;
937 if (internal_time.month >= months_per_year) {
938 internal_time.month = 0;
939 if (!SafeAdd(year, 1)) {
940 return ERROR_OVERFLOW;
941 }
942 }
943 }
944 internal_time.day = static_cast<s8>(day);
945
946 if (!SafeAdd(year, -year_base)) {
947 return ERROR_OVERFLOW;
948 }
949 internal_time.year = year;
950
951 s32 saved_seconds{};
952 if (internal_time.second >= 0 && internal_time.second < seconds_per_minute) {
953 saved_seconds = 0;
954 } else if (year + year_base < epoch_year) {
955 s32 second{internal_time.second};
956 if (!SafeAdd(second, 1 - seconds_per_minute)) {
957 return ERROR_OVERFLOW;
958 }
959 saved_seconds = second;
960 internal_time.second = 1 - seconds_per_minute;
961 } else {
962 saved_seconds = internal_time.second;
963 internal_time.second = 0;
964 }
965
966 s64 low{LLONG_MIN};
967 s64 high{LLONG_MAX};
968 while (true) {
969 s64 pivot{low / 2 + high / 2};
970 if (pivot < low) {
971 pivot = low;
972 } else if (pivot > high) {
973 pivot = high;
974 }
975 s32 direction{};
976 CalendarTimeInternal candidate_calendar_time{};
977 CalendarAdditionalInfo unused{};
978 if (ToCalendarTimeInternal(rules, pivot, candidate_calendar_time, unused) !=
979 RESULT_SUCCESS) {
980 if (pivot > 0) {
981 direction = 1;
982 } else {
983 direction = -1;
984 }
985 } else {
986 direction = candidate_calendar_time.Compare(internal_time);
987 }
988 if (!direction) {
989 const s64 time_result{pivot + saved_seconds};
990 if ((time_result < pivot) != (saved_seconds < 0)) {
991 return ERROR_OVERFLOW;
992 }
993 posix_time = time_result;
994 break;
995 } else {
996 if (pivot == low) {
997 if (pivot == LLONG_MAX) {
998 return ERROR_TIME_NOT_FOUND;
999 }
1000 pivot++;
1001 low++;
1002 } else if (pivot == high) {
1003 if (pivot == LLONG_MIN) {
1004 return ERROR_TIME_NOT_FOUND;
1005 }
1006 pivot--;
1007 high--;
1008 }
1009 if (low > high) {
1010 return ERROR_TIME_NOT_FOUND;
1011 }
1012 if (direction > 0) {
1013 high = pivot;
1014 } else {
1015 low = pivot;
1016 }
1017 }
1018 }
1019 return RESULT_SUCCESS;
1020}
1021
1022ResultCode TimeZoneManager::GetDeviceLocationName(LocationName& value) const {
1023 if (!is_initialized) {
1024 return ERROR_UNINITIALIZED_CLOCK;
1025 }
1026 std::memcpy(value.data(), device_location_name.c_str(), device_location_name.size());
1027 return RESULT_SUCCESS;
1028}
1029
1030} // namespace Service::Time::TimeZone
diff --git a/src/core/hle/service/time/time_zone_manager.h b/src/core/hle/service/time/time_zone_manager.h
new file mode 100644
index 000000000..7c6f975ae
--- /dev/null
+++ b/src/core/hle/service/time/time_zone_manager.h
@@ -0,0 +1,53 @@
1// Copyright 2019 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 <string>
8
9#include "common/common_types.h"
10#include "core/file_sys/vfs_types.h"
11#include "core/hle/service/time/clock_types.h"
12#include "core/hle/service/time/time_zone_types.h"
13
14namespace Service::Time::TimeZone {
15
16class TimeZoneManager final {
17public:
18 TimeZoneManager();
19 ~TimeZoneManager();
20
21 void SetTotalLocationNameCount(std::size_t value) {
22 total_location_name_count = value;
23 }
24
25 void SetTimeZoneRuleVersion(const u128& value) {
26 time_zone_rule_version = value;
27 }
28
29 void MarkAsInitialized() {
30 is_initialized = true;
31 }
32
33 ResultCode SetDeviceLocationNameWithTimeZoneRule(const std::string& location_name,
34 FileSys::VirtualFile& vfs_file);
35 ResultCode SetUpdatedTime(const Clock::SteadyClockTimePoint& value);
36 ResultCode GetDeviceLocationName(TimeZone::LocationName& value) const;
37 ResultCode ToCalendarTime(const TimeZoneRule& rules, s64 time, CalendarInfo& calendar) const;
38 ResultCode ToCalendarTimeWithMyRules(s64 time, CalendarInfo& calendar) const;
39 ResultCode ParseTimeZoneRuleBinary(TimeZoneRule& rules, FileSys::VirtualFile& vfs_file) const;
40 ResultCode ToPosixTime(const TimeZoneRule& rules, const CalendarTime& calendar_time,
41 s64& posix_time) const;
42
43private:
44 bool is_initialized{};
45 TimeZoneRule time_zone_rule{};
46 std::string device_location_name{"GMT"};
47 u128 time_zone_rule_version{};
48 std::size_t total_location_name_count{};
49 Clock::SteadyClockTimePoint time_zone_update_time_point{
50 Clock::SteadyClockTimePoint::GetRandom()};
51};
52
53} // namespace Service::Time::TimeZone
diff --git a/src/core/hle/service/time/time_zone_service.cpp b/src/core/hle/service/time/time_zone_service.cpp
new file mode 100644
index 000000000..1566e778e
--- /dev/null
+++ b/src/core/hle/service/time/time_zone_service.cpp
@@ -0,0 +1,148 @@
1// Copyright 2019 yuzu emulator team
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include "common/logging/log.h"
6#include "core/hle/ipc_helpers.h"
7#include "core/hle/service/time/time_zone_content_manager.h"
8#include "core/hle/service/time/time_zone_service.h"
9#include "core/hle/service/time/time_zone_types.h"
10
11namespace Service::Time {
12
13ITimeZoneService ::ITimeZoneService(TimeZone::TimeZoneContentManager& time_zone_content_manager)
14 : ServiceFramework("ITimeZoneService"), time_zone_content_manager{time_zone_content_manager} {
15 static const FunctionInfo functions[] = {
16 {0, &ITimeZoneService::GetDeviceLocationName, "GetDeviceLocationName"},
17 {1, nullptr, "SetDeviceLocationName"},
18 {2, nullptr, "GetTotalLocationNameCount"},
19 {3, nullptr, "LoadLocationNameList"},
20 {4, &ITimeZoneService::LoadTimeZoneRule, "LoadTimeZoneRule"},
21 {5, nullptr, "GetTimeZoneRuleVersion"},
22 {100, &ITimeZoneService::ToCalendarTime, "ToCalendarTime"},
23 {101, &ITimeZoneService::ToCalendarTimeWithMyRule, "ToCalendarTimeWithMyRule"},
24 {201, &ITimeZoneService::ToPosixTime, "ToPosixTime"},
25 {202, nullptr, "ToPosixTimeWithMyRule"},
26 };
27 RegisterHandlers(functions);
28}
29
30void ITimeZoneService::GetDeviceLocationName(Kernel::HLERequestContext& ctx) {
31 LOG_DEBUG(Service_Time, "called");
32
33 TimeZone::LocationName location_name{};
34 if (const ResultCode result{
35 time_zone_content_manager.GetTimeZoneManager().GetDeviceLocationName(location_name)};
36 result != RESULT_SUCCESS) {
37 IPC::ResponseBuilder rb{ctx, 2};
38 rb.Push(result);
39 return;
40 }
41
42 IPC::ResponseBuilder rb{ctx, (sizeof(location_name) / 4) + 2};
43 rb.Push(RESULT_SUCCESS);
44 rb.PushRaw(location_name);
45}
46
47void ITimeZoneService::LoadTimeZoneRule(Kernel::HLERequestContext& ctx) {
48 IPC::RequestParser rp{ctx};
49 const auto raw_location_name{rp.PopRaw<std::array<u8, 0x24>>()};
50
51 std::string location_name;
52 for (const auto& byte : raw_location_name) {
53 // Strip extra bytes
54 if (byte == '\0') {
55 break;
56 }
57 location_name.push_back(byte);
58 }
59
60 LOG_DEBUG(Service_Time, "called, location_name={}", location_name);
61
62 TimeZone::TimeZoneRule time_zone_rule{};
63 if (const ResultCode result{
64 time_zone_content_manager.LoadTimeZoneRule(time_zone_rule, location_name)};
65 result != RESULT_SUCCESS) {
66 IPC::ResponseBuilder rb{ctx, 2};
67 rb.Push(result);
68 return;
69 }
70
71 std::vector<u8> time_zone_rule_outbuffer(sizeof(TimeZone::TimeZoneRule));
72 std::memcpy(time_zone_rule_outbuffer.data(), &time_zone_rule, sizeof(TimeZone::TimeZoneRule));
73 ctx.WriteBuffer(time_zone_rule_outbuffer);
74
75 IPC::ResponseBuilder rb{ctx, 2};
76 rb.Push(RESULT_SUCCESS);
77}
78
79void ITimeZoneService::ToCalendarTime(Kernel::HLERequestContext& ctx) {
80 IPC::RequestParser rp{ctx};
81 const auto posix_time{rp.Pop<s64>()};
82
83 LOG_DEBUG(Service_Time, "called, posix_time=0x{:016X}", posix_time);
84
85 TimeZone::TimeZoneRule time_zone_rule{};
86 const auto buffer{ctx.ReadBuffer()};
87 std::memcpy(&time_zone_rule, buffer.data(), buffer.size());
88
89 TimeZone::CalendarInfo calendar_info{};
90 if (const ResultCode result{time_zone_content_manager.GetTimeZoneManager().ToCalendarTime(
91 time_zone_rule, posix_time, calendar_info)};
92 result != RESULT_SUCCESS) {
93 IPC::ResponseBuilder rb{ctx, 2};
94 rb.Push(result);
95 return;
96 }
97
98 IPC::ResponseBuilder rb{ctx, 2 + (sizeof(TimeZone::CalendarInfo) / 4)};
99 rb.Push(RESULT_SUCCESS);
100 rb.PushRaw(calendar_info);
101}
102
103void ITimeZoneService::ToCalendarTimeWithMyRule(Kernel::HLERequestContext& ctx) {
104 IPC::RequestParser rp{ctx};
105 const auto posix_time{rp.Pop<s64>()};
106
107 LOG_DEBUG(Service_Time, "called, posix_time=0x{:016X}", posix_time);
108
109 TimeZone::CalendarInfo calendar_info{};
110 if (const ResultCode result{
111 time_zone_content_manager.GetTimeZoneManager().ToCalendarTimeWithMyRules(
112 posix_time, calendar_info)};
113 result != RESULT_SUCCESS) {
114 IPC::ResponseBuilder rb{ctx, 2};
115 rb.Push(result);
116 return;
117 }
118
119 IPC::ResponseBuilder rb{ctx, 2 + (sizeof(TimeZone::CalendarInfo) / 4)};
120 rb.Push(RESULT_SUCCESS);
121 rb.PushRaw(calendar_info);
122}
123
124void ITimeZoneService::ToPosixTime(Kernel::HLERequestContext& ctx) {
125 LOG_DEBUG(Service_Time, "called");
126
127 IPC::RequestParser rp{ctx};
128 const auto calendar_time{rp.PopRaw<TimeZone::CalendarTime>()};
129 TimeZone::TimeZoneRule time_zone_rule{};
130 std::memcpy(&time_zone_rule, ctx.ReadBuffer().data(), sizeof(TimeZone::TimeZoneRule));
131
132 s64 posix_time{};
133 if (const ResultCode result{time_zone_content_manager.GetTimeZoneManager().ToPosixTime(
134 time_zone_rule, calendar_time, posix_time)};
135 result != RESULT_SUCCESS) {
136 IPC::ResponseBuilder rb{ctx, 2};
137 rb.Push(result);
138 return;
139 }
140
141 // TODO(bunnei): Handle multiple times
142 IPC::ResponseBuilder rb{ctx, 3};
143 rb.Push(RESULT_SUCCESS);
144 rb.PushRaw<u32>(1); // Number of times we're returning
145 ctx.WriteBuffer(&posix_time, sizeof(s64));
146}
147
148} // namespace Service::Time
diff --git a/src/core/hle/service/time/time_zone_service.h b/src/core/hle/service/time/time_zone_service.h
new file mode 100644
index 000000000..a92b4312b
--- /dev/null
+++ b/src/core/hle/service/time/time_zone_service.h
@@ -0,0 +1,30 @@
1// Copyright 2019 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 "core/hle/service/service.h"
8
9namespace Service::Time {
10
11namespace TimeZone {
12class TimeZoneContentManager;
13}
14
15class ITimeZoneService final : public ServiceFramework<ITimeZoneService> {
16public:
17 explicit ITimeZoneService(TimeZone::TimeZoneContentManager& time_zone_manager);
18
19private:
20 void GetDeviceLocationName(Kernel::HLERequestContext& ctx);
21 void LoadTimeZoneRule(Kernel::HLERequestContext& ctx);
22 void ToCalendarTime(Kernel::HLERequestContext& ctx);
23 void ToCalendarTimeWithMyRule(Kernel::HLERequestContext& ctx);
24 void ToPosixTime(Kernel::HLERequestContext& ctx);
25
26private:
27 TimeZone::TimeZoneContentManager& time_zone_content_manager;
28};
29
30} // namespace Service::Time
diff --git a/src/core/hle/service/time/time_zone_types.h b/src/core/hle/service/time/time_zone_types.h
new file mode 100644
index 000000000..9be15b53e
--- /dev/null
+++ b/src/core/hle/service/time/time_zone_types.h
@@ -0,0 +1,87 @@
1// Copyright 2019 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 <array>
8
9#include "common/common_funcs.h"
10#include "common/common_types.h"
11#include "common/swap.h"
12
13namespace Service::Time::TimeZone {
14
15using LocationName = std::array<char, 0x24>;
16
17/// https://switchbrew.org/wiki/Glue_services#ttinfo
18struct TimeTypeInfo {
19 s32 gmt_offset{};
20 u8 is_dst{};
21 INSERT_PADDING_BYTES(3);
22 s32 abbreviation_list_index{};
23 u8 is_standard_time_daylight{};
24 u8 is_gmt{};
25 INSERT_PADDING_BYTES(2);
26};
27static_assert(sizeof(TimeTypeInfo) == 0x10, "TimeTypeInfo is incorrect size");
28
29/// https://switchbrew.org/wiki/Glue_services#TimeZoneRule
30struct TimeZoneRule {
31 s32 time_count{};
32 s32 type_count{};
33 s32 char_count{};
34 u8 go_back{};
35 u8 go_ahead{};
36 INSERT_PADDING_BYTES(2);
37 std::array<s64, 1000> ats{};
38 std::array<s8, 1000> types{};
39 std::array<TimeTypeInfo, 128> ttis{};
40 std::array<char, 512> chars{};
41 s32 default_type{};
42 INSERT_PADDING_BYTES(0x12C4);
43};
44static_assert(sizeof(TimeZoneRule) == 0x4000, "TimeZoneRule is incorrect size");
45
46/// https://switchbrew.org/wiki/Glue_services#CalendarAdditionalInfo
47struct CalendarAdditionalInfo {
48 u32 day_of_week{};
49 u32 day_of_year{};
50 std::array<char, 8> timezone_name;
51 u32 is_dst{};
52 s32 gmt_offset{};
53};
54static_assert(sizeof(CalendarAdditionalInfo) == 0x18, "CalendarAdditionalInfo is incorrect size");
55
56/// https://switchbrew.org/wiki/Glue_services#CalendarTime
57struct CalendarTime {
58 s16 year{};
59 s8 month{};
60 s8 day{};
61 s8 hour{};
62 s8 minute{};
63 s8 second{};
64 INSERT_PADDING_BYTES(1);
65};
66static_assert(sizeof(CalendarTime) == 0x8, "CalendarTime is incorrect size");
67
68struct CalendarInfo {
69 CalendarTime time{};
70 CalendarAdditionalInfo additiona_info{};
71};
72static_assert(sizeof(CalendarInfo) == 0x20, "CalendarInfo is incorrect size");
73
74struct TzifHeader {
75 u32_be magic{};
76 u8 version{};
77 INSERT_PADDING_BYTES(15);
78 s32_be ttis_gmt_count{};
79 s32_be ttis_std_count{};
80 s32_be leap_count{};
81 s32_be time_count{};
82 s32_be type_count{};
83 s32_be char_count{};
84};
85static_assert(sizeof(TzifHeader) == 0x2C, "TzifHeader is incorrect size");
86
87} // namespace Service::Time::TimeZone
diff --git a/src/core/loader/elf.cpp b/src/core/loader/elf.cpp
index f1795fdd6..8908e5328 100644
--- a/src/core/loader/elf.cpp
+++ b/src/core/loader/elf.cpp
@@ -335,7 +335,8 @@ Kernel::CodeSet ElfReader::LoadInto(VAddr vaddr) {
335 codeset_segment->addr = segment_addr; 335 codeset_segment->addr = segment_addr;
336 codeset_segment->size = aligned_size; 336 codeset_segment->size = aligned_size;
337 337
338 memcpy(&program_image[current_image_position], GetSegmentPtr(i), p->p_filesz); 338 std::memcpy(program_image.data() + current_image_position, GetSegmentPtr(i),
339 p->p_filesz);
339 current_image_position += aligned_size; 340 current_image_position += aligned_size;
340 } 341 }
341 } 342 }
diff --git a/src/core/loader/kip.cpp b/src/core/loader/kip.cpp
index 474b55cb1..092103abe 100644
--- a/src/core/loader/kip.cpp
+++ b/src/core/loader/kip.cpp
@@ -2,6 +2,7 @@
2// Licensed under GPLv2 or any later version 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <cstring>
5#include "core/file_sys/kernel_executable.h" 6#include "core/file_sys/kernel_executable.h"
6#include "core/file_sys/program_metadata.h" 7#include "core/file_sys/program_metadata.h"
7#include "core/gdbstub/gdbstub.h" 8#include "core/gdbstub/gdbstub.h"
@@ -76,8 +77,8 @@ AppLoader::LoadResult AppLoader_KIP::Load(Kernel::Process& process) {
76 segment.addr = offset; 77 segment.addr = offset;
77 segment.offset = offset; 78 segment.offset = offset;
78 segment.size = PageAlignSize(static_cast<u32>(data.size())); 79 segment.size = PageAlignSize(static_cast<u32>(data.size()));
79 program_image.resize(offset); 80 program_image.resize(offset + data.size());
80 program_image.insert(program_image.end(), data.begin(), data.end()); 81 std::memcpy(program_image.data() + offset, data.data(), data.size());
81 }; 82 };
82 83
83 load_segment(codeset.CodeSegment(), kip->GetTextSection(), kip->GetTextOffset()); 84 load_segment(codeset.CodeSegment(), kip->GetTextSection(), kip->GetTextOffset());
diff --git a/src/core/loader/nso.cpp b/src/core/loader/nso.cpp
index f629892ae..515c5accb 100644
--- a/src/core/loader/nso.cpp
+++ b/src/core/loader/nso.cpp
@@ -3,6 +3,7 @@
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <cinttypes> 5#include <cinttypes>
6#include <cstring>
6#include <vector> 7#include <vector>
7 8
8#include "common/common_funcs.h" 9#include "common/common_funcs.h"
@@ -96,8 +97,9 @@ std::optional<VAddr> AppLoader_NSO::LoadModule(Kernel::Process& process,
96 if (nso_header.IsSegmentCompressed(i)) { 97 if (nso_header.IsSegmentCompressed(i)) {
97 data = DecompressSegment(data, nso_header.segments[i]); 98 data = DecompressSegment(data, nso_header.segments[i]);
98 } 99 }
99 program_image.resize(nso_header.segments[i].location); 100 program_image.resize(nso_header.segments[i].location + data.size());
100 program_image.insert(program_image.end(), data.begin(), data.end()); 101 std::memcpy(program_image.data() + nso_header.segments[i].location, data.data(),
102 data.size());
101 codeset.segments[i].addr = nso_header.segments[i].location; 103 codeset.segments[i].addr = nso_header.segments[i].location;
102 codeset.segments[i].offset = nso_header.segments[i].location; 104 codeset.segments[i].offset = nso_header.segments[i].location;
103 codeset.segments[i].size = PageAlignSize(static_cast<u32>(data.size())); 105 codeset.segments[i].size = PageAlignSize(static_cast<u32>(data.size()));
@@ -139,12 +141,12 @@ std::optional<VAddr> AppLoader_NSO::LoadModule(Kernel::Process& process,
139 std::vector<u8> pi_header; 141 std::vector<u8> pi_header;
140 pi_header.insert(pi_header.begin(), reinterpret_cast<u8*>(&nso_header), 142 pi_header.insert(pi_header.begin(), reinterpret_cast<u8*>(&nso_header),
141 reinterpret_cast<u8*>(&nso_header) + sizeof(NSOHeader)); 143 reinterpret_cast<u8*>(&nso_header) + sizeof(NSOHeader));
142 pi_header.insert(pi_header.begin() + sizeof(NSOHeader), program_image.begin(), 144 pi_header.insert(pi_header.begin() + sizeof(NSOHeader), program_image.data(),
143 program_image.end()); 145 program_image.data() + program_image.size());
144 146
145 pi_header = pm->PatchNSO(pi_header, file.GetName()); 147 pi_header = pm->PatchNSO(pi_header, file.GetName());
146 148
147 std::copy(pi_header.begin() + sizeof(NSOHeader), pi_header.end(), program_image.begin()); 149 std::copy(pi_header.begin() + sizeof(NSOHeader), pi_header.end(), program_image.data());
148 } 150 }
149 151
150 // Apply cheats if they exist and the program has a valid title ID 152 // Apply cheats if they exist and the program has a valid title ID
diff --git a/src/core/memory.cpp b/src/core/memory.cpp
index 3c2a29d9b..f0888327f 100644
--- a/src/core/memory.cpp
+++ b/src/core/memory.cpp
@@ -14,6 +14,7 @@
14#include "common/swap.h" 14#include "common/swap.h"
15#include "core/arm/arm_interface.h" 15#include "core/arm/arm_interface.h"
16#include "core/core.h" 16#include "core/core.h"
17#include "core/hle/kernel/physical_memory.h"
17#include "core/hle/kernel/process.h" 18#include "core/hle/kernel/process.h"
18#include "core/hle/kernel/vm_manager.h" 19#include "core/hle/kernel/vm_manager.h"
19#include "core/memory.h" 20#include "core/memory.h"
@@ -38,6 +39,11 @@ struct Memory::Impl {
38 system.ArmInterface(3).PageTableChanged(*current_page_table, address_space_width); 39 system.ArmInterface(3).PageTableChanged(*current_page_table, address_space_width);
39 } 40 }
40 41
42 void MapMemoryRegion(Common::PageTable& page_table, VAddr base, u64 size,
43 Kernel::PhysicalMemory& memory, VAddr offset) {
44 MapMemoryRegion(page_table, base, size, memory.data() + offset);
45 }
46
41 void MapMemoryRegion(Common::PageTable& page_table, VAddr base, u64 size, u8* target) { 47 void MapMemoryRegion(Common::PageTable& page_table, VAddr base, u64 size, u8* target) {
42 ASSERT_MSG((size & PAGE_MASK) == 0, "non-page aligned size: {:016X}", size); 48 ASSERT_MSG((size & PAGE_MASK) == 0, "non-page aligned size: {:016X}", size);
43 ASSERT_MSG((base & PAGE_MASK) == 0, "non-page aligned base: {:016X}", base); 49 ASSERT_MSG((base & PAGE_MASK) == 0, "non-page aligned base: {:016X}", base);
@@ -601,6 +607,11 @@ void Memory::SetCurrentPageTable(Kernel::Process& process) {
601 impl->SetCurrentPageTable(process); 607 impl->SetCurrentPageTable(process);
602} 608}
603 609
610void Memory::MapMemoryRegion(Common::PageTable& page_table, VAddr base, u64 size,
611 Kernel::PhysicalMemory& memory, VAddr offset) {
612 impl->MapMemoryRegion(page_table, base, size, memory, offset);
613}
614
604void Memory::MapMemoryRegion(Common::PageTable& page_table, VAddr base, u64 size, u8* target) { 615void Memory::MapMemoryRegion(Common::PageTable& page_table, VAddr base, u64 size, u8* target) {
605 impl->MapMemoryRegion(page_table, base, size, target); 616 impl->MapMemoryRegion(page_table, base, size, target);
606} 617}
diff --git a/src/core/memory.h b/src/core/memory.h
index 1428a6d60..8913a9da4 100644
--- a/src/core/memory.h
+++ b/src/core/memory.h
@@ -19,8 +19,9 @@ class System;
19} 19}
20 20
21namespace Kernel { 21namespace Kernel {
22class PhysicalMemory;
22class Process; 23class Process;
23} 24} // namespace Kernel
24 25
25namespace Memory { 26namespace Memory {
26 27
@@ -66,6 +67,19 @@ public:
66 void SetCurrentPageTable(Kernel::Process& process); 67 void SetCurrentPageTable(Kernel::Process& process);
67 68
68 /** 69 /**
70 * Maps an physical buffer onto a region of the emulated process address space.
71 *
72 * @param page_table The page table of the emulated process.
73 * @param base The address to start mapping at. Must be page-aligned.
74 * @param size The amount of bytes to map. Must be page-aligned.
75 * @param memory Physical buffer with the memory backing the mapping. Must be of length
76 * at least `size + offset`.
77 * @param offset The offset within the physical memory. Must be page-aligned.
78 */
79 void MapMemoryRegion(Common::PageTable& page_table, VAddr base, u64 size,
80 Kernel::PhysicalMemory& memory, VAddr offset);
81
82 /**
69 * Maps an allocated buffer onto a region of the emulated process address space. 83 * Maps an allocated buffer onto a region of the emulated process address space.
70 * 84 *
71 * @param page_table The page table of the emulated process. 85 * @param page_table The page table of the emulated process.
diff --git a/src/video_core/CMakeLists.txt b/src/video_core/CMakeLists.txt
index 729ee4a01..12c46e86f 100644
--- a/src/video_core/CMakeLists.txt
+++ b/src/video_core/CMakeLists.txt
@@ -153,6 +153,7 @@ if (ENABLE_VULKAN)
153 renderer_vulkan/fixed_pipeline_state.h 153 renderer_vulkan/fixed_pipeline_state.h
154 renderer_vulkan/maxwell_to_vk.cpp 154 renderer_vulkan/maxwell_to_vk.cpp
155 renderer_vulkan/maxwell_to_vk.h 155 renderer_vulkan/maxwell_to_vk.h
156 renderer_vulkan/renderer_vulkan.h
156 renderer_vulkan/vk_buffer_cache.cpp 157 renderer_vulkan/vk_buffer_cache.cpp
157 renderer_vulkan/vk_buffer_cache.h 158 renderer_vulkan/vk_buffer_cache.h
158 renderer_vulkan/vk_compute_pass.cpp 159 renderer_vulkan/vk_compute_pass.cpp
@@ -171,6 +172,7 @@ if (ENABLE_VULKAN)
171 renderer_vulkan/vk_memory_manager.h 172 renderer_vulkan/vk_memory_manager.h
172 renderer_vulkan/vk_pipeline_cache.cpp 173 renderer_vulkan/vk_pipeline_cache.cpp
173 renderer_vulkan/vk_pipeline_cache.h 174 renderer_vulkan/vk_pipeline_cache.h
175 renderer_vulkan/vk_rasterizer.cpp
174 renderer_vulkan/vk_rasterizer.h 176 renderer_vulkan/vk_rasterizer.h
175 renderer_vulkan/vk_renderpass_cache.cpp 177 renderer_vulkan/vk_renderpass_cache.cpp
176 renderer_vulkan/vk_renderpass_cache.h 178 renderer_vulkan/vk_renderpass_cache.h
diff --git a/src/video_core/engines/maxwell_3d.h b/src/video_core/engines/maxwell_3d.h
index 16f95b77d..ee79260fc 100644
--- a/src/video_core/engines/maxwell_3d.h
+++ b/src/video_core/engines/maxwell_3d.h
@@ -1018,7 +1018,14 @@ public:
1018 } 1018 }
1019 } instanced_arrays; 1019 } instanced_arrays;
1020 1020
1021 INSERT_UNION_PADDING_WORDS(0x6); 1021 INSERT_UNION_PADDING_WORDS(0x4);
1022
1023 union {
1024 BitField<0, 1, u32> enable;
1025 BitField<4, 8, u32> unk4;
1026 } vp_point_size;
1027
1028 INSERT_UNION_PADDING_WORDS(1);
1022 1029
1023 Cull cull; 1030 Cull cull;
1024 1031
@@ -1503,6 +1510,7 @@ ASSERT_REG_POSITION(primitive_restart, 0x591);
1503ASSERT_REG_POSITION(index_array, 0x5F2); 1510ASSERT_REG_POSITION(index_array, 0x5F2);
1504ASSERT_REG_POSITION(polygon_offset_clamp, 0x61F); 1511ASSERT_REG_POSITION(polygon_offset_clamp, 0x61F);
1505ASSERT_REG_POSITION(instanced_arrays, 0x620); 1512ASSERT_REG_POSITION(instanced_arrays, 0x620);
1513ASSERT_REG_POSITION(vp_point_size, 0x644);
1506ASSERT_REG_POSITION(cull, 0x646); 1514ASSERT_REG_POSITION(cull, 0x646);
1507ASSERT_REG_POSITION(pixel_center_integer, 0x649); 1515ASSERT_REG_POSITION(pixel_center_integer, 0x649);
1508ASSERT_REG_POSITION(viewport_transform_enabled, 0x64B); 1516ASSERT_REG_POSITION(viewport_transform_enabled, 0x64B);
diff --git a/src/video_core/engines/shader_bytecode.h b/src/video_core/engines/shader_bytecode.h
index 57b57c647..6f98bd827 100644
--- a/src/video_core/engines/shader_bytecode.h
+++ b/src/video_core/engines/shader_bytecode.h
@@ -215,6 +215,18 @@ enum class F2fRoundingOp : u64 {
215 Trunc = 11, 215 Trunc = 11,
216}; 216};
217 217
218enum class AtomicOp : u64 {
219 Add = 0,
220 Min = 1,
221 Max = 2,
222 Inc = 3,
223 Dec = 4,
224 And = 5,
225 Or = 6,
226 Xor = 7,
227 Exch = 8,
228};
229
218enum class UniformType : u64 { 230enum class UniformType : u64 {
219 UnsignedByte = 0, 231 UnsignedByte = 0,
220 SignedByte = 1, 232 SignedByte = 1,
@@ -236,6 +248,13 @@ enum class StoreType : u64 {
236 Bits128 = 6, 248 Bits128 = 6,
237}; 249};
238 250
251enum class AtomicType : u64 {
252 U32 = 0,
253 S32 = 1,
254 U64 = 2,
255 S64 = 3,
256};
257
239enum class IMinMaxExchange : u64 { 258enum class IMinMaxExchange : u64 {
240 None = 0, 259 None = 0,
241 XLo = 1, 260 XLo = 1,
@@ -939,6 +958,16 @@ union Instruction {
939 } stg; 958 } stg;
940 959
941 union { 960 union {
961 BitField<52, 4, AtomicOp> operation;
962 BitField<28, 2, AtomicType> type;
963 BitField<30, 22, s64> offset;
964
965 s32 GetImmediateOffset() const {
966 return static_cast<s32>(offset << 2);
967 }
968 } atoms;
969
970 union {
942 BitField<32, 1, PhysicalAttributeDirection> direction; 971 BitField<32, 1, PhysicalAttributeDirection> direction;
943 BitField<47, 3, AttributeSize> size; 972 BitField<47, 3, AttributeSize> size;
944 BitField<20, 11, u64> address; 973 BitField<20, 11, u64> address;
@@ -1659,9 +1688,10 @@ public:
1659 ST_A, 1688 ST_A,
1660 ST_L, 1689 ST_L,
1661 ST_S, 1690 ST_S,
1662 ST, // Store in generic memory 1691 ST, // Store in generic memory
1663 STG, // Store in global memory 1692 STG, // Store in global memory
1664 AL2P, // Transforms attribute memory into physical memory 1693 ATOMS, // Atomic operation on shared memory
1694 AL2P, // Transforms attribute memory into physical memory
1665 TEX, 1695 TEX,
1666 TEX_B, // Texture Load Bindless 1696 TEX_B, // Texture Load Bindless
1667 TXQ, // Texture Query 1697 TXQ, // Texture Query
@@ -1964,6 +1994,7 @@ private:
1964 INST("1110111101010---", Id::ST_L, Type::Memory, "ST_L"), 1994 INST("1110111101010---", Id::ST_L, Type::Memory, "ST_L"),
1965 INST("101-------------", Id::ST, Type::Memory, "ST"), 1995 INST("101-------------", Id::ST, Type::Memory, "ST"),
1966 INST("1110111011011---", Id::STG, Type::Memory, "STG"), 1996 INST("1110111011011---", Id::STG, Type::Memory, "STG"),
1997 INST("11101100--------", Id::ATOMS, Type::Memory, "ATOMS"),
1967 INST("1110111110100---", Id::AL2P, Type::Memory, "AL2P"), 1998 INST("1110111110100---", Id::AL2P, Type::Memory, "AL2P"),
1968 INST("110000----111---", Id::TEX, Type::Texture, "TEX"), 1999 INST("110000----111---", Id::TEX, Type::Texture, "TEX"),
1969 INST("1101111010111---", Id::TEX_B, Type::Texture, "TEX_B"), 2000 INST("1101111010111---", Id::TEX_B, Type::Texture, "TEX_B"),
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp
index 672051102..c428f06e4 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.cpp
+++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp
@@ -1272,6 +1272,7 @@ void RasterizerOpenGL::SyncPointState() {
1272 const auto& regs = system.GPU().Maxwell3D().regs; 1272 const auto& regs = system.GPU().Maxwell3D().regs;
1273 // Limit the point size to 1 since nouveau sometimes sets a point size of 0 (and that's invalid 1273 // Limit the point size to 1 since nouveau sometimes sets a point size of 0 (and that's invalid
1274 // in OpenGL). 1274 // in OpenGL).
1275 state.point.program_control = regs.vp_point_size.enable != 0;
1275 state.point.size = std::max(1.0f, regs.point_size); 1276 state.point.size = std::max(1.0f, regs.point_size);
1276} 1277}
1277 1278
diff --git a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
index f9f7a97b5..2996aaf08 100644
--- a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
+++ b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
@@ -1856,6 +1856,16 @@ private:
1856 Type::Uint}; 1856 Type::Uint};
1857 } 1857 }
1858 1858
1859 template <const std::string_view& opname, Type type>
1860 Expression Atomic(Operation operation) {
1861 ASSERT(stage == ShaderType::Compute);
1862 auto& smem = std::get<SmemNode>(*operation[0]);
1863
1864 return {fmt::format("atomic{}(smem[{} >> 2], {})", opname, Visit(smem.GetAddress()).AsInt(),
1865 Visit(operation[1]).As(type)),
1866 type};
1867 }
1868
1859 Expression Branch(Operation operation) { 1869 Expression Branch(Operation operation) {
1860 const auto target = std::get_if<ImmediateNode>(&*operation[0]); 1870 const auto target = std::get_if<ImmediateNode>(&*operation[0]);
1861 UNIMPLEMENTED_IF(!target); 1871 UNIMPLEMENTED_IF(!target);
@@ -2194,6 +2204,8 @@ private:
2194 &GLSLDecompiler::AtomicImage<Func::Xor>, 2204 &GLSLDecompiler::AtomicImage<Func::Xor>,
2195 &GLSLDecompiler::AtomicImage<Func::Exchange>, 2205 &GLSLDecompiler::AtomicImage<Func::Exchange>,
2196 2206
2207 &GLSLDecompiler::Atomic<Func::Add, Type::Uint>,
2208
2197 &GLSLDecompiler::Branch, 2209 &GLSLDecompiler::Branch,
2198 &GLSLDecompiler::BranchIndirect, 2210 &GLSLDecompiler::BranchIndirect,
2199 &GLSLDecompiler::PushFlowStack, 2211 &GLSLDecompiler::PushFlowStack,
@@ -2313,7 +2325,7 @@ public:
2313 explicit ExprDecompiler(GLSLDecompiler& decomp) : decomp{decomp} {} 2325 explicit ExprDecompiler(GLSLDecompiler& decomp) : decomp{decomp} {}
2314 2326
2315 void operator()(const ExprAnd& expr) { 2327 void operator()(const ExprAnd& expr) {
2316 inner += "( "; 2328 inner += '(';
2317 std::visit(*this, *expr.operand1); 2329 std::visit(*this, *expr.operand1);
2318 inner += " && "; 2330 inner += " && ";
2319 std::visit(*this, *expr.operand2); 2331 std::visit(*this, *expr.operand2);
@@ -2321,7 +2333,7 @@ public:
2321 } 2333 }
2322 2334
2323 void operator()(const ExprOr& expr) { 2335 void operator()(const ExprOr& expr) {
2324 inner += "( "; 2336 inner += '(';
2325 std::visit(*this, *expr.operand1); 2337 std::visit(*this, *expr.operand1);
2326 inner += " || "; 2338 inner += " || ";
2327 std::visit(*this, *expr.operand2); 2339 std::visit(*this, *expr.operand2);
@@ -2339,28 +2351,7 @@ public:
2339 } 2351 }
2340 2352
2341 void operator()(const ExprCondCode& expr) { 2353 void operator()(const ExprCondCode& expr) {
2342 const Node cc = decomp.ir.GetConditionCode(expr.cc); 2354 inner += decomp.Visit(decomp.ir.GetConditionCode(expr.cc)).AsBool();
2343 std::string target;
2344
2345 if (const auto pred = std::get_if<PredicateNode>(&*cc)) {
2346 const auto index = pred->GetIndex();
2347 switch (index) {
2348 case Tegra::Shader::Pred::NeverExecute:
2349 target = "false";
2350 break;
2351 case Tegra::Shader::Pred::UnusedIndex:
2352 target = "true";
2353 break;
2354 default:
2355 target = decomp.GetPredicate(index);
2356 break;
2357 }
2358 } else if (const auto flag = std::get_if<InternalFlagNode>(&*cc)) {
2359 target = decomp.GetInternalFlag(flag->GetFlag());
2360 } else {
2361 UNREACHABLE();
2362 }
2363 inner += target;
2364 } 2355 }
2365 2356
2366 void operator()(const ExprVar& expr) { 2357 void operator()(const ExprVar& expr) {
@@ -2372,8 +2363,7 @@ public:
2372 } 2363 }
2373 2364
2374 void operator()(VideoCommon::Shader::ExprGprEqual& expr) { 2365 void operator()(VideoCommon::Shader::ExprGprEqual& expr) {
2375 inner += 2366 inner += fmt::format("(ftou({}) == {})", decomp.GetRegister(expr.gpr), expr.value);
2376 "( ftou(" + decomp.GetRegister(expr.gpr) + ") == " + std::to_string(expr.value) + ')';
2377 } 2367 }
2378 2368
2379 const std::string& GetResult() const { 2369 const std::string& GetResult() const {
@@ -2381,8 +2371,8 @@ public:
2381 } 2371 }
2382 2372
2383private: 2373private:
2384 std::string inner;
2385 GLSLDecompiler& decomp; 2374 GLSLDecompiler& decomp;
2375 std::string inner;
2386}; 2376};
2387 2377
2388class ASTDecompiler { 2378class ASTDecompiler {
diff --git a/src/video_core/renderer_opengl/gl_state.cpp b/src/video_core/renderer_opengl/gl_state.cpp
index df2e2395a..cc185e9e1 100644
--- a/src/video_core/renderer_opengl/gl_state.cpp
+++ b/src/video_core/renderer_opengl/gl_state.cpp
@@ -127,6 +127,7 @@ void OpenGLState::ApplyClipDistances() {
127} 127}
128 128
129void OpenGLState::ApplyPointSize() { 129void OpenGLState::ApplyPointSize() {
130 Enable(GL_PROGRAM_POINT_SIZE, cur_state.point.program_control, point.program_control);
130 if (UpdateValue(cur_state.point.size, point.size)) { 131 if (UpdateValue(cur_state.point.size, point.size)) {
131 glPointSize(point.size); 132 glPointSize(point.size);
132 } 133 }
diff --git a/src/video_core/renderer_opengl/gl_state.h b/src/video_core/renderer_opengl/gl_state.h
index fb180f302..678e5cd89 100644
--- a/src/video_core/renderer_opengl/gl_state.h
+++ b/src/video_core/renderer_opengl/gl_state.h
@@ -131,7 +131,8 @@ public:
131 std::array<Viewport, Tegra::Engines::Maxwell3D::Regs::NumViewports> viewports; 131 std::array<Viewport, Tegra::Engines::Maxwell3D::Regs::NumViewports> viewports;
132 132
133 struct { 133 struct {
134 float size = 1.0f; // GL_POINT_SIZE 134 bool program_control = false; // GL_PROGRAM_POINT_SIZE
135 GLfloat size = 1.0f; // GL_POINT_SIZE
135 } point; 136 } point;
136 137
137 struct { 138 struct {
diff --git a/src/video_core/renderer_opengl/gl_texture_cache.cpp b/src/video_core/renderer_opengl/gl_texture_cache.cpp
index b790b0ef4..e95eb069e 100644
--- a/src/video_core/renderer_opengl/gl_texture_cache.cpp
+++ b/src/video_core/renderer_opengl/gl_texture_cache.cpp
@@ -44,7 +44,7 @@ struct FormatTuple {
44 44
45constexpr std::array<FormatTuple, VideoCore::Surface::MaxPixelFormat> tex_format_tuples = {{ 45constexpr std::array<FormatTuple, VideoCore::Surface::MaxPixelFormat> tex_format_tuples = {{
46 {GL_RGBA8, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, false}, // ABGR8U 46 {GL_RGBA8, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, false}, // ABGR8U
47 {GL_RGBA8, GL_RGBA, GL_BYTE, false}, // ABGR8S 47 {GL_RGBA8_SNORM, GL_RGBA, GL_BYTE, false}, // ABGR8S
48 {GL_RGBA8UI, GL_RGBA_INTEGER, GL_UNSIGNED_BYTE, false}, // ABGR8UI 48 {GL_RGBA8UI, GL_RGBA_INTEGER, GL_UNSIGNED_BYTE, false}, // ABGR8UI
49 {GL_RGB565, GL_RGB, GL_UNSIGNED_SHORT_5_6_5_REV, false}, // B5G6R5U 49 {GL_RGB565, GL_RGB, GL_UNSIGNED_SHORT_5_6_5_REV, false}, // B5G6R5U
50 {GL_RGB10_A2, GL_RGBA, GL_UNSIGNED_INT_2_10_10_10_REV, false}, // A2B10G10R10U 50 {GL_RGB10_A2, GL_RGBA, GL_UNSIGNED_INT_2_10_10_10_REV, false}, // A2B10G10R10U
@@ -83,9 +83,9 @@ constexpr std::array<FormatTuple, VideoCore::Surface::MaxPixelFormat> tex_format
83 {GL_RGB32F, GL_RGB, GL_FLOAT, false}, // RGB32F 83 {GL_RGB32F, GL_RGB, GL_FLOAT, false}, // RGB32F
84 {GL_SRGB8_ALPHA8, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, false}, // RGBA8_SRGB 84 {GL_SRGB8_ALPHA8, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, false}, // RGBA8_SRGB
85 {GL_RG8, GL_RG, GL_UNSIGNED_BYTE, false}, // RG8U 85 {GL_RG8, GL_RG, GL_UNSIGNED_BYTE, false}, // RG8U
86 {GL_RG8, GL_RG, GL_BYTE, false}, // RG8S 86 {GL_RG8_SNORM, GL_RG, GL_BYTE, false}, // RG8S
87 {GL_RG32UI, GL_RG_INTEGER, GL_UNSIGNED_INT, false}, // RG32UI 87 {GL_RG32UI, GL_RG_INTEGER, GL_UNSIGNED_INT, false}, // RG32UI
88 {GL_RGB16F, GL_RGBA16, GL_HALF_FLOAT, false}, // RGBX16F 88 {GL_RGB16F, GL_RGBA, GL_HALF_FLOAT, false}, // RGBX16F
89 {GL_R32UI, GL_RED_INTEGER, GL_UNSIGNED_INT, false}, // R32UI 89 {GL_R32UI, GL_RED_INTEGER, GL_UNSIGNED_INT, false}, // R32UI
90 {GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE, false}, // ASTC_2D_8X8 90 {GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE, false}, // ASTC_2D_8X8
91 {GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE, false}, // ASTC_2D_8X5 91 {GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE, false}, // ASTC_2D_8X5
@@ -253,14 +253,12 @@ void CachedSurface::DownloadTexture(std::vector<u8>& staging_buffer) {
253 glPixelStorei(GL_PACK_ALIGNMENT, std::min(8U, params.GetRowAlignment(level))); 253 glPixelStorei(GL_PACK_ALIGNMENT, std::min(8U, params.GetRowAlignment(level)));
254 glPixelStorei(GL_PACK_ROW_LENGTH, static_cast<GLint>(params.GetMipWidth(level))); 254 glPixelStorei(GL_PACK_ROW_LENGTH, static_cast<GLint>(params.GetMipWidth(level)));
255 const std::size_t mip_offset = params.GetHostMipmapLevelOffset(level); 255 const std::size_t mip_offset = params.GetHostMipmapLevelOffset(level);
256 u8* const mip_data = staging_buffer.data() + mip_offset;
257 const GLsizei size = static_cast<GLsizei>(params.GetHostMipmapSize(level));
256 if (is_compressed) { 258 if (is_compressed) {
257 glGetCompressedTextureImage(texture.handle, level, 259 glGetCompressedTextureImage(texture.handle, level, size, mip_data);
258 static_cast<GLsizei>(params.GetHostMipmapSize(level)),
259 staging_buffer.data() + mip_offset);
260 } else { 260 } else {
261 glGetTextureImage(texture.handle, level, format, type, 261 glGetTextureImage(texture.handle, level, format, type, size, mip_data);
262 static_cast<GLsizei>(params.GetHostMipmapSize(level)),
263 staging_buffer.data() + mip_offset);
264 } 262 }
265 } 263 }
266} 264}
diff --git a/src/video_core/renderer_vulkan/renderer_vulkan.h b/src/video_core/renderer_vulkan/renderer_vulkan.h
new file mode 100644
index 000000000..a472c5dc9
--- /dev/null
+++ b/src/video_core/renderer_vulkan/renderer_vulkan.h
@@ -0,0 +1,72 @@
1// Copyright 2018 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 <optional>
8#include <vector>
9#include "video_core/renderer_base.h"
10#include "video_core/renderer_vulkan/declarations.h"
11
12namespace Core {
13class System;
14}
15
16namespace Vulkan {
17
18class VKBlitScreen;
19class VKDevice;
20class VKFence;
21class VKMemoryManager;
22class VKResourceManager;
23class VKSwapchain;
24class VKScheduler;
25class VKImage;
26
27struct VKScreenInfo {
28 VKImage* image{};
29 u32 width{};
30 u32 height{};
31 bool is_srgb{};
32};
33
34class RendererVulkan final : public VideoCore::RendererBase {
35public:
36 explicit RendererVulkan(Core::Frontend::EmuWindow& window, Core::System& system);
37 ~RendererVulkan() override;
38
39 /// Swap buffers (render frame)
40 void SwapBuffers(const Tegra::FramebufferConfig* framebuffer) override;
41
42 /// Initialize the renderer
43 bool Init() override;
44
45 /// Shutdown the renderer
46 void ShutDown() override;
47
48private:
49 std::optional<vk::DebugUtilsMessengerEXT> CreateDebugCallback(
50 const vk::DispatchLoaderDynamic& dldi);
51
52 bool PickDevices(const vk::DispatchLoaderDynamic& dldi);
53
54 void Report() const;
55
56 Core::System& system;
57
58 vk::Instance instance;
59 vk::SurfaceKHR surface;
60
61 VKScreenInfo screen_info;
62
63 UniqueDebugUtilsMessengerEXT debug_callback;
64 std::unique_ptr<VKDevice> device;
65 std::unique_ptr<VKSwapchain> swapchain;
66 std::unique_ptr<VKMemoryManager> memory_manager;
67 std::unique_ptr<VKResourceManager> resource_manager;
68 std::unique_ptr<VKScheduler> scheduler;
69 std::unique_ptr<VKBlitScreen> blit_screen;
70};
71
72} // namespace Vulkan
diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.cpp b/src/video_core/renderer_vulkan/vk_rasterizer.cpp
new file mode 100644
index 000000000..d2c6b1189
--- /dev/null
+++ b/src/video_core/renderer_vulkan/vk_rasterizer.cpp
@@ -0,0 +1,1141 @@
1// Copyright 2019 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include <algorithm>
6#include <array>
7#include <memory>
8#include <mutex>
9#include <vector>
10
11#include <boost/container/static_vector.hpp>
12#include <boost/functional/hash.hpp>
13
14#include "common/alignment.h"
15#include "common/assert.h"
16#include "common/logging/log.h"
17#include "common/microprofile.h"
18#include "core/core.h"
19#include "core/memory.h"
20#include "video_core/engines/kepler_compute.h"
21#include "video_core/engines/maxwell_3d.h"
22#include "video_core/renderer_vulkan/declarations.h"
23#include "video_core/renderer_vulkan/fixed_pipeline_state.h"
24#include "video_core/renderer_vulkan/maxwell_to_vk.h"
25#include "video_core/renderer_vulkan/renderer_vulkan.h"
26#include "video_core/renderer_vulkan/vk_buffer_cache.h"
27#include "video_core/renderer_vulkan/vk_compute_pass.h"
28#include "video_core/renderer_vulkan/vk_compute_pipeline.h"
29#include "video_core/renderer_vulkan/vk_descriptor_pool.h"
30#include "video_core/renderer_vulkan/vk_device.h"
31#include "video_core/renderer_vulkan/vk_graphics_pipeline.h"
32#include "video_core/renderer_vulkan/vk_pipeline_cache.h"
33#include "video_core/renderer_vulkan/vk_rasterizer.h"
34#include "video_core/renderer_vulkan/vk_renderpass_cache.h"
35#include "video_core/renderer_vulkan/vk_resource_manager.h"
36#include "video_core/renderer_vulkan/vk_sampler_cache.h"
37#include "video_core/renderer_vulkan/vk_scheduler.h"
38#include "video_core/renderer_vulkan/vk_staging_buffer_pool.h"
39#include "video_core/renderer_vulkan/vk_texture_cache.h"
40#include "video_core/renderer_vulkan/vk_update_descriptor.h"
41
42namespace Vulkan {
43
44using Maxwell = Tegra::Engines::Maxwell3D::Regs;
45
46MICROPROFILE_DEFINE(Vulkan_WaitForWorker, "Vulkan", "Wait for worker", MP_RGB(255, 192, 192));
47MICROPROFILE_DEFINE(Vulkan_Drawing, "Vulkan", "Record drawing", MP_RGB(192, 128, 128));
48MICROPROFILE_DEFINE(Vulkan_Compute, "Vulkan", "Record compute", MP_RGB(192, 128, 128));
49MICROPROFILE_DEFINE(Vulkan_Clearing, "Vulkan", "Record clearing", MP_RGB(192, 128, 128));
50MICROPROFILE_DEFINE(Vulkan_Geometry, "Vulkan", "Setup geometry", MP_RGB(192, 128, 128));
51MICROPROFILE_DEFINE(Vulkan_ConstBuffers, "Vulkan", "Setup constant buffers", MP_RGB(192, 128, 128));
52MICROPROFILE_DEFINE(Vulkan_GlobalBuffers, "Vulkan", "Setup global buffers", MP_RGB(192, 128, 128));
53MICROPROFILE_DEFINE(Vulkan_RenderTargets, "Vulkan", "Setup render targets", MP_RGB(192, 128, 128));
54MICROPROFILE_DEFINE(Vulkan_Textures, "Vulkan", "Setup textures", MP_RGB(192, 128, 128));
55MICROPROFILE_DEFINE(Vulkan_Images, "Vulkan", "Setup images", MP_RGB(192, 128, 128));
56MICROPROFILE_DEFINE(Vulkan_PipelineCache, "Vulkan", "Pipeline cache", MP_RGB(192, 128, 128));
57
58namespace {
59
60constexpr auto ComputeShaderIndex = static_cast<std::size_t>(Tegra::Engines::ShaderType::Compute);
61
62vk::Viewport GetViewportState(const VKDevice& device, const Maxwell& regs, std::size_t index) {
63 const auto& viewport = regs.viewport_transform[index];
64 const float x = viewport.translate_x - viewport.scale_x;
65 const float y = viewport.translate_y - viewport.scale_y;
66 const float width = viewport.scale_x * 2.0f;
67 const float height = viewport.scale_y * 2.0f;
68
69 const float reduce_z = regs.depth_mode == Maxwell::DepthMode::MinusOneToOne;
70 float near = viewport.translate_z - viewport.scale_z * reduce_z;
71 float far = viewport.translate_z + viewport.scale_z;
72 if (!device.IsExtDepthRangeUnrestrictedSupported()) {
73 near = std::clamp(near, 0.0f, 1.0f);
74 far = std::clamp(far, 0.0f, 1.0f);
75 }
76
77 return vk::Viewport(x, y, width != 0 ? width : 1.0f, height != 0 ? height : 1.0f, near, far);
78}
79
80constexpr vk::Rect2D GetScissorState(const Maxwell& regs, std::size_t index) {
81 const auto& scissor = regs.scissor_test[index];
82 if (!scissor.enable) {
83 return {{0, 0}, {INT32_MAX, INT32_MAX}};
84 }
85 const u32 width = scissor.max_x - scissor.min_x;
86 const u32 height = scissor.max_y - scissor.min_y;
87 return {{static_cast<s32>(scissor.min_x), static_cast<s32>(scissor.min_y)}, {width, height}};
88}
89
90std::array<GPUVAddr, Maxwell::MaxShaderProgram> GetShaderAddresses(
91 const std::array<Shader, Maxwell::MaxShaderProgram>& shaders) {
92 std::array<GPUVAddr, Maxwell::MaxShaderProgram> addresses;
93 for (std::size_t i = 0; i < std::size(addresses); ++i) {
94 addresses[i] = shaders[i] ? shaders[i]->GetGpuAddr() : 0;
95 }
96 return addresses;
97}
98
99void TransitionImages(const std::vector<ImageView>& views, vk::PipelineStageFlags pipeline_stage,
100 vk::AccessFlags access) {
101 for (auto& [view, layout] : views) {
102 view->Transition(*layout, pipeline_stage, access);
103 }
104}
105
106template <typename Engine, typename Entry>
107Tegra::Texture::FullTextureInfo GetTextureInfo(const Engine& engine, const Entry& entry,
108 std::size_t stage) {
109 const auto stage_type = static_cast<Tegra::Engines::ShaderType>(stage);
110 if (entry.IsBindless()) {
111 const Tegra::Texture::TextureHandle tex_handle =
112 engine.AccessConstBuffer32(stage_type, entry.GetBuffer(), entry.GetOffset());
113 return engine.GetTextureInfo(tex_handle);
114 }
115 if constexpr (std::is_same_v<Engine, Tegra::Engines::Maxwell3D>) {
116 return engine.GetStageTexture(stage_type, entry.GetOffset());
117 } else {
118 return engine.GetTexture(entry.GetOffset());
119 }
120}
121
122} // Anonymous namespace
123
124class BufferBindings final {
125public:
126 void AddVertexBinding(const vk::Buffer* buffer, vk::DeviceSize offset) {
127 vertex.buffer_ptrs[vertex.num_buffers] = buffer;
128 vertex.offsets[vertex.num_buffers] = offset;
129 ++vertex.num_buffers;
130 }
131
132 void SetIndexBinding(const vk::Buffer* buffer, vk::DeviceSize offset, vk::IndexType type) {
133 index.buffer = buffer;
134 index.offset = offset;
135 index.type = type;
136 }
137
138 void Bind(VKScheduler& scheduler) const {
139 // Use this large switch case to avoid dispatching more memory in the record lambda than
140 // what we need. It looks horrible, but it's the best we can do on standard C++.
141 switch (vertex.num_buffers) {
142 case 0:
143 return BindStatic<0>(scheduler);
144 case 1:
145 return BindStatic<1>(scheduler);
146 case 2:
147 return BindStatic<2>(scheduler);
148 case 3:
149 return BindStatic<3>(scheduler);
150 case 4:
151 return BindStatic<4>(scheduler);
152 case 5:
153 return BindStatic<5>(scheduler);
154 case 6:
155 return BindStatic<6>(scheduler);
156 case 7:
157 return BindStatic<7>(scheduler);
158 case 8:
159 return BindStatic<8>(scheduler);
160 case 9:
161 return BindStatic<9>(scheduler);
162 case 10:
163 return BindStatic<10>(scheduler);
164 case 11:
165 return BindStatic<11>(scheduler);
166 case 12:
167 return BindStatic<12>(scheduler);
168 case 13:
169 return BindStatic<13>(scheduler);
170 case 14:
171 return BindStatic<14>(scheduler);
172 case 15:
173 return BindStatic<15>(scheduler);
174 case 16:
175 return BindStatic<16>(scheduler);
176 case 17:
177 return BindStatic<17>(scheduler);
178 case 18:
179 return BindStatic<18>(scheduler);
180 case 19:
181 return BindStatic<19>(scheduler);
182 case 20:
183 return BindStatic<20>(scheduler);
184 case 21:
185 return BindStatic<21>(scheduler);
186 case 22:
187 return BindStatic<22>(scheduler);
188 case 23:
189 return BindStatic<23>(scheduler);
190 case 24:
191 return BindStatic<24>(scheduler);
192 case 25:
193 return BindStatic<25>(scheduler);
194 case 26:
195 return BindStatic<26>(scheduler);
196 case 27:
197 return BindStatic<27>(scheduler);
198 case 28:
199 return BindStatic<28>(scheduler);
200 case 29:
201 return BindStatic<29>(scheduler);
202 case 30:
203 return BindStatic<30>(scheduler);
204 case 31:
205 return BindStatic<31>(scheduler);
206 case 32:
207 return BindStatic<32>(scheduler);
208 }
209 UNREACHABLE();
210 }
211
212private:
213 // Some of these fields are intentionally left uninitialized to avoid initializing them twice.
214 struct {
215 std::size_t num_buffers = 0;
216 std::array<const vk::Buffer*, Maxwell::NumVertexArrays> buffer_ptrs;
217 std::array<vk::DeviceSize, Maxwell::NumVertexArrays> offsets;
218 } vertex;
219
220 struct {
221 const vk::Buffer* buffer = nullptr;
222 vk::DeviceSize offset;
223 vk::IndexType type;
224 } index;
225
226 template <std::size_t N>
227 void BindStatic(VKScheduler& scheduler) const {
228 if (index.buffer != nullptr) {
229 BindStatic<N, true>(scheduler);
230 } else {
231 BindStatic<N, false>(scheduler);
232 }
233 }
234
235 template <std::size_t N, bool is_indexed>
236 void BindStatic(VKScheduler& scheduler) const {
237 static_assert(N <= Maxwell::NumVertexArrays);
238 if constexpr (N == 0) {
239 return;
240 }
241
242 std::array<vk::Buffer, N> buffers;
243 std::transform(vertex.buffer_ptrs.begin(), vertex.buffer_ptrs.begin() + N, buffers.begin(),
244 [](const auto ptr) { return *ptr; });
245
246 std::array<vk::DeviceSize, N> offsets;
247 std::copy(vertex.offsets.begin(), vertex.offsets.begin() + N, offsets.begin());
248
249 if constexpr (is_indexed) {
250 // Indexed draw
251 scheduler.Record([buffers, offsets, index_buffer = *index.buffer,
252 index_offset = index.offset,
253 index_type = index.type](auto cmdbuf, auto& dld) {
254 cmdbuf.bindIndexBuffer(index_buffer, index_offset, index_type, dld);
255 cmdbuf.bindVertexBuffers(0, static_cast<u32>(N), buffers.data(), offsets.data(),
256 dld);
257 });
258 } else {
259 // Array draw
260 scheduler.Record([buffers, offsets](auto cmdbuf, auto& dld) {
261 cmdbuf.bindVertexBuffers(0, static_cast<u32>(N), buffers.data(), offsets.data(),
262 dld);
263 });
264 }
265 }
266};
267
268void RasterizerVulkan::DrawParameters::Draw(vk::CommandBuffer cmdbuf,
269 const vk::DispatchLoaderDynamic& dld) const {
270 if (is_indexed) {
271 cmdbuf.drawIndexed(num_vertices, num_instances, 0, base_vertex, base_instance, dld);
272 } else {
273 cmdbuf.draw(num_vertices, num_instances, base_vertex, base_instance, dld);
274 }
275}
276
277RasterizerVulkan::RasterizerVulkan(Core::System& system, Core::Frontend::EmuWindow& renderer,
278 VKScreenInfo& screen_info, const VKDevice& device,
279 VKResourceManager& resource_manager,
280 VKMemoryManager& memory_manager, VKScheduler& scheduler)
281 : RasterizerAccelerated{system.Memory()}, system{system}, render_window{renderer},
282 screen_info{screen_info}, device{device}, resource_manager{resource_manager},
283 memory_manager{memory_manager}, scheduler{scheduler},
284 staging_pool(device, memory_manager, scheduler), descriptor_pool(device),
285 update_descriptor_queue(device, scheduler),
286 quad_array_pass(device, scheduler, descriptor_pool, staging_pool, update_descriptor_queue),
287 uint8_pass(device, scheduler, descriptor_pool, staging_pool, update_descriptor_queue),
288 texture_cache(system, *this, device, resource_manager, memory_manager, scheduler,
289 staging_pool),
290 pipeline_cache(system, *this, device, scheduler, descriptor_pool, update_descriptor_queue),
291 buffer_cache(*this, system, device, memory_manager, scheduler, staging_pool),
292 sampler_cache(device) {}
293
294RasterizerVulkan::~RasterizerVulkan() = default;
295
296bool RasterizerVulkan::DrawBatch(bool is_indexed) {
297 Draw(is_indexed, false);
298 return true;
299}
300
301bool RasterizerVulkan::DrawMultiBatch(bool is_indexed) {
302 Draw(is_indexed, true);
303 return true;
304}
305
306void RasterizerVulkan::Draw(bool is_indexed, bool is_instanced) {
307 MICROPROFILE_SCOPE(Vulkan_Drawing);
308
309 FlushWork();
310
311 const auto& gpu = system.GPU().Maxwell3D();
312 GraphicsPipelineCacheKey key{GetFixedPipelineState(gpu.regs)};
313
314 buffer_cache.Map(CalculateGraphicsStreamBufferSize(is_indexed));
315
316 BufferBindings buffer_bindings;
317 const DrawParameters draw_params =
318 SetupGeometry(key.fixed_state, buffer_bindings, is_indexed, is_instanced);
319
320 update_descriptor_queue.Acquire();
321 sampled_views.clear();
322 image_views.clear();
323
324 const auto shaders = pipeline_cache.GetShaders();
325 key.shaders = GetShaderAddresses(shaders);
326 SetupShaderDescriptors(shaders);
327
328 buffer_cache.Unmap();
329
330 const auto texceptions = UpdateAttachments();
331 SetupImageTransitions(texceptions, color_attachments, zeta_attachment);
332
333 key.renderpass_params = GetRenderPassParams(texceptions);
334
335 auto& pipeline = pipeline_cache.GetGraphicsPipeline(key);
336 scheduler.BindGraphicsPipeline(pipeline.GetHandle());
337
338 const auto renderpass = pipeline.GetRenderPass();
339 const auto [framebuffer, render_area] = ConfigureFramebuffers(renderpass);
340 scheduler.RequestRenderpass({renderpass, framebuffer, {{0, 0}, render_area}, 0, nullptr});
341
342 UpdateDynamicStates();
343
344 buffer_bindings.Bind(scheduler);
345
346 if (device.IsNvDeviceDiagnosticCheckpoints()) {
347 scheduler.Record(
348 [&pipeline](auto cmdbuf, auto& dld) { cmdbuf.setCheckpointNV(&pipeline, dld); });
349 }
350
351 const auto pipeline_layout = pipeline.GetLayout();
352 const auto descriptor_set = pipeline.CommitDescriptorSet();
353 scheduler.Record([pipeline_layout, descriptor_set, draw_params](auto cmdbuf, auto& dld) {
354 if (descriptor_set) {
355 cmdbuf.bindDescriptorSets(vk::PipelineBindPoint::eGraphics, pipeline_layout,
356 DESCRIPTOR_SET, 1, &descriptor_set, 0, nullptr, dld);
357 }
358 draw_params.Draw(cmdbuf, dld);
359 });
360}
361
362void RasterizerVulkan::Clear() {
363 MICROPROFILE_SCOPE(Vulkan_Clearing);
364
365 const auto& gpu = system.GPU().Maxwell3D();
366 if (!system.GPU().Maxwell3D().ShouldExecute()) {
367 return;
368 }
369
370 const auto& regs = gpu.regs;
371 const bool use_color = regs.clear_buffers.R || regs.clear_buffers.G || regs.clear_buffers.B ||
372 regs.clear_buffers.A;
373 const bool use_depth = regs.clear_buffers.Z;
374 const bool use_stencil = regs.clear_buffers.S;
375 if (!use_color && !use_depth && !use_stencil) {
376 return;
377 }
378 // Clearing images requires to be out of a renderpass
379 scheduler.RequestOutsideRenderPassOperationContext();
380
381 // TODO(Rodrigo): Implement clears rendering a quad or using beginning a renderpass.
382
383 if (use_color) {
384 View color_view;
385 {
386 MICROPROFILE_SCOPE(Vulkan_RenderTargets);
387 color_view = texture_cache.GetColorBufferSurface(regs.clear_buffers.RT.Value(), false);
388 }
389
390 color_view->Transition(vk::ImageLayout::eTransferDstOptimal,
391 vk::PipelineStageFlagBits::eTransfer,
392 vk::AccessFlagBits::eTransferWrite);
393
394 const std::array clear_color = {regs.clear_color[0], regs.clear_color[1],
395 regs.clear_color[2], regs.clear_color[3]};
396 const vk::ClearColorValue clear(clear_color);
397 scheduler.Record([image = color_view->GetImage(),
398 subresource = color_view->GetImageSubresourceRange(),
399 clear](auto cmdbuf, auto& dld) {
400 cmdbuf.clearColorImage(image, vk::ImageLayout::eTransferDstOptimal, clear, subresource,
401 dld);
402 });
403 }
404 if (use_depth || use_stencil) {
405 View zeta_surface;
406 {
407 MICROPROFILE_SCOPE(Vulkan_RenderTargets);
408 zeta_surface = texture_cache.GetDepthBufferSurface(false);
409 }
410
411 zeta_surface->Transition(vk::ImageLayout::eTransferDstOptimal,
412 vk::PipelineStageFlagBits::eTransfer,
413 vk::AccessFlagBits::eTransferWrite);
414
415 const vk::ClearDepthStencilValue clear(regs.clear_depth,
416 static_cast<u32>(regs.clear_stencil));
417 scheduler.Record([image = zeta_surface->GetImage(),
418 subresource = zeta_surface->GetImageSubresourceRange(),
419 clear](auto cmdbuf, auto& dld) {
420 cmdbuf.clearDepthStencilImage(image, vk::ImageLayout::eTransferDstOptimal, clear,
421 subresource, dld);
422 });
423 }
424}
425
426void RasterizerVulkan::DispatchCompute(GPUVAddr code_addr) {
427 MICROPROFILE_SCOPE(Vulkan_Compute);
428 update_descriptor_queue.Acquire();
429 sampled_views.clear();
430 image_views.clear();
431
432 const auto& launch_desc = system.GPU().KeplerCompute().launch_description;
433 const ComputePipelineCacheKey key{
434 code_addr,
435 launch_desc.shared_alloc,
436 {launch_desc.block_dim_x, launch_desc.block_dim_y, launch_desc.block_dim_z}};
437 auto& pipeline = pipeline_cache.GetComputePipeline(key);
438
439 // Compute dispatches can't be executed inside a renderpass
440 scheduler.RequestOutsideRenderPassOperationContext();
441
442 buffer_cache.Map(CalculateComputeStreamBufferSize());
443
444 const auto& entries = pipeline.GetEntries();
445 SetupComputeConstBuffers(entries);
446 SetupComputeGlobalBuffers(entries);
447 SetupComputeTexelBuffers(entries);
448 SetupComputeTextures(entries);
449 SetupComputeImages(entries);
450
451 buffer_cache.Unmap();
452
453 TransitionImages(sampled_views, vk::PipelineStageFlagBits::eComputeShader,
454 vk::AccessFlagBits::eShaderRead);
455 TransitionImages(image_views, vk::PipelineStageFlagBits::eComputeShader,
456 vk::AccessFlagBits::eShaderRead | vk::AccessFlagBits::eShaderWrite);
457
458 if (device.IsNvDeviceDiagnosticCheckpoints()) {
459 scheduler.Record(
460 [&pipeline](auto cmdbuf, auto& dld) { cmdbuf.setCheckpointNV(nullptr, dld); });
461 }
462
463 scheduler.Record([grid_x = launch_desc.grid_dim_x, grid_y = launch_desc.grid_dim_y,
464 grid_z = launch_desc.grid_dim_z, pipeline_handle = pipeline.GetHandle(),
465 layout = pipeline.GetLayout(),
466 descriptor_set = pipeline.CommitDescriptorSet()](auto cmdbuf, auto& dld) {
467 cmdbuf.bindPipeline(vk::PipelineBindPoint::eCompute, pipeline_handle, dld);
468 cmdbuf.bindDescriptorSets(vk::PipelineBindPoint::eCompute, layout, DESCRIPTOR_SET, 1,
469 &descriptor_set, 0, nullptr, dld);
470 cmdbuf.dispatch(grid_x, grid_y, grid_z, dld);
471 });
472}
473
474void RasterizerVulkan::FlushAll() {}
475
476void RasterizerVulkan::FlushRegion(CacheAddr addr, u64 size) {
477 texture_cache.FlushRegion(addr, size);
478 buffer_cache.FlushRegion(addr, size);
479}
480
481void RasterizerVulkan::InvalidateRegion(CacheAddr addr, u64 size) {
482 texture_cache.InvalidateRegion(addr, size);
483 pipeline_cache.InvalidateRegion(addr, size);
484 buffer_cache.InvalidateRegion(addr, size);
485}
486
487void RasterizerVulkan::FlushAndInvalidateRegion(CacheAddr addr, u64 size) {
488 FlushRegion(addr, size);
489 InvalidateRegion(addr, size);
490}
491
492void RasterizerVulkan::FlushCommands() {
493 if (draw_counter > 0) {
494 draw_counter = 0;
495 scheduler.Flush();
496 }
497}
498
499void RasterizerVulkan::TickFrame() {
500 draw_counter = 0;
501 update_descriptor_queue.TickFrame();
502 buffer_cache.TickFrame();
503 staging_pool.TickFrame();
504}
505
506bool RasterizerVulkan::AccelerateSurfaceCopy(const Tegra::Engines::Fermi2D::Regs::Surface& src,
507 const Tegra::Engines::Fermi2D::Regs::Surface& dst,
508 const Tegra::Engines::Fermi2D::Config& copy_config) {
509 texture_cache.DoFermiCopy(src, dst, copy_config);
510 return true;
511}
512
513bool RasterizerVulkan::AccelerateDisplay(const Tegra::FramebufferConfig& config,
514 VAddr framebuffer_addr, u32 pixel_stride) {
515 if (!framebuffer_addr) {
516 return false;
517 }
518
519 const u8* host_ptr{system.Memory().GetPointer(framebuffer_addr)};
520 const auto surface{texture_cache.TryFindFramebufferSurface(host_ptr)};
521 if (!surface) {
522 return false;
523 }
524
525 // Verify that the cached surface is the same size and format as the requested framebuffer
526 const auto& params{surface->GetSurfaceParams()};
527 const auto& pixel_format{
528 VideoCore::Surface::PixelFormatFromGPUPixelFormat(config.pixel_format)};
529 ASSERT_MSG(params.width == config.width, "Framebuffer width is different");
530 ASSERT_MSG(params.height == config.height, "Framebuffer height is different");
531
532 screen_info.image = &surface->GetImage();
533 screen_info.width = params.width;
534 screen_info.height = params.height;
535 screen_info.is_srgb = surface->GetSurfaceParams().srgb_conversion;
536 return true;
537}
538
539void RasterizerVulkan::FlushWork() {
540 static constexpr u32 DRAWS_TO_DISPATCH = 4096;
541
542 // Only check multiples of 8 draws
543 static_assert(DRAWS_TO_DISPATCH % 8 == 0);
544 if ((++draw_counter & 7) != 7) {
545 return;
546 }
547
548 if (draw_counter < DRAWS_TO_DISPATCH) {
549 // Send recorded tasks to the worker thread
550 scheduler.DispatchWork();
551 return;
552 }
553
554 // Otherwise (every certain number of draws) flush execution.
555 // This submits commands to the Vulkan driver.
556 scheduler.Flush();
557 draw_counter = 0;
558}
559
560RasterizerVulkan::Texceptions RasterizerVulkan::UpdateAttachments() {
561 MICROPROFILE_SCOPE(Vulkan_RenderTargets);
562 auto& dirty = system.GPU().Maxwell3D().dirty;
563 const bool update_rendertargets = dirty.render_settings;
564 dirty.render_settings = false;
565
566 texture_cache.GuardRenderTargets(true);
567
568 Texceptions texceptions;
569 for (std::size_t rt = 0; rt < Maxwell::NumRenderTargets; ++rt) {
570 if (update_rendertargets) {
571 color_attachments[rt] = texture_cache.GetColorBufferSurface(rt, true);
572 }
573 if (color_attachments[rt] && WalkAttachmentOverlaps(*color_attachments[rt])) {
574 texceptions.set(rt);
575 }
576 }
577
578 if (update_rendertargets) {
579 zeta_attachment = texture_cache.GetDepthBufferSurface(true);
580 }
581 if (zeta_attachment && WalkAttachmentOverlaps(*zeta_attachment)) {
582 texceptions.set(ZETA_TEXCEPTION_INDEX);
583 }
584
585 texture_cache.GuardRenderTargets(false);
586
587 return texceptions;
588}
589
590bool RasterizerVulkan::WalkAttachmentOverlaps(const CachedSurfaceView& attachment) {
591 bool overlap = false;
592 for (auto& [view, layout] : sampled_views) {
593 if (!attachment.IsSameSurface(*view)) {
594 continue;
595 }
596 overlap = true;
597 *layout = vk::ImageLayout::eGeneral;
598 }
599 return overlap;
600}
601
602std::tuple<vk::Framebuffer, vk::Extent2D> RasterizerVulkan::ConfigureFramebuffers(
603 vk::RenderPass renderpass) {
604 FramebufferCacheKey key{renderpass, std::numeric_limits<u32>::max(),
605 std::numeric_limits<u32>::max()};
606
607 const auto MarkAsModifiedAndPush = [&](const View& view) {
608 if (view == nullptr) {
609 return false;
610 }
611 key.views.push_back(view->GetHandle());
612 key.width = std::min(key.width, view->GetWidth());
613 key.height = std::min(key.height, view->GetHeight());
614 return true;
615 };
616
617 for (std::size_t index = 0; index < std::size(color_attachments); ++index) {
618 if (MarkAsModifiedAndPush(color_attachments[index])) {
619 texture_cache.MarkColorBufferInUse(index);
620 }
621 }
622 if (MarkAsModifiedAndPush(zeta_attachment)) {
623 texture_cache.MarkDepthBufferInUse();
624 }
625
626 const auto [fbentry, is_cache_miss] = framebuffer_cache.try_emplace(key);
627 auto& framebuffer = fbentry->second;
628 if (is_cache_miss) {
629 const vk::FramebufferCreateInfo framebuffer_ci({}, key.renderpass,
630 static_cast<u32>(key.views.size()),
631 key.views.data(), key.width, key.height, 1);
632 const auto dev = device.GetLogical();
633 const auto& dld = device.GetDispatchLoader();
634 framebuffer = dev.createFramebufferUnique(framebuffer_ci, nullptr, dld);
635 }
636
637 return {*framebuffer, vk::Extent2D{key.width, key.height}};
638}
639
640RasterizerVulkan::DrawParameters RasterizerVulkan::SetupGeometry(FixedPipelineState& fixed_state,
641 BufferBindings& buffer_bindings,
642 bool is_indexed,
643 bool is_instanced) {
644 MICROPROFILE_SCOPE(Vulkan_Geometry);
645
646 const auto& gpu = system.GPU().Maxwell3D();
647 const auto& regs = gpu.regs;
648
649 SetupVertexArrays(fixed_state.vertex_input, buffer_bindings);
650
651 const u32 base_instance = regs.vb_base_instance;
652 const u32 num_instances = is_instanced ? gpu.mme_draw.instance_count : 1;
653 const u32 base_vertex = is_indexed ? regs.vb_element_base : regs.vertex_buffer.first;
654 const u32 num_vertices = is_indexed ? regs.index_array.count : regs.vertex_buffer.count;
655
656 DrawParameters params{base_instance, num_instances, base_vertex, num_vertices, is_indexed};
657 SetupIndexBuffer(buffer_bindings, params, is_indexed);
658
659 return params;
660}
661
662void RasterizerVulkan::SetupShaderDescriptors(
663 const std::array<Shader, Maxwell::MaxShaderProgram>& shaders) {
664 texture_cache.GuardSamplers(true);
665
666 for (std::size_t stage = 0; stage < Maxwell::MaxShaderStage; ++stage) {
667 // Skip VertexA stage
668 const auto& shader = shaders[stage + 1];
669 if (!shader) {
670 continue;
671 }
672 const auto& entries = shader->GetEntries();
673 SetupGraphicsConstBuffers(entries, stage);
674 SetupGraphicsGlobalBuffers(entries, stage);
675 SetupGraphicsTexelBuffers(entries, stage);
676 SetupGraphicsTextures(entries, stage);
677 SetupGraphicsImages(entries, stage);
678 }
679 texture_cache.GuardSamplers(false);
680}
681
682void RasterizerVulkan::SetupImageTransitions(
683 Texceptions texceptions, const std::array<View, Maxwell::NumRenderTargets>& color_attachments,
684 const View& zeta_attachment) {
685 TransitionImages(sampled_views, vk::PipelineStageFlagBits::eAllGraphics,
686 vk::AccessFlagBits::eShaderRead);
687 TransitionImages(image_views, vk::PipelineStageFlagBits::eAllGraphics,
688 vk::AccessFlagBits::eShaderRead | vk::AccessFlagBits::eShaderWrite);
689
690 for (std::size_t rt = 0; rt < std::size(color_attachments); ++rt) {
691 const auto color_attachment = color_attachments[rt];
692 if (color_attachment == nullptr) {
693 continue;
694 }
695 const auto image_layout =
696 texceptions[rt] ? vk::ImageLayout::eGeneral : vk::ImageLayout::eColorAttachmentOptimal;
697 color_attachment->Transition(
698 image_layout, vk::PipelineStageFlagBits::eColorAttachmentOutput,
699 vk::AccessFlagBits::eColorAttachmentRead | vk::AccessFlagBits::eColorAttachmentWrite);
700 }
701
702 if (zeta_attachment != nullptr) {
703 const auto image_layout = texceptions[ZETA_TEXCEPTION_INDEX]
704 ? vk::ImageLayout::eGeneral
705 : vk::ImageLayout::eDepthStencilAttachmentOptimal;
706 zeta_attachment->Transition(image_layout, vk::PipelineStageFlagBits::eLateFragmentTests,
707 vk::AccessFlagBits::eDepthStencilAttachmentRead |
708 vk::AccessFlagBits::eDepthStencilAttachmentWrite);
709 }
710}
711
712void RasterizerVulkan::UpdateDynamicStates() {
713 auto& gpu = system.GPU().Maxwell3D();
714 UpdateViewportsState(gpu);
715 UpdateScissorsState(gpu);
716 UpdateDepthBias(gpu);
717 UpdateBlendConstants(gpu);
718 UpdateDepthBounds(gpu);
719 UpdateStencilFaces(gpu);
720}
721
722void RasterizerVulkan::SetupVertexArrays(FixedPipelineState::VertexInput& vertex_input,
723 BufferBindings& buffer_bindings) {
724 const auto& regs = system.GPU().Maxwell3D().regs;
725
726 for (u32 index = 0; index < static_cast<u32>(Maxwell::NumVertexAttributes); ++index) {
727 const auto& attrib = regs.vertex_attrib_format[index];
728 if (!attrib.IsValid()) {
729 continue;
730 }
731
732 const auto& buffer = regs.vertex_array[attrib.buffer];
733 ASSERT(buffer.IsEnabled());
734
735 vertex_input.attributes[vertex_input.num_attributes++] =
736 FixedPipelineState::VertexAttribute(index, attrib.buffer, attrib.type, attrib.size,
737 attrib.offset);
738 }
739
740 for (u32 index = 0; index < static_cast<u32>(Maxwell::NumVertexArrays); ++index) {
741 const auto& vertex_array = regs.vertex_array[index];
742 if (!vertex_array.IsEnabled()) {
743 continue;
744 }
745
746 const GPUVAddr start{vertex_array.StartAddress()};
747 const GPUVAddr end{regs.vertex_array_limit[index].LimitAddress()};
748
749 ASSERT(end > start);
750 const std::size_t size{end - start + 1};
751 const auto [buffer, offset] = buffer_cache.UploadMemory(start, size);
752
753 vertex_input.bindings[vertex_input.num_bindings++] = FixedPipelineState::VertexBinding(
754 index, vertex_array.stride,
755 regs.instanced_arrays.IsInstancingEnabled(index) ? vertex_array.divisor : 0);
756 buffer_bindings.AddVertexBinding(buffer, offset);
757 }
758}
759
760void RasterizerVulkan::SetupIndexBuffer(BufferBindings& buffer_bindings, DrawParameters& params,
761 bool is_indexed) {
762 const auto& regs = system.GPU().Maxwell3D().regs;
763 switch (regs.draw.topology) {
764 case Maxwell::PrimitiveTopology::Quads:
765 if (params.is_indexed) {
766 UNIMPLEMENTED();
767 } else {
768 const auto [buffer, offset] =
769 quad_array_pass.Assemble(params.num_vertices, params.base_vertex);
770 buffer_bindings.SetIndexBinding(&buffer, offset, vk::IndexType::eUint32);
771 params.base_vertex = 0;
772 params.num_vertices = params.num_vertices * 6 / 4;
773 params.is_indexed = true;
774 }
775 break;
776 default: {
777 if (!is_indexed) {
778 break;
779 }
780 const GPUVAddr gpu_addr = regs.index_array.IndexStart();
781 auto [buffer, offset] = buffer_cache.UploadMemory(gpu_addr, CalculateIndexBufferSize());
782
783 auto format = regs.index_array.format;
784 const bool is_uint8 = format == Maxwell::IndexFormat::UnsignedByte;
785 if (is_uint8 && !device.IsExtIndexTypeUint8Supported()) {
786 std::tie(buffer, offset) = uint8_pass.Assemble(params.num_vertices, *buffer, offset);
787 format = Maxwell::IndexFormat::UnsignedShort;
788 }
789
790 buffer_bindings.SetIndexBinding(buffer, offset, MaxwellToVK::IndexFormat(device, format));
791 break;
792 }
793 }
794}
795
796void RasterizerVulkan::SetupGraphicsConstBuffers(const ShaderEntries& entries, std::size_t stage) {
797 MICROPROFILE_SCOPE(Vulkan_ConstBuffers);
798 const auto& gpu = system.GPU().Maxwell3D();
799 const auto& shader_stage = gpu.state.shader_stages[stage];
800 for (const auto& entry : entries.const_buffers) {
801 SetupConstBuffer(entry, shader_stage.const_buffers[entry.GetIndex()]);
802 }
803}
804
805void RasterizerVulkan::SetupGraphicsGlobalBuffers(const ShaderEntries& entries, std::size_t stage) {
806 MICROPROFILE_SCOPE(Vulkan_GlobalBuffers);
807 auto& gpu{system.GPU()};
808 const auto cbufs{gpu.Maxwell3D().state.shader_stages[stage]};
809
810 for (const auto& entry : entries.global_buffers) {
811 const auto addr = cbufs.const_buffers[entry.GetCbufIndex()].address + entry.GetCbufOffset();
812 SetupGlobalBuffer(entry, addr);
813 }
814}
815
816void RasterizerVulkan::SetupGraphicsTexelBuffers(const ShaderEntries& entries, std::size_t stage) {
817 MICROPROFILE_SCOPE(Vulkan_Textures);
818 const auto& gpu = system.GPU().Maxwell3D();
819 for (const auto& entry : entries.texel_buffers) {
820 const auto image = GetTextureInfo(gpu, entry, stage).tic;
821 SetupTexelBuffer(image, entry);
822 }
823}
824
825void RasterizerVulkan::SetupGraphicsTextures(const ShaderEntries& entries, std::size_t stage) {
826 MICROPROFILE_SCOPE(Vulkan_Textures);
827 const auto& gpu = system.GPU().Maxwell3D();
828 for (const auto& entry : entries.samplers) {
829 const auto texture = GetTextureInfo(gpu, entry, stage);
830 SetupTexture(texture, entry);
831 }
832}
833
834void RasterizerVulkan::SetupGraphicsImages(const ShaderEntries& entries, std::size_t stage) {
835 MICROPROFILE_SCOPE(Vulkan_Images);
836 const auto& gpu = system.GPU().KeplerCompute();
837 for (const auto& entry : entries.images) {
838 const auto tic = GetTextureInfo(gpu, entry, stage).tic;
839 SetupImage(tic, entry);
840 }
841}
842
843void RasterizerVulkan::SetupComputeConstBuffers(const ShaderEntries& entries) {
844 MICROPROFILE_SCOPE(Vulkan_ConstBuffers);
845 const auto& launch_desc = system.GPU().KeplerCompute().launch_description;
846 for (const auto& entry : entries.const_buffers) {
847 const auto& config = launch_desc.const_buffer_config[entry.GetIndex()];
848 const std::bitset<8> mask = launch_desc.const_buffer_enable_mask.Value();
849 Tegra::Engines::ConstBufferInfo buffer;
850 buffer.address = config.Address();
851 buffer.size = config.size;
852 buffer.enabled = mask[entry.GetIndex()];
853 SetupConstBuffer(entry, buffer);
854 }
855}
856
857void RasterizerVulkan::SetupComputeGlobalBuffers(const ShaderEntries& entries) {
858 MICROPROFILE_SCOPE(Vulkan_GlobalBuffers);
859 const auto cbufs{system.GPU().KeplerCompute().launch_description.const_buffer_config};
860 for (const auto& entry : entries.global_buffers) {
861 const auto addr{cbufs[entry.GetCbufIndex()].Address() + entry.GetCbufOffset()};
862 SetupGlobalBuffer(entry, addr);
863 }
864}
865
866void RasterizerVulkan::SetupComputeTexelBuffers(const ShaderEntries& entries) {
867 MICROPROFILE_SCOPE(Vulkan_Textures);
868 const auto& gpu = system.GPU().KeplerCompute();
869 for (const auto& entry : entries.texel_buffers) {
870 const auto image = GetTextureInfo(gpu, entry, ComputeShaderIndex).tic;
871 SetupTexelBuffer(image, entry);
872 }
873}
874
875void RasterizerVulkan::SetupComputeTextures(const ShaderEntries& entries) {
876 MICROPROFILE_SCOPE(Vulkan_Textures);
877 const auto& gpu = system.GPU().KeplerCompute();
878 for (const auto& entry : entries.samplers) {
879 const auto texture = GetTextureInfo(gpu, entry, ComputeShaderIndex);
880 SetupTexture(texture, entry);
881 }
882}
883
884void RasterizerVulkan::SetupComputeImages(const ShaderEntries& entries) {
885 MICROPROFILE_SCOPE(Vulkan_Images);
886 const auto& gpu = system.GPU().KeplerCompute();
887 for (const auto& entry : entries.images) {
888 const auto tic = GetTextureInfo(gpu, entry, ComputeShaderIndex).tic;
889 SetupImage(tic, entry);
890 }
891}
892
893void RasterizerVulkan::SetupConstBuffer(const ConstBufferEntry& entry,
894 const Tegra::Engines::ConstBufferInfo& buffer) {
895 // Align the size to avoid bad std140 interactions
896 const std::size_t size =
897 Common::AlignUp(CalculateConstBufferSize(entry, buffer), 4 * sizeof(float));
898 ASSERT(size <= MaxConstbufferSize);
899
900 const auto [buffer_handle, offset] =
901 buffer_cache.UploadMemory(buffer.address, size, device.GetUniformBufferAlignment());
902
903 update_descriptor_queue.AddBuffer(buffer_handle, offset, size);
904}
905
906void RasterizerVulkan::SetupGlobalBuffer(const GlobalBufferEntry& entry, GPUVAddr address) {
907 auto& memory_manager{system.GPU().MemoryManager()};
908 const auto actual_addr = memory_manager.Read<u64>(address);
909 const auto size = memory_manager.Read<u32>(address + 8);
910
911 if (size == 0) {
912 // Sometimes global memory pointers don't have a proper size. Upload a dummy entry because
913 // Vulkan doesn't like empty buffers.
914 constexpr std::size_t dummy_size = 4;
915 const auto buffer = buffer_cache.GetEmptyBuffer(dummy_size);
916 update_descriptor_queue.AddBuffer(buffer, 0, dummy_size);
917 return;
918 }
919
920 const auto [buffer, offset] = buffer_cache.UploadMemory(
921 actual_addr, size, device.GetStorageBufferAlignment(), entry.IsWritten());
922 update_descriptor_queue.AddBuffer(buffer, offset, size);
923}
924
925void RasterizerVulkan::SetupTexelBuffer(const Tegra::Texture::TICEntry& tic,
926 const TexelBufferEntry& entry) {
927 const auto view = texture_cache.GetTextureSurface(tic, entry);
928 ASSERT(view->IsBufferView());
929
930 update_descriptor_queue.AddTexelBuffer(view->GetBufferView());
931}
932
933void RasterizerVulkan::SetupTexture(const Tegra::Texture::FullTextureInfo& texture,
934 const SamplerEntry& entry) {
935 auto view = texture_cache.GetTextureSurface(texture.tic, entry);
936 ASSERT(!view->IsBufferView());
937
938 const auto image_view = view->GetHandle(texture.tic.x_source, texture.tic.y_source,
939 texture.tic.z_source, texture.tic.w_source);
940 const auto sampler = sampler_cache.GetSampler(texture.tsc);
941 update_descriptor_queue.AddSampledImage(sampler, image_view);
942
943 const auto image_layout = update_descriptor_queue.GetLastImageLayout();
944 *image_layout = vk::ImageLayout::eShaderReadOnlyOptimal;
945 sampled_views.push_back(ImageView{std::move(view), image_layout});
946}
947
948void RasterizerVulkan::SetupImage(const Tegra::Texture::TICEntry& tic, const ImageEntry& entry) {
949 auto view = texture_cache.GetImageSurface(tic, entry);
950
951 if (entry.IsWritten()) {
952 view->MarkAsModified(texture_cache.Tick());
953 }
954
955 UNIMPLEMENTED_IF(tic.IsBuffer());
956
957 const auto image_view = view->GetHandle(tic.x_source, tic.y_source, tic.z_source, tic.w_source);
958 update_descriptor_queue.AddImage(image_view);
959
960 const auto image_layout = update_descriptor_queue.GetLastImageLayout();
961 *image_layout = vk::ImageLayout::eGeneral;
962 image_views.push_back(ImageView{std::move(view), image_layout});
963}
964
965void RasterizerVulkan::UpdateViewportsState(Tegra::Engines::Maxwell3D& gpu) {
966 if (!gpu.dirty.viewport_transform && scheduler.TouchViewports()) {
967 return;
968 }
969 gpu.dirty.viewport_transform = false;
970 const auto& regs = gpu.regs;
971 const std::array viewports{
972 GetViewportState(device, regs, 0), GetViewportState(device, regs, 1),
973 GetViewportState(device, regs, 2), GetViewportState(device, regs, 3),
974 GetViewportState(device, regs, 4), GetViewportState(device, regs, 5),
975 GetViewportState(device, regs, 6), GetViewportState(device, regs, 7),
976 GetViewportState(device, regs, 8), GetViewportState(device, regs, 9),
977 GetViewportState(device, regs, 10), GetViewportState(device, regs, 11),
978 GetViewportState(device, regs, 12), GetViewportState(device, regs, 13),
979 GetViewportState(device, regs, 14), GetViewportState(device, regs, 15)};
980 scheduler.Record([viewports](auto cmdbuf, auto& dld) {
981 cmdbuf.setViewport(0, static_cast<u32>(viewports.size()), viewports.data(), dld);
982 });
983}
984
985void RasterizerVulkan::UpdateScissorsState(Tegra::Engines::Maxwell3D& gpu) {
986 if (!gpu.dirty.scissor_test && scheduler.TouchScissors()) {
987 return;
988 }
989 gpu.dirty.scissor_test = false;
990 const auto& regs = gpu.regs;
991 const std::array scissors = {
992 GetScissorState(regs, 0), GetScissorState(regs, 1), GetScissorState(regs, 2),
993 GetScissorState(regs, 3), GetScissorState(regs, 4), GetScissorState(regs, 5),
994 GetScissorState(regs, 6), GetScissorState(regs, 7), GetScissorState(regs, 8),
995 GetScissorState(regs, 9), GetScissorState(regs, 10), GetScissorState(regs, 11),
996 GetScissorState(regs, 12), GetScissorState(regs, 13), GetScissorState(regs, 14),
997 GetScissorState(regs, 15)};
998 scheduler.Record([scissors](auto cmdbuf, auto& dld) {
999 cmdbuf.setScissor(0, static_cast<u32>(scissors.size()), scissors.data(), dld);
1000 });
1001}
1002
1003void RasterizerVulkan::UpdateDepthBias(Tegra::Engines::Maxwell3D& gpu) {
1004 if (!gpu.dirty.polygon_offset && scheduler.TouchDepthBias()) {
1005 return;
1006 }
1007 gpu.dirty.polygon_offset = false;
1008 const auto& regs = gpu.regs;
1009 scheduler.Record([constant = regs.polygon_offset_units, clamp = regs.polygon_offset_clamp,
1010 factor = regs.polygon_offset_factor](auto cmdbuf, auto& dld) {
1011 cmdbuf.setDepthBias(constant, clamp, factor / 2.0f, dld);
1012 });
1013}
1014
1015void RasterizerVulkan::UpdateBlendConstants(Tegra::Engines::Maxwell3D& gpu) {
1016 if (!gpu.dirty.blend_state && scheduler.TouchBlendConstants()) {
1017 return;
1018 }
1019 gpu.dirty.blend_state = false;
1020 const std::array blend_color = {gpu.regs.blend_color.r, gpu.regs.blend_color.g,
1021 gpu.regs.blend_color.b, gpu.regs.blend_color.a};
1022 scheduler.Record([blend_color](auto cmdbuf, auto& dld) {
1023 cmdbuf.setBlendConstants(blend_color.data(), dld);
1024 });
1025}
1026
1027void RasterizerVulkan::UpdateDepthBounds(Tegra::Engines::Maxwell3D& gpu) {
1028 if (!gpu.dirty.depth_bounds_values && scheduler.TouchDepthBounds()) {
1029 return;
1030 }
1031 gpu.dirty.depth_bounds_values = false;
1032 const auto& regs = gpu.regs;
1033 scheduler.Record([min = regs.depth_bounds[0], max = regs.depth_bounds[1]](
1034 auto cmdbuf, auto& dld) { cmdbuf.setDepthBounds(min, max, dld); });
1035}
1036
1037void RasterizerVulkan::UpdateStencilFaces(Tegra::Engines::Maxwell3D& gpu) {
1038 if (!gpu.dirty.stencil_test && scheduler.TouchStencilValues()) {
1039 return;
1040 }
1041 gpu.dirty.stencil_test = false;
1042 const auto& regs = gpu.regs;
1043 if (regs.stencil_two_side_enable) {
1044 // Separate values per face
1045 scheduler.Record(
1046 [front_ref = regs.stencil_front_func_ref, front_write_mask = regs.stencil_front_mask,
1047 front_test_mask = regs.stencil_front_func_mask, back_ref = regs.stencil_back_func_ref,
1048 back_write_mask = regs.stencil_back_mask,
1049 back_test_mask = regs.stencil_back_func_mask](auto cmdbuf, auto& dld) {
1050 // Front face
1051 cmdbuf.setStencilReference(vk::StencilFaceFlagBits::eFront, front_ref, dld);
1052 cmdbuf.setStencilWriteMask(vk::StencilFaceFlagBits::eFront, front_write_mask, dld);
1053 cmdbuf.setStencilCompareMask(vk::StencilFaceFlagBits::eFront, front_test_mask, dld);
1054
1055 // Back face
1056 cmdbuf.setStencilReference(vk::StencilFaceFlagBits::eBack, back_ref, dld);
1057 cmdbuf.setStencilWriteMask(vk::StencilFaceFlagBits::eBack, back_write_mask, dld);
1058 cmdbuf.setStencilCompareMask(vk::StencilFaceFlagBits::eBack, back_test_mask, dld);
1059 });
1060 } else {
1061 // Front face defines both faces
1062 scheduler.Record([ref = regs.stencil_back_func_ref, write_mask = regs.stencil_back_mask,
1063 test_mask = regs.stencil_back_func_mask](auto cmdbuf, auto& dld) {
1064 cmdbuf.setStencilReference(vk::StencilFaceFlagBits::eFrontAndBack, ref, dld);
1065 cmdbuf.setStencilWriteMask(vk::StencilFaceFlagBits::eFrontAndBack, write_mask, dld);
1066 cmdbuf.setStencilCompareMask(vk::StencilFaceFlagBits::eFrontAndBack, test_mask, dld);
1067 });
1068 }
1069}
1070
1071std::size_t RasterizerVulkan::CalculateGraphicsStreamBufferSize(bool is_indexed) const {
1072 std::size_t size = CalculateVertexArraysSize();
1073 if (is_indexed) {
1074 size = Common::AlignUp(size, 4) + CalculateIndexBufferSize();
1075 }
1076 size += Maxwell::MaxConstBuffers * (MaxConstbufferSize + device.GetUniformBufferAlignment());
1077 return size;
1078}
1079
1080std::size_t RasterizerVulkan::CalculateComputeStreamBufferSize() const {
1081 return Tegra::Engines::KeplerCompute::NumConstBuffers *
1082 (Maxwell::MaxConstBufferSize + device.GetUniformBufferAlignment());
1083}
1084
1085std::size_t RasterizerVulkan::CalculateVertexArraysSize() const {
1086 const auto& regs = system.GPU().Maxwell3D().regs;
1087
1088 std::size_t size = 0;
1089 for (u32 index = 0; index < Maxwell::NumVertexArrays; ++index) {
1090 // This implementation assumes that all attributes are used in the shader.
1091 const GPUVAddr start{regs.vertex_array[index].StartAddress()};
1092 const GPUVAddr end{regs.vertex_array_limit[index].LimitAddress()};
1093 DEBUG_ASSERT(end > start);
1094
1095 size += (end - start + 1) * regs.vertex_array[index].enable;
1096 }
1097 return size;
1098}
1099
1100std::size_t RasterizerVulkan::CalculateIndexBufferSize() const {
1101 const auto& regs = system.GPU().Maxwell3D().regs;
1102 return static_cast<std::size_t>(regs.index_array.count) *
1103 static_cast<std::size_t>(regs.index_array.FormatSizeInBytes());
1104}
1105
1106std::size_t RasterizerVulkan::CalculateConstBufferSize(
1107 const ConstBufferEntry& entry, const Tegra::Engines::ConstBufferInfo& buffer) const {
1108 if (entry.IsIndirect()) {
1109 // Buffer is accessed indirectly, so upload the entire thing
1110 return buffer.size;
1111 } else {
1112 // Buffer is accessed directly, upload just what we use
1113 return entry.GetSize();
1114 }
1115}
1116
1117RenderPassParams RasterizerVulkan::GetRenderPassParams(Texceptions texceptions) const {
1118 using namespace VideoCore::Surface;
1119
1120 const auto& regs = system.GPU().Maxwell3D().regs;
1121 RenderPassParams renderpass_params;
1122
1123 for (std::size_t rt = 0; rt < static_cast<std::size_t>(regs.rt_control.count); ++rt) {
1124 const auto& rendertarget = regs.rt[rt];
1125 if (rendertarget.Address() == 0 || rendertarget.format == Tegra::RenderTargetFormat::NONE)
1126 continue;
1127 renderpass_params.color_attachments.push_back(RenderPassParams::ColorAttachment{
1128 static_cast<u32>(rt), PixelFormatFromRenderTargetFormat(rendertarget.format),
1129 texceptions.test(rt)});
1130 }
1131
1132 renderpass_params.has_zeta = regs.zeta_enable;
1133 if (renderpass_params.has_zeta) {
1134 renderpass_params.zeta_pixel_format = PixelFormatFromDepthFormat(regs.zeta.format);
1135 renderpass_params.zeta_texception = texceptions[ZETA_TEXCEPTION_INDEX];
1136 }
1137
1138 return renderpass_params;
1139}
1140
1141} // namespace Vulkan
diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.h b/src/video_core/renderer_vulkan/vk_rasterizer.h
index fc324952b..7be71e734 100644
--- a/src/video_core/renderer_vulkan/vk_rasterizer.h
+++ b/src/video_core/renderer_vulkan/vk_rasterizer.h
@@ -4,10 +4,260 @@
4 4
5#pragma once 5#pragma once
6 6
7#include <array>
8#include <bitset>
9#include <memory>
10#include <utility>
11#include <vector>
12
13#include <boost/container/static_vector.hpp>
14#include <boost/functional/hash.hpp>
15
16#include "common/common_types.h"
17#include "video_core/memory_manager.h"
18#include "video_core/rasterizer_accelerated.h"
7#include "video_core/rasterizer_interface.h" 19#include "video_core/rasterizer_interface.h"
20#include "video_core/renderer_vulkan/declarations.h"
21#include "video_core/renderer_vulkan/fixed_pipeline_state.h"
22#include "video_core/renderer_vulkan/vk_buffer_cache.h"
23#include "video_core/renderer_vulkan/vk_compute_pass.h"
24#include "video_core/renderer_vulkan/vk_descriptor_pool.h"
25#include "video_core/renderer_vulkan/vk_memory_manager.h"
26#include "video_core/renderer_vulkan/vk_pipeline_cache.h"
27#include "video_core/renderer_vulkan/vk_renderpass_cache.h"
28#include "video_core/renderer_vulkan/vk_resource_manager.h"
29#include "video_core/renderer_vulkan/vk_sampler_cache.h"
30#include "video_core/renderer_vulkan/vk_scheduler.h"
31#include "video_core/renderer_vulkan/vk_staging_buffer_pool.h"
32#include "video_core/renderer_vulkan/vk_texture_cache.h"
33#include "video_core/renderer_vulkan/vk_update_descriptor.h"
34
35namespace Core {
36class System;
37}
38
39namespace Core::Frontend {
40class EmuWindow;
41}
42
43namespace Tegra::Engines {
44class Maxwell3D;
45}
46
47namespace Vulkan {
48
49struct VKScreenInfo;
50
51using ImageViewsPack =
52 boost::container::static_vector<vk::ImageView, Maxwell::NumRenderTargets + 1>;
53
54struct FramebufferCacheKey {
55 vk::RenderPass renderpass{};
56 u32 width = 0;
57 u32 height = 0;
58 ImageViewsPack views;
59
60 std::size_t Hash() const noexcept {
61 std::size_t hash = 0;
62 boost::hash_combine(hash, static_cast<VkRenderPass>(renderpass));
63 for (const auto& view : views) {
64 boost::hash_combine(hash, static_cast<VkImageView>(view));
65 }
66 boost::hash_combine(hash, width);
67 boost::hash_combine(hash, height);
68 return hash;
69 }
70
71 bool operator==(const FramebufferCacheKey& rhs) const noexcept {
72 return std::tie(renderpass, views, width, height) ==
73 std::tie(rhs.renderpass, rhs.views, rhs.width, rhs.height);
74 }
75};
76
77} // namespace Vulkan
78
79namespace std {
80
81template <>
82struct hash<Vulkan::FramebufferCacheKey> {
83 std::size_t operator()(const Vulkan::FramebufferCacheKey& k) const noexcept {
84 return k.Hash();
85 }
86};
87
88} // namespace std
8 89
9namespace Vulkan { 90namespace Vulkan {
10 91
11class RasterizerVulkan : public VideoCore::RasterizerInterface {}; 92class BufferBindings;
93
94struct ImageView {
95 View view;
96 vk::ImageLayout* layout = nullptr;
97};
98
99class RasterizerVulkan : public VideoCore::RasterizerAccelerated {
100public:
101 explicit RasterizerVulkan(Core::System& system, Core::Frontend::EmuWindow& render_window,
102 VKScreenInfo& screen_info, const VKDevice& device,
103 VKResourceManager& resource_manager, VKMemoryManager& memory_manager,
104 VKScheduler& scheduler);
105 ~RasterizerVulkan() override;
106
107 bool DrawBatch(bool is_indexed) override;
108 bool DrawMultiBatch(bool is_indexed) override;
109 void Clear() override;
110 void DispatchCompute(GPUVAddr code_addr) override;
111 void FlushAll() override;
112 void FlushRegion(CacheAddr addr, u64 size) override;
113 void InvalidateRegion(CacheAddr addr, u64 size) override;
114 void FlushAndInvalidateRegion(CacheAddr addr, u64 size) override;
115 void FlushCommands() override;
116 void TickFrame() override;
117 bool AccelerateSurfaceCopy(const Tegra::Engines::Fermi2D::Regs::Surface& src,
118 const Tegra::Engines::Fermi2D::Regs::Surface& dst,
119 const Tegra::Engines::Fermi2D::Config& copy_config) override;
120 bool AccelerateDisplay(const Tegra::FramebufferConfig& config, VAddr framebuffer_addr,
121 u32 pixel_stride) override;
122
123 /// Maximum supported size that a constbuffer can have in bytes.
124 static constexpr std::size_t MaxConstbufferSize = 0x10000;
125 static_assert(MaxConstbufferSize % (4 * sizeof(float)) == 0,
126 "The maximum size of a constbuffer must be a multiple of the size of GLvec4");
127
128private:
129 struct DrawParameters {
130 void Draw(vk::CommandBuffer cmdbuf, const vk::DispatchLoaderDynamic& dld) const;
131
132 u32 base_instance = 0;
133 u32 num_instances = 0;
134 u32 base_vertex = 0;
135 u32 num_vertices = 0;
136 bool is_indexed = 0;
137 };
138
139 using Texceptions = std::bitset<Maxwell::NumRenderTargets + 1>;
140
141 static constexpr std::size_t ZETA_TEXCEPTION_INDEX = 8;
142
143 void Draw(bool is_indexed, bool is_instanced);
144
145 void FlushWork();
146
147 Texceptions UpdateAttachments();
148
149 std::tuple<vk::Framebuffer, vk::Extent2D> ConfigureFramebuffers(vk::RenderPass renderpass);
150
151 /// Setups geometry buffers and state.
152 DrawParameters SetupGeometry(FixedPipelineState& fixed_state, BufferBindings& buffer_bindings,
153 bool is_indexed, bool is_instanced);
154
155 /// Setup descriptors in the graphics pipeline.
156 void SetupShaderDescriptors(const std::array<Shader, Maxwell::MaxShaderProgram>& shaders);
157
158 void SetupImageTransitions(Texceptions texceptions,
159 const std::array<View, Maxwell::NumRenderTargets>& color_attachments,
160 const View& zeta_attachment);
161
162 void UpdateDynamicStates();
163
164 bool WalkAttachmentOverlaps(const CachedSurfaceView& attachment);
165
166 void SetupVertexArrays(FixedPipelineState::VertexInput& vertex_input,
167 BufferBindings& buffer_bindings);
168
169 void SetupIndexBuffer(BufferBindings& buffer_bindings, DrawParameters& params, bool is_indexed);
170
171 /// Setup constant buffers in the graphics pipeline.
172 void SetupGraphicsConstBuffers(const ShaderEntries& entries, std::size_t stage);
173
174 /// Setup global buffers in the graphics pipeline.
175 void SetupGraphicsGlobalBuffers(const ShaderEntries& entries, std::size_t stage);
176
177 /// Setup texel buffers in the graphics pipeline.
178 void SetupGraphicsTexelBuffers(const ShaderEntries& entries, std::size_t stage);
179
180 /// Setup textures in the graphics pipeline.
181 void SetupGraphicsTextures(const ShaderEntries& entries, std::size_t stage);
182
183 /// Setup images in the graphics pipeline.
184 void SetupGraphicsImages(const ShaderEntries& entries, std::size_t stage);
185
186 /// Setup constant buffers in the compute pipeline.
187 void SetupComputeConstBuffers(const ShaderEntries& entries);
188
189 /// Setup global buffers in the compute pipeline.
190 void SetupComputeGlobalBuffers(const ShaderEntries& entries);
191
192 /// Setup texel buffers in the compute pipeline.
193 void SetupComputeTexelBuffers(const ShaderEntries& entries);
194
195 /// Setup textures in the compute pipeline.
196 void SetupComputeTextures(const ShaderEntries& entries);
197
198 /// Setup images in the compute pipeline.
199 void SetupComputeImages(const ShaderEntries& entries);
200
201 void SetupConstBuffer(const ConstBufferEntry& entry,
202 const Tegra::Engines::ConstBufferInfo& buffer);
203
204 void SetupGlobalBuffer(const GlobalBufferEntry& entry, GPUVAddr address);
205
206 void SetupTexelBuffer(const Tegra::Texture::TICEntry& image, const TexelBufferEntry& entry);
207
208 void SetupTexture(const Tegra::Texture::FullTextureInfo& texture, const SamplerEntry& entry);
209
210 void SetupImage(const Tegra::Texture::TICEntry& tic, const ImageEntry& entry);
211
212 void UpdateViewportsState(Tegra::Engines::Maxwell3D& gpu);
213 void UpdateScissorsState(Tegra::Engines::Maxwell3D& gpu);
214 void UpdateDepthBias(Tegra::Engines::Maxwell3D& gpu);
215 void UpdateBlendConstants(Tegra::Engines::Maxwell3D& gpu);
216 void UpdateDepthBounds(Tegra::Engines::Maxwell3D& gpu);
217 void UpdateStencilFaces(Tegra::Engines::Maxwell3D& gpu);
218
219 std::size_t CalculateGraphicsStreamBufferSize(bool is_indexed) const;
220
221 std::size_t CalculateComputeStreamBufferSize() const;
222
223 std::size_t CalculateVertexArraysSize() const;
224
225 std::size_t CalculateIndexBufferSize() const;
226
227 std::size_t CalculateConstBufferSize(const ConstBufferEntry& entry,
228 const Tegra::Engines::ConstBufferInfo& buffer) const;
229
230 RenderPassParams GetRenderPassParams(Texceptions texceptions) const;
231
232 Core::System& system;
233 Core::Frontend::EmuWindow& render_window;
234 VKScreenInfo& screen_info;
235 const VKDevice& device;
236 VKResourceManager& resource_manager;
237 VKMemoryManager& memory_manager;
238 VKScheduler& scheduler;
239
240 VKStagingBufferPool staging_pool;
241 VKDescriptorPool descriptor_pool;
242 VKUpdateDescriptorQueue update_descriptor_queue;
243 QuadArrayPass quad_array_pass;
244 Uint8Pass uint8_pass;
245
246 VKTextureCache texture_cache;
247 VKPipelineCache pipeline_cache;
248 VKBufferCache buffer_cache;
249 VKSamplerCache sampler_cache;
250
251 std::array<View, Maxwell::NumRenderTargets> color_attachments;
252 View zeta_attachment;
253
254 std::vector<ImageView> sampled_views;
255 std::vector<ImageView> image_views;
256
257 u32 draw_counter = 0;
258
259 // TODO(Rodrigo): Invalidate on image destruction
260 std::unordered_map<FramebufferCacheKey, UniqueFramebuffer> framebuffer_cache;
261};
12 262
13} // namespace Vulkan 263} // namespace Vulkan
diff --git a/src/video_core/renderer_vulkan/vk_shader_decompiler.cpp b/src/video_core/renderer_vulkan/vk_shader_decompiler.cpp
index 8fe852ce8..0cf97cafa 100644
--- a/src/video_core/renderer_vulkan/vk_shader_decompiler.cpp
+++ b/src/video_core/renderer_vulkan/vk_shader_decompiler.cpp
@@ -1796,6 +1796,11 @@ private:
1796 return {}; 1796 return {};
1797 } 1797 }
1798 1798
1799 Expression UAtomicAdd(Operation) {
1800 UNIMPLEMENTED();
1801 return {};
1802 }
1803
1799 Expression Branch(Operation operation) { 1804 Expression Branch(Operation operation) {
1800 const auto& target = std::get<ImmediateNode>(*operation[0]); 1805 const auto& target = std::get<ImmediateNode>(*operation[0]);
1801 OpStore(jmp_to, Constant(t_uint, target.GetValue())); 1806 OpStore(jmp_to, Constant(t_uint, target.GetValue()));
@@ -2373,6 +2378,8 @@ private:
2373 &SPIRVDecompiler::AtomicImageXor, 2378 &SPIRVDecompiler::AtomicImageXor,
2374 &SPIRVDecompiler::AtomicImageExchange, 2379 &SPIRVDecompiler::AtomicImageExchange,
2375 2380
2381 &SPIRVDecompiler::UAtomicAdd,
2382
2376 &SPIRVDecompiler::Branch, 2383 &SPIRVDecompiler::Branch,
2377 &SPIRVDecompiler::BranchIndirect, 2384 &SPIRVDecompiler::BranchIndirect,
2378 &SPIRVDecompiler::PushFlowStack, 2385 &SPIRVDecompiler::PushFlowStack,
diff --git a/src/video_core/shader/decode/memory.cpp b/src/video_core/shader/decode/memory.cpp
index 8cc84e935..7591a715f 100644
--- a/src/video_core/shader/decode/memory.cpp
+++ b/src/video_core/shader/decode/memory.cpp
@@ -16,6 +16,8 @@
16 16
17namespace VideoCommon::Shader { 17namespace VideoCommon::Shader {
18 18
19using Tegra::Shader::AtomicOp;
20using Tegra::Shader::AtomicType;
19using Tegra::Shader::Attribute; 21using Tegra::Shader::Attribute;
20using Tegra::Shader::Instruction; 22using Tegra::Shader::Instruction;
21using Tegra::Shader::OpCode; 23using Tegra::Shader::OpCode;
@@ -333,6 +335,23 @@ u32 ShaderIR::DecodeMemory(NodeBlock& bb, u32 pc) {
333 } 335 }
334 break; 336 break;
335 } 337 }
338 case OpCode::Id::ATOMS: {
339 UNIMPLEMENTED_IF_MSG(instr.atoms.operation != AtomicOp::Add, "operation={}",
340 static_cast<int>(instr.atoms.operation.Value()));
341 UNIMPLEMENTED_IF_MSG(instr.atoms.type != AtomicType::U32, "type={}",
342 static_cast<int>(instr.atoms.type.Value()));
343
344 const s32 offset = instr.atoms.GetImmediateOffset();
345 Node address = GetRegister(instr.gpr8);
346 address = Operation(OperationCode::IAdd, std::move(address), Immediate(offset));
347
348 Node memory = GetSharedMemory(std::move(address));
349 Node data = GetRegister(instr.gpr20);
350
351 Node value = Operation(OperationCode::UAtomicAdd, std::move(memory), std::move(data));
352 SetRegister(bb, instr.gpr0, std::move(value));
353 break;
354 }
336 case OpCode::Id::AL2P: { 355 case OpCode::Id::AL2P: {
337 // Ignore al2p.direction since we don't care about it. 356 // Ignore al2p.direction since we don't care about it.
338 357
diff --git a/src/video_core/shader/node.h b/src/video_core/shader/node.h
index 4e155542a..075c7d07c 100644
--- a/src/video_core/shader/node.h
+++ b/src/video_core/shader/node.h
@@ -162,6 +162,8 @@ enum class OperationCode {
162 AtomicImageXor, /// (MetaImage, int[N] coords) -> void 162 AtomicImageXor, /// (MetaImage, int[N] coords) -> void
163 AtomicImageExchange, /// (MetaImage, int[N] coords) -> void 163 AtomicImageExchange, /// (MetaImage, int[N] coords) -> void
164 164
165 UAtomicAdd, /// (smem, uint) -> uint
166
165 Branch, /// (uint branch_target) -> void 167 Branch, /// (uint branch_target) -> void
166 BranchIndirect, /// (uint branch_target) -> void 168 BranchIndirect, /// (uint branch_target) -> void
167 PushFlowStack, /// (uint branch_target) -> void 169 PushFlowStack, /// (uint branch_target) -> void
diff --git a/src/yuzu/configuration/configure_gamelist.cpp b/src/yuzu/configuration/configure_gamelist.cpp
index daedbc33e..e43e84d39 100644
--- a/src/yuzu/configuration/configure_gamelist.cpp
+++ b/src/yuzu/configuration/configure_gamelist.cpp
@@ -21,10 +21,8 @@ constexpr std::array default_icon_sizes{
21}; 21};
22 22
23constexpr std::array row_text_names{ 23constexpr std::array row_text_names{
24 QT_TR_NOOP("Filename"), 24 QT_TR_NOOP("Filename"), QT_TR_NOOP("Filetype"), QT_TR_NOOP("Title ID"),
25 QT_TR_NOOP("Filetype"), 25 QT_TR_NOOP("Title Name"), QT_TR_NOOP("None"),
26 QT_TR_NOOP("Title ID"),
27 QT_TR_NOOP("Title Name"),
28}; 26};
29} // Anonymous namespace 27} // Anonymous namespace
30 28
@@ -46,6 +44,12 @@ ConfigureGameList::ConfigureGameList(QWidget* parent)
46 &ConfigureGameList::RequestGameListUpdate); 44 &ConfigureGameList::RequestGameListUpdate);
47 connect(ui->row_2_text_combobox, QOverload<int>::of(&QComboBox::currentIndexChanged), this, 45 connect(ui->row_2_text_combobox, QOverload<int>::of(&QComboBox::currentIndexChanged), this,
48 &ConfigureGameList::RequestGameListUpdate); 46 &ConfigureGameList::RequestGameListUpdate);
47
48 // Update text ComboBoxes after user interaction.
49 connect(ui->row_1_text_combobox, QOverload<int>::of(&QComboBox::activated),
50 [=]() { ConfigureGameList::UpdateSecondRowComboBox(); });
51 connect(ui->row_2_text_combobox, QOverload<int>::of(&QComboBox::activated),
52 [=]() { ConfigureGameList::UpdateFirstRowComboBox(); });
49} 53}
50 54
51ConfigureGameList::~ConfigureGameList() = default; 55ConfigureGameList::~ConfigureGameList() = default;
@@ -68,10 +72,6 @@ void ConfigureGameList::SetConfiguration() {
68 ui->show_add_ons->setChecked(UISettings::values.show_add_ons); 72 ui->show_add_ons->setChecked(UISettings::values.show_add_ons);
69 ui->icon_size_combobox->setCurrentIndex( 73 ui->icon_size_combobox->setCurrentIndex(
70 ui->icon_size_combobox->findData(UISettings::values.icon_size)); 74 ui->icon_size_combobox->findData(UISettings::values.icon_size));
71 ui->row_1_text_combobox->setCurrentIndex(
72 ui->row_1_text_combobox->findData(UISettings::values.row_1_text_id));
73 ui->row_2_text_combobox->setCurrentIndex(
74 ui->row_2_text_combobox->findData(UISettings::values.row_2_text_id));
75} 75}
76 76
77void ConfigureGameList::changeEvent(QEvent* event) { 77void ConfigureGameList::changeEvent(QEvent* event) {
@@ -104,10 +104,43 @@ void ConfigureGameList::InitializeIconSizeComboBox() {
104} 104}
105 105
106void ConfigureGameList::InitializeRowComboBoxes() { 106void ConfigureGameList::InitializeRowComboBoxes() {
107 for (std::size_t i = 0; i < row_text_names.size(); ++i) { 107 UpdateFirstRowComboBox(true);
108 const QString row_text_name = QString::fromUtf8(row_text_names[i]); 108 UpdateSecondRowComboBox(true);
109}
110
111void ConfigureGameList::UpdateFirstRowComboBox(bool init) {
112 const int currentIndex =
113 init ? UISettings::values.row_1_text_id
114 : ui->row_1_text_combobox->findData(ui->row_1_text_combobox->currentData());
109 115
116 ui->row_1_text_combobox->clear();
117
118 for (std::size_t i = 0; i < row_text_names.size(); i++) {
119 const QString row_text_name = QString::fromUtf8(row_text_names[i]);
110 ui->row_1_text_combobox->addItem(row_text_name, QVariant::fromValue(i)); 120 ui->row_1_text_combobox->addItem(row_text_name, QVariant::fromValue(i));
121 }
122
123 ui->row_1_text_combobox->setCurrentIndex(ui->row_1_text_combobox->findData(currentIndex));
124
125 ui->row_1_text_combobox->removeItem(4); // None
126 ui->row_1_text_combobox->removeItem(
127 ui->row_1_text_combobox->findData(ui->row_2_text_combobox->currentData()));
128}
129
130void ConfigureGameList::UpdateSecondRowComboBox(bool init) {
131 const int currentIndex =
132 init ? UISettings::values.row_2_text_id
133 : ui->row_2_text_combobox->findData(ui->row_2_text_combobox->currentData());
134
135 ui->row_2_text_combobox->clear();
136
137 for (std::size_t i = 0; i < row_text_names.size(); ++i) {
138 const QString row_text_name = QString::fromUtf8(row_text_names[i]);
111 ui->row_2_text_combobox->addItem(row_text_name, QVariant::fromValue(i)); 139 ui->row_2_text_combobox->addItem(row_text_name, QVariant::fromValue(i));
112 } 140 }
141
142 ui->row_2_text_combobox->setCurrentIndex(ui->row_2_text_combobox->findData(currentIndex));
143
144 ui->row_2_text_combobox->removeItem(
145 ui->row_2_text_combobox->findData(ui->row_1_text_combobox->currentData()));
113} 146}
diff --git a/src/yuzu/configuration/configure_gamelist.h b/src/yuzu/configuration/configure_gamelist.h
index e11822919..ecd3fa174 100644
--- a/src/yuzu/configuration/configure_gamelist.h
+++ b/src/yuzu/configuration/configure_gamelist.h
@@ -31,5 +31,8 @@ private:
31 void InitializeIconSizeComboBox(); 31 void InitializeIconSizeComboBox();
32 void InitializeRowComboBoxes(); 32 void InitializeRowComboBoxes();
33 33
34 void UpdateFirstRowComboBox(bool init = false);
35 void UpdateSecondRowComboBox(bool init = false);
36
34 std::unique_ptr<Ui::ConfigureGameList> ui; 37 std::unique_ptr<Ui::ConfigureGameList> ui;
35}; 38};
diff --git a/src/yuzu/game_list_p.h b/src/yuzu/game_list_p.h
index 1c2b37afd..7cde72d1b 100644
--- a/src/yuzu/game_list_p.h
+++ b/src/yuzu/game_list_p.h
@@ -108,11 +108,14 @@ public:
108 }}; 108 }};
109 109
110 const auto& row1 = row_data.at(UISettings::values.row_1_text_id); 110 const auto& row1 = row_data.at(UISettings::values.row_1_text_id);
111 const auto& row2 = row_data.at(UISettings::values.row_2_text_id); 111 const int row2_id = UISettings::values.row_2_text_id;
112 112
113 if (row1.isEmpty() || row1 == row2) 113 if (row2_id == 4) // None
114 return row2; 114 return row1;
115 if (row2.isEmpty()) 115
116 const auto& row2 = row_data.at(row2_id);
117
118 if (row1 == row2)
116 return row1; 119 return row1;
117 120
118 return QString(row1 + QStringLiteral("\n ") + row2); 121 return QString(row1 + QStringLiteral("\n ") + row2);
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp
index b21fbf826..b5dd3e0d6 100644
--- a/src/yuzu/main.cpp
+++ b/src/yuzu/main.cpp
@@ -526,19 +526,30 @@ void GMainWindow::InitializeHotkeys() {
526 526
527 const QString main_window = QStringLiteral("Main Window"); 527 const QString main_window = QStringLiteral("Main Window");
528 const QString load_file = QStringLiteral("Load File"); 528 const QString load_file = QStringLiteral("Load File");
529 const QString load_amiibo = QStringLiteral("Load Amiibo");
529 const QString exit_yuzu = QStringLiteral("Exit yuzu"); 530 const QString exit_yuzu = QStringLiteral("Exit yuzu");
531 const QString restart_emulation = QStringLiteral("Restart Emulation");
530 const QString stop_emulation = QStringLiteral("Stop Emulation"); 532 const QString stop_emulation = QStringLiteral("Stop Emulation");
531 const QString toggle_filter_bar = QStringLiteral("Toggle Filter Bar"); 533 const QString toggle_filter_bar = QStringLiteral("Toggle Filter Bar");
532 const QString toggle_status_bar = QStringLiteral("Toggle Status Bar"); 534 const QString toggle_status_bar = QStringLiteral("Toggle Status Bar");
533 const QString fullscreen = QStringLiteral("Fullscreen"); 535 const QString fullscreen = QStringLiteral("Fullscreen");
536 const QString capture_screenshot = QStringLiteral("Capture Screenshot");
534 537
535 ui.action_Load_File->setShortcut(hotkey_registry.GetKeySequence(main_window, load_file)); 538 ui.action_Load_File->setShortcut(hotkey_registry.GetKeySequence(main_window, load_file));
536 ui.action_Load_File->setShortcutContext( 539 ui.action_Load_File->setShortcutContext(
537 hotkey_registry.GetShortcutContext(main_window, load_file)); 540 hotkey_registry.GetShortcutContext(main_window, load_file));
538 541
542 ui.action_Load_Amiibo->setShortcut(hotkey_registry.GetKeySequence(main_window, load_amiibo));
543 ui.action_Load_Amiibo->setShortcutContext(
544 hotkey_registry.GetShortcutContext(main_window, load_amiibo));
545
539 ui.action_Exit->setShortcut(hotkey_registry.GetKeySequence(main_window, exit_yuzu)); 546 ui.action_Exit->setShortcut(hotkey_registry.GetKeySequence(main_window, exit_yuzu));
540 ui.action_Exit->setShortcutContext(hotkey_registry.GetShortcutContext(main_window, exit_yuzu)); 547 ui.action_Exit->setShortcutContext(hotkey_registry.GetShortcutContext(main_window, exit_yuzu));
541 548
549 ui.action_Restart->setShortcut(hotkey_registry.GetKeySequence(main_window, restart_emulation));
550 ui.action_Restart->setShortcutContext(
551 hotkey_registry.GetShortcutContext(main_window, restart_emulation));
552
542 ui.action_Stop->setShortcut(hotkey_registry.GetKeySequence(main_window, stop_emulation)); 553 ui.action_Stop->setShortcut(hotkey_registry.GetKeySequence(main_window, stop_emulation));
543 ui.action_Stop->setShortcutContext( 554 ui.action_Stop->setShortcutContext(
544 hotkey_registry.GetShortcutContext(main_window, stop_emulation)); 555 hotkey_registry.GetShortcutContext(main_window, stop_emulation));
@@ -553,6 +564,11 @@ void GMainWindow::InitializeHotkeys() {
553 ui.action_Show_Status_Bar->setShortcutContext( 564 ui.action_Show_Status_Bar->setShortcutContext(
554 hotkey_registry.GetShortcutContext(main_window, toggle_status_bar)); 565 hotkey_registry.GetShortcutContext(main_window, toggle_status_bar));
555 566
567 ui.action_Capture_Screenshot->setShortcut(
568 hotkey_registry.GetKeySequence(main_window, capture_screenshot));
569 ui.action_Capture_Screenshot->setShortcutContext(
570 hotkey_registry.GetShortcutContext(main_window, capture_screenshot));
571
556 connect(hotkey_registry.GetHotkey(main_window, QStringLiteral("Load File"), this), 572 connect(hotkey_registry.GetHotkey(main_window, QStringLiteral("Load File"), this),
557 &QShortcut::activated, this, &GMainWindow::OnMenuLoadFile); 573 &QShortcut::activated, this, &GMainWindow::OnMenuLoadFile);
558 connect( 574 connect(
diff --git a/src/yuzu/main.ui b/src/yuzu/main.ui
index 21f422500..a2c9e4547 100644
--- a/src/yuzu/main.ui
+++ b/src/yuzu/main.ui
@@ -15,7 +15,7 @@
15 </property> 15 </property>
16 <property name="windowIcon"> 16 <property name="windowIcon">
17 <iconset> 17 <iconset>
18 <normaloff>src/pcafe/res/icon3_64x64.ico</normaloff>src/pcafe/res/icon3_64x64.ico</iconset> 18 <normaloff>../dist/yuzu.ico</normaloff>../dist/yuzu.ico</iconset>
19 </property> 19 </property>
20 <property name="tabShape"> 20 <property name="tabShape">
21 <enum>QTabWidget::Rounded</enum> 21 <enum>QTabWidget::Rounded</enum>
@@ -98,6 +98,7 @@
98 <addaction name="action_Display_Dock_Widget_Headers"/> 98 <addaction name="action_Display_Dock_Widget_Headers"/>
99 <addaction name="action_Show_Filter_Bar"/> 99 <addaction name="action_Show_Filter_Bar"/>
100 <addaction name="action_Show_Status_Bar"/> 100 <addaction name="action_Show_Status_Bar"/>
101 <addaction name="separator"/>
101 <addaction name="menu_View_Debugging"/> 102 <addaction name="menu_View_Debugging"/>
102 </widget> 103 </widget>
103 <widget class="QMenu" name="menu_Tools"> 104 <widget class="QMenu" name="menu_Tools">