summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/common/CMakeLists.txt1
-rw-r--r--src/common/concepts.h4
-rw-r--r--src/common/dynamic_library.cpp2
-rw-r--r--src/common/file_util.cpp4
-rw-r--r--src/common/telemetry.cpp4
-rw-r--r--src/common/telemetry.h4
-rw-r--r--src/common/time_zone.cpp14
-rw-r--r--src/core/arm/dynarmic/arm_dynarmic_32.cpp13
-rw-r--r--src/core/arm/dynarmic/arm_dynarmic_64.cpp13
-rw-r--r--src/core/core.cpp12
-rw-r--r--src/core/core_timing.cpp12
-rw-r--r--src/core/core_timing_util.cpp1
-rw-r--r--src/core/core_timing_util.h1
-rw-r--r--src/core/settings.h6
-rw-r--r--src/core/telemetry_session.cpp2
-rw-r--r--src/core/telemetry_session.h5
-rw-r--r--src/video_core/macro/macro_interpreter.cpp1
-rw-r--r--src/video_core/renderer_opengl/gl_shader_disk_cache.cpp23
-rw-r--r--src/video_core/renderer_opengl/renderer_opengl.cpp7
-rw-r--r--src/video_core/renderer_vulkan/renderer_vulkan.cpp2
-rw-r--r--src/video_core/renderer_vulkan/wrapper.cpp2
-rw-r--r--src/web_service/CMakeLists.txt1
-rw-r--r--src/web_service/telemetry_json.cpp6
-rw-r--r--src/web_service/telemetry_json.h30
-rw-r--r--src/web_service/verify_login.cpp2
-rw-r--r--src/web_service/web_backend.cpp56
-rw-r--r--src/web_service/web_backend.h20
-rw-r--r--src/web_service/web_result.h (renamed from src/common/web_result.h)4
-rw-r--r--src/yuzu/compatdb.cpp3
-rw-r--r--src/yuzu/configuration/config.cpp10
-rw-r--r--src/yuzu/configuration/configure_cpu.cpp17
-rw-r--r--src/yuzu/configuration/configure_cpu.h1
-rw-r--r--src/yuzu/configuration/configure_cpu.ui52
-rw-r--r--src/yuzu/main.cpp2
-rw-r--r--src/yuzu_cmd/yuzu.cpp2
-rw-r--r--src/yuzu_tester/yuzu.cpp3
36 files changed, 225 insertions, 117 deletions
diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt
index 78c3bfb3b..5d54516eb 100644
--- a/src/common/CMakeLists.txt
+++ b/src/common/CMakeLists.txt
@@ -172,7 +172,6 @@ add_library(common STATIC
172 virtual_buffer.h 172 virtual_buffer.h
173 wall_clock.cpp 173 wall_clock.cpp
174 wall_clock.h 174 wall_clock.h
175 web_result.h
176 zstd_compression.cpp 175 zstd_compression.cpp
177 zstd_compression.h 176 zstd_compression.h
178) 177)
diff --git a/src/common/concepts.h b/src/common/concepts.h
index 54252e778..5bef3ad67 100644
--- a/src/common/concepts.h
+++ b/src/common/concepts.h
@@ -4,10 +4,10 @@
4 4
5#pragma once 5#pragma once
6 6
7namespace Common {
8
9#include <type_traits> 7#include <type_traits>
10 8
9namespace Common {
10
11// Check if type is like an STL container 11// Check if type is like an STL container
12template <typename T> 12template <typename T>
13concept IsSTLContainer = requires(T t) { 13concept IsSTLContainer = requires(T t) {
diff --git a/src/common/dynamic_library.cpp b/src/common/dynamic_library.cpp
index 7ab54e9e4..7f0a10521 100644
--- a/src/common/dynamic_library.cpp
+++ b/src/common/dynamic_library.cpp
@@ -21,7 +21,7 @@ namespace Common {
21DynamicLibrary::DynamicLibrary() = default; 21DynamicLibrary::DynamicLibrary() = default;
22 22
23DynamicLibrary::DynamicLibrary(const char* filename) { 23DynamicLibrary::DynamicLibrary(const char* filename) {
24 Open(filename); 24 void(Open(filename));
25} 25}
26 26
27DynamicLibrary::DynamicLibrary(DynamicLibrary&& rhs) noexcept 27DynamicLibrary::DynamicLibrary(DynamicLibrary&& rhs) noexcept
diff --git a/src/common/file_util.cpp b/src/common/file_util.cpp
index c869e7b82..16c3713e0 100644
--- a/src/common/file_util.cpp
+++ b/src/common/file_util.cpp
@@ -909,10 +909,10 @@ std::string SanitizePath(std::string_view path_, DirectorySeparator directory_se
909 return std::string(RemoveTrailingSlash(path)); 909 return std::string(RemoveTrailingSlash(path));
910} 910}
911 911
912IOFile::IOFile() {} 912IOFile::IOFile() = default;
913 913
914IOFile::IOFile(const std::string& filename, const char openmode[], int flags) { 914IOFile::IOFile(const std::string& filename, const char openmode[], int flags) {
915 Open(filename, openmode, flags); 915 void(Open(filename, openmode, flags));
916} 916}
917 917
918IOFile::~IOFile() { 918IOFile::~IOFile() {
diff --git a/src/common/telemetry.cpp b/src/common/telemetry.cpp
index 16d42facd..6241d08b3 100644
--- a/src/common/telemetry.cpp
+++ b/src/common/telemetry.cpp
@@ -12,7 +12,7 @@
12#include "common/x64/cpu_detect.h" 12#include "common/x64/cpu_detect.h"
13#endif 13#endif
14 14
15namespace Telemetry { 15namespace Common::Telemetry {
16 16
17void FieldCollection::Accept(VisitorInterface& visitor) const { 17void FieldCollection::Accept(VisitorInterface& visitor) const {
18 for (const auto& field : fields) { 18 for (const auto& field : fields) {
@@ -88,4 +88,4 @@ void AppendOSInfo(FieldCollection& fc) {
88#endif 88#endif
89} 89}
90 90
91} // namespace Telemetry 91} // namespace Common::Telemetry
diff --git a/src/common/telemetry.h b/src/common/telemetry.h
index 4aa299f9a..a50c5d1de 100644
--- a/src/common/telemetry.h
+++ b/src/common/telemetry.h
@@ -10,7 +10,7 @@
10#include <string> 10#include <string>
11#include "common/common_types.h" 11#include "common/common_types.h"
12 12
13namespace Telemetry { 13namespace Common::Telemetry {
14 14
15/// Field type, used for grouping fields together in the final submitted telemetry log 15/// Field type, used for grouping fields together in the final submitted telemetry log
16enum class FieldType : u8 { 16enum class FieldType : u8 {
@@ -196,4 +196,4 @@ void AppendCPUInfo(FieldCollection& fc);
196/// such as platform name, etc. 196/// such as platform name, etc.
197void AppendOSInfo(FieldCollection& fc); 197void AppendOSInfo(FieldCollection& fc);
198 198
199} // namespace Telemetry 199} // namespace Common::Telemetry
diff --git a/src/common/time_zone.cpp b/src/common/time_zone.cpp
index 7aa1b59ea..ce239eb63 100644
--- a/src/common/time_zone.cpp
+++ b/src/common/time_zone.cpp
@@ -3,9 +3,8 @@
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <chrono> 5#include <chrono>
6#include <ctime> 6#include <iomanip>
7 7#include <sstream>
8#include <fmt/chrono.h>
9 8
10#include "common/logging/log.h" 9#include "common/logging/log.h"
11#include "common/time_zone.h" 10#include "common/time_zone.h"
@@ -17,8 +16,13 @@ std::string GetDefaultTimeZone() {
17} 16}
18 17
19static std::string GetOsTimeZoneOffset() { 18static std::string GetOsTimeZoneOffset() {
20 // Get the current timezone offset, e.g. "-400", as a string 19 const std::time_t t{std::time(nullptr)};
21 return fmt::format("%z", fmt::localtime(std::time(nullptr))); 20 const std::tm tm{*std::localtime(&t)};
21
22 std::stringstream ss;
23 ss << std::put_time(&tm, "%z"); // Get the current timezone offset, e.g. "-400", as a string
24
25 return ss.str();
22} 26}
23 27
24static int ConvertOsTimeZoneOffsetToInt(const std::string& timezone) { 28static int ConvertOsTimeZoneOffsetToInt(const std::string& timezone) {
diff --git a/src/core/arm/dynarmic/arm_dynarmic_32.cpp b/src/core/arm/dynarmic/arm_dynarmic_32.cpp
index 443ca72eb..b5f28a86e 100644
--- a/src/core/arm/dynarmic/arm_dynarmic_32.cpp
+++ b/src/core/arm/dynarmic/arm_dynarmic_32.cpp
@@ -143,7 +143,7 @@ std::shared_ptr<Dynarmic::A32::Jit> ARM_Dynarmic_32::MakeJit(Common::PageTable&
143 config.wall_clock_cntpct = uses_wall_clock; 143 config.wall_clock_cntpct = uses_wall_clock;
144 144
145 // Safe optimizations 145 // Safe optimizations
146 if (Settings::values.cpu_accuracy != Settings::CPUAccuracy::Accurate) { 146 if (Settings::values.cpu_accuracy == Settings::CPUAccuracy::DebugMode) {
147 if (!Settings::values.cpuopt_page_tables) { 147 if (!Settings::values.cpuopt_page_tables) {
148 config.page_table = nullptr; 148 config.page_table = nullptr;
149 } 149 }
@@ -170,6 +170,17 @@ std::shared_ptr<Dynarmic::A32::Jit> ARM_Dynarmic_32::MakeJit(Common::PageTable&
170 } 170 }
171 } 171 }
172 172
173 // Unsafe optimizations
174 if (Settings::values.cpu_accuracy == Settings::CPUAccuracy::Unsafe) {
175 config.unsafe_optimizations = true;
176 if (Settings::values.cpuopt_unsafe_unfuse_fma) {
177 config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_UnfuseFMA;
178 }
179 if (Settings::values.cpuopt_unsafe_reduce_fp_error) {
180 config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_ReducedErrorFP;
181 }
182 }
183
173 return std::make_unique<Dynarmic::A32::Jit>(config); 184 return std::make_unique<Dynarmic::A32::Jit>(config);
174} 185}
175 186
diff --git a/src/core/arm/dynarmic/arm_dynarmic_64.cpp b/src/core/arm/dynarmic/arm_dynarmic_64.cpp
index a63a04a25..ce9968724 100644
--- a/src/core/arm/dynarmic/arm_dynarmic_64.cpp
+++ b/src/core/arm/dynarmic/arm_dynarmic_64.cpp
@@ -195,7 +195,7 @@ std::shared_ptr<Dynarmic::A64::Jit> ARM_Dynarmic_64::MakeJit(Common::PageTable&
195 config.wall_clock_cntpct = uses_wall_clock; 195 config.wall_clock_cntpct = uses_wall_clock;
196 196
197 // Safe optimizations 197 // Safe optimizations
198 if (Settings::values.cpu_accuracy != Settings::CPUAccuracy::Accurate) { 198 if (Settings::values.cpu_accuracy == Settings::CPUAccuracy::DebugMode) {
199 if (!Settings::values.cpuopt_page_tables) { 199 if (!Settings::values.cpuopt_page_tables) {
200 config.page_table = nullptr; 200 config.page_table = nullptr;
201 } 201 }
@@ -222,6 +222,17 @@ std::shared_ptr<Dynarmic::A64::Jit> ARM_Dynarmic_64::MakeJit(Common::PageTable&
222 } 222 }
223 } 223 }
224 224
225 // Unsafe optimizations
226 if (Settings::values.cpu_accuracy == Settings::CPUAccuracy::Unsafe) {
227 config.unsafe_optimizations = true;
228 if (Settings::values.cpuopt_unsafe_unfuse_fma) {
229 config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_UnfuseFMA;
230 }
231 if (Settings::values.cpuopt_unsafe_reduce_fp_error) {
232 config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_ReducedErrorFP;
233 }
234 }
235
225 return std::make_shared<Dynarmic::A64::Jit>(config); 236 return std::make_shared<Dynarmic::A64::Jit>(config);
226} 237}
227 238
diff --git a/src/core/core.cpp b/src/core/core.cpp
index 1d8c0f1cd..c2c0eec0b 100644
--- a/src/core/core.cpp
+++ b/src/core/core.cpp
@@ -269,14 +269,14 @@ struct System::Impl {
269 // Log last frame performance stats if game was loded 269 // Log last frame performance stats if game was loded
270 if (perf_stats) { 270 if (perf_stats) {
271 const auto perf_results = GetAndResetPerfStats(); 271 const auto perf_results = GetAndResetPerfStats();
272 telemetry_session->AddField(Telemetry::FieldType::Performance, 272 constexpr auto performance = Common::Telemetry::FieldType::Performance;
273 "Shutdown_EmulationSpeed", 273
274 telemetry_session->AddField(performance, "Shutdown_EmulationSpeed",
274 perf_results.emulation_speed * 100.0); 275 perf_results.emulation_speed * 100.0);
275 telemetry_session->AddField(Telemetry::FieldType::Performance, "Shutdown_Framerate", 276 telemetry_session->AddField(performance, "Shutdown_Framerate", perf_results.game_fps);
276 perf_results.game_fps); 277 telemetry_session->AddField(performance, "Shutdown_Frametime",
277 telemetry_session->AddField(Telemetry::FieldType::Performance, "Shutdown_Frametime",
278 perf_results.frametime * 1000.0); 278 perf_results.frametime * 1000.0);
279 telemetry_session->AddField(Telemetry::FieldType::Performance, "Mean_Frametime_MS", 279 telemetry_session->AddField(performance, "Mean_Frametime_MS",
280 perf_stats->GetMeanFrametime()); 280 perf_stats->GetMeanFrametime());
281 } 281 }
282 282
diff --git a/src/core/core_timing.cpp b/src/core/core_timing.cpp
index 71af26ec5..e6c8461a5 100644
--- a/src/core/core_timing.cpp
+++ b/src/core/core_timing.cpp
@@ -7,14 +7,14 @@
7#include <string> 7#include <string>
8#include <tuple> 8#include <tuple>
9 9
10#include "common/assert.h"
11#include "common/microprofile.h" 10#include "common/microprofile.h"
12#include "core/core_timing.h" 11#include "core/core_timing.h"
13#include "core/core_timing_util.h" 12#include "core/core_timing_util.h"
13#include "core/hardware_properties.h"
14 14
15namespace Core::Timing { 15namespace Core::Timing {
16 16
17constexpr u64 MAX_SLICE_LENGTH = 4000; 17constexpr s64 MAX_SLICE_LENGTH = 4000;
18 18
19std::shared_ptr<EventType> CreateEvent(std::string name, TimedCallback&& callback) { 19std::shared_ptr<EventType> CreateEvent(std::string name, TimedCallback&& callback) {
20 return std::make_shared<EventType>(std::move(callback), std::move(name)); 20 return std::make_shared<EventType>(std::move(callback), std::move(name));
@@ -37,10 +37,8 @@ struct CoreTiming::Event {
37 } 37 }
38}; 38};
39 39
40CoreTiming::CoreTiming() { 40CoreTiming::CoreTiming()
41 clock = 41 : clock{Common::CreateBestMatchingClock(Hardware::BASE_CLOCK_RATE, Hardware::CNTFREQ)} {}
42 Common::CreateBestMatchingClock(Core::Hardware::BASE_CLOCK_RATE, Core::Hardware::CNTFREQ);
43}
44 42
45CoreTiming::~CoreTiming() = default; 43CoreTiming::~CoreTiming() = default;
46 44
@@ -136,7 +134,7 @@ void CoreTiming::UnscheduleEvent(const std::shared_ptr<EventType>& event_type,
136 134
137void CoreTiming::AddTicks(u64 ticks) { 135void CoreTiming::AddTicks(u64 ticks) {
138 this->ticks += ticks; 136 this->ticks += ticks;
139 downcount -= ticks; 137 downcount -= static_cast<s64>(ticks);
140} 138}
141 139
142void CoreTiming::Idle() { 140void CoreTiming::Idle() {
diff --git a/src/core/core_timing_util.cpp b/src/core/core_timing_util.cpp
index aefc63663..8ce8e602e 100644
--- a/src/core/core_timing_util.cpp
+++ b/src/core/core_timing_util.cpp
@@ -8,6 +8,7 @@
8#include <limits> 8#include <limits>
9#include "common/logging/log.h" 9#include "common/logging/log.h"
10#include "common/uint128.h" 10#include "common/uint128.h"
11#include "core/hardware_properties.h"
11 12
12namespace Core::Timing { 13namespace Core::Timing {
13 14
diff --git a/src/core/core_timing_util.h b/src/core/core_timing_util.h
index 2ed979e14..e4a046bf9 100644
--- a/src/core/core_timing_util.h
+++ b/src/core/core_timing_util.h
@@ -6,7 +6,6 @@
6 6
7#include <chrono> 7#include <chrono>
8#include "common/common_types.h" 8#include "common/common_types.h"
9#include "core/hardware_properties.h"
10 9
11namespace Core::Timing { 10namespace Core::Timing {
12 11
diff --git a/src/core/settings.h b/src/core/settings.h
index bb145f193..3681b5e9d 100644
--- a/src/core/settings.h
+++ b/src/core/settings.h
@@ -359,7 +359,8 @@ enum class GPUAccuracy : u32 {
359 359
360enum class CPUAccuracy { 360enum class CPUAccuracy {
361 Accurate = 0, 361 Accurate = 0,
362 DebugMode = 1, 362 Unsafe = 1,
363 DebugMode = 2,
363}; 364};
364 365
365extern bool configuring_global; 366extern bool configuring_global;
@@ -419,6 +420,9 @@ struct Values {
419 bool cpuopt_misc_ir; 420 bool cpuopt_misc_ir;
420 bool cpuopt_reduce_misalign_checks; 421 bool cpuopt_reduce_misalign_checks;
421 422
423 bool cpuopt_unsafe_unfuse_fma;
424 bool cpuopt_unsafe_reduce_fp_error;
425
422 // Renderer 426 // Renderer
423 Setting<RendererBackend> renderer_backend; 427 Setting<RendererBackend> renderer_backend;
424 bool renderer_debug; 428 bool renderer_debug;
diff --git a/src/core/telemetry_session.cpp b/src/core/telemetry_session.cpp
index 7dae48bc6..da09c0dbc 100644
--- a/src/core/telemetry_session.cpp
+++ b/src/core/telemetry_session.cpp
@@ -25,6 +25,8 @@
25 25
26namespace Core { 26namespace Core {
27 27
28namespace Telemetry = Common::Telemetry;
29
28static u64 GenerateTelemetryId() { 30static u64 GenerateTelemetryId() {
29 u64 telemetry_id{}; 31 u64 telemetry_id{};
30 32
diff --git a/src/core/telemetry_session.h b/src/core/telemetry_session.h
index 17ac22377..66789d4bd 100644
--- a/src/core/telemetry_session.h
+++ b/src/core/telemetry_session.h
@@ -52,7 +52,7 @@ public:
52 * @param value Value for the field to add. 52 * @param value Value for the field to add.
53 */ 53 */
54 template <typename T> 54 template <typename T>
55 void AddField(Telemetry::FieldType type, const char* name, T value) { 55 void AddField(Common::Telemetry::FieldType type, const char* name, T value) {
56 field_collection.AddField(type, name, std::move(value)); 56 field_collection.AddField(type, name, std::move(value));
57 } 57 }
58 58
@@ -63,7 +63,8 @@ public:
63 bool SubmitTestcase(); 63 bool SubmitTestcase();
64 64
65private: 65private:
66 Telemetry::FieldCollection field_collection; ///< Tracks all added fields for the session 66 /// Tracks all added fields for the session
67 Common::Telemetry::FieldCollection field_collection;
67}; 68};
68 69
69/** 70/**
diff --git a/src/video_core/macro/macro_interpreter.cpp b/src/video_core/macro/macro_interpreter.cpp
index aa5256419..bd01fd1f2 100644
--- a/src/video_core/macro/macro_interpreter.cpp
+++ b/src/video_core/macro/macro_interpreter.cpp
@@ -34,7 +34,6 @@ void MacroInterpreterImpl::Execute(const std::vector<u32>& parameters, u32 metho
34 this->parameters = std::make_unique<u32[]>(num_parameters); 34 this->parameters = std::make_unique<u32[]>(num_parameters);
35 } 35 }
36 std::memcpy(this->parameters.get(), parameters.data(), num_parameters * sizeof(u32)); 36 std::memcpy(this->parameters.get(), parameters.data(), num_parameters * sizeof(u32));
37 this->num_parameters = num_parameters;
38 37
39 // Execute the code until we hit an exit condition. 38 // Execute the code until we hit an exit condition.
40 bool keep_executing = true; 39 bool keep_executing = true;
diff --git a/src/video_core/renderer_opengl/gl_shader_disk_cache.cpp b/src/video_core/renderer_opengl/gl_shader_disk_cache.cpp
index 52fbab3c1..40c0877c1 100644
--- a/src/video_core/renderer_opengl/gl_shader_disk_cache.cpp
+++ b/src/video_core/renderer_opengl/gl_shader_disk_cache.cpp
@@ -214,20 +214,20 @@ std::optional<std::vector<ShaderDiskCacheEntry>> ShaderDiskCacheOpenGL::LoadTran
214 // Skip games without title id 214 // Skip games without title id
215 const bool has_title_id = system.CurrentProcess()->GetTitleID() != 0; 215 const bool has_title_id = system.CurrentProcess()->GetTitleID() != 0;
216 if (!Settings::values.use_disk_shader_cache.GetValue() || !has_title_id) { 216 if (!Settings::values.use_disk_shader_cache.GetValue() || !has_title_id) {
217 return {}; 217 return std::nullopt;
218 } 218 }
219 219
220 Common::FS::IOFile file(GetTransferablePath(), "rb"); 220 Common::FS::IOFile file(GetTransferablePath(), "rb");
221 if (!file.IsOpen()) { 221 if (!file.IsOpen()) {
222 LOG_INFO(Render_OpenGL, "No transferable shader cache found"); 222 LOG_INFO(Render_OpenGL, "No transferable shader cache found");
223 is_usable = true; 223 is_usable = true;
224 return {}; 224 return std::nullopt;
225 } 225 }
226 226
227 u32 version{}; 227 u32 version{};
228 if (file.ReadBytes(&version, sizeof(version)) != sizeof(version)) { 228 if (file.ReadBytes(&version, sizeof(version)) != sizeof(version)) {
229 LOG_ERROR(Render_OpenGL, "Failed to get transferable cache version, skipping it"); 229 LOG_ERROR(Render_OpenGL, "Failed to get transferable cache version, skipping it");
230 return {}; 230 return std::nullopt;
231 } 231 }
232 232
233 if (version < NativeVersion) { 233 if (version < NativeVersion) {
@@ -235,12 +235,12 @@ std::optional<std::vector<ShaderDiskCacheEntry>> ShaderDiskCacheOpenGL::LoadTran
235 file.Close(); 235 file.Close();
236 InvalidateTransferable(); 236 InvalidateTransferable();
237 is_usable = true; 237 is_usable = true;
238 return {}; 238 return std::nullopt;
239 } 239 }
240 if (version > NativeVersion) { 240 if (version > NativeVersion) {
241 LOG_WARNING(Render_OpenGL, "Transferable shader cache was generated with a newer version " 241 LOG_WARNING(Render_OpenGL, "Transferable shader cache was generated with a newer version "
242 "of the emulator, skipping"); 242 "of the emulator, skipping");
243 return {}; 243 return std::nullopt;
244 } 244 }
245 245
246 // Version is valid, load the shaders 246 // Version is valid, load the shaders
@@ -249,7 +249,7 @@ std::optional<std::vector<ShaderDiskCacheEntry>> ShaderDiskCacheOpenGL::LoadTran
249 ShaderDiskCacheEntry& entry = entries.emplace_back(); 249 ShaderDiskCacheEntry& entry = entries.emplace_back();
250 if (!entry.Load(file)) { 250 if (!entry.Load(file)) {
251 LOG_ERROR(Render_OpenGL, "Failed to load transferable raw entry, skipping"); 251 LOG_ERROR(Render_OpenGL, "Failed to load transferable raw entry, skipping");
252 return {}; 252 return std::nullopt;
253 } 253 }
254 } 254 }
255 255
@@ -290,12 +290,12 @@ std::optional<std::vector<ShaderDiskCachePrecompiled>> ShaderDiskCacheOpenGL::Lo
290 ShaderCacheVersionHash file_hash{}; 290 ShaderCacheVersionHash file_hash{};
291 if (!LoadArrayFromPrecompiled(file_hash.data(), file_hash.size())) { 291 if (!LoadArrayFromPrecompiled(file_hash.data(), file_hash.size())) {
292 precompiled_cache_virtual_file_offset = 0; 292 precompiled_cache_virtual_file_offset = 0;
293 return {}; 293 return std::nullopt;
294 } 294 }
295 if (GetShaderCacheVersionHash() != file_hash) { 295 if (GetShaderCacheVersionHash() != file_hash) {
296 LOG_INFO(Render_OpenGL, "Precompiled cache is from another version of the emulator"); 296 LOG_INFO(Render_OpenGL, "Precompiled cache is from another version of the emulator");
297 precompiled_cache_virtual_file_offset = 0; 297 precompiled_cache_virtual_file_offset = 0;
298 return {}; 298 return std::nullopt;
299 } 299 }
300 300
301 std::vector<ShaderDiskCachePrecompiled> entries; 301 std::vector<ShaderDiskCachePrecompiled> entries;
@@ -305,15 +305,16 @@ std::optional<std::vector<ShaderDiskCachePrecompiled>> ShaderDiskCacheOpenGL::Lo
305 if (!LoadObjectFromPrecompiled(entry.unique_identifier) || 305 if (!LoadObjectFromPrecompiled(entry.unique_identifier) ||
306 !LoadObjectFromPrecompiled(entry.binary_format) || 306 !LoadObjectFromPrecompiled(entry.binary_format) ||
307 !LoadObjectFromPrecompiled(binary_size)) { 307 !LoadObjectFromPrecompiled(binary_size)) {
308 return {}; 308 return std::nullopt;
309 } 309 }
310 310
311 entry.binary.resize(binary_size); 311 entry.binary.resize(binary_size);
312 if (!LoadArrayFromPrecompiled(entry.binary.data(), entry.binary.size())) { 312 if (!LoadArrayFromPrecompiled(entry.binary.data(), entry.binary.size())) {
313 return {}; 313 return std::nullopt;
314 } 314 }
315 } 315 }
316 return entries; 316
317 return std::move(entries);
317} 318}
318 319
319void ShaderDiskCacheOpenGL::InvalidateTransferable() { 320void ShaderDiskCacheOpenGL::InvalidateTransferable() {
diff --git a/src/video_core/renderer_opengl/renderer_opengl.cpp b/src/video_core/renderer_opengl/renderer_opengl.cpp
index 52e9e8250..14bbc3a1c 100644
--- a/src/video_core/renderer_opengl/renderer_opengl.cpp
+++ b/src/video_core/renderer_opengl/renderer_opengl.cpp
@@ -509,9 +509,10 @@ void RendererOpenGL::AddTelemetryFields() {
509 LOG_INFO(Render_OpenGL, "GL_RENDERER: {}", gpu_model); 509 LOG_INFO(Render_OpenGL, "GL_RENDERER: {}", gpu_model);
510 510
511 auto& telemetry_session = system.TelemetrySession(); 511 auto& telemetry_session = system.TelemetrySession();
512 telemetry_session.AddField(Telemetry::FieldType::UserSystem, "GPU_Vendor", gpu_vendor); 512 constexpr auto user_system = Common::Telemetry::FieldType::UserSystem;
513 telemetry_session.AddField(Telemetry::FieldType::UserSystem, "GPU_Model", gpu_model); 513 telemetry_session.AddField(user_system, "GPU_Vendor", gpu_vendor);
514 telemetry_session.AddField(Telemetry::FieldType::UserSystem, "GPU_OpenGL_Version", gl_version); 514 telemetry_session.AddField(user_system, "GPU_Model", gpu_model);
515 telemetry_session.AddField(user_system, "GPU_OpenGL_Version", gl_version);
515} 516}
516 517
517void RendererOpenGL::CreateRasterizer() { 518void RendererOpenGL::CreateRasterizer() {
diff --git a/src/video_core/renderer_vulkan/renderer_vulkan.cpp b/src/video_core/renderer_vulkan/renderer_vulkan.cpp
index 0c62c8061..6e49699d0 100644
--- a/src/video_core/renderer_vulkan/renderer_vulkan.cpp
+++ b/src/video_core/renderer_vulkan/renderer_vulkan.cpp
@@ -439,7 +439,7 @@ void RendererVulkan::Report() const {
439 LOG_INFO(Render_Vulkan, "Vulkan: {}", api_version); 439 LOG_INFO(Render_Vulkan, "Vulkan: {}", api_version);
440 440
441 auto& telemetry_session = system.TelemetrySession(); 441 auto& telemetry_session = system.TelemetrySession();
442 constexpr auto field = Telemetry::FieldType::UserSystem; 442 constexpr auto field = Common::Telemetry::FieldType::UserSystem;
443 telemetry_session.AddField(field, "GPU_Vendor", vendor_name); 443 telemetry_session.AddField(field, "GPU_Vendor", vendor_name);
444 telemetry_session.AddField(field, "GPU_Model", model_name); 444 telemetry_session.AddField(field, "GPU_Model", model_name);
445 telemetry_session.AddField(field, "GPU_Vulkan_Driver", driver_name); 445 telemetry_session.AddField(field, "GPU_Vulkan_Driver", driver_name);
diff --git a/src/video_core/renderer_vulkan/wrapper.cpp b/src/video_core/renderer_vulkan/wrapper.cpp
index c43d60adf..013865aa4 100644
--- a/src/video_core/renderer_vulkan/wrapper.cpp
+++ b/src/video_core/renderer_vulkan/wrapper.cpp
@@ -786,7 +786,7 @@ std::optional<std::vector<VkExtensionProperties>> EnumerateInstanceExtensionProp
786 VK_SUCCESS) { 786 VK_SUCCESS) {
787 return std::nullopt; 787 return std::nullopt;
788 } 788 }
789 return properties; 789 return std::move(properties);
790} 790}
791 791
792std::optional<std::vector<VkLayerProperties>> EnumerateInstanceLayerProperties( 792std::optional<std::vector<VkLayerProperties>> EnumerateInstanceLayerProperties(
diff --git a/src/web_service/CMakeLists.txt b/src/web_service/CMakeLists.txt
index 06ab7c59d..7e484b906 100644
--- a/src/web_service/CMakeLists.txt
+++ b/src/web_service/CMakeLists.txt
@@ -5,6 +5,7 @@ add_library(web_service STATIC
5 verify_login.h 5 verify_login.h
6 web_backend.cpp 6 web_backend.cpp
7 web_backend.h 7 web_backend.h
8 web_result.h
8) 9)
9 10
10create_target_directory_groups(web_service) 11create_target_directory_groups(web_service)
diff --git a/src/web_service/telemetry_json.cpp b/src/web_service/telemetry_json.cpp
index 7a480e33c..6215c914f 100644
--- a/src/web_service/telemetry_json.cpp
+++ b/src/web_service/telemetry_json.cpp
@@ -4,12 +4,14 @@
4 4
5#include <nlohmann/json.hpp> 5#include <nlohmann/json.hpp>
6#include "common/detached_tasks.h" 6#include "common/detached_tasks.h"
7#include "common/web_result.h"
8#include "web_service/telemetry_json.h" 7#include "web_service/telemetry_json.h"
9#include "web_service/web_backend.h" 8#include "web_service/web_backend.h"
9#include "web_service/web_result.h"
10 10
11namespace WebService { 11namespace WebService {
12 12
13namespace Telemetry = Common::Telemetry;
14
13struct TelemetryJson::Impl { 15struct TelemetryJson::Impl {
14 Impl(std::string host, std::string username, std::string token) 16 Impl(std::string host, std::string username, std::string token)
15 : host{std::move(host)}, username{std::move(username)}, token{std::move(token)} {} 17 : host{std::move(host)}, username{std::move(username)}, token{std::move(token)} {}
@@ -123,7 +125,7 @@ bool TelemetryJson::SubmitTestcase() {
123 Client client(impl->host, impl->username, impl->token); 125 Client client(impl->host, impl->username, impl->token);
124 auto value = client.PostJson("/gamedb/testcase", content, false); 126 auto value = client.PostJson("/gamedb/testcase", content, false);
125 127
126 return value.result_code == Common::WebResult::Code::Success; 128 return value.result_code == WebResult::Code::Success;
127} 129}
128 130
129} // namespace WebService 131} // namespace WebService
diff --git a/src/web_service/telemetry_json.h b/src/web_service/telemetry_json.h
index dfd202829..df51e00f8 100644
--- a/src/web_service/telemetry_json.h
+++ b/src/web_service/telemetry_json.h
@@ -14,25 +14,25 @@ namespace WebService {
14 * Implementation of VisitorInterface that serialized telemetry into JSON, and submits it to the 14 * Implementation of VisitorInterface that serialized telemetry into JSON, and submits it to the
15 * yuzu web service 15 * yuzu web service
16 */ 16 */
17class TelemetryJson : public Telemetry::VisitorInterface { 17class TelemetryJson : public Common::Telemetry::VisitorInterface {
18public: 18public:
19 TelemetryJson(std::string host, std::string username, std::string token); 19 TelemetryJson(std::string host, std::string username, std::string token);
20 ~TelemetryJson() override; 20 ~TelemetryJson() override;
21 21
22 void Visit(const Telemetry::Field<bool>& field) override; 22 void Visit(const Common::Telemetry::Field<bool>& field) override;
23 void Visit(const Telemetry::Field<double>& field) override; 23 void Visit(const Common::Telemetry::Field<double>& field) override;
24 void Visit(const Telemetry::Field<float>& field) override; 24 void Visit(const Common::Telemetry::Field<float>& field) override;
25 void Visit(const Telemetry::Field<u8>& field) override; 25 void Visit(const Common::Telemetry::Field<u8>& field) override;
26 void Visit(const Telemetry::Field<u16>& field) override; 26 void Visit(const Common::Telemetry::Field<u16>& field) override;
27 void Visit(const Telemetry::Field<u32>& field) override; 27 void Visit(const Common::Telemetry::Field<u32>& field) override;
28 void Visit(const Telemetry::Field<u64>& field) override; 28 void Visit(const Common::Telemetry::Field<u64>& field) override;
29 void Visit(const Telemetry::Field<s8>& field) override; 29 void Visit(const Common::Telemetry::Field<s8>& field) override;
30 void Visit(const Telemetry::Field<s16>& field) override; 30 void Visit(const Common::Telemetry::Field<s16>& field) override;
31 void Visit(const Telemetry::Field<s32>& field) override; 31 void Visit(const Common::Telemetry::Field<s32>& field) override;
32 void Visit(const Telemetry::Field<s64>& field) override; 32 void Visit(const Common::Telemetry::Field<s64>& field) override;
33 void Visit(const Telemetry::Field<std::string>& field) override; 33 void Visit(const Common::Telemetry::Field<std::string>& field) override;
34 void Visit(const Telemetry::Field<const char*>& field) override; 34 void Visit(const Common::Telemetry::Field<const char*>& field) override;
35 void Visit(const Telemetry::Field<std::chrono::microseconds>& field) override; 35 void Visit(const Common::Telemetry::Field<std::chrono::microseconds>& field) override;
36 36
37 void Complete() override; 37 void Complete() override;
38 bool SubmitTestcase() override; 38 bool SubmitTestcase() override;
diff --git a/src/web_service/verify_login.cpp b/src/web_service/verify_login.cpp
index bfaa5b70a..ceb55ca6b 100644
--- a/src/web_service/verify_login.cpp
+++ b/src/web_service/verify_login.cpp
@@ -3,9 +3,9 @@
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <nlohmann/json.hpp> 5#include <nlohmann/json.hpp>
6#include "common/web_result.h"
7#include "web_service/verify_login.h" 6#include "web_service/verify_login.h"
8#include "web_service/web_backend.h" 7#include "web_service/web_backend.h"
8#include "web_service/web_result.h"
9 9
10namespace WebService { 10namespace WebService {
11 11
diff --git a/src/web_service/web_backend.cpp b/src/web_service/web_backend.cpp
index 09d1651ac..74e287045 100644
--- a/src/web_service/web_backend.cpp
+++ b/src/web_service/web_backend.cpp
@@ -6,13 +6,14 @@
6#include <cstdlib> 6#include <cstdlib>
7#include <mutex> 7#include <mutex>
8#include <string> 8#include <string>
9
9#include <LUrlParser.h> 10#include <LUrlParser.h>
10#include <fmt/format.h> 11#include <fmt/format.h>
11#include <httplib.h> 12#include <httplib.h>
12#include "common/common_types.h" 13
13#include "common/logging/log.h" 14#include "common/logging/log.h"
14#include "common/web_result.h"
15#include "web_service/web_backend.h" 15#include "web_service/web_backend.h"
16#include "web_service/web_result.h"
16 17
17namespace WebService { 18namespace WebService {
18 19
@@ -33,17 +34,16 @@ struct Client::Impl {
33 } 34 }
34 35
35 /// A generic function handles POST, GET and DELETE request together 36 /// A generic function handles POST, GET and DELETE request together
36 Common::WebResult GenericRequest(const std::string& method, const std::string& path, 37 WebResult GenericRequest(const std::string& method, const std::string& path,
37 const std::string& data, bool allow_anonymous, 38 const std::string& data, bool allow_anonymous,
38 const std::string& accept) { 39 const std::string& accept) {
39 if (jwt.empty()) { 40 if (jwt.empty()) {
40 UpdateJWT(); 41 UpdateJWT();
41 } 42 }
42 43
43 if (jwt.empty() && !allow_anonymous) { 44 if (jwt.empty() && !allow_anonymous) {
44 LOG_ERROR(WebService, "Credentials must be provided for authenticated requests"); 45 LOG_ERROR(WebService, "Credentials must be provided for authenticated requests");
45 return Common::WebResult{Common::WebResult::Code::CredentialsMissing, 46 return WebResult{WebResult::Code::CredentialsMissing, "Credentials needed", ""};
46 "Credentials needed", ""};
47 } 47 }
48 48
49 auto result = GenericRequest(method, path, data, accept, jwt); 49 auto result = GenericRequest(method, path, data, accept, jwt);
@@ -62,10 +62,10 @@ struct Client::Impl {
62 * username + token is used if jwt is empty but username and token are 62 * username + token is used if jwt is empty but username and token are
63 * not empty anonymous if all of jwt, username and token are empty 63 * not empty anonymous if all of jwt, username and token are empty
64 */ 64 */
65 Common::WebResult GenericRequest(const std::string& method, const std::string& path, 65 WebResult GenericRequest(const std::string& method, const std::string& path,
66 const std::string& data, const std::string& accept, 66 const std::string& data, const std::string& accept,
67 const std::string& jwt = "", const std::string& username = "", 67 const std::string& jwt = "", const std::string& username = "",
68 const std::string& token = "") { 68 const std::string& token = "") {
69 if (cli == nullptr) { 69 if (cli == nullptr) {
70 auto parsedUrl = LUrlParser::clParseURL::ParseURL(host); 70 auto parsedUrl = LUrlParser::clParseURL::ParseURL(host);
71 int port; 71 int port;
@@ -81,12 +81,12 @@ struct Client::Impl {
81 cli = std::make_unique<httplib::SSLClient>(parsedUrl.m_Host.c_str(), port); 81 cli = std::make_unique<httplib::SSLClient>(parsedUrl.m_Host.c_str(), port);
82 } else { 82 } else {
83 LOG_ERROR(WebService, "Bad URL scheme {}", parsedUrl.m_Scheme); 83 LOG_ERROR(WebService, "Bad URL scheme {}", parsedUrl.m_Scheme);
84 return Common::WebResult{Common::WebResult::Code::InvalidURL, "Bad URL scheme", ""}; 84 return WebResult{WebResult::Code::InvalidURL, "Bad URL scheme", ""};
85 } 85 }
86 } 86 }
87 if (cli == nullptr) { 87 if (cli == nullptr) {
88 LOG_ERROR(WebService, "Invalid URL {}", host + path); 88 LOG_ERROR(WebService, "Invalid URL {}", host + path);
89 return Common::WebResult{Common::WebResult::Code::InvalidURL, "Invalid URL", ""}; 89 return WebResult{WebResult::Code::InvalidURL, "Invalid URL", ""};
90 } 90 }
91 cli->set_timeout_sec(TIMEOUT_SECONDS); 91 cli->set_timeout_sec(TIMEOUT_SECONDS);
92 92
@@ -106,7 +106,7 @@ struct Client::Impl {
106 std::string(API_VERSION.begin(), API_VERSION.end())); 106 std::string(API_VERSION.begin(), API_VERSION.end()));
107 if (method != "GET") { 107 if (method != "GET") {
108 params.emplace(std::string("Content-Type"), std::string("application/json")); 108 params.emplace(std::string("Content-Type"), std::string("application/json"));
109 }; 109 }
110 110
111 httplib::Request request; 111 httplib::Request request;
112 request.method = method; 112 request.method = method;
@@ -118,29 +118,28 @@ struct Client::Impl {
118 118
119 if (!cli->send(request, response)) { 119 if (!cli->send(request, response)) {
120 LOG_ERROR(WebService, "{} to {} returned null", method, host + path); 120 LOG_ERROR(WebService, "{} to {} returned null", method, host + path);
121 return Common::WebResult{Common::WebResult::Code::LibError, "Null response", ""}; 121 return WebResult{WebResult::Code::LibError, "Null response", ""};
122 } 122 }
123 123
124 if (response.status >= 400) { 124 if (response.status >= 400) {
125 LOG_ERROR(WebService, "{} to {} returned error status code: {}", method, host + path, 125 LOG_ERROR(WebService, "{} to {} returned error status code: {}", method, host + path,
126 response.status); 126 response.status);
127 return Common::WebResult{Common::WebResult::Code::HttpError, 127 return WebResult{WebResult::Code::HttpError, std::to_string(response.status), ""};
128 std::to_string(response.status), ""};
129 } 128 }
130 129
131 auto content_type = response.headers.find("content-type"); 130 auto content_type = response.headers.find("content-type");
132 131
133 if (content_type == response.headers.end()) { 132 if (content_type == response.headers.end()) {
134 LOG_ERROR(WebService, "{} to {} returned no content", method, host + path); 133 LOG_ERROR(WebService, "{} to {} returned no content", method, host + path);
135 return Common::WebResult{Common::WebResult::Code::WrongContent, "", ""}; 134 return WebResult{WebResult::Code::WrongContent, "", ""};
136 } 135 }
137 136
138 if (content_type->second.find(accept) == std::string::npos) { 137 if (content_type->second.find(accept) == std::string::npos) {
139 LOG_ERROR(WebService, "{} to {} returned wrong content: {}", method, host + path, 138 LOG_ERROR(WebService, "{} to {} returned wrong content: {}", method, host + path,
140 content_type->second); 139 content_type->second);
141 return Common::WebResult{Common::WebResult::Code::WrongContent, "Wrong content", ""}; 140 return WebResult{WebResult::Code::WrongContent, "Wrong content", ""};
142 } 141 }
143 return Common::WebResult{Common::WebResult::Code::Success, "", response.body}; 142 return WebResult{WebResult::Code::Success, "", response.body};
144 } 143 }
145 144
146 // Retrieve a new JWT from given username and token 145 // Retrieve a new JWT from given username and token
@@ -150,7 +149,7 @@ struct Client::Impl {
150 } 149 }
151 150
152 auto result = GenericRequest("POST", "/jwt/internal", "", "text/html", "", username, token); 151 auto result = GenericRequest("POST", "/jwt/internal", "", "text/html", "", username, token);
153 if (result.result_code != Common::WebResult::Code::Success) { 152 if (result.result_code != WebResult::Code::Success) {
154 LOG_ERROR(WebService, "UpdateJWT failed"); 153 LOG_ERROR(WebService, "UpdateJWT failed");
155 } else { 154 } else {
156 std::lock_guard lock{jwt_cache.mutex}; 155 std::lock_guard lock{jwt_cache.mutex};
@@ -180,29 +179,28 @@ Client::Client(std::string host, std::string username, std::string token)
180 179
181Client::~Client() = default; 180Client::~Client() = default;
182 181
183Common::WebResult Client::PostJson(const std::string& path, const std::string& data, 182WebResult Client::PostJson(const std::string& path, const std::string& data, bool allow_anonymous) {
184 bool allow_anonymous) {
185 return impl->GenericRequest("POST", path, data, allow_anonymous, "application/json"); 183 return impl->GenericRequest("POST", path, data, allow_anonymous, "application/json");
186} 184}
187 185
188Common::WebResult Client::GetJson(const std::string& path, bool allow_anonymous) { 186WebResult Client::GetJson(const std::string& path, bool allow_anonymous) {
189 return impl->GenericRequest("GET", path, "", allow_anonymous, "application/json"); 187 return impl->GenericRequest("GET", path, "", allow_anonymous, "application/json");
190} 188}
191 189
192Common::WebResult Client::DeleteJson(const std::string& path, const std::string& data, 190WebResult Client::DeleteJson(const std::string& path, const std::string& data,
193 bool allow_anonymous) { 191 bool allow_anonymous) {
194 return impl->GenericRequest("DELETE", path, data, allow_anonymous, "application/json"); 192 return impl->GenericRequest("DELETE", path, data, allow_anonymous, "application/json");
195} 193}
196 194
197Common::WebResult Client::GetPlain(const std::string& path, bool allow_anonymous) { 195WebResult Client::GetPlain(const std::string& path, bool allow_anonymous) {
198 return impl->GenericRequest("GET", path, "", allow_anonymous, "text/plain"); 196 return impl->GenericRequest("GET", path, "", allow_anonymous, "text/plain");
199} 197}
200 198
201Common::WebResult Client::GetImage(const std::string& path, bool allow_anonymous) { 199WebResult Client::GetImage(const std::string& path, bool allow_anonymous) {
202 return impl->GenericRequest("GET", path, "", allow_anonymous, "image/png"); 200 return impl->GenericRequest("GET", path, "", allow_anonymous, "image/png");
203} 201}
204 202
205Common::WebResult Client::GetExternalJWT(const std::string& audience) { 203WebResult Client::GetExternalJWT(const std::string& audience) {
206 return impl->GenericRequest("POST", fmt::format("/jwt/external/{}", audience), "", false, 204 return impl->GenericRequest("POST", fmt::format("/jwt/external/{}", audience), "", false,
207 "text/html"); 205 "text/html");
208} 206}
diff --git a/src/web_service/web_backend.h b/src/web_service/web_backend.h
index 04121f17e..81f58583c 100644
--- a/src/web_service/web_backend.h
+++ b/src/web_service/web_backend.h
@@ -7,12 +7,10 @@
7#include <memory> 7#include <memory>
8#include <string> 8#include <string>
9 9
10namespace Common {
11struct WebResult;
12}
13
14namespace WebService { 10namespace WebService {
15 11
12struct WebResult;
13
16class Client { 14class Client {
17public: 15public:
18 Client(std::string host, std::string username, std::string token); 16 Client(std::string host, std::string username, std::string token);
@@ -25,8 +23,7 @@ public:
25 * @param allow_anonymous If true, allow anonymous unauthenticated requests. 23 * @param allow_anonymous If true, allow anonymous unauthenticated requests.
26 * @return the result of the request. 24 * @return the result of the request.
27 */ 25 */
28 Common::WebResult PostJson(const std::string& path, const std::string& data, 26 WebResult PostJson(const std::string& path, const std::string& data, bool allow_anonymous);
29 bool allow_anonymous);
30 27
31 /** 28 /**
32 * Gets JSON from the specified path. 29 * Gets JSON from the specified path.
@@ -34,7 +31,7 @@ public:
34 * @param allow_anonymous If true, allow anonymous unauthenticated requests. 31 * @param allow_anonymous If true, allow anonymous unauthenticated requests.
35 * @return the result of the request. 32 * @return the result of the request.
36 */ 33 */
37 Common::WebResult GetJson(const std::string& path, bool allow_anonymous); 34 WebResult GetJson(const std::string& path, bool allow_anonymous);
38 35
39 /** 36 /**
40 * Deletes JSON to the specified path. 37 * Deletes JSON to the specified path.
@@ -43,8 +40,7 @@ public:
43 * @param allow_anonymous If true, allow anonymous unauthenticated requests. 40 * @param allow_anonymous If true, allow anonymous unauthenticated requests.
44 * @return the result of the request. 41 * @return the result of the request.
45 */ 42 */
46 Common::WebResult DeleteJson(const std::string& path, const std::string& data, 43 WebResult DeleteJson(const std::string& path, const std::string& data, bool allow_anonymous);
47 bool allow_anonymous);
48 44
49 /** 45 /**
50 * Gets a plain string from the specified path. 46 * Gets a plain string from the specified path.
@@ -52,7 +48,7 @@ public:
52 * @param allow_anonymous If true, allow anonymous unauthenticated requests. 48 * @param allow_anonymous If true, allow anonymous unauthenticated requests.
53 * @return the result of the request. 49 * @return the result of the request.
54 */ 50 */
55 Common::WebResult GetPlain(const std::string& path, bool allow_anonymous); 51 WebResult GetPlain(const std::string& path, bool allow_anonymous);
56 52
57 /** 53 /**
58 * Gets an PNG image from the specified path. 54 * Gets an PNG image from the specified path.
@@ -60,14 +56,14 @@ public:
60 * @param allow_anonymous If true, allow anonymous unauthenticated requests. 56 * @param allow_anonymous If true, allow anonymous unauthenticated requests.
61 * @return the result of the request. 57 * @return the result of the request.
62 */ 58 */
63 Common::WebResult GetImage(const std::string& path, bool allow_anonymous); 59 WebResult GetImage(const std::string& path, bool allow_anonymous);
64 60
65 /** 61 /**
66 * Requests an external JWT for the specific audience provided. 62 * Requests an external JWT for the specific audience provided.
67 * @param audience the audience of the JWT requested. 63 * @param audience the audience of the JWT requested.
68 * @return the result of the request. 64 * @return the result of the request.
69 */ 65 */
70 Common::WebResult GetExternalJWT(const std::string& audience); 66 WebResult GetExternalJWT(const std::string& audience);
71 67
72private: 68private:
73 struct Impl; 69 struct Impl;
diff --git a/src/common/web_result.h b/src/web_service/web_result.h
index 8bfa2141d..3aeeb5288 100644
--- a/src/common/web_result.h
+++ b/src/web_service/web_result.h
@@ -7,7 +7,7 @@
7#include <string> 7#include <string>
8#include "common/common_types.h" 8#include "common/common_types.h"
9 9
10namespace Common { 10namespace WebService {
11struct WebResult { 11struct WebResult {
12 enum class Code : u32 { 12 enum class Code : u32 {
13 Success, 13 Success,
@@ -22,4 +22,4 @@ struct WebResult {
22 std::string result_string; 22 std::string result_string;
23 std::string returned_data; 23 std::string returned_data;
24}; 24};
25} // namespace Common 25} // namespace WebService
diff --git a/src/yuzu/compatdb.cpp b/src/yuzu/compatdb.cpp
index 5477f050c..649912557 100644
--- a/src/yuzu/compatdb.cpp
+++ b/src/yuzu/compatdb.cpp
@@ -54,7 +54,8 @@ void CompatDB::Submit() {
54 back(); 54 back();
55 LOG_DEBUG(Frontend, "Compatibility Rating: {}", compatibility->checkedId()); 55 LOG_DEBUG(Frontend, "Compatibility Rating: {}", compatibility->checkedId());
56 Core::System::GetInstance().TelemetrySession().AddField( 56 Core::System::GetInstance().TelemetrySession().AddField(
57 Telemetry::FieldType::UserFeedback, "Compatibility", compatibility->checkedId()); 57 Common::Telemetry::FieldType::UserFeedback, "Compatibility",
58 compatibility->checkedId());
58 59
59 button(NextButton)->setEnabled(false); 60 button(NextButton)->setEnabled(false);
60 button(NextButton)->setText(tr("Submitting")); 61 button(NextButton)->setText(tr("Submitting"));
diff --git a/src/yuzu/configuration/config.cpp b/src/yuzu/configuration/config.cpp
index a372190cc..7af974d8d 100644
--- a/src/yuzu/configuration/config.cpp
+++ b/src/yuzu/configuration/config.cpp
@@ -635,6 +635,11 @@ void Config::ReadCpuValues() {
635 ReadSetting(QStringLiteral("cpuopt_misc_ir"), true).toBool(); 635 ReadSetting(QStringLiteral("cpuopt_misc_ir"), true).toBool();
636 Settings::values.cpuopt_reduce_misalign_checks = 636 Settings::values.cpuopt_reduce_misalign_checks =
637 ReadSetting(QStringLiteral("cpuopt_reduce_misalign_checks"), true).toBool(); 637 ReadSetting(QStringLiteral("cpuopt_reduce_misalign_checks"), true).toBool();
638
639 Settings::values.cpuopt_unsafe_unfuse_fma =
640 ReadSetting(QStringLiteral("cpuopt_unsafe_unfuse_fma"), true).toBool();
641 Settings::values.cpuopt_unsafe_reduce_fp_error =
642 ReadSetting(QStringLiteral("cpuopt_unsafe_reduce_fp_error"), true).toBool();
638 } 643 }
639 644
640 qt_config->endGroup(); 645 qt_config->endGroup();
@@ -1132,6 +1137,11 @@ void Config::SaveCpuValues() {
1132 WriteSetting(QStringLiteral("cpuopt_misc_ir"), Settings::values.cpuopt_misc_ir, true); 1137 WriteSetting(QStringLiteral("cpuopt_misc_ir"), Settings::values.cpuopt_misc_ir, true);
1133 WriteSetting(QStringLiteral("cpuopt_reduce_misalign_checks"), 1138 WriteSetting(QStringLiteral("cpuopt_reduce_misalign_checks"),
1134 Settings::values.cpuopt_reduce_misalign_checks, true); 1139 Settings::values.cpuopt_reduce_misalign_checks, true);
1140
1141 WriteSetting(QStringLiteral("cpuopt_unsafe_unfuse_fma"),
1142 Settings::values.cpuopt_unsafe_unfuse_fma, true);
1143 WriteSetting(QStringLiteral("cpuopt_unsafe_reduce_fp_error"),
1144 Settings::values.cpuopt_unsafe_reduce_fp_error, true);
1135 } 1145 }
1136 1146
1137 qt_config->endGroup(); 1147 qt_config->endGroup();
diff --git a/src/yuzu/configuration/configure_cpu.cpp b/src/yuzu/configuration/configure_cpu.cpp
index 7493e5ffb..37fcd6adc 100644
--- a/src/yuzu/configuration/configure_cpu.cpp
+++ b/src/yuzu/configuration/configure_cpu.cpp
@@ -19,6 +19,8 @@ ConfigureCpu::ConfigureCpu(QWidget* parent) : QWidget(parent), ui(new Ui::Config
19 19
20 connect(ui->accuracy, qOverload<int>(&QComboBox::activated), this, 20 connect(ui->accuracy, qOverload<int>(&QComboBox::activated), this,
21 &ConfigureCpu::AccuracyUpdated); 21 &ConfigureCpu::AccuracyUpdated);
22 connect(ui->accuracy, qOverload<int>(&QComboBox::currentIndexChanged), this,
23 &ConfigureCpu::UpdateGroup);
22} 24}
23 25
24ConfigureCpu::~ConfigureCpu() = default; 26ConfigureCpu::~ConfigureCpu() = default;
@@ -28,6 +30,12 @@ void ConfigureCpu::SetConfiguration() {
28 30
29 ui->accuracy->setEnabled(runtime_lock); 31 ui->accuracy->setEnabled(runtime_lock);
30 ui->accuracy->setCurrentIndex(static_cast<int>(Settings::values.cpu_accuracy)); 32 ui->accuracy->setCurrentIndex(static_cast<int>(Settings::values.cpu_accuracy));
33 UpdateGroup(static_cast<int>(Settings::values.cpu_accuracy));
34
35 ui->cpuopt_unsafe_unfuse_fma->setEnabled(runtime_lock);
36 ui->cpuopt_unsafe_unfuse_fma->setChecked(Settings::values.cpuopt_unsafe_unfuse_fma);
37 ui->cpuopt_unsafe_reduce_fp_error->setEnabled(runtime_lock);
38 ui->cpuopt_unsafe_reduce_fp_error->setChecked(Settings::values.cpuopt_unsafe_reduce_fp_error);
31} 39}
32 40
33void ConfigureCpu::AccuracyUpdated(int index) { 41void ConfigureCpu::AccuracyUpdated(int index) {
@@ -38,14 +46,21 @@ void ConfigureCpu::AccuracyUpdated(int index) {
38 QMessageBox::Yes | QMessageBox::No); 46 QMessageBox::Yes | QMessageBox::No);
39 if (result == QMessageBox::No) { 47 if (result == QMessageBox::No) {
40 ui->accuracy->setCurrentIndex(static_cast<int>(Settings::CPUAccuracy::Accurate)); 48 ui->accuracy->setCurrentIndex(static_cast<int>(Settings::CPUAccuracy::Accurate));
41 return; 49 UpdateGroup(static_cast<int>(Settings::CPUAccuracy::Accurate));
42 } 50 }
43 } 51 }
44} 52}
45 53
54void ConfigureCpu::UpdateGroup(int index) {
55 ui->unsafe_group->setVisible(static_cast<Settings::CPUAccuracy>(index) ==
56 Settings::CPUAccuracy::Unsafe);
57}
58
46void ConfigureCpu::ApplyConfiguration() { 59void ConfigureCpu::ApplyConfiguration() {
47 Settings::values.cpu_accuracy = 60 Settings::values.cpu_accuracy =
48 static_cast<Settings::CPUAccuracy>(ui->accuracy->currentIndex()); 61 static_cast<Settings::CPUAccuracy>(ui->accuracy->currentIndex());
62 Settings::values.cpuopt_unsafe_unfuse_fma = ui->cpuopt_unsafe_unfuse_fma->isChecked();
63 Settings::values.cpuopt_unsafe_reduce_fp_error = ui->cpuopt_unsafe_reduce_fp_error->isChecked();
49} 64}
50 65
51void ConfigureCpu::changeEvent(QEvent* event) { 66void ConfigureCpu::changeEvent(QEvent* event) {
diff --git a/src/yuzu/configuration/configure_cpu.h b/src/yuzu/configuration/configure_cpu.h
index e4741d3a4..3c5683d81 100644
--- a/src/yuzu/configuration/configure_cpu.h
+++ b/src/yuzu/configuration/configure_cpu.h
@@ -26,6 +26,7 @@ private:
26 void RetranslateUI(); 26 void RetranslateUI();
27 27
28 void AccuracyUpdated(int index); 28 void AccuracyUpdated(int index);
29 void UpdateGroup(int index);
29 30
30 void SetConfiguration(); 31 void SetConfiguration();
31 32
diff --git a/src/yuzu/configuration/configure_cpu.ui b/src/yuzu/configuration/configure_cpu.ui
index bf6ea79bb..ebdd2e6e9 100644
--- a/src/yuzu/configuration/configure_cpu.ui
+++ b/src/yuzu/configuration/configure_cpu.ui
@@ -40,6 +40,11 @@
40 </item> 40 </item>
41 <item> 41 <item>
42 <property name="text"> 42 <property name="text">
43 <string>Unsafe</string>
44 </property>
45 </item>
46 <item>
47 <property name="text">
43 <string>Enable Debug Mode</string> 48 <string>Enable Debug Mode</string>
44 </property> 49 </property>
45 </item> 50 </item>
@@ -63,6 +68,53 @@
63 </layout> 68 </layout>
64 </item> 69 </item>
65 <item> 70 <item>
71 <layout class="QVBoxLayout">
72 <item>
73 <widget class="QGroupBox" name="unsafe_group">
74 <property name="title">
75 <string>Unsafe CPU Optimization Settings</string>
76 </property>
77 <layout class="QVBoxLayout">
78 <item>
79 <widget class="QLabel">
80 <property name="wordWrap">
81 <bool>1</bool>
82 </property>
83 <property name="text">
84 <string>These settings reduce accuracy for speed.</string>
85 </property>
86 </widget>
87 </item>
88 <item>
89 <widget class="QCheckBox" name="cpuopt_unsafe_unfuse_fma">
90 <property name="text">
91 <string>Unfuse FMA (improve performance on CPUs without FMA)</string>
92 </property>
93 <property name="toolTip">
94 <string>
95 &lt;div&gt;This option improves speed by reducing accuracy of fused-multiply-add instructions on CPUs without native FMA support.&lt;/div&gt;
96 </string>
97 </property>
98 </widget>
99 </item>
100 <item>
101 <widget class="QCheckBox" name="cpuopt_unsafe_reduce_fp_error">
102 <property name="text">
103 <string>Faster FRSQRTE and FRECPE</string>
104 </property>
105 <property name="toolTip">
106 <string>
107 &lt;div&gt;This option improves the speed of some approximate floating-point functions by using less accurate native approximations.&lt;/div&gt;
108 </string>
109 </property>
110 </widget>
111 </item>
112 </layout>
113 </widget>
114 </item>
115 </layout>
116 </item>
117 <item>
66 <spacer name="verticalSpacer"> 118 <spacer name="verticalSpacer">
67 <property name="orientation"> 119 <property name="orientation">
68 <enum>Qt::Vertical</enum> 120 <enum>Qt::Vertical</enum>
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp
index c6b7e2c00..cd7e78eb4 100644
--- a/src/yuzu/main.cpp
+++ b/src/yuzu/main.cpp
@@ -1041,7 +1041,7 @@ bool GMainWindow::LoadROM(const QString& filename) {
1041 } 1041 }
1042 game_path = filename; 1042 game_path = filename;
1043 1043
1044 system.TelemetrySession().AddField(Telemetry::FieldType::App, "Frontend", "Qt"); 1044 system.TelemetrySession().AddField(Common::Telemetry::FieldType::App, "Frontend", "Qt");
1045 return true; 1045 return true;
1046} 1046}
1047 1047
diff --git a/src/yuzu_cmd/yuzu.cpp b/src/yuzu_cmd/yuzu.cpp
index 3f2f61ca0..8efe49390 100644
--- a/src/yuzu_cmd/yuzu.cpp
+++ b/src/yuzu_cmd/yuzu.cpp
@@ -229,7 +229,7 @@ int main(int argc, char** argv) {
229 } 229 }
230 } 230 }
231 231
232 system.TelemetrySession().AddField(Telemetry::FieldType::App, "Frontend", "SDL"); 232 system.TelemetrySession().AddField(Common::Telemetry::FieldType::App, "Frontend", "SDL");
233 233
234 // Core is loaded, start the GPU (makes the GPU contexts current to this thread) 234 // Core is loaded, start the GPU (makes the GPU contexts current to this thread)
235 system.GPU().Start(); 235 system.GPU().Start();
diff --git a/src/yuzu_tester/yuzu.cpp b/src/yuzu_tester/yuzu.cpp
index 7c5ac5681..7acf0caad 100644
--- a/src/yuzu_tester/yuzu.cpp
+++ b/src/yuzu_tester/yuzu.cpp
@@ -251,7 +251,8 @@ int main(int argc, char** argv) {
251 251
252 Service::Yuzu::InstallInterfaces(system.ServiceManager(), datastring, callback); 252 Service::Yuzu::InstallInterfaces(system.ServiceManager(), datastring, callback);
253 253
254 system.TelemetrySession().AddField(Telemetry::FieldType::App, "Frontend", "SDLHideTester"); 254 system.TelemetrySession().AddField(Common::Telemetry::FieldType::App, "Frontend",
255 "SDLHideTester");
255 256
256 system.GPU().Start(); 257 system.GPU().Start();
257 system.Renderer().Rasterizer().LoadDiskResources(); 258 system.Renderer().Rasterizer().LoadDiskResources();