summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/audio_core/audio_renderer.cpp89
-rw-r--r--src/audio_core/audio_renderer.h49
-rw-r--r--src/core/file_sys/ips_layer.cpp69
-rw-r--r--src/core/file_sys/ips_layer.h11
-rw-r--r--src/core/file_sys/patch_manager.cpp15
-rw-r--r--src/core/file_sys/patch_manager.h5
-rw-r--r--src/core/hle/kernel/svc.cpp25
-rw-r--r--src/core/loader/nsp.cpp2
-rw-r--r--src/core/loader/nsp.h2
-rw-r--r--src/core/loader/xci.cpp2
-rw-r--r--src/core/loader/xci.h2
-rw-r--r--src/core/telemetry_session.cpp12
-rw-r--r--src/core/telemetry_session.h4
-rw-r--r--src/video_core/renderer_opengl/gl_shader_decompiler.cpp10
-rw-r--r--src/yuzu/bootmanager.cpp71
-rw-r--r--src/yuzu/bootmanager.h10
-rw-r--r--src/yuzu/game_list_worker.cpp11
-rw-r--r--src/yuzu_cmd/emu_window/emu_window_sdl2.cpp48
-rw-r--r--src/yuzu_cmd/emu_window/emu_window_sdl2.h12
19 files changed, 364 insertions, 85 deletions
diff --git a/src/audio_core/audio_renderer.cpp b/src/audio_core/audio_renderer.cpp
index 6f0ff953a..23e5d3f10 100644
--- a/src/audio_core/audio_renderer.cpp
+++ b/src/audio_core/audio_renderer.cpp
@@ -30,7 +30,7 @@ public:
30 return info; 30 return info;
31 } 31 }
32 32
33 VoiceInfo& Info() { 33 VoiceInfo& GetInfo() {
34 return info; 34 return info;
35 } 35 }
36 36
@@ -51,9 +51,30 @@ private:
51 VoiceInfo info{}; 51 VoiceInfo info{};
52}; 52};
53 53
54class AudioRenderer::EffectState {
55public:
56 const EffectOutStatus& GetOutStatus() const {
57 return out_status;
58 }
59
60 const EffectInStatus& GetInfo() const {
61 return info;
62 }
63
64 EffectInStatus& GetInfo() {
65 return info;
66 }
67
68 void UpdateState();
69
70private:
71 EffectOutStatus out_status{};
72 EffectInStatus info{};
73};
54AudioRenderer::AudioRenderer(AudioRendererParameter params, 74AudioRenderer::AudioRenderer(AudioRendererParameter params,
55 Kernel::SharedPtr<Kernel::Event> buffer_event) 75 Kernel::SharedPtr<Kernel::Event> buffer_event)
56 : worker_params{params}, buffer_event{buffer_event}, voices(params.voice_count) { 76 : worker_params{params}, buffer_event{buffer_event}, voices(params.voice_count),
77 effects(params.effect_count) {
57 78
58 audio_out = std::make_unique<AudioCore::AudioOut>(); 79 audio_out = std::make_unique<AudioCore::AudioOut>();
59 stream = audio_out->OpenStream(STREAM_SAMPLE_RATE, STREAM_NUM_CHANNELS, "AudioRenderer", 80 stream = audio_out->OpenStream(STREAM_SAMPLE_RATE, STREAM_NUM_CHANNELS, "AudioRenderer",
@@ -96,11 +117,29 @@ std::vector<u8> AudioRenderer::UpdateAudioRenderer(const std::vector<u8>& input_
96 memory_pool_count * sizeof(MemoryPoolInfo)); 117 memory_pool_count * sizeof(MemoryPoolInfo));
97 118
98 // Copy VoiceInfo structs 119 // Copy VoiceInfo structs
99 std::size_t offset{sizeof(UpdateDataHeader) + config.behavior_size + config.memory_pools_size + 120 std::size_t voice_offset{sizeof(UpdateDataHeader) + config.behavior_size +
100 config.voice_resource_size}; 121 config.memory_pools_size + config.voice_resource_size};
101 for (auto& voice : voices) { 122 for (auto& voice : voices) {
102 std::memcpy(&voice.Info(), input_params.data() + offset, sizeof(VoiceInfo)); 123 std::memcpy(&voice.GetInfo(), input_params.data() + voice_offset, sizeof(VoiceInfo));
103 offset += sizeof(VoiceInfo); 124 voice_offset += sizeof(VoiceInfo);
125 }
126
127 std::size_t effect_offset{sizeof(UpdateDataHeader) + config.behavior_size +
128 config.memory_pools_size + config.voice_resource_size +
129 config.voices_size};
130 for (auto& effect : effects) {
131 std::memcpy(&effect.GetInfo(), input_params.data() + effect_offset, sizeof(EffectInStatus));
132 effect_offset += sizeof(EffectInStatus);
133 }
134
135 // Update memory pool state
136 std::vector<MemoryPoolEntry> memory_pool(memory_pool_count);
137 for (std::size_t index = 0; index < memory_pool.size(); ++index) {
138 if (mem_pool_info[index].pool_state == MemoryPoolStates::RequestAttach) {
139 memory_pool[index].state = MemoryPoolStates::Attached;
140 } else if (mem_pool_info[index].pool_state == MemoryPoolStates::RequestDetach) {
141 memory_pool[index].state = MemoryPoolStates::Detached;
142 }
104 } 143 }
105 144
106 // Update voices 145 // Update voices
@@ -114,14 +153,8 @@ std::vector<u8> AudioRenderer::UpdateAudioRenderer(const std::vector<u8>& input_
114 } 153 }
115 } 154 }
116 155
117 // Update memory pool state 156 for (auto& effect : effects) {
118 std::vector<MemoryPoolEntry> memory_pool(memory_pool_count); 157 effect.UpdateState();
119 for (std::size_t index = 0; index < memory_pool.size(); ++index) {
120 if (mem_pool_info[index].pool_state == MemoryPoolStates::RequestAttach) {
121 memory_pool[index].state = MemoryPoolStates::Attached;
122 } else if (mem_pool_info[index].pool_state == MemoryPoolStates::RequestDetach) {
123 memory_pool[index].state = MemoryPoolStates::Detached;
124 }
125 } 158 }
126 159
127 // Release previous buffers and queue next ones for playback 160 // Release previous buffers and queue next ones for playback
@@ -144,6 +177,14 @@ std::vector<u8> AudioRenderer::UpdateAudioRenderer(const std::vector<u8>& input_
144 voice_out_status_offset += sizeof(VoiceOutStatus); 177 voice_out_status_offset += sizeof(VoiceOutStatus);
145 } 178 }
146 179
180 std::size_t effect_out_status_offset{
181 sizeof(UpdateDataHeader) + response_data.memory_pools_size + response_data.voices_size +
182 response_data.voice_resource_size};
183 for (const auto& effect : effects) {
184 std::memcpy(output_params.data() + effect_out_status_offset, &effect.GetOutStatus(),
185 sizeof(EffectOutStatus));
186 effect_out_status_offset += sizeof(EffectOutStatus);
187 }
147 return output_params; 188 return output_params;
148} 189}
149 190
@@ -244,11 +285,29 @@ void AudioRenderer::VoiceState::RefreshBuffer() {
244 break; 285 break;
245 } 286 }
246 287
247 samples = Interpolate(interp_state, std::move(samples), Info().sample_rate, STREAM_SAMPLE_RATE); 288 samples =
289 Interpolate(interp_state, std::move(samples), GetInfo().sample_rate, STREAM_SAMPLE_RATE);
248 290
249 is_refresh_pending = false; 291 is_refresh_pending = false;
250} 292}
251 293
294void AudioRenderer::EffectState::UpdateState() {
295 if (info.is_new) {
296 out_status.state = EffectStatus::New;
297 } else {
298 if (info.type == Effect::Aux) {
299 ASSERT_MSG(Memory::Read32(info.aux_info.return_buffer_info) == 0,
300 "Aux buffers tried to update");
301 ASSERT_MSG(Memory::Read32(info.aux_info.send_buffer_info) == 0,
302 "Aux buffers tried to update");
303 ASSERT_MSG(Memory::Read32(info.aux_info.return_buffer_base) == 0,
304 "Aux buffers tried to update");
305 ASSERT_MSG(Memory::Read32(info.aux_info.send_buffer_base) == 0,
306 "Aux buffers tried to update");
307 }
308 }
309}
310
252static constexpr s16 ClampToS16(s32 value) { 311static constexpr s16 ClampToS16(s32 value) {
253 return static_cast<s16>(std::clamp(value, -32768, 32767)); 312 return static_cast<s16>(std::clamp(value, -32768, 32767));
254} 313}
diff --git a/src/audio_core/audio_renderer.h b/src/audio_core/audio_renderer.h
index dfef89e1d..046417da3 100644
--- a/src/audio_core/audio_renderer.h
+++ b/src/audio_core/audio_renderer.h
@@ -28,6 +28,16 @@ enum class PlayState : u8 {
28 Paused = 2, 28 Paused = 2,
29}; 29};
30 30
31enum class Effect : u8 {
32 None = 0,
33 Aux = 2,
34};
35
36enum class EffectStatus : u8 {
37 None = 0,
38 New = 1,
39};
40
31struct AudioRendererParameter { 41struct AudioRendererParameter {
32 u32_le sample_rate; 42 u32_le sample_rate;
33 u32_le sample_count; 43 u32_le sample_count;
@@ -128,6 +138,43 @@ struct VoiceOutStatus {
128}; 138};
129static_assert(sizeof(VoiceOutStatus) == 0x10, "VoiceOutStatus has wrong size"); 139static_assert(sizeof(VoiceOutStatus) == 0x10, "VoiceOutStatus has wrong size");
130 140
141struct AuxInfo {
142 std::array<u8, 24> input_mix_buffers;
143 std::array<u8, 24> output_mix_buffers;
144 u32_le mix_buffer_count;
145 u32_le sample_rate; // Stored in the aux buffer currently
146 u32_le sampe_count;
147 u64_le send_buffer_info;
148 u64_le send_buffer_base;
149
150 u64_le return_buffer_info;
151 u64_le return_buffer_base;
152};
153static_assert(sizeof(AuxInfo) == 0x60, "AuxInfo is an invalid size");
154
155struct EffectInStatus {
156 Effect type;
157 u8 is_new;
158 u8 is_enabled;
159 INSERT_PADDING_BYTES(1);
160 u32_le mix_id;
161 u64_le buffer_base;
162 u64_le buffer_sz;
163 s32_le priority;
164 INSERT_PADDING_BYTES(4);
165 union {
166 std::array<u8, 0xa0> raw;
167 AuxInfo aux_info;
168 };
169};
170static_assert(sizeof(EffectInStatus) == 0xc0, "EffectInStatus is an invalid size");
171
172struct EffectOutStatus {
173 EffectStatus state;
174 INSERT_PADDING_BYTES(0xf);
175};
176static_assert(sizeof(EffectOutStatus) == 0x10, "EffectOutStatus is an invalid size");
177
131struct UpdateDataHeader { 178struct UpdateDataHeader {
132 UpdateDataHeader() {} 179 UpdateDataHeader() {}
133 180
@@ -173,11 +220,13 @@ public:
173 Stream::State GetStreamState() const; 220 Stream::State GetStreamState() const;
174 221
175private: 222private:
223 class EffectState;
176 class VoiceState; 224 class VoiceState;
177 225
178 AudioRendererParameter worker_params; 226 AudioRendererParameter worker_params;
179 Kernel::SharedPtr<Kernel::Event> buffer_event; 227 Kernel::SharedPtr<Kernel::Event> buffer_event;
180 std::vector<VoiceState> voices; 228 std::vector<VoiceState> voices;
229 std::vector<EffectState> effects;
181 std::unique_ptr<AudioOut> audio_out; 230 std::unique_ptr<AudioOut> audio_out;
182 AudioCore::StreamPtr stream; 231 AudioCore::StreamPtr stream;
183}; 232};
diff --git a/src/core/file_sys/ips_layer.cpp b/src/core/file_sys/ips_layer.cpp
index 184509716..554eae9bc 100644
--- a/src/core/file_sys/ips_layer.cpp
+++ b/src/core/file_sys/ips_layer.cpp
@@ -2,9 +2,15 @@
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 <algorithm>
6#include <cstring>
7#include <map>
5#include <sstream> 8#include <sstream>
6#include "common/assert.h" 9#include <string>
10#include <utility>
11
7#include "common/hex_util.h" 12#include "common/hex_util.h"
13#include "common/logging/log.h"
8#include "common/swap.h" 14#include "common/swap.h"
9#include "core/file_sys/ips_layer.h" 15#include "core/file_sys/ips_layer.h"
10#include "core/file_sys/vfs_vector.h" 16#include "core/file_sys/vfs_vector.h"
@@ -17,22 +23,48 @@ enum class IPSFileType {
17 Error, 23 Error,
18}; 24};
19 25
20constexpr std::array<std::pair<const char*, const char*>, 11> ESCAPE_CHARACTER_MAP{ 26constexpr std::array<std::pair<const char*, const char*>, 11> ESCAPE_CHARACTER_MAP{{
21 std::pair{"\\a", "\a"}, {"\\b", "\b"}, {"\\f", "\f"}, {"\\n", "\n"}, 27 {"\\a", "\a"},
22 {"\\r", "\r"}, {"\\t", "\t"}, {"\\v", "\v"}, {"\\\\", "\\"}, 28 {"\\b", "\b"},
23 {"\\\'", "\'"}, {"\\\"", "\""}, {"\\\?", "\?"}, 29 {"\\f", "\f"},
24}; 30 {"\\n", "\n"},
31 {"\\r", "\r"},
32 {"\\t", "\t"},
33 {"\\v", "\v"},
34 {"\\\\", "\\"},
35 {"\\\'", "\'"},
36 {"\\\"", "\""},
37 {"\\\?", "\?"},
38}};
25 39
26static IPSFileType IdentifyMagic(const std::vector<u8>& magic) { 40static IPSFileType IdentifyMagic(const std::vector<u8>& magic) {
27 if (magic.size() != 5) 41 if (magic.size() != 5) {
28 return IPSFileType::Error; 42 return IPSFileType::Error;
29 if (magic == std::vector<u8>{'P', 'A', 'T', 'C', 'H'}) 43 }
44
45 constexpr std::array<u8, 5> patch_magic{{'P', 'A', 'T', 'C', 'H'}};
46 if (std::equal(magic.begin(), magic.end(), patch_magic.begin())) {
30 return IPSFileType::IPS; 47 return IPSFileType::IPS;
31 if (magic == std::vector<u8>{'I', 'P', 'S', '3', '2'}) 48 }
49
50 constexpr std::array<u8, 5> ips32_magic{{'I', 'P', 'S', '3', '2'}};
51 if (std::equal(magic.begin(), magic.end(), ips32_magic.begin())) {
32 return IPSFileType::IPS32; 52 return IPSFileType::IPS32;
53 }
54
33 return IPSFileType::Error; 55 return IPSFileType::Error;
34} 56}
35 57
58static bool IsEOF(IPSFileType type, const std::vector<u8>& data) {
59 constexpr std::array<u8, 3> eof{{'E', 'O', 'F'}};
60 if (type == IPSFileType::IPS && std::equal(data.begin(), data.end(), eof.begin())) {
61 return true;
62 }
63
64 constexpr std::array<u8, 4> eeof{{'E', 'E', 'O', 'F'}};
65 return type == IPSFileType::IPS32 && std::equal(data.begin(), data.end(), eeof.begin());
66}
67
36VirtualFile PatchIPS(const VirtualFile& in, const VirtualFile& ips) { 68VirtualFile PatchIPS(const VirtualFile& in, const VirtualFile& ips) {
37 if (in == nullptr || ips == nullptr) 69 if (in == nullptr || ips == nullptr)
38 return nullptr; 70 return nullptr;
@@ -47,8 +79,7 @@ VirtualFile PatchIPS(const VirtualFile& in, const VirtualFile& ips) {
47 u64 offset = 5; // After header 79 u64 offset = 5; // After header
48 while (ips->Read(temp.data(), temp.size(), offset) == temp.size()) { 80 while (ips->Read(temp.data(), temp.size(), offset) == temp.size()) {
49 offset += temp.size(); 81 offset += temp.size();
50 if (type == IPSFileType::IPS32 && temp == std::vector<u8>{'E', 'E', 'O', 'F'} || 82 if (IsEOF(type, temp)) {
51 type == IPSFileType::IPS && temp == std::vector<u8>{'E', 'O', 'F'}) {
52 break; 83 break;
53 } 84 }
54 85
@@ -88,11 +119,20 @@ VirtualFile PatchIPS(const VirtualFile& in, const VirtualFile& ips) {
88 } 119 }
89 } 120 }
90 121
91 if (temp != std::vector<u8>{'E', 'E', 'O', 'F'} && temp != std::vector<u8>{'E', 'O', 'F'}) 122 if (!IsEOF(type, temp)) {
92 return nullptr; 123 return nullptr;
93 return std::make_shared<VectorVfsFile>(in_data, in->GetName(), in->GetContainingDirectory()); 124 }
125
126 return std::make_shared<VectorVfsFile>(std::move(in_data), in->GetName(),
127 in->GetContainingDirectory());
94} 128}
95 129
130struct IPSwitchCompiler::IPSwitchPatch {
131 std::string name;
132 bool enabled;
133 std::map<u32, std::vector<u8>> records;
134};
135
96IPSwitchCompiler::IPSwitchCompiler(VirtualFile patch_text_) : patch_text(std::move(patch_text_)) { 136IPSwitchCompiler::IPSwitchCompiler(VirtualFile patch_text_) : patch_text(std::move(patch_text_)) {
97 Parse(); 137 Parse();
98} 138}
@@ -291,7 +331,8 @@ VirtualFile IPSwitchCompiler::Apply(const VirtualFile& in) const {
291 } 331 }
292 } 332 }
293 333
294 return std::make_shared<VectorVfsFile>(in_data, in->GetName(), in->GetContainingDirectory()); 334 return std::make_shared<VectorVfsFile>(std::move(in_data), in->GetName(),
335 in->GetContainingDirectory());
295} 336}
296 337
297} // namespace FileSys 338} // namespace FileSys
diff --git a/src/core/file_sys/ips_layer.h b/src/core/file_sys/ips_layer.h
index 57da00da8..450b2f71e 100644
--- a/src/core/file_sys/ips_layer.h
+++ b/src/core/file_sys/ips_layer.h
@@ -4,8 +4,11 @@
4 4
5#pragma once 5#pragma once
6 6
7#include <array>
7#include <memory> 8#include <memory>
9#include <vector>
8 10
11#include "common/common_types.h"
9#include "core/file_sys/vfs.h" 12#include "core/file_sys/vfs.h"
10 13
11namespace FileSys { 14namespace FileSys {
@@ -22,17 +25,13 @@ public:
22 VirtualFile Apply(const VirtualFile& in) const; 25 VirtualFile Apply(const VirtualFile& in) const;
23 26
24private: 27private:
28 struct IPSwitchPatch;
29
25 void ParseFlag(const std::string& flag); 30 void ParseFlag(const std::string& flag);
26 void Parse(); 31 void Parse();
27 32
28 bool valid = false; 33 bool valid = false;
29 34
30 struct IPSwitchPatch {
31 std::string name;
32 bool enabled;
33 std::map<u32, std::vector<u8>> records;
34 };
35
36 VirtualFile patch_text; 35 VirtualFile patch_text;
37 std::vector<IPSwitchPatch> patches; 36 std::vector<IPSwitchPatch> patches;
38 std::array<u8, 0x20> nso_build_id{}; 37 std::array<u8, 0x20> nso_build_id{};
diff --git a/src/core/file_sys/patch_manager.cpp b/src/core/file_sys/patch_manager.cpp
index b14d7cb0a..019caebe9 100644
--- a/src/core/file_sys/patch_manager.cpp
+++ b/src/core/file_sys/patch_manager.cpp
@@ -345,23 +345,22 @@ std::map<std::string, std::string, std::less<>> PatchManager::GetPatchVersionNam
345 return out; 345 return out;
346} 346}
347 347
348std::pair<std::shared_ptr<NACP>, VirtualFile> PatchManager::GetControlMetadata() const { 348std::pair<std::unique_ptr<NACP>, VirtualFile> PatchManager::GetControlMetadata() const {
349 const auto& installed{Service::FileSystem::GetUnionContents()}; 349 const auto& installed{Service::FileSystem::GetUnionContents()};
350 350
351 const auto base_control_nca = installed->GetEntry(title_id, ContentRecordType::Control); 351 const auto base_control_nca = installed->GetEntry(title_id, ContentRecordType::Control);
352 if (base_control_nca == nullptr) 352 if (base_control_nca == nullptr)
353 return {}; 353 return {};
354 354
355 return ParseControlNCA(base_control_nca); 355 return ParseControlNCA(*base_control_nca);
356} 356}
357 357
358std::pair<std::shared_ptr<NACP>, VirtualFile> PatchManager::ParseControlNCA( 358std::pair<std::unique_ptr<NACP>, VirtualFile> PatchManager::ParseControlNCA(const NCA& nca) const {
359 const std::shared_ptr<NCA>& nca) const { 359 const auto base_romfs = nca.GetRomFS();
360 const auto base_romfs = nca->GetRomFS();
361 if (base_romfs == nullptr) 360 if (base_romfs == nullptr)
362 return {}; 361 return {};
363 362
364 const auto romfs = PatchRomFS(base_romfs, nca->GetBaseIVFCOffset(), ContentRecordType::Control); 363 const auto romfs = PatchRomFS(base_romfs, nca.GetBaseIVFCOffset(), ContentRecordType::Control);
365 if (romfs == nullptr) 364 if (romfs == nullptr)
366 return {}; 365 return {};
367 366
@@ -373,7 +372,7 @@ std::pair<std::shared_ptr<NACP>, VirtualFile> PatchManager::ParseControlNCA(
373 if (nacp_file == nullptr) 372 if (nacp_file == nullptr)
374 nacp_file = extracted->GetFile("Control.nacp"); 373 nacp_file = extracted->GetFile("Control.nacp");
375 374
376 const auto nacp = nacp_file == nullptr ? nullptr : std::make_shared<NACP>(nacp_file); 375 auto nacp = nacp_file == nullptr ? nullptr : std::make_unique<NACP>(nacp_file);
377 376
378 VirtualFile icon_file; 377 VirtualFile icon_file;
379 for (const auto& language : FileSys::LANGUAGE_NAMES) { 378 for (const auto& language : FileSys::LANGUAGE_NAMES) {
@@ -382,6 +381,6 @@ std::pair<std::shared_ptr<NACP>, VirtualFile> PatchManager::ParseControlNCA(
382 break; 381 break;
383 } 382 }
384 383
385 return {nacp, icon_file}; 384 return {std::move(nacp), icon_file};
386} 385}
387} // namespace FileSys 386} // namespace FileSys
diff --git a/src/core/file_sys/patch_manager.h b/src/core/file_sys/patch_manager.h
index eb6fc4607..7d168837f 100644
--- a/src/core/file_sys/patch_manager.h
+++ b/src/core/file_sys/patch_manager.h
@@ -57,11 +57,10 @@ public:
57 57
58 // Given title_id of the program, attempts to get the control data of the update and parse it, 58 // Given title_id of the program, attempts to get the control data of the update and parse it,
59 // falling back to the base control data. 59 // falling back to the base control data.
60 std::pair<std::shared_ptr<NACP>, VirtualFile> GetControlMetadata() const; 60 std::pair<std::unique_ptr<NACP>, VirtualFile> GetControlMetadata() const;
61 61
62 // Version of GetControlMetadata that takes an arbitrary NCA 62 // Version of GetControlMetadata that takes an arbitrary NCA
63 std::pair<std::shared_ptr<NACP>, VirtualFile> ParseControlNCA( 63 std::pair<std::unique_ptr<NACP>, VirtualFile> ParseControlNCA(const NCA& nca) const;
64 const std::shared_ptr<NCA>& nca) const;
65 64
66private: 65private:
67 u64 title_id; 66 u64 title_id;
diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp
index 6c4af7e47..b488b508d 100644
--- a/src/core/hle/kernel/svc.cpp
+++ b/src/core/hle/kernel/svc.cpp
@@ -301,13 +301,28 @@ static ResultCode ArbitrateUnlock(VAddr mutex_addr) {
301 return Mutex::Release(mutex_addr); 301 return Mutex::Release(mutex_addr);
302} 302}
303 303
304struct BreakReason {
305 union {
306 u64 raw;
307 BitField<31, 1, u64> dont_kill_application;
308 };
309};
310
304/// Break program execution 311/// Break program execution
305static void Break(u64 reason, u64 info1, u64 info2) { 312static void Break(u64 reason, u64 info1, u64 info2) {
306 LOG_CRITICAL( 313 BreakReason break_reason{reason};
307 Debug_Emulated, 314 if (break_reason.dont_kill_application) {
308 "Emulated program broke execution! reason=0x{:016X}, info1=0x{:016X}, info2=0x{:016X}", 315 LOG_ERROR(
309 reason, info1, info2); 316 Debug_Emulated,
310 ASSERT(false); 317 "Emulated program broke execution! reason=0x{:016X}, info1=0x{:016X}, info2=0x{:016X}",
318 reason, info1, info2);
319 } else {
320 LOG_CRITICAL(
321 Debug_Emulated,
322 "Emulated program broke execution! reason=0x{:016X}, info1=0x{:016X}, info2=0x{:016X}",
323 reason, info1, info2);
324 ASSERT(false);
325 }
311} 326}
312 327
313/// Used to output a message on a debug hardware unit - does nothing on a retail unit 328/// Used to output a message on a debug hardware unit - does nothing on a retail unit
diff --git a/src/core/loader/nsp.cpp b/src/core/loader/nsp.cpp
index 5534ce01c..13e57848d 100644
--- a/src/core/loader/nsp.cpp
+++ b/src/core/loader/nsp.cpp
@@ -35,7 +35,7 @@ AppLoader_NSP::AppLoader_NSP(FileSys::VirtualFile file)
35 return; 35 return;
36 36
37 std::tie(nacp_file, icon_file) = 37 std::tie(nacp_file, icon_file) =
38 FileSys::PatchManager(nsp->GetProgramTitleID()).ParseControlNCA(control_nca); 38 FileSys::PatchManager(nsp->GetProgramTitleID()).ParseControlNCA(*control_nca);
39} 39}
40 40
41AppLoader_NSP::~AppLoader_NSP() = default; 41AppLoader_NSP::~AppLoader_NSP() = default;
diff --git a/src/core/loader/nsp.h b/src/core/loader/nsp.h
index b006594a6..db91cd01e 100644
--- a/src/core/loader/nsp.h
+++ b/src/core/loader/nsp.h
@@ -49,7 +49,7 @@ private:
49 std::unique_ptr<AppLoader> secondary_loader; 49 std::unique_ptr<AppLoader> secondary_loader;
50 50
51 FileSys::VirtualFile icon_file; 51 FileSys::VirtualFile icon_file;
52 std::shared_ptr<FileSys::NACP> nacp_file; 52 std::unique_ptr<FileSys::NACP> nacp_file;
53 u64 title_id; 53 u64 title_id;
54}; 54};
55 55
diff --git a/src/core/loader/xci.cpp b/src/core/loader/xci.cpp
index ee5452eb9..7a619acb4 100644
--- a/src/core/loader/xci.cpp
+++ b/src/core/loader/xci.cpp
@@ -30,7 +30,7 @@ AppLoader_XCI::AppLoader_XCI(FileSys::VirtualFile file)
30 return; 30 return;
31 31
32 std::tie(nacp_file, icon_file) = 32 std::tie(nacp_file, icon_file) =
33 FileSys::PatchManager(xci->GetProgramTitleID()).ParseControlNCA(control_nca); 33 FileSys::PatchManager(xci->GetProgramTitleID()).ParseControlNCA(*control_nca);
34} 34}
35 35
36AppLoader_XCI::~AppLoader_XCI() = default; 36AppLoader_XCI::~AppLoader_XCI() = default;
diff --git a/src/core/loader/xci.h b/src/core/loader/xci.h
index 770ed1437..46f8dfc9e 100644
--- a/src/core/loader/xci.h
+++ b/src/core/loader/xci.h
@@ -49,7 +49,7 @@ private:
49 std::unique_ptr<AppLoader_NCA> nca_loader; 49 std::unique_ptr<AppLoader_NCA> nca_loader;
50 50
51 FileSys::VirtualFile icon_file; 51 FileSys::VirtualFile icon_file;
52 std::shared_ptr<FileSys::NACP> nacp_file; 52 std::unique_ptr<FileSys::NACP> nacp_file;
53}; 53};
54 54
55} // namespace Loader 55} // namespace Loader
diff --git a/src/core/telemetry_session.cpp b/src/core/telemetry_session.cpp
index f29fff1e7..7b04792b5 100644
--- a/src/core/telemetry_session.cpp
+++ b/src/core/telemetry_session.cpp
@@ -2,12 +2,16 @@
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 <array>
6
7#include <mbedtls/ctr_drbg.h>
8#include <mbedtls/entropy.h>
9
5#include "common/assert.h" 10#include "common/assert.h"
6#include "common/common_types.h" 11#include "common/common_types.h"
7#include "common/file_util.h" 12#include "common/file_util.h"
13#include "common/logging/log.h"
8 14
9#include <mbedtls/ctr_drbg.h>
10#include <mbedtls/entropy.h>
11#include "core/core.h" 15#include "core/core.h"
12#include "core/file_sys/control_metadata.h" 16#include "core/file_sys/control_metadata.h"
13#include "core/file_sys/patch_manager.h" 17#include "core/file_sys/patch_manager.h"
@@ -28,11 +32,11 @@ static u64 GenerateTelemetryId() {
28 mbedtls_entropy_context entropy; 32 mbedtls_entropy_context entropy;
29 mbedtls_entropy_init(&entropy); 33 mbedtls_entropy_init(&entropy);
30 mbedtls_ctr_drbg_context ctr_drbg; 34 mbedtls_ctr_drbg_context ctr_drbg;
31 std::string personalization = "yuzu Telemetry ID"; 35 constexpr std::array<char, 18> personalization{{"yuzu Telemetry ID"}};
32 36
33 mbedtls_ctr_drbg_init(&ctr_drbg); 37 mbedtls_ctr_drbg_init(&ctr_drbg);
34 ASSERT(mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy, 38 ASSERT(mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy,
35 reinterpret_cast<const unsigned char*>(personalization.c_str()), 39 reinterpret_cast<const unsigned char*>(personalization.data()),
36 personalization.size()) == 0); 40 personalization.size()) == 0);
37 ASSERT(mbedtls_ctr_drbg_random(&ctr_drbg, reinterpret_cast<unsigned char*>(&telemetry_id), 41 ASSERT(mbedtls_ctr_drbg_random(&ctr_drbg, reinterpret_cast<unsigned char*>(&telemetry_id),
38 sizeof(u64)) == 0); 42 sizeof(u64)) == 0);
diff --git a/src/core/telemetry_session.h b/src/core/telemetry_session.h
index cec271df0..2a4845797 100644
--- a/src/core/telemetry_session.h
+++ b/src/core/telemetry_session.h
@@ -5,6 +5,7 @@
5#pragma once 5#pragma once
6 6
7#include <memory> 7#include <memory>
8#include <string>
8#include "common/telemetry.h" 9#include "common/telemetry.h"
9 10
10namespace Core { 11namespace Core {
@@ -30,8 +31,6 @@ public:
30 field_collection.AddField(type, name, std::move(value)); 31 field_collection.AddField(type, name, std::move(value));
31 } 32 }
32 33
33 static void FinalizeAsyncJob();
34
35private: 34private:
36 Telemetry::FieldCollection field_collection; ///< Tracks all added fields for the session 35 Telemetry::FieldCollection field_collection; ///< Tracks all added fields for the session
37 std::unique_ptr<Telemetry::VisitorInterface> backend; ///< Backend interface that logs fields 36 std::unique_ptr<Telemetry::VisitorInterface> backend; ///< Backend interface that logs fields
@@ -53,7 +52,6 @@ u64 RegenerateTelemetryId();
53 * Verifies the username and token. 52 * Verifies the username and token.
54 * @param username yuzu username to use for authentication. 53 * @param username yuzu username to use for authentication.
55 * @param token yuzu token to use for authentication. 54 * @param token yuzu token to use for authentication.
56 * @param func A function that gets exectued when the verification is finished
57 * @returns Future with bool indicating whether the verification succeeded 55 * @returns Future with bool indicating whether the verification succeeded
58 */ 56 */
59bool VerifyLogin(const std::string& username, const std::string& token); 57bool VerifyLogin(const std::string& username, const std::string& token);
diff --git a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
index 7e57de78a..85c668ca1 100644
--- a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
+++ b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
@@ -2299,8 +2299,7 @@ private:
2299 ASSERT_MSG(!instr.tmml.UsesMiscMode(Tegra::Shader::TextureMiscMode::NDV), 2299 ASSERT_MSG(!instr.tmml.UsesMiscMode(Tegra::Shader::TextureMiscMode::NDV),
2300 "NDV is not implemented"); 2300 "NDV is not implemented");
2301 2301
2302 const std::string op_a = regs.GetRegisterAsFloat(instr.gpr8); 2302 const std::string x = regs.GetRegisterAsFloat(instr.gpr8);
2303 const std::string op_b = regs.GetRegisterAsFloat(instr.gpr8.Value() + 1);
2304 const bool is_array = instr.tmml.array != 0; 2303 const bool is_array = instr.tmml.array != 0;
2305 auto texture_type = instr.tmml.texture_type.Value(); 2304 auto texture_type = instr.tmml.texture_type.Value();
2306 const std::string sampler = 2305 const std::string sampler =
@@ -2311,13 +2310,11 @@ private:
2311 std::string coord; 2310 std::string coord;
2312 switch (texture_type) { 2311 switch (texture_type) {
2313 case Tegra::Shader::TextureType::Texture1D: { 2312 case Tegra::Shader::TextureType::Texture1D: {
2314 std::string x = regs.GetRegisterAsFloat(instr.gpr8);
2315 coord = "float coords = " + x + ';'; 2313 coord = "float coords = " + x + ';';
2316 break; 2314 break;
2317 } 2315 }
2318 case Tegra::Shader::TextureType::Texture2D: { 2316 case Tegra::Shader::TextureType::Texture2D: {
2319 std::string x = regs.GetRegisterAsFloat(instr.gpr8); 2317 const std::string y = regs.GetRegisterAsFloat(instr.gpr8.Value() + 1);
2320 std::string y = regs.GetRegisterAsFloat(instr.gpr8.Value() + 1);
2321 coord = "vec2 coords = vec2(" + x + ", " + y + ");"; 2318 coord = "vec2 coords = vec2(" + x + ", " + y + ");";
2322 break; 2319 break;
2323 } 2320 }
@@ -2327,8 +2324,7 @@ private:
2327 UNREACHABLE(); 2324 UNREACHABLE();
2328 2325
2329 // Fallback to interpreting as a 2D texture for now 2326 // Fallback to interpreting as a 2D texture for now
2330 std::string x = regs.GetRegisterAsFloat(instr.gpr8); 2327 const std::string y = regs.GetRegisterAsFloat(instr.gpr8.Value() + 1);
2331 std::string y = regs.GetRegisterAsFloat(instr.gpr8.Value() + 1);
2332 coord = "vec2 coords = vec2(" + x + ", " + y + ");"; 2328 coord = "vec2 coords = vec2(" + x + ", " + y + ");";
2333 texture_type = Tegra::Shader::TextureType::Texture2D; 2329 texture_type = Tegra::Shader::TextureType::Texture2D;
2334 } 2330 }
diff --git a/src/yuzu/bootmanager.cpp b/src/yuzu/bootmanager.cpp
index 4e4c108ab..e8ab23326 100644
--- a/src/yuzu/bootmanager.cpp
+++ b/src/yuzu/bootmanager.cpp
@@ -110,6 +110,7 @@ GRenderWindow::GRenderWindow(QWidget* parent, EmuThread* emu_thread)
110 std::string window_title = fmt::format("yuzu {} | {}-{}", Common::g_build_name, 110 std::string window_title = fmt::format("yuzu {} | {}-{}", Common::g_build_name,
111 Common::g_scm_branch, Common::g_scm_desc); 111 Common::g_scm_branch, Common::g_scm_desc);
112 setWindowTitle(QString::fromStdString(window_title)); 112 setWindowTitle(QString::fromStdString(window_title));
113 setAttribute(Qt::WA_AcceptTouchEvents);
113 114
114 InputCommon::Init(); 115 InputCommon::Init();
115 InputCommon::StartJoystickEventHandler(); 116 InputCommon::StartJoystickEventHandler();
@@ -190,11 +191,17 @@ QByteArray GRenderWindow::saveGeometry() {
190 return geometry; 191 return geometry;
191} 192}
192 193
193qreal GRenderWindow::windowPixelRatio() { 194qreal GRenderWindow::windowPixelRatio() const {
194 // windowHandle() might not be accessible until the window is displayed to screen. 195 // windowHandle() might not be accessible until the window is displayed to screen.
195 return windowHandle() ? windowHandle()->screen()->devicePixelRatio() : 1.0f; 196 return windowHandle() ? windowHandle()->screen()->devicePixelRatio() : 1.0f;
196} 197}
197 198
199std::pair<unsigned, unsigned> GRenderWindow::ScaleTouch(const QPointF pos) const {
200 const qreal pixel_ratio = windowPixelRatio();
201 return {static_cast<unsigned>(std::max(std::round(pos.x() * pixel_ratio), qreal{0.0})),
202 static_cast<unsigned>(std::max(std::round(pos.y() * pixel_ratio), qreal{0.0}))};
203}
204
198void GRenderWindow::closeEvent(QCloseEvent* event) { 205void GRenderWindow::closeEvent(QCloseEvent* event) {
199 emit Closed(); 206 emit Closed();
200 QWidget::closeEvent(event); 207 QWidget::closeEvent(event);
@@ -209,31 +216,81 @@ void GRenderWindow::keyReleaseEvent(QKeyEvent* event) {
209} 216}
210 217
211void GRenderWindow::mousePressEvent(QMouseEvent* event) { 218void GRenderWindow::mousePressEvent(QMouseEvent* event) {
219 if (event->source() == Qt::MouseEventSynthesizedBySystem)
220 return; // touch input is handled in TouchBeginEvent
221
212 auto pos = event->pos(); 222 auto pos = event->pos();
213 if (event->button() == Qt::LeftButton) { 223 if (event->button() == Qt::LeftButton) {
214 qreal pixelRatio = windowPixelRatio(); 224 const auto [x, y] = ScaleTouch(pos);
215 this->TouchPressed(static_cast<unsigned>(pos.x() * pixelRatio), 225 this->TouchPressed(x, y);
216 static_cast<unsigned>(pos.y() * pixelRatio));
217 } else if (event->button() == Qt::RightButton) { 226 } else if (event->button() == Qt::RightButton) {
218 InputCommon::GetMotionEmu()->BeginTilt(pos.x(), pos.y()); 227 InputCommon::GetMotionEmu()->BeginTilt(pos.x(), pos.y());
219 } 228 }
220} 229}
221 230
222void GRenderWindow::mouseMoveEvent(QMouseEvent* event) { 231void GRenderWindow::mouseMoveEvent(QMouseEvent* event) {
232 if (event->source() == Qt::MouseEventSynthesizedBySystem)
233 return; // touch input is handled in TouchUpdateEvent
234
223 auto pos = event->pos(); 235 auto pos = event->pos();
224 qreal pixelRatio = windowPixelRatio(); 236 const auto [x, y] = ScaleTouch(pos);
225 this->TouchMoved(std::max(static_cast<unsigned>(pos.x() * pixelRatio), 0u), 237 this->TouchMoved(x, y);
226 std::max(static_cast<unsigned>(pos.y() * pixelRatio), 0u));
227 InputCommon::GetMotionEmu()->Tilt(pos.x(), pos.y()); 238 InputCommon::GetMotionEmu()->Tilt(pos.x(), pos.y());
228} 239}
229 240
230void GRenderWindow::mouseReleaseEvent(QMouseEvent* event) { 241void GRenderWindow::mouseReleaseEvent(QMouseEvent* event) {
242 if (event->source() == Qt::MouseEventSynthesizedBySystem)
243 return; // touch input is handled in TouchEndEvent
244
231 if (event->button() == Qt::LeftButton) 245 if (event->button() == Qt::LeftButton)
232 this->TouchReleased(); 246 this->TouchReleased();
233 else if (event->button() == Qt::RightButton) 247 else if (event->button() == Qt::RightButton)
234 InputCommon::GetMotionEmu()->EndTilt(); 248 InputCommon::GetMotionEmu()->EndTilt();
235} 249}
236 250
251void GRenderWindow::TouchBeginEvent(const QTouchEvent* event) {
252 // TouchBegin always has exactly one touch point, so take the .first()
253 const auto [x, y] = ScaleTouch(event->touchPoints().first().pos());
254 this->TouchPressed(x, y);
255}
256
257void GRenderWindow::TouchUpdateEvent(const QTouchEvent* event) {
258 QPointF pos;
259 int active_points = 0;
260
261 // average all active touch points
262 for (const auto tp : event->touchPoints()) {
263 if (tp.state() & (Qt::TouchPointPressed | Qt::TouchPointMoved | Qt::TouchPointStationary)) {
264 active_points++;
265 pos += tp.pos();
266 }
267 }
268
269 pos /= active_points;
270
271 const auto [x, y] = ScaleTouch(pos);
272 this->TouchMoved(x, y);
273}
274
275void GRenderWindow::TouchEndEvent() {
276 this->TouchReleased();
277}
278
279bool GRenderWindow::event(QEvent* event) {
280 if (event->type() == QEvent::TouchBegin) {
281 TouchBeginEvent(static_cast<QTouchEvent*>(event));
282 return true;
283 } else if (event->type() == QEvent::TouchUpdate) {
284 TouchUpdateEvent(static_cast<QTouchEvent*>(event));
285 return true;
286 } else if (event->type() == QEvent::TouchEnd || event->type() == QEvent::TouchCancel) {
287 TouchEndEvent();
288 return true;
289 }
290
291 return QWidget::event(event);
292}
293
237void GRenderWindow::focusOutEvent(QFocusEvent* event) { 294void GRenderWindow::focusOutEvent(QFocusEvent* event) {
238 QWidget::focusOutEvent(event); 295 QWidget::focusOutEvent(event);
239 InputCommon::GetKeyboard()->ReleaseAllKeys(); 296 InputCommon::GetKeyboard()->ReleaseAllKeys();
diff --git a/src/yuzu/bootmanager.h b/src/yuzu/bootmanager.h
index f133bfadf..873985564 100644
--- a/src/yuzu/bootmanager.h
+++ b/src/yuzu/bootmanager.h
@@ -15,6 +15,7 @@
15 15
16class QKeyEvent; 16class QKeyEvent;
17class QScreen; 17class QScreen;
18class QTouchEvent;
18 19
19class GGLWidgetInternal; 20class GGLWidgetInternal;
20class GMainWindow; 21class GMainWindow;
@@ -119,7 +120,7 @@ public:
119 void restoreGeometry(const QByteArray& geometry); // overridden 120 void restoreGeometry(const QByteArray& geometry); // overridden
120 QByteArray saveGeometry(); // overridden 121 QByteArray saveGeometry(); // overridden
121 122
122 qreal windowPixelRatio(); 123 qreal windowPixelRatio() const;
123 124
124 void closeEvent(QCloseEvent* event) override; 125 void closeEvent(QCloseEvent* event) override;
125 126
@@ -130,6 +131,8 @@ public:
130 void mouseMoveEvent(QMouseEvent* event) override; 131 void mouseMoveEvent(QMouseEvent* event) override;
131 void mouseReleaseEvent(QMouseEvent* event) override; 132 void mouseReleaseEvent(QMouseEvent* event) override;
132 133
134 bool event(QEvent* event) override;
135
133 void focusOutEvent(QFocusEvent* event) override; 136 void focusOutEvent(QFocusEvent* event) override;
134 137
135 void OnClientAreaResized(unsigned width, unsigned height); 138 void OnClientAreaResized(unsigned width, unsigned height);
@@ -148,6 +151,11 @@ signals:
148 void Closed(); 151 void Closed();
149 152
150private: 153private:
154 std::pair<unsigned, unsigned> ScaleTouch(const QPointF pos) const;
155 void TouchBeginEvent(const QTouchEvent* event);
156 void TouchUpdateEvent(const QTouchEvent* event);
157 void TouchEndEvent();
158
151 void OnMinimalClientAreaChangeRequest( 159 void OnMinimalClientAreaChangeRequest(
152 const std::pair<unsigned, unsigned>& minimal_size) override; 160 const std::pair<unsigned, unsigned>& minimal_size) override;
153 161
diff --git a/src/yuzu/game_list_worker.cpp b/src/yuzu/game_list_worker.cpp
index d2b3de683..8f99a1c78 100644
--- a/src/yuzu/game_list_worker.cpp
+++ b/src/yuzu/game_list_worker.cpp
@@ -27,9 +27,8 @@
27#include "yuzu/ui_settings.h" 27#include "yuzu/ui_settings.h"
28 28
29namespace { 29namespace {
30void GetMetadataFromControlNCA(const FileSys::PatchManager& patch_manager, 30void GetMetadataFromControlNCA(const FileSys::PatchManager& patch_manager, const FileSys::NCA& nca,
31 const std::shared_ptr<FileSys::NCA>& nca, std::vector<u8>& icon, 31 std::vector<u8>& icon, std::string& name) {
32 std::string& name) {
33 auto [nacp, icon_file] = patch_manager.ParseControlNCA(nca); 32 auto [nacp, icon_file] = patch_manager.ParseControlNCA(nca);
34 if (icon_file != nullptr) 33 if (icon_file != nullptr)
35 icon = icon_file->ReadAllBytes(); 34 icon = icon_file->ReadAllBytes();
@@ -110,7 +109,7 @@ void GameListWorker::AddInstalledTitlesToGameList() {
110 const FileSys::PatchManager patch{program_id}; 109 const FileSys::PatchManager patch{program_id};
111 const auto& control = cache->GetEntry(game.title_id, FileSys::ContentRecordType::Control); 110 const auto& control = cache->GetEntry(game.title_id, FileSys::ContentRecordType::Control);
112 if (control != nullptr) 111 if (control != nullptr)
113 GetMetadataFromControlNCA(patch, control, icon, name); 112 GetMetadataFromControlNCA(patch, *control, icon, name);
114 113
115 auto it = FindMatchingCompatibilityEntry(compatibility_list, program_id); 114 auto it = FindMatchingCompatibilityEntry(compatibility_list, program_id);
116 115
@@ -197,8 +196,8 @@ void GameListWorker::AddFstEntriesToGameList(const std::string& dir_path, unsign
197 res2 == Loader::ResultStatus::Success) { 196 res2 == Loader::ResultStatus::Success) {
198 // Use from metadata pool. 197 // Use from metadata pool.
199 if (nca_control_map.find(program_id) != nca_control_map.end()) { 198 if (nca_control_map.find(program_id) != nca_control_map.end()) {
200 const auto nca = nca_control_map[program_id]; 199 const auto& nca = nca_control_map[program_id];
201 GetMetadataFromControlNCA(patch, nca, icon, name); 200 GetMetadataFromControlNCA(patch, *nca, icon, name);
202 } 201 }
203 } 202 }
204 203
diff --git a/src/yuzu_cmd/emu_window/emu_window_sdl2.cpp b/src/yuzu_cmd/emu_window/emu_window_sdl2.cpp
index 155095095..a9ad92a80 100644
--- a/src/yuzu_cmd/emu_window/emu_window_sdl2.cpp
+++ b/src/yuzu_cmd/emu_window/emu_window_sdl2.cpp
@@ -40,6 +40,35 @@ void EmuWindow_SDL2::OnMouseButton(u32 button, u8 state, s32 x, s32 y) {
40 } 40 }
41} 41}
42 42
43std::pair<unsigned, unsigned> EmuWindow_SDL2::TouchToPixelPos(float touch_x, float touch_y) const {
44 int w, h;
45 SDL_GetWindowSize(render_window, &w, &h);
46
47 touch_x *= w;
48 touch_y *= h;
49
50 return {static_cast<unsigned>(std::max(std::round(touch_x), 0.0f)),
51 static_cast<unsigned>(std::max(std::round(touch_y), 0.0f))};
52}
53
54void EmuWindow_SDL2::OnFingerDown(float x, float y) {
55 // TODO(NeatNit): keep track of multitouch using the fingerID and a dictionary of some kind
56 // This isn't critical because the best we can do when we have that is to average them, like the
57 // 3DS does
58
59 const auto [px, py] = TouchToPixelPos(x, y);
60 TouchPressed(px, py);
61}
62
63void EmuWindow_SDL2::OnFingerMotion(float x, float y) {
64 const auto [px, py] = TouchToPixelPos(x, y);
65 TouchMoved(px, py);
66}
67
68void EmuWindow_SDL2::OnFingerUp() {
69 TouchReleased();
70}
71
43void EmuWindow_SDL2::OnKeyEvent(int key, u8 state) { 72void EmuWindow_SDL2::OnKeyEvent(int key, u8 state) {
44 if (state == SDL_PRESSED) { 73 if (state == SDL_PRESSED) {
45 InputCommon::GetKeyboard()->PressKey(key); 74 InputCommon::GetKeyboard()->PressKey(key);
@@ -219,11 +248,26 @@ void EmuWindow_SDL2::PollEvents() {
219 OnKeyEvent(static_cast<int>(event.key.keysym.scancode), event.key.state); 248 OnKeyEvent(static_cast<int>(event.key.keysym.scancode), event.key.state);
220 break; 249 break;
221 case SDL_MOUSEMOTION: 250 case SDL_MOUSEMOTION:
222 OnMouseMotion(event.motion.x, event.motion.y); 251 // ignore if it came from touch
252 if (event.button.which != SDL_TOUCH_MOUSEID)
253 OnMouseMotion(event.motion.x, event.motion.y);
223 break; 254 break;
224 case SDL_MOUSEBUTTONDOWN: 255 case SDL_MOUSEBUTTONDOWN:
225 case SDL_MOUSEBUTTONUP: 256 case SDL_MOUSEBUTTONUP:
226 OnMouseButton(event.button.button, event.button.state, event.button.x, event.button.y); 257 // ignore if it came from touch
258 if (event.button.which != SDL_TOUCH_MOUSEID) {
259 OnMouseButton(event.button.button, event.button.state, event.button.x,
260 event.button.y);
261 }
262 break;
263 case SDL_FINGERDOWN:
264 OnFingerDown(event.tfinger.x, event.tfinger.y);
265 break;
266 case SDL_FINGERMOTION:
267 OnFingerMotion(event.tfinger.x, event.tfinger.y);
268 break;
269 case SDL_FINGERUP:
270 OnFingerUp();
227 break; 271 break;
228 case SDL_QUIT: 272 case SDL_QUIT:
229 is_open = false; 273 is_open = false;
diff --git a/src/yuzu_cmd/emu_window/emu_window_sdl2.h b/src/yuzu_cmd/emu_window/emu_window_sdl2.h
index d34902109..b0d4116cc 100644
--- a/src/yuzu_cmd/emu_window/emu_window_sdl2.h
+++ b/src/yuzu_cmd/emu_window/emu_window_sdl2.h
@@ -40,6 +40,18 @@ private:
40 /// Called by PollEvents when a mouse button is pressed or released 40 /// Called by PollEvents when a mouse button is pressed or released
41 void OnMouseButton(u32 button, u8 state, s32 x, s32 y); 41 void OnMouseButton(u32 button, u8 state, s32 x, s32 y);
42 42
43 /// Translates pixel position (0..1) to pixel positions
44 std::pair<unsigned, unsigned> TouchToPixelPos(float touch_x, float touch_y) const;
45
46 /// Called by PollEvents when a finger starts touching the touchscreen
47 void OnFingerDown(float x, float y);
48
49 /// Called by PollEvents when a finger moves while touching the touchscreen
50 void OnFingerMotion(float x, float y);
51
52 /// Called by PollEvents when a finger stops touching the touchscreen
53 void OnFingerUp();
54
43 /// Called by PollEvents when any event that may cause the window to be resized occurs 55 /// Called by PollEvents when any event that may cause the window to be resized occurs
44 void OnResize(); 56 void OnResize();
45 57