summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/audio_core/CMakeLists.txt2
-rw-r--r--src/audio_core/algorithm/filter.cpp6
-rw-r--r--src/audio_core/algorithm/filter.h4
-rw-r--r--src/audio_core/audio_renderer.cpp6
-rw-r--r--src/audio_core/audio_renderer.h3
-rw-r--r--src/audio_core/buffer.h2
-rw-r--r--src/audio_core/command_generator.cpp27
-rw-r--r--src/audio_core/command_generator.h8
-rw-r--r--src/audio_core/cubeb_sink.cpp15
-rw-r--r--src/audio_core/effect_context.cpp60
-rw-r--r--src/audio_core/effect_context.h6
-rw-r--r--src/audio_core/info_updater.cpp32
-rw-r--r--src/audio_core/info_updater.h4
-rw-r--r--src/audio_core/memory_pool.cpp13
-rw-r--r--src/audio_core/memory_pool.h11
-rw-r--r--src/audio_core/sink_context.cpp2
-rw-r--r--src/audio_core/sink_context.h12
-rw-r--r--src/audio_core/splitter_context.cpp22
-rw-r--r--src/audio_core/splitter_context.h20
-rw-r--r--src/audio_core/stream.cpp10
-rw-r--r--src/audio_core/stream.h4
-rw-r--r--src/audio_core/voice_context.cpp7
-rw-r--r--src/audio_core/voice_context.h10
-rw-r--r--src/common/CMakeLists.txt1
-rw-r--r--src/common/div_ceil.h26
-rw-r--r--src/common/wall_clock.cpp4
-rw-r--r--src/common/wall_clock.h6
-rw-r--r--src/common/x64/native_clock.cpp8
-rw-r--r--src/common/x64/native_clock.h3
-rw-r--r--src/core/core_timing.h8
-rw-r--r--src/core/frontend/input.h9
-rw-r--r--src/core/hle/result.h2
-rw-r--r--src/core/settings.h4
-rw-r--r--src/input_common/CMakeLists.txt6
-rw-r--r--src/input_common/main.cpp75
-rw-r--r--src/input_common/main.h41
-rw-r--r--src/input_common/motion_emu.cpp179
-rw-r--r--src/input_common/motion_emu.h46
-rw-r--r--src/input_common/mouse/mouse_input.cpp129
-rw-r--r--src/input_common/mouse/mouse_input.h98
-rw-r--r--src/input_common/mouse/mouse_poller.cpp259
-rw-r--r--src/input_common/mouse/mouse_poller.h109
-rw-r--r--src/input_common/udp/client.cpp143
-rw-r--r--src/input_common/udp/client.h40
-rw-r--r--src/input_common/udp/udp.cpp64
-rw-r--r--src/video_core/command_classes/codecs/codec.cpp33
-rw-r--r--src/video_core/command_classes/codecs/codec.h11
-rw-r--r--src/video_core/command_classes/codecs/h264.cpp2
-rw-r--r--src/video_core/command_classes/codecs/h264.h4
-rw-r--r--src/video_core/command_classes/codecs/vp9.cpp333
-rw-r--r--src/video_core/command_classes/codecs/vp9.h7
-rw-r--r--src/video_core/command_classes/codecs/vp9_types.h160
-rw-r--r--src/video_core/command_classes/nvdec.cpp6
-rw-r--r--src/video_core/command_classes/nvdec.h3
-rw-r--r--src/video_core/command_classes/vic.cpp15
-rw-r--r--src/video_core/engines/maxwell_3d.h7
-rw-r--r--src/video_core/renderer_vulkan/fixed_pipeline_state.cpp7
-rw-r--r--src/video_core/renderer_vulkan/fixed_pipeline_state.h8
-rw-r--r--src/video_core/renderer_vulkan/vk_pipeline_cache.cpp1
-rw-r--r--src/video_core/renderer_vulkan/vk_shader_decompiler.cpp6
-rw-r--r--src/video_core/renderer_vulkan/vk_shader_decompiler.h1
-rw-r--r--src/yuzu/bootmanager.cpp26
-rw-r--r--src/yuzu/configuration/config.cpp20
-rw-r--r--src/yuzu/configuration/configure_input_player.cpp87
-rw-r--r--src/yuzu/configuration/configure_motion_touch.cpp134
-rw-r--r--src/yuzu/configuration/configure_motion_touch.h5
-rw-r--r--src/yuzu/configuration/configure_motion_touch.ui269
-rw-r--r--src/yuzu/main.cpp2
-rw-r--r--src/yuzu_cmd/config.cpp6
-rw-r--r--src/yuzu_cmd/emu_window/emu_window_sdl2.cpp8
-rw-r--r--src/yuzu_cmd/emu_window/emu_window_sdl2_gl.cpp1
71 files changed, 1659 insertions, 1049 deletions
diff --git a/src/audio_core/CMakeLists.txt b/src/audio_core/CMakeLists.txt
index 68c67507b..d1d177b51 100644
--- a/src/audio_core/CMakeLists.txt
+++ b/src/audio_core/CMakeLists.txt
@@ -51,6 +51,8 @@ if (NOT MSVC)
51 -Werror=implicit-fallthrough 51 -Werror=implicit-fallthrough
52 -Werror=reorder 52 -Werror=reorder
53 -Werror=sign-compare 53 -Werror=sign-compare
54 -Werror=shadow
55 -Werror=unused-parameter
54 -Werror=unused-variable 56 -Werror=unused-variable
55 57
56 $<$<CXX_COMPILER_ID:GNU>:-Werror=unused-but-set-parameter> 58 $<$<CXX_COMPILER_ID:GNU>:-Werror=unused-but-set-parameter>
diff --git a/src/audio_core/algorithm/filter.cpp b/src/audio_core/algorithm/filter.cpp
index f34a5b9f3..01b8dff6b 100644
--- a/src/audio_core/algorithm/filter.cpp
+++ b/src/audio_core/algorithm/filter.cpp
@@ -31,8 +31,8 @@ Filter Filter::LowPass(double cutoff, double Q) {
31 31
32Filter::Filter() : Filter(1.0, 0.0, 0.0, 1.0, 0.0, 0.0) {} 32Filter::Filter() : Filter(1.0, 0.0, 0.0, 1.0, 0.0, 0.0) {}
33 33
34Filter::Filter(double a0, double a1, double a2, double b0, double b1, double b2) 34Filter::Filter(double a0_, double a1_, double a2_, double b0_, double b1_, double b2_)
35 : a1(a1 / a0), a2(a2 / a0), b0(b0 / a0), b1(b1 / a0), b2(b2 / a0) {} 35 : a1(a1_ / a0_), a2(a2_ / a0_), b0(b0_ / a0_), b1(b1_ / a0_), b2(b2_ / a0_) {}
36 36
37void Filter::Process(std::vector<s16>& signal) { 37void Filter::Process(std::vector<s16>& signal) {
38 const std::size_t num_frames = signal.size() / 2; 38 const std::size_t num_frames = signal.size() / 2;
@@ -69,7 +69,7 @@ CascadingFilter CascadingFilter::LowPass(double cutoff, std::size_t cascade_size
69} 69}
70 70
71CascadingFilter::CascadingFilter() = default; 71CascadingFilter::CascadingFilter() = default;
72CascadingFilter::CascadingFilter(std::vector<Filter> filters) : filters(std::move(filters)) {} 72CascadingFilter::CascadingFilter(std::vector<Filter> filters_) : filters(std::move(filters_)) {}
73 73
74void CascadingFilter::Process(std::vector<s16>& signal) { 74void CascadingFilter::Process(std::vector<s16>& signal) {
75 for (auto& filter : filters) { 75 for (auto& filter : filters) {
diff --git a/src/audio_core/algorithm/filter.h b/src/audio_core/algorithm/filter.h
index 3546d149b..a291fe79b 100644
--- a/src/audio_core/algorithm/filter.h
+++ b/src/audio_core/algorithm/filter.h
@@ -25,7 +25,7 @@ public:
25 /// Passthrough filter. 25 /// Passthrough filter.
26 Filter(); 26 Filter();
27 27
28 Filter(double a0, double a1, double a2, double b0, double b1, double b2); 28 Filter(double a0_, double a1_, double a2_, double b0_, double b1_, double b2_);
29 29
30 void Process(std::vector<s16>& signal); 30 void Process(std::vector<s16>& signal);
31 31
@@ -51,7 +51,7 @@ public:
51 /// Passthrough. 51 /// Passthrough.
52 CascadingFilter(); 52 CascadingFilter();
53 53
54 explicit CascadingFilter(std::vector<Filter> filters); 54 explicit CascadingFilter(std::vector<Filter> filters_);
55 55
56 void Process(std::vector<s16>& signal); 56 void Process(std::vector<s16>& signal);
57 57
diff --git a/src/audio_core/audio_renderer.cpp b/src/audio_core/audio_renderer.cpp
index 5f532ed31..179560cd7 100644
--- a/src/audio_core/audio_renderer.cpp
+++ b/src/audio_core/audio_renderer.cpp
@@ -71,9 +71,9 @@ namespace {
71namespace AudioCore { 71namespace AudioCore {
72AudioRenderer::AudioRenderer(Core::Timing::CoreTiming& core_timing, Core::Memory::Memory& memory_, 72AudioRenderer::AudioRenderer(Core::Timing::CoreTiming& core_timing, Core::Memory::Memory& memory_,
73 AudioCommon::AudioRendererParameter params, 73 AudioCommon::AudioRendererParameter params,
74 std::shared_ptr<Kernel::WritableEvent> buffer_event, 74 std::shared_ptr<Kernel::WritableEvent> buffer_event_,
75 std::size_t instance_number) 75 std::size_t instance_number)
76 : worker_params{params}, buffer_event{buffer_event}, 76 : worker_params{params}, buffer_event{buffer_event_},
77 memory_pool_info(params.effect_count + params.voice_count * 4), 77 memory_pool_info(params.effect_count + params.voice_count * 4),
78 voice_context(params.voice_count), effect_context(params.effect_count), mix_context(), 78 voice_context(params.voice_count), effect_context(params.effect_count), mix_context(),
79 sink_context(params.sink_count), splitter_context(), 79 sink_context(params.sink_count), splitter_context(),
@@ -88,7 +88,7 @@ AudioRenderer::AudioRenderer(Core::Timing::CoreTiming& core_timing, Core::Memory
88 stream = 88 stream =
89 audio_out->OpenStream(core_timing, params.sample_rate, AudioCommon::STREAM_NUM_CHANNELS, 89 audio_out->OpenStream(core_timing, params.sample_rate, AudioCommon::STREAM_NUM_CHANNELS,
90 fmt::format("AudioRenderer-Instance{}", instance_number), 90 fmt::format("AudioRenderer-Instance{}", instance_number),
91 [=]() { buffer_event->Signal(); }); 91 [=]() { buffer_event_->Signal(); });
92 audio_out->StartStream(stream); 92 audio_out->StartStream(stream);
93 93
94 QueueMixedBuffer(0); 94 QueueMixedBuffer(0);
diff --git a/src/audio_core/audio_renderer.h b/src/audio_core/audio_renderer.h
index 54ac68b80..90f7eafa4 100644
--- a/src/audio_core/audio_renderer.h
+++ b/src/audio_core/audio_renderer.h
@@ -44,7 +44,8 @@ class AudioRenderer {
44public: 44public:
45 AudioRenderer(Core::Timing::CoreTiming& core_timing, Core::Memory::Memory& memory_, 45 AudioRenderer(Core::Timing::CoreTiming& core_timing, Core::Memory::Memory& memory_,
46 AudioCommon::AudioRendererParameter params, 46 AudioCommon::AudioRendererParameter params,
47 std::shared_ptr<Kernel::WritableEvent> buffer_event, std::size_t instance_number); 47 std::shared_ptr<Kernel::WritableEvent> buffer_event_,
48 std::size_t instance_number);
48 ~AudioRenderer(); 49 ~AudioRenderer();
49 50
50 [[nodiscard]] ResultCode UpdateAudioRenderer(const std::vector<u8>& input_params, 51 [[nodiscard]] ResultCode UpdateAudioRenderer(const std::vector<u8>& input_params,
diff --git a/src/audio_core/buffer.h b/src/audio_core/buffer.h
index 5ee09e9aa..ccc46ef82 100644
--- a/src/audio_core/buffer.h
+++ b/src/audio_core/buffer.h
@@ -18,7 +18,7 @@ class Buffer {
18public: 18public:
19 using Tag = u64; 19 using Tag = u64;
20 20
21 Buffer(Tag tag, std::vector<s16>&& samples) : tag{tag}, samples{std::move(samples)} {} 21 Buffer(Tag tag_, std::vector<s16>&& samples_) : tag{tag_}, samples{std::move(samples_)} {}
22 22
23 /// Returns the raw audio data for the buffer 23 /// Returns the raw audio data for the buffer
24 std::vector<s16>& GetSamples() { 24 std::vector<s16>& GetSamples() {
diff --git a/src/audio_core/command_generator.cpp b/src/audio_core/command_generator.cpp
index fb8700ccf..a4a9a757d 100644
--- a/src/audio_core/command_generator.cpp
+++ b/src/audio_core/command_generator.cpp
@@ -67,12 +67,12 @@ s32 ApplyMixDepop(s32* output, s32 first_sample, s32 delta, s32 sample_count) {
67 67
68} // namespace 68} // namespace
69 69
70CommandGenerator::CommandGenerator(AudioCommon::AudioRendererParameter& worker_params, 70CommandGenerator::CommandGenerator(AudioCommon::AudioRendererParameter& worker_params_,
71 VoiceContext& voice_context, MixContext& mix_context, 71 VoiceContext& voice_context_, MixContext& mix_context_,
72 SplitterContext& splitter_context, EffectContext& effect_context, 72 SplitterContext& splitter_context_,
73 Core::Memory::Memory& memory) 73 EffectContext& effect_context_, Core::Memory::Memory& memory_)
74 : worker_params(worker_params), voice_context(voice_context), mix_context(mix_context), 74 : worker_params(worker_params_), voice_context(voice_context_), mix_context(mix_context_),
75 splitter_context(splitter_context), effect_context(effect_context), memory(memory), 75 splitter_context(splitter_context_), effect_context(effect_context_), memory(memory_),
76 mix_buffer((worker_params.mix_buffer_count + AudioCommon::MAX_CHANNEL_COUNT) * 76 mix_buffer((worker_params.mix_buffer_count + AudioCommon::MAX_CHANNEL_COUNT) *
77 worker_params.sample_count), 77 worker_params.sample_count),
78 sample_buffer(MIX_BUFFER_SIZE), 78 sample_buffer(MIX_BUFFER_SIZE),
@@ -255,7 +255,8 @@ void CommandGenerator::GenerateDataSourceCommand(ServerVoiceInfo& voice_info, Vo
255 255
256void CommandGenerator::GenerateBiquadFilterCommandForVoice(ServerVoiceInfo& voice_info, 256void CommandGenerator::GenerateBiquadFilterCommandForVoice(ServerVoiceInfo& voice_info,
257 VoiceState& dsp_state, 257 VoiceState& dsp_state,
258 s32 mix_buffer_count, s32 channel) { 258 [[maybe_unused]] s32 mix_buffer_count,
259 [[maybe_unused]] s32 channel) {
259 for (std::size_t i = 0; i < AudioCommon::MAX_BIQUAD_FILTERS; i++) { 260 for (std::size_t i = 0; i < AudioCommon::MAX_BIQUAD_FILTERS; i++) {
260 const auto& in_params = voice_info.GetInParams(); 261 const auto& in_params = voice_info.GetInParams();
261 auto& biquad_filter = in_params.biquad_filter[i]; 262 auto& biquad_filter = in_params.biquad_filter[i];
@@ -278,9 +279,12 @@ void CommandGenerator::GenerateBiquadFilterCommandForVoice(ServerVoiceInfo& voic
278 } 279 }
279} 280}
280 281
281void AudioCore::CommandGenerator::GenerateBiquadFilterCommand( 282void CommandGenerator::GenerateBiquadFilterCommand([[maybe_unused]] s32 mix_buffer_id,
282 s32 mix_buffer, const BiquadFilterParameter& params, std::array<s64, 2>& state, 283 const BiquadFilterParameter& params,
283 std::size_t input_offset, std::size_t output_offset, s32 sample_count, s32 node_id) { 284 std::array<s64, 2>& state,
285 std::size_t input_offset,
286 std::size_t output_offset, s32 sample_count,
287 s32 node_id) {
284 if (dumping_frame) { 288 if (dumping_frame) {
285 LOG_DEBUG(Audio, 289 LOG_DEBUG(Audio,
286 "(DSP_TRACE) GenerateBiquadFilterCommand node_id={}, " 290 "(DSP_TRACE) GenerateBiquadFilterCommand node_id={}, "
@@ -714,7 +718,8 @@ s32 CommandGenerator::DecodePcm16(ServerVoiceInfo& voice_info, VoiceState& dsp_s
714} 718}
715 719
716s32 CommandGenerator::DecodeAdpcm(ServerVoiceInfo& voice_info, VoiceState& dsp_state, 720s32 CommandGenerator::DecodeAdpcm(ServerVoiceInfo& voice_info, VoiceState& dsp_state,
717 s32 sample_count, s32 channel, std::size_t mix_offset) { 721 s32 sample_count, [[maybe_unused]] s32 channel,
722 std::size_t mix_offset) {
718 const auto& in_params = voice_info.GetInParams(); 723 const auto& in_params = voice_info.GetInParams();
719 const auto& wave_buffer = in_params.wave_buffer[dsp_state.wave_buffer_index]; 724 const auto& wave_buffer = in_params.wave_buffer[dsp_state.wave_buffer_index];
720 if (wave_buffer.buffer_address == 0) { 725 if (wave_buffer.buffer_address == 0) {
diff --git a/src/audio_core/command_generator.h b/src/audio_core/command_generator.h
index 87ece00c4..b937350b1 100644
--- a/src/audio_core/command_generator.h
+++ b/src/audio_core/command_generator.h
@@ -25,10 +25,10 @@ using MixVolumeBuffer = std::array<float, AudioCommon::MAX_MIX_BUFFERS>;
25 25
26class CommandGenerator { 26class CommandGenerator {
27public: 27public:
28 explicit CommandGenerator(AudioCommon::AudioRendererParameter& worker_params, 28 explicit CommandGenerator(AudioCommon::AudioRendererParameter& worker_params_,
29 VoiceContext& voice_context, MixContext& mix_context, 29 VoiceContext& voice_context_, MixContext& mix_context_,
30 SplitterContext& splitter_context, EffectContext& effect_context, 30 SplitterContext& splitter_context_, EffectContext& effect_context_,
31 Core::Memory::Memory& memory); 31 Core::Memory::Memory& memory_);
32 ~CommandGenerator(); 32 ~CommandGenerator();
33 33
34 void ClearMixBuffers(); 34 void ClearMixBuffers();
diff --git a/src/audio_core/cubeb_sink.cpp b/src/audio_core/cubeb_sink.cpp
index 6eaa60815..cf7b186e4 100644
--- a/src/audio_core/cubeb_sink.cpp
+++ b/src/audio_core/cubeb_sink.cpp
@@ -21,10 +21,10 @@ namespace AudioCore {
21 21
22class CubebSinkStream final : public SinkStream { 22class CubebSinkStream final : public SinkStream {
23public: 23public:
24 CubebSinkStream(cubeb* ctx, u32 sample_rate, u32 num_channels_, cubeb_devid output_device, 24 CubebSinkStream(cubeb* ctx_, u32 sample_rate, u32 num_channels_, cubeb_devid output_device,
25 const std::string& name) 25 const std::string& name)
26 : ctx{ctx}, num_channels{std::min(num_channels_, 6u)}, time_stretch{sample_rate, 26 : ctx{ctx_}, num_channels{std::min(num_channels_, 6u)}, time_stretch{sample_rate,
27 num_channels} { 27 num_channels} {
28 28
29 cubeb_stream_params params{}; 29 cubeb_stream_params params{};
30 params.rate = sample_rate; 30 params.rate = sample_rate;
@@ -192,8 +192,9 @@ SinkStream& CubebSink::AcquireSinkStream(u32 sample_rate, u32 num_channels,
192 return *sink_streams.back(); 192 return *sink_streams.back();
193} 193}
194 194
195long CubebSinkStream::DataCallback(cubeb_stream* stream, void* user_data, const void* input_buffer, 195long CubebSinkStream::DataCallback([[maybe_unused]] cubeb_stream* stream, void* user_data,
196 void* output_buffer, long num_frames) { 196 [[maybe_unused]] const void* input_buffer, void* output_buffer,
197 long num_frames) {
197 auto* impl = static_cast<CubebSinkStream*>(user_data); 198 auto* impl = static_cast<CubebSinkStream*>(user_data);
198 auto* buffer = static_cast<u8*>(output_buffer); 199 auto* buffer = static_cast<u8*>(output_buffer);
199 200
@@ -236,7 +237,9 @@ long CubebSinkStream::DataCallback(cubeb_stream* stream, void* user_data, const
236 return num_frames; 237 return num_frames;
237} 238}
238 239
239void CubebSinkStream::StateCallback(cubeb_stream* stream, void* user_data, cubeb_state state) {} 240void CubebSinkStream::StateCallback([[maybe_unused]] cubeb_stream* stream,
241 [[maybe_unused]] void* user_data,
242 [[maybe_unused]] cubeb_state state) {}
240 243
241std::vector<std::string> ListCubebSinkDevices() { 244std::vector<std::string> ListCubebSinkDevices() {
242 std::vector<std::string> device_list; 245 std::vector<std::string> device_list;
diff --git a/src/audio_core/effect_context.cpp b/src/audio_core/effect_context.cpp
index 4d9cdf524..f770b9608 100644
--- a/src/audio_core/effect_context.cpp
+++ b/src/audio_core/effect_context.cpp
@@ -12,7 +12,7 @@ bool ValidChannelCountForEffect(s32 channel_count) {
12} 12}
13} // namespace 13} // namespace
14 14
15EffectContext::EffectContext(std::size_t effect_count) : effect_count(effect_count) { 15EffectContext::EffectContext(std::size_t effect_count_) : effect_count(effect_count_) {
16 effects.reserve(effect_count); 16 effects.reserve(effect_count);
17 std::generate_n(std::back_inserter(effects), effect_count, 17 std::generate_n(std::back_inserter(effects), effect_count,
18 [] { return std::make_unique<EffectStubbed>(); }); 18 [] { return std::make_unique<EffectStubbed>(); });
@@ -61,13 +61,13 @@ const EffectBase* EffectContext::GetInfo(std::size_t i) const {
61 return effects.at(i).get(); 61 return effects.at(i).get();
62} 62}
63 63
64EffectStubbed::EffectStubbed() : EffectBase::EffectBase(EffectType::Invalid) {} 64EffectStubbed::EffectStubbed() : EffectBase(EffectType::Invalid) {}
65EffectStubbed::~EffectStubbed() = default; 65EffectStubbed::~EffectStubbed() = default;
66 66
67void EffectStubbed::Update(EffectInfo::InParams& in_params) {} 67void EffectStubbed::Update([[maybe_unused]] EffectInfo::InParams& in_params) {}
68void EffectStubbed::UpdateForCommandGeneration() {} 68void EffectStubbed::UpdateForCommandGeneration() {}
69 69
70EffectBase::EffectBase(EffectType effect_type) : effect_type(effect_type) {} 70EffectBase::EffectBase(EffectType effect_type_) : effect_type(effect_type_) {}
71EffectBase::~EffectBase() = default; 71EffectBase::~EffectBase() = default;
72 72
73UsageState EffectBase::GetUsage() const { 73UsageState EffectBase::GetUsage() const {
@@ -90,32 +90,32 @@ s32 EffectBase::GetProcessingOrder() const {
90 return processing_order; 90 return processing_order;
91} 91}
92 92
93EffectI3dl2Reverb::EffectI3dl2Reverb() : EffectGeneric::EffectGeneric(EffectType::I3dl2Reverb) {} 93EffectI3dl2Reverb::EffectI3dl2Reverb() : EffectGeneric(EffectType::I3dl2Reverb) {}
94EffectI3dl2Reverb::~EffectI3dl2Reverb() = default; 94EffectI3dl2Reverb::~EffectI3dl2Reverb() = default;
95 95
96void EffectI3dl2Reverb::Update(EffectInfo::InParams& in_params) { 96void EffectI3dl2Reverb::Update(EffectInfo::InParams& in_params) {
97 auto& internal_params = GetParams(); 97 auto& params = GetParams();
98 const auto* reverb_params = reinterpret_cast<I3dl2ReverbParams*>(in_params.raw.data()); 98 const auto* reverb_params = reinterpret_cast<I3dl2ReverbParams*>(in_params.raw.data());
99 if (!ValidChannelCountForEffect(reverb_params->max_channels)) { 99 if (!ValidChannelCountForEffect(reverb_params->max_channels)) {
100 UNREACHABLE_MSG("Invalid reverb max channel count {}", reverb_params->max_channels); 100 UNREACHABLE_MSG("Invalid reverb max channel count {}", reverb_params->max_channels);
101 return; 101 return;
102 } 102 }
103 103
104 const auto last_status = internal_params.status; 104 const auto last_status = params.status;
105 mix_id = in_params.mix_id; 105 mix_id = in_params.mix_id;
106 processing_order = in_params.processing_order; 106 processing_order = in_params.processing_order;
107 internal_params = *reverb_params; 107 params = *reverb_params;
108 if (!ValidChannelCountForEffect(reverb_params->channel_count)) { 108 if (!ValidChannelCountForEffect(reverb_params->channel_count)) {
109 internal_params.channel_count = internal_params.max_channels; 109 params.channel_count = params.max_channels;
110 } 110 }
111 enabled = in_params.is_enabled; 111 enabled = in_params.is_enabled;
112 if (last_status != ParameterStatus::Updated) { 112 if (last_status != ParameterStatus::Updated) {
113 internal_params.status = last_status; 113 params.status = last_status;
114 } 114 }
115 115
116 if (in_params.is_new || skipped) { 116 if (in_params.is_new || skipped) {
117 usage = UsageState::Initialized; 117 usage = UsageState::Initialized;
118 internal_params.status = ParameterStatus::Initialized; 118 params.status = ParameterStatus::Initialized;
119 skipped = in_params.buffer_address == 0 || in_params.buffer_size == 0; 119 skipped = in_params.buffer_address == 0 || in_params.buffer_size == 0;
120 } 120 }
121} 121}
@@ -129,15 +129,15 @@ void EffectI3dl2Reverb::UpdateForCommandGeneration() {
129 GetParams().status = ParameterStatus::Updated; 129 GetParams().status = ParameterStatus::Updated;
130} 130}
131 131
132EffectBiquadFilter::EffectBiquadFilter() : EffectGeneric::EffectGeneric(EffectType::BiquadFilter) {} 132EffectBiquadFilter::EffectBiquadFilter() : EffectGeneric(EffectType::BiquadFilter) {}
133EffectBiquadFilter::~EffectBiquadFilter() = default; 133EffectBiquadFilter::~EffectBiquadFilter() = default;
134 134
135void EffectBiquadFilter::Update(EffectInfo::InParams& in_params) { 135void EffectBiquadFilter::Update(EffectInfo::InParams& in_params) {
136 auto& internal_params = GetParams(); 136 auto& params = GetParams();
137 const auto* biquad_params = reinterpret_cast<BiquadFilterParams*>(in_params.raw.data()); 137 const auto* biquad_params = reinterpret_cast<BiquadFilterParams*>(in_params.raw.data());
138 mix_id = in_params.mix_id; 138 mix_id = in_params.mix_id;
139 processing_order = in_params.processing_order; 139 processing_order = in_params.processing_order;
140 internal_params = *biquad_params; 140 params = *biquad_params;
141 enabled = in_params.is_enabled; 141 enabled = in_params.is_enabled;
142} 142}
143 143
@@ -150,7 +150,7 @@ void EffectBiquadFilter::UpdateForCommandGeneration() {
150 GetParams().status = ParameterStatus::Updated; 150 GetParams().status = ParameterStatus::Updated;
151} 151}
152 152
153EffectAuxInfo::EffectAuxInfo() : EffectGeneric::EffectGeneric(EffectType::Aux) {} 153EffectAuxInfo::EffectAuxInfo() : EffectGeneric(EffectType::Aux) {}
154EffectAuxInfo::~EffectAuxInfo() = default; 154EffectAuxInfo::~EffectAuxInfo() = default;
155 155
156void EffectAuxInfo::Update(EffectInfo::InParams& in_params) { 156void EffectAuxInfo::Update(EffectInfo::InParams& in_params) {
@@ -200,32 +200,32 @@ VAddr EffectAuxInfo::GetRecvBuffer() const {
200 return recv_buffer; 200 return recv_buffer;
201} 201}
202 202
203EffectDelay::EffectDelay() : EffectGeneric::EffectGeneric(EffectType::Delay) {} 203EffectDelay::EffectDelay() : EffectGeneric(EffectType::Delay) {}
204EffectDelay::~EffectDelay() = default; 204EffectDelay::~EffectDelay() = default;
205 205
206void EffectDelay::Update(EffectInfo::InParams& in_params) { 206void EffectDelay::Update(EffectInfo::InParams& in_params) {
207 const auto* delay_params = reinterpret_cast<DelayParams*>(in_params.raw.data()); 207 const auto* delay_params = reinterpret_cast<DelayParams*>(in_params.raw.data());
208 auto& internal_params = GetParams(); 208 auto& params = GetParams();
209 if (!ValidChannelCountForEffect(delay_params->max_channels)) { 209 if (!ValidChannelCountForEffect(delay_params->max_channels)) {
210 return; 210 return;
211 } 211 }
212 212
213 const auto last_status = internal_params.status; 213 const auto last_status = params.status;
214 mix_id = in_params.mix_id; 214 mix_id = in_params.mix_id;
215 processing_order = in_params.processing_order; 215 processing_order = in_params.processing_order;
216 internal_params = *delay_params; 216 params = *delay_params;
217 if (!ValidChannelCountForEffect(delay_params->channels)) { 217 if (!ValidChannelCountForEffect(delay_params->channels)) {
218 internal_params.channels = internal_params.max_channels; 218 params.channels = params.max_channels;
219 } 219 }
220 enabled = in_params.is_enabled; 220 enabled = in_params.is_enabled;
221 221
222 if (last_status != ParameterStatus::Updated) { 222 if (last_status != ParameterStatus::Updated) {
223 internal_params.status = last_status; 223 params.status = last_status;
224 } 224 }
225 225
226 if (in_params.is_new || skipped) { 226 if (in_params.is_new || skipped) {
227 usage = UsageState::Initialized; 227 usage = UsageState::Initialized;
228 internal_params.status = ParameterStatus::Initialized; 228 params.status = ParameterStatus::Initialized;
229 skipped = in_params.buffer_address == 0 || in_params.buffer_size == 0; 229 skipped = in_params.buffer_address == 0 || in_params.buffer_size == 0;
230 } 230 }
231} 231}
@@ -239,7 +239,7 @@ void EffectDelay::UpdateForCommandGeneration() {
239 GetParams().status = ParameterStatus::Updated; 239 GetParams().status = ParameterStatus::Updated;
240} 240}
241 241
242EffectBufferMixer::EffectBufferMixer() : EffectGeneric::EffectGeneric(EffectType::BufferMixer) {} 242EffectBufferMixer::EffectBufferMixer() : EffectGeneric(EffectType::BufferMixer) {}
243EffectBufferMixer::~EffectBufferMixer() = default; 243EffectBufferMixer::~EffectBufferMixer() = default;
244 244
245void EffectBufferMixer::Update(EffectInfo::InParams& in_params) { 245void EffectBufferMixer::Update(EffectInfo::InParams& in_params) {
@@ -257,32 +257,32 @@ void EffectBufferMixer::UpdateForCommandGeneration() {
257 } 257 }
258} 258}
259 259
260EffectReverb::EffectReverb() : EffectGeneric::EffectGeneric(EffectType::Reverb) {} 260EffectReverb::EffectReverb() : EffectGeneric(EffectType::Reverb) {}
261EffectReverb::~EffectReverb() = default; 261EffectReverb::~EffectReverb() = default;
262 262
263void EffectReverb::Update(EffectInfo::InParams& in_params) { 263void EffectReverb::Update(EffectInfo::InParams& in_params) {
264 const auto* reverb_params = reinterpret_cast<ReverbParams*>(in_params.raw.data()); 264 const auto* reverb_params = reinterpret_cast<ReverbParams*>(in_params.raw.data());
265 auto& internal_params = GetParams(); 265 auto& params = GetParams();
266 if (!ValidChannelCountForEffect(reverb_params->max_channels)) { 266 if (!ValidChannelCountForEffect(reverb_params->max_channels)) {
267 return; 267 return;
268 } 268 }
269 269
270 const auto last_status = internal_params.status; 270 const auto last_status = params.status;
271 mix_id = in_params.mix_id; 271 mix_id = in_params.mix_id;
272 processing_order = in_params.processing_order; 272 processing_order = in_params.processing_order;
273 internal_params = *reverb_params; 273 params = *reverb_params;
274 if (!ValidChannelCountForEffect(reverb_params->channels)) { 274 if (!ValidChannelCountForEffect(reverb_params->channels)) {
275 internal_params.channels = internal_params.max_channels; 275 params.channels = params.max_channels;
276 } 276 }
277 enabled = in_params.is_enabled; 277 enabled = in_params.is_enabled;
278 278
279 if (last_status != ParameterStatus::Updated) { 279 if (last_status != ParameterStatus::Updated) {
280 internal_params.status = last_status; 280 params.status = last_status;
281 } 281 }
282 282
283 if (in_params.is_new || skipped) { 283 if (in_params.is_new || skipped) {
284 usage = UsageState::Initialized; 284 usage = UsageState::Initialized;
285 internal_params.status = ParameterStatus::Initialized; 285 params.status = ParameterStatus::Initialized;
286 skipped = in_params.buffer_address == 0 || in_params.buffer_size == 0; 286 skipped = in_params.buffer_address == 0 || in_params.buffer_size == 0;
287 } 287 }
288} 288}
diff --git a/src/audio_core/effect_context.h b/src/audio_core/effect_context.h
index 03c5a0f04..c5e0b398c 100644
--- a/src/audio_core/effect_context.h
+++ b/src/audio_core/effect_context.h
@@ -184,7 +184,7 @@ struct AuxAddress {
184 184
185class EffectBase { 185class EffectBase {
186public: 186public:
187 explicit EffectBase(EffectType effect_type); 187 explicit EffectBase(EffectType effect_type_);
188 virtual ~EffectBase(); 188 virtual ~EffectBase();
189 189
190 virtual void Update(EffectInfo::InParams& in_params) = 0; 190 virtual void Update(EffectInfo::InParams& in_params) = 0;
@@ -206,7 +206,7 @@ protected:
206template <typename T> 206template <typename T>
207class EffectGeneric : public EffectBase { 207class EffectGeneric : public EffectBase {
208public: 208public:
209 explicit EffectGeneric(EffectType effect_type) : EffectBase(effect_type) {} 209 explicit EffectGeneric(EffectType effect_type_) : EffectBase(effect_type_) {}
210 210
211 T& GetParams() { 211 T& GetParams() {
212 return internal_params; 212 return internal_params;
@@ -306,7 +306,7 @@ private:
306 306
307class EffectContext { 307class EffectContext {
308public: 308public:
309 explicit EffectContext(std::size_t effect_count); 309 explicit EffectContext(std::size_t effect_count_);
310 ~EffectContext(); 310 ~EffectContext();
311 311
312 [[nodiscard]] std::size_t GetCount() const; 312 [[nodiscard]] std::size_t GetCount() const;
diff --git a/src/audio_core/info_updater.cpp b/src/audio_core/info_updater.cpp
index 2940e53a9..d3ac90827 100644
--- a/src/audio_core/info_updater.cpp
+++ b/src/audio_core/info_updater.cpp
@@ -14,9 +14,9 @@
14 14
15namespace AudioCore { 15namespace AudioCore {
16 16
17InfoUpdater::InfoUpdater(const std::vector<u8>& in_params, std::vector<u8>& out_params, 17InfoUpdater::InfoUpdater(const std::vector<u8>& in_params_, std::vector<u8>& out_params_,
18 BehaviorInfo& behavior_info) 18 BehaviorInfo& behavior_info_)
19 : in_params(in_params), out_params(out_params), behavior_info(behavior_info) { 19 : in_params(in_params_), out_params(out_params_), behavior_info(behavior_info_) {
20 ASSERT( 20 ASSERT(
21 AudioCommon::CanConsumeBuffer(in_params.size(), 0, sizeof(AudioCommon::UpdateDataHeader))); 21 AudioCommon::CanConsumeBuffer(in_params.size(), 0, sizeof(AudioCommon::UpdateDataHeader)));
22 std::memcpy(&input_header, in_params.data(), sizeof(AudioCommon::UpdateDataHeader)); 22 std::memcpy(&input_header, in_params.data(), sizeof(AudioCommon::UpdateDataHeader));
@@ -135,8 +135,8 @@ bool InfoUpdater::UpdateVoiceChannelResources(VoiceContext& voice_context) {
135} 135}
136 136
137bool InfoUpdater::UpdateVoices(VoiceContext& voice_context, 137bool InfoUpdater::UpdateVoices(VoiceContext& voice_context,
138 std::vector<ServerMemoryPoolInfo>& memory_pool_info, 138 [[maybe_unused]] std::vector<ServerMemoryPoolInfo>& memory_pool_info,
139 VAddr audio_codec_dsp_addr) { 139 [[maybe_unused]] VAddr audio_codec_dsp_addr) {
140 const auto voice_count = voice_context.GetVoiceCount(); 140 const auto voice_count = voice_context.GetVoiceCount();
141 std::vector<VoiceInfo::InParams> voice_in(voice_count); 141 std::vector<VoiceInfo::InParams> voice_in(voice_count);
142 std::vector<VoiceInfo::OutParams> voice_out(voice_count); 142 std::vector<VoiceInfo::OutParams> voice_out(voice_count);
@@ -165,28 +165,28 @@ bool InfoUpdater::UpdateVoices(VoiceContext& voice_context,
165 165
166 // Update our voices 166 // Update our voices
167 for (std::size_t i = 0; i < voice_count; i++) { 167 for (std::size_t i = 0; i < voice_count; i++) {
168 auto& in_params = voice_in[i]; 168 auto& voice_in_params = voice_in[i];
169 const auto channel_count = static_cast<std::size_t>(in_params.channel_count); 169 const auto channel_count = static_cast<std::size_t>(voice_in_params.channel_count);
170 // Skip if it's not currently in use 170 // Skip if it's not currently in use
171 if (!in_params.is_in_use) { 171 if (!voice_in_params.is_in_use) {
172 continue; 172 continue;
173 } 173 }
174 // Voice states for each channel 174 // Voice states for each channel
175 std::array<VoiceState*, AudioCommon::MAX_CHANNEL_COUNT> voice_states{}; 175 std::array<VoiceState*, AudioCommon::MAX_CHANNEL_COUNT> voice_states{};
176 ASSERT(static_cast<std::size_t>(in_params.id) < voice_count); 176 ASSERT(static_cast<std::size_t>(voice_in_params.id) < voice_count);
177 177
178 // Grab our current voice info 178 // Grab our current voice info
179 auto& voice_info = voice_context.GetInfo(static_cast<std::size_t>(in_params.id)); 179 auto& voice_info = voice_context.GetInfo(static_cast<std::size_t>(voice_in_params.id));
180 180
181 ASSERT(channel_count <= AudioCommon::MAX_CHANNEL_COUNT); 181 ASSERT(channel_count <= AudioCommon::MAX_CHANNEL_COUNT);
182 182
183 // Get all our channel voice states 183 // Get all our channel voice states
184 for (std::size_t channel = 0; channel < channel_count; channel++) { 184 for (std::size_t channel = 0; channel < channel_count; channel++) {
185 voice_states[channel] = 185 voice_states[channel] =
186 &voice_context.GetState(in_params.voice_channel_resource_ids[channel]); 186 &voice_context.GetState(voice_in_params.voice_channel_resource_ids[channel]);
187 } 187 }
188 188
189 if (in_params.is_new) { 189 if (voice_in_params.is_new) {
190 // Default our values for our voice 190 // Default our values for our voice
191 voice_info.Initialize(); 191 voice_info.Initialize();
192 if (channel_count == 0 || channel_count > AudioCommon::MAX_CHANNEL_COUNT) { 192 if (channel_count == 0 || channel_count > AudioCommon::MAX_CHANNEL_COUNT) {
@@ -200,12 +200,12 @@ bool InfoUpdater::UpdateVoices(VoiceContext& voice_context,
200 } 200 }
201 201
202 // Update our voice 202 // Update our voice
203 voice_info.UpdateParameters(in_params, behavior_info); 203 voice_info.UpdateParameters(voice_in_params, behavior_info);
204 // TODO(ogniK): Handle mapping errors with behavior info based on in params response 204 // TODO(ogniK): Handle mapping errors with behavior info based on in params response
205 205
206 // Update our wave buffers 206 // Update our wave buffers
207 voice_info.UpdateWaveBuffers(in_params, voice_states, behavior_info); 207 voice_info.UpdateWaveBuffers(voice_in_params, voice_states, behavior_info);
208 voice_info.WriteOutStatus(voice_out[i], in_params, voice_states); 208 voice_info.WriteOutStatus(voice_out[i], voice_in_params, voice_states);
209 } 209 }
210 210
211 if (!AudioCommon::CanConsumeBuffer(out_params.size(), output_offset, voice_out_size)) { 211 if (!AudioCommon::CanConsumeBuffer(out_params.size(), output_offset, voice_out_size)) {
@@ -445,7 +445,7 @@ bool InfoUpdater::UpdatePerformanceBuffer() {
445 return true; 445 return true;
446} 446}
447 447
448bool InfoUpdater::UpdateErrorInfo(BehaviorInfo& in_behavior_info) { 448bool InfoUpdater::UpdateErrorInfo([[maybe_unused]] BehaviorInfo& in_behavior_info) {
449 const auto total_beahvior_info_out = sizeof(BehaviorInfo::OutParams); 449 const auto total_beahvior_info_out = sizeof(BehaviorInfo::OutParams);
450 450
451 if (!AudioCommon::CanConsumeBuffer(out_params.size(), output_offset, total_beahvior_info_out)) { 451 if (!AudioCommon::CanConsumeBuffer(out_params.size(), output_offset, total_beahvior_info_out)) {
diff --git a/src/audio_core/info_updater.h b/src/audio_core/info_updater.h
index 06f9d770f..d315c91ed 100644
--- a/src/audio_core/info_updater.h
+++ b/src/audio_core/info_updater.h
@@ -21,8 +21,8 @@ class SplitterContext;
21class InfoUpdater { 21class InfoUpdater {
22public: 22public:
23 // TODO(ogniK): Pass process handle when we support it 23 // TODO(ogniK): Pass process handle when we support it
24 InfoUpdater(const std::vector<u8>& in_params, std::vector<u8>& out_params, 24 InfoUpdater(const std::vector<u8>& in_params_, std::vector<u8>& out_params_,
25 BehaviorInfo& behavior_info); 25 BehaviorInfo& behavior_info_);
26 ~InfoUpdater(); 26 ~InfoUpdater();
27 27
28 bool UpdateBehaviorInfo(BehaviorInfo& in_behavior_info); 28 bool UpdateBehaviorInfo(BehaviorInfo& in_behavior_info);
diff --git a/src/audio_core/memory_pool.cpp b/src/audio_core/memory_pool.cpp
index 5a3453063..6b6908d26 100644
--- a/src/audio_core/memory_pool.cpp
+++ b/src/audio_core/memory_pool.cpp
@@ -10,11 +10,10 @@ namespace AudioCore {
10 10
11ServerMemoryPoolInfo::ServerMemoryPoolInfo() = default; 11ServerMemoryPoolInfo::ServerMemoryPoolInfo() = default;
12ServerMemoryPoolInfo::~ServerMemoryPoolInfo() = default; 12ServerMemoryPoolInfo::~ServerMemoryPoolInfo() = default;
13bool ServerMemoryPoolInfo::Update(const ServerMemoryPoolInfo::InParams& in_params, 13
14 ServerMemoryPoolInfo::OutParams& out_params) { 14bool ServerMemoryPoolInfo::Update(const InParams& in_params, OutParams& out_params) {
15 // Our state does not need to be changed 15 // Our state does not need to be changed
16 if (in_params.state != ServerMemoryPoolInfo::State::RequestAttach && 16 if (in_params.state != State::RequestAttach && in_params.state != State::RequestDetach) {
17 in_params.state != ServerMemoryPoolInfo::State::RequestDetach) {
18 return true; 17 return true;
19 } 18 }
20 19
@@ -32,11 +31,11 @@ bool ServerMemoryPoolInfo::Update(const ServerMemoryPoolInfo::InParams& in_param
32 return false; 31 return false;
33 } 32 }
34 33
35 if (in_params.state == ServerMemoryPoolInfo::State::RequestAttach) { 34 if (in_params.state == State::RequestAttach) {
36 cpu_address = in_params.address; 35 cpu_address = in_params.address;
37 size = in_params.size; 36 size = in_params.size;
38 used = true; 37 used = true;
39 out_params.state = ServerMemoryPoolInfo::State::Attached; 38 out_params.state = State::Attached;
40 } else { 39 } else {
41 // Unexpected address 40 // Unexpected address
42 if (cpu_address != in_params.address) { 41 if (cpu_address != in_params.address) {
@@ -54,7 +53,7 @@ bool ServerMemoryPoolInfo::Update(const ServerMemoryPoolInfo::InParams& in_param
54 cpu_address = 0; 53 cpu_address = 0;
55 size = 0; 54 size = 0;
56 used = false; 55 used = false;
57 out_params.state = ServerMemoryPoolInfo::State::Detached; 56 out_params.state = State::Detached;
58 } 57 }
59 return true; 58 return true;
60} 59}
diff --git a/src/audio_core/memory_pool.h b/src/audio_core/memory_pool.h
index 8ac503f1c..3e9e777ae 100644
--- a/src/audio_core/memory_pool.h
+++ b/src/audio_core/memory_pool.h
@@ -28,19 +28,18 @@ public:
28 struct InParams { 28 struct InParams {
29 u64_le address{}; 29 u64_le address{};
30 u64_le size{}; 30 u64_le size{};
31 ServerMemoryPoolInfo::State state{}; 31 State state{};
32 INSERT_PADDING_WORDS(3); 32 INSERT_PADDING_WORDS(3);
33 }; 33 };
34 static_assert(sizeof(ServerMemoryPoolInfo::InParams) == 0x20, "InParams are an invalid size"); 34 static_assert(sizeof(InParams) == 0x20, "InParams are an invalid size");
35 35
36 struct OutParams { 36 struct OutParams {
37 ServerMemoryPoolInfo::State state{}; 37 State state{};
38 INSERT_PADDING_WORDS(3); 38 INSERT_PADDING_WORDS(3);
39 }; 39 };
40 static_assert(sizeof(ServerMemoryPoolInfo::OutParams) == 0x10, "OutParams are an invalid size"); 40 static_assert(sizeof(OutParams) == 0x10, "OutParams are an invalid size");
41 41
42 bool Update(const ServerMemoryPoolInfo::InParams& in_params, 42 bool Update(const InParams& in_params, OutParams& out_params);
43 ServerMemoryPoolInfo::OutParams& out_params);
44 43
45private: 44private:
46 // There's another entry here which is the DSP address, however since we're not talking to the 45 // There's another entry here which is the DSP address, however since we're not talking to the
diff --git a/src/audio_core/sink_context.cpp b/src/audio_core/sink_context.cpp
index b29b47890..a69543696 100644
--- a/src/audio_core/sink_context.cpp
+++ b/src/audio_core/sink_context.cpp
@@ -5,7 +5,7 @@
5#include "audio_core/sink_context.h" 5#include "audio_core/sink_context.h"
6 6
7namespace AudioCore { 7namespace AudioCore {
8SinkContext::SinkContext(std::size_t sink_count) : sink_count(sink_count) {} 8SinkContext::SinkContext(std::size_t sink_count_) : sink_count{sink_count_} {}
9SinkContext::~SinkContext() = default; 9SinkContext::~SinkContext() = default;
10 10
11std::size_t SinkContext::GetCount() const { 11std::size_t SinkContext::GetCount() const {
diff --git a/src/audio_core/sink_context.h b/src/audio_core/sink_context.h
index e2e7880b7..05541becb 100644
--- a/src/audio_core/sink_context.h
+++ b/src/audio_core/sink_context.h
@@ -42,7 +42,7 @@ public:
42 bool in_use; 42 bool in_use;
43 INSERT_UNION_PADDING_BYTES(5); 43 INSERT_UNION_PADDING_BYTES(5);
44 }; 44 };
45 static_assert(sizeof(SinkInfo::CircularBufferIn) == 0x28, 45 static_assert(sizeof(CircularBufferIn) == 0x28,
46 "SinkInfo::CircularBufferIn is in invalid size"); 46 "SinkInfo::CircularBufferIn is in invalid size");
47 47
48 struct DeviceIn { 48 struct DeviceIn {
@@ -54,7 +54,7 @@ public:
54 bool down_matrix_enabled; 54 bool down_matrix_enabled;
55 DownmixCoefficients down_matrix_coef; 55 DownmixCoefficients down_matrix_coef;
56 }; 56 };
57 static_assert(sizeof(SinkInfo::DeviceIn) == 0x11c, "SinkInfo::DeviceIn is an invalid size"); 57 static_assert(sizeof(DeviceIn) == 0x11c, "SinkInfo::DeviceIn is an invalid size");
58 58
59 struct InParams { 59 struct InParams {
60 SinkTypes type{}; 60 SinkTypes type{};
@@ -64,16 +64,16 @@ public:
64 INSERT_PADDING_WORDS(6); 64 INSERT_PADDING_WORDS(6);
65 union { 65 union {
66 // std::array<u8, 0x120> raw{}; 66 // std::array<u8, 0x120> raw{};
67 SinkInfo::DeviceIn device; 67 DeviceIn device;
68 SinkInfo::CircularBufferIn circular_buffer; 68 CircularBufferIn circular_buffer;
69 }; 69 };
70 }; 70 };
71 static_assert(sizeof(SinkInfo::InParams) == 0x140, "SinkInfo::InParams are an invalid size!"); 71 static_assert(sizeof(InParams) == 0x140, "SinkInfo::InParams are an invalid size!");
72}; 72};
73 73
74class SinkContext { 74class SinkContext {
75public: 75public:
76 explicit SinkContext(std::size_t sink_count); 76 explicit SinkContext(std::size_t sink_count_);
77 ~SinkContext(); 77 ~SinkContext();
78 78
79 [[nodiscard]] std::size_t GetCount() const; 79 [[nodiscard]] std::size_t GetCount() const;
diff --git a/src/audio_core/splitter_context.cpp b/src/audio_core/splitter_context.cpp
index f21b53147..f4bcd0391 100644
--- a/src/audio_core/splitter_context.cpp
+++ b/src/audio_core/splitter_context.cpp
@@ -10,7 +10,7 @@
10 10
11namespace AudioCore { 11namespace AudioCore {
12 12
13ServerSplitterDestinationData::ServerSplitterDestinationData(s32 id) : id(id) {} 13ServerSplitterDestinationData::ServerSplitterDestinationData(s32 id_) : id{id_} {}
14ServerSplitterDestinationData::~ServerSplitterDestinationData() = default; 14ServerSplitterDestinationData::~ServerSplitterDestinationData() = default;
15 15
16void ServerSplitterDestinationData::Update(SplitterInfo::InDestinationParams& header) { 16void ServerSplitterDestinationData::Update(SplitterInfo::InDestinationParams& header) {
@@ -87,7 +87,7 @@ void ServerSplitterDestinationData::UpdateInternalState() {
87 needs_update = false; 87 needs_update = false;
88} 88}
89 89
90ServerSplitterInfo::ServerSplitterInfo(s32 id) : id(id) {} 90ServerSplitterInfo::ServerSplitterInfo(s32 id_) : id(id_) {}
91ServerSplitterInfo::~ServerSplitterInfo() = default; 91ServerSplitterInfo::~ServerSplitterInfo() = default;
92 92
93void ServerSplitterInfo::InitializeInfos() { 93void ServerSplitterInfo::InitializeInfos() {
@@ -121,7 +121,7 @@ const ServerSplitterDestinationData* ServerSplitterInfo::GetHead() const {
121} 121}
122 122
123ServerSplitterDestinationData* ServerSplitterInfo::GetData(std::size_t depth) { 123ServerSplitterDestinationData* ServerSplitterInfo::GetData(std::size_t depth) {
124 auto current_head = head; 124 auto* current_head = head;
125 for (std::size_t i = 0; i < depth; i++) { 125 for (std::size_t i = 0; i < depth; i++) {
126 if (current_head == nullptr) { 126 if (current_head == nullptr) {
127 return nullptr; 127 return nullptr;
@@ -132,7 +132,7 @@ ServerSplitterDestinationData* ServerSplitterInfo::GetData(std::size_t depth) {
132} 132}
133 133
134const ServerSplitterDestinationData* ServerSplitterInfo::GetData(std::size_t depth) const { 134const ServerSplitterDestinationData* ServerSplitterInfo::GetData(std::size_t depth) const {
135 auto current_head = head; 135 auto* current_head = head;
136 for (std::size_t i = 0; i < depth; i++) { 136 for (std::size_t i = 0; i < depth; i++) {
137 if (current_head == nullptr) { 137 if (current_head == nullptr) {
138 return nullptr; 138 return nullptr;
@@ -245,7 +245,7 @@ ServerSplitterDestinationData* SplitterContext::GetDestinationData(std::size_t i
245const ServerSplitterDestinationData* SplitterContext::GetDestinationData(std::size_t info, 245const ServerSplitterDestinationData* SplitterContext::GetDestinationData(std::size_t info,
246 std::size_t data) const { 246 std::size_t data) const {
247 ASSERT(info < info_count); 247 ASSERT(info < info_count);
248 auto& cur_info = GetInfo(info); 248 const auto& cur_info = GetInfo(info);
249 return cur_info.GetData(data); 249 return cur_info.GetData(data);
250} 250}
251 251
@@ -267,11 +267,11 @@ std::size_t SplitterContext::GetDataCount() const {
267 return data_count; 267 return data_count;
268} 268}
269 269
270void SplitterContext::Setup(std::size_t _info_count, std::size_t _data_count, 270void SplitterContext::Setup(std::size_t info_count_, std::size_t data_count_,
271 bool is_splitter_bug_fixed) { 271 bool is_splitter_bug_fixed) {
272 272
273 info_count = _info_count; 273 info_count = info_count_;
274 data_count = _data_count; 274 data_count = data_count_;
275 275
276 for (std::size_t i = 0; i < info_count; i++) { 276 for (std::size_t i = 0; i < info_count; i++) {
277 auto& splitter = infos.emplace_back(static_cast<s32>(i)); 277 auto& splitter = infos.emplace_back(static_cast<s32>(i));
@@ -364,7 +364,7 @@ bool SplitterContext::RecomposeDestination(ServerSplitterInfo& info,
364 // Clear our current destinations 364 // Clear our current destinations
365 auto* current_head = info.GetHead(); 365 auto* current_head = info.GetHead();
366 while (current_head != nullptr) { 366 while (current_head != nullptr) {
367 auto next_head = current_head->GetNextDestination(); 367 auto* next_head = current_head->GetNextDestination();
368 current_head->SetNextDestination(nullptr); 368 current_head->SetNextDestination(nullptr);
369 current_head = next_head; 369 current_head = next_head;
370 } 370 }
@@ -471,8 +471,8 @@ bool NodeStates::DepthFirstSearch(EdgeMatrix& edge_matrix) {
471 continue; 471 continue;
472 } 472 }
473 473
474 const auto node_count = edge_matrix.GetNodeCount(); 474 const auto edge_node_count = edge_matrix.GetNodeCount();
475 for (s32 j = 0; j < static_cast<s32>(node_count); j++) { 475 for (s32 j = 0; j < static_cast<s32>(edge_node_count); j++) {
476 // Check if our node is connected to our edge matrix 476 // Check if our node is connected to our edge matrix
477 if (!edge_matrix.Connected(current_stack_index, j)) { 477 if (!edge_matrix.Connected(current_stack_index, j)) {
478 continue; 478 continue;
diff --git a/src/audio_core/splitter_context.h b/src/audio_core/splitter_context.h
index ea6239fdb..b490627f5 100644
--- a/src/audio_core/splitter_context.h
+++ b/src/audio_core/splitter_context.h
@@ -63,7 +63,7 @@ public:
63 NodeStates(); 63 NodeStates();
64 ~NodeStates(); 64 ~NodeStates();
65 65
66 void Initialize(std::size_t _node_count); 66 void Initialize(std::size_t node_count_);
67 bool Tsort(EdgeMatrix& edge_matrix); 67 bool Tsort(EdgeMatrix& edge_matrix);
68 std::size_t GetIndexPos() const; 68 std::size_t GetIndexPos() const;
69 const std::vector<s32>& GetIndexList() const; 69 const std::vector<s32>& GetIndexList() const;
@@ -72,15 +72,15 @@ private:
72 void PushTsortResult(s32 index); 72 void PushTsortResult(s32 index);
73 bool DepthFirstSearch(EdgeMatrix& edge_matrix); 73 bool DepthFirstSearch(EdgeMatrix& edge_matrix);
74 void ResetState(); 74 void ResetState();
75 void UpdateState(NodeStates::State state, std::size_t i); 75 void UpdateState(State state, std::size_t i);
76 NodeStates::State GetState(std::size_t i); 76 State GetState(std::size_t i);
77 77
78 std::size_t node_count{}; 78 std::size_t node_count{};
79 std::vector<bool> was_node_found{}; 79 std::vector<bool> was_node_found{};
80 std::vector<bool> was_node_completed{}; 80 std::vector<bool> was_node_completed{};
81 std::size_t index_pos{}; 81 std::size_t index_pos{};
82 std::vector<s32> index_list{}; 82 std::vector<s32> index_list{};
83 NodeStates::Stack index_stack{}; 83 Stack index_stack{};
84}; 84};
85 85
86enum class SplitterMagic : u32_le { 86enum class SplitterMagic : u32_le {
@@ -97,8 +97,7 @@ public:
97 s32_le data_count{}; 97 s32_le data_count{};
98 INSERT_PADDING_WORDS(5); 98 INSERT_PADDING_WORDS(5);
99 }; 99 };
100 static_assert(sizeof(SplitterInfo::InHeader) == 0x20, 100 static_assert(sizeof(InHeader) == 0x20, "SplitterInfo::InHeader is an invalid size");
101 "SplitterInfo::InHeader is an invalid size");
102 101
103 struct InInfoPrams { 102 struct InInfoPrams {
104 SplitterMagic magic{}; 103 SplitterMagic magic{};
@@ -107,8 +106,7 @@ public:
107 s32_le length{}; 106 s32_le length{};
108 s32_le resource_id_base{}; 107 s32_le resource_id_base{};
109 }; 108 };
110 static_assert(sizeof(SplitterInfo::InInfoPrams) == 0x14, 109 static_assert(sizeof(InInfoPrams) == 0x14, "SplitterInfo::InInfoPrams is an invalid size");
111 "SplitterInfo::InInfoPrams is an invalid size");
112 110
113 struct InDestinationParams { 111 struct InDestinationParams {
114 SplitterMagic magic{}; 112 SplitterMagic magic{};
@@ -118,13 +116,13 @@ public:
118 bool in_use{}; 116 bool in_use{};
119 INSERT_PADDING_BYTES(3); 117 INSERT_PADDING_BYTES(3);
120 }; 118 };
121 static_assert(sizeof(SplitterInfo::InDestinationParams) == 0x70, 119 static_assert(sizeof(InDestinationParams) == 0x70,
122 "SplitterInfo::InDestinationParams is an invalid size"); 120 "SplitterInfo::InDestinationParams is an invalid size");
123}; 121};
124 122
125class ServerSplitterDestinationData { 123class ServerSplitterDestinationData {
126public: 124public:
127 explicit ServerSplitterDestinationData(s32 id); 125 explicit ServerSplitterDestinationData(s32 id_);
128 ~ServerSplitterDestinationData(); 126 ~ServerSplitterDestinationData();
129 127
130 void Update(SplitterInfo::InDestinationParams& header); 128 void Update(SplitterInfo::InDestinationParams& header);
@@ -153,7 +151,7 @@ private:
153 151
154class ServerSplitterInfo { 152class ServerSplitterInfo {
155public: 153public:
156 explicit ServerSplitterInfo(s32 id); 154 explicit ServerSplitterInfo(s32 id_);
157 ~ServerSplitterInfo(); 155 ~ServerSplitterInfo();
158 156
159 void InitializeInfos(); 157 void InitializeInfos();
diff --git a/src/audio_core/stream.cpp b/src/audio_core/stream.cpp
index 41bc2f4d6..eca296589 100644
--- a/src/audio_core/stream.cpp
+++ b/src/audio_core/stream.cpp
@@ -31,10 +31,10 @@ u32 Stream::GetNumChannels() const {
31 return {}; 31 return {};
32} 32}
33 33
34Stream::Stream(Core::Timing::CoreTiming& core_timing, u32 sample_rate, Format format, 34Stream::Stream(Core::Timing::CoreTiming& core_timing_, u32 sample_rate_, Format format_,
35 ReleaseCallback&& release_callback, SinkStream& sink_stream, std::string&& name_) 35 ReleaseCallback&& release_callback_, SinkStream& sink_stream_, std::string&& name_)
36 : sample_rate{sample_rate}, format{format}, release_callback{std::move(release_callback)}, 36 : sample_rate{sample_rate_}, format{format_}, release_callback{std::move(release_callback_)},
37 sink_stream{sink_stream}, core_timing{core_timing}, name{std::move(name_)} { 37 sink_stream{sink_stream_}, core_timing{core_timing_}, name{std::move(name_)} {
38 release_event = 38 release_event =
39 Core::Timing::CreateEvent(name, [this](std::uintptr_t, std::chrono::nanoseconds ns_late) { 39 Core::Timing::CreateEvent(name, [this](std::uintptr_t, std::chrono::nanoseconds ns_late) {
40 ReleaseActiveBuffer(ns_late); 40 ReleaseActiveBuffer(ns_late);
@@ -122,7 +122,7 @@ bool Stream::QueueBuffer(BufferPtr&& buffer) {
122 return false; 122 return false;
123} 123}
124 124
125bool Stream::ContainsBuffer(Buffer::Tag tag) const { 125bool Stream::ContainsBuffer([[maybe_unused]] Buffer::Tag tag) const {
126 UNIMPLEMENTED(); 126 UNIMPLEMENTED();
127 return {}; 127 return {};
128} 128}
diff --git a/src/audio_core/stream.h b/src/audio_core/stream.h
index 71c2d0b4f..506ac536b 100644
--- a/src/audio_core/stream.h
+++ b/src/audio_core/stream.h
@@ -44,8 +44,8 @@ public:
44 /// Callback function type, used to change guest state on a buffer being released 44 /// Callback function type, used to change guest state on a buffer being released
45 using ReleaseCallback = std::function<void()>; 45 using ReleaseCallback = std::function<void()>;
46 46
47 Stream(Core::Timing::CoreTiming& core_timing, u32 sample_rate, Format format, 47 Stream(Core::Timing::CoreTiming& core_timing_, u32 sample_rate_, Format format_,
48 ReleaseCallback&& release_callback, SinkStream& sink_stream, std::string&& name_); 48 ReleaseCallback&& release_callback_, SinkStream& sink_stream_, std::string&& name_);
49 49
50 /// Plays the audio stream 50 /// Plays the audio stream
51 void Play(); 51 void Play();
diff --git a/src/audio_core/voice_context.cpp b/src/audio_core/voice_context.cpp
index c46ee55f1..867b8fc6b 100644
--- a/src/audio_core/voice_context.cpp
+++ b/src/audio_core/voice_context.cpp
@@ -8,7 +8,7 @@
8 8
9namespace AudioCore { 9namespace AudioCore {
10 10
11ServerVoiceChannelResource::ServerVoiceChannelResource(s32 id) : id(id) {} 11ServerVoiceChannelResource::ServerVoiceChannelResource(s32 id_) : id(id_) {}
12ServerVoiceChannelResource::~ServerVoiceChannelResource() = default; 12ServerVoiceChannelResource::~ServerVoiceChannelResource() = default;
13 13
14bool ServerVoiceChannelResource::InUse() const { 14bool ServerVoiceChannelResource::InUse() const {
@@ -209,7 +209,8 @@ void ServerVoiceInfo::UpdateWaveBuffers(
209 209
210void ServerVoiceInfo::UpdateWaveBuffer(ServerWaveBuffer& out_wavebuffer, 210void ServerVoiceInfo::UpdateWaveBuffer(ServerWaveBuffer& out_wavebuffer,
211 const WaveBuffer& in_wave_buffer, SampleFormat sample_format, 211 const WaveBuffer& in_wave_buffer, SampleFormat sample_format,
212 bool is_buffer_valid, BehaviorInfo& behavior_info) { 212 bool is_buffer_valid,
213 [[maybe_unused]] BehaviorInfo& behavior_info) {
213 if (!is_buffer_valid && out_wavebuffer.sent_to_dsp) { 214 if (!is_buffer_valid && out_wavebuffer.sent_to_dsp) {
214 out_wavebuffer.buffer_address = 0; 215 out_wavebuffer.buffer_address = 0;
215 out_wavebuffer.buffer_size = 0; 216 out_wavebuffer.buffer_size = 0;
@@ -400,7 +401,7 @@ bool ServerVoiceInfo::HasValidWaveBuffer(const VoiceState* state) const {
400 return std::find(valid_wb.begin(), valid_wb.end(), true) != valid_wb.end(); 401 return std::find(valid_wb.begin(), valid_wb.end(), true) != valid_wb.end();
401} 402}
402 403
403VoiceContext::VoiceContext(std::size_t voice_count) : voice_count(voice_count) { 404VoiceContext::VoiceContext(std::size_t voice_count_) : voice_count{voice_count_} {
404 for (std::size_t i = 0; i < voice_count; i++) { 405 for (std::size_t i = 0; i < voice_count; i++) {
405 voice_channel_resources.emplace_back(static_cast<s32>(i)); 406 voice_channel_resources.emplace_back(static_cast<s32>(i));
406 sorted_voice_info.push_back(&voice_info.emplace_back()); 407 sorted_voice_info.push_back(&voice_info.emplace_back());
diff --git a/src/audio_core/voice_context.h b/src/audio_core/voice_context.h
index 59d3d7dfb..863248761 100644
--- a/src/audio_core/voice_context.h
+++ b/src/audio_core/voice_context.h
@@ -118,12 +118,12 @@ public:
118 bool in_use{}; 118 bool in_use{};
119 INSERT_PADDING_BYTES(11); 119 INSERT_PADDING_BYTES(11);
120 }; 120 };
121 static_assert(sizeof(VoiceChannelResource::InParams) == 0x70, "InParams is an invalid size"); 121 static_assert(sizeof(InParams) == 0x70, "InParams is an invalid size");
122}; 122};
123 123
124class ServerVoiceChannelResource { 124class ServerVoiceChannelResource {
125public: 125public:
126 explicit ServerVoiceChannelResource(s32 id); 126 explicit ServerVoiceChannelResource(s32 id_);
127 ~ServerVoiceChannelResource(); 127 ~ServerVoiceChannelResource();
128 128
129 bool InUse() const; 129 bool InUse() const;
@@ -174,7 +174,7 @@ public:
174 BehaviorFlags behavior_flags{}; 174 BehaviorFlags behavior_flags{};
175 INSERT_PADDING_BYTES(16); 175 INSERT_PADDING_BYTES(16);
176 }; 176 };
177 static_assert(sizeof(VoiceInfo::InParams) == 0x170, "InParams is an invalid size"); 177 static_assert(sizeof(InParams) == 0x170, "InParams is an invalid size");
178 178
179 struct OutParams { 179 struct OutParams {
180 u64_le played_sample_count{}; 180 u64_le played_sample_count{};
@@ -182,7 +182,7 @@ public:
182 u8 voice_dropped{}; 182 u8 voice_dropped{};
183 INSERT_PADDING_BYTES(3); 183 INSERT_PADDING_BYTES(3);
184 }; 184 };
185 static_assert(sizeof(VoiceInfo::OutParams) == 0x10, "OutParams is an invalid size"); 185 static_assert(sizeof(OutParams) == 0x10, "OutParams is an invalid size");
186}; 186};
187 187
188class ServerVoiceInfo { 188class ServerVoiceInfo {
@@ -263,7 +263,7 @@ private:
263 263
264class VoiceContext { 264class VoiceContext {
265public: 265public:
266 VoiceContext(std::size_t voice_count); 266 explicit VoiceContext(std::size_t voice_count_);
267 ~VoiceContext(); 267 ~VoiceContext();
268 268
269 std::size_t GetVoiceCount() const; 269 std::size_t GetVoiceCount() const;
diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt
index d20e6c3b5..56c7e21f5 100644
--- a/src/common/CMakeLists.txt
+++ b/src/common/CMakeLists.txt
@@ -112,6 +112,7 @@ add_library(common STATIC
112 common_paths.h 112 common_paths.h
113 common_types.h 113 common_types.h
114 concepts.h 114 concepts.h
115 div_ceil.h
115 dynamic_library.cpp 116 dynamic_library.cpp
116 dynamic_library.h 117 dynamic_library.h
117 fiber.cpp 118 fiber.cpp
diff --git a/src/common/div_ceil.h b/src/common/div_ceil.h
new file mode 100644
index 000000000..6b2c48f91
--- /dev/null
+++ b/src/common/div_ceil.h
@@ -0,0 +1,26 @@
1// Copyright 2020 yuzu emulator team
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <cstddef>
8#include <type_traits>
9
10namespace Common {
11
12/// Ceiled integer division.
13template <typename N, typename D>
14requires std::is_integral_v<N>&& std::is_unsigned_v<D>[[nodiscard]] constexpr auto DivCeil(
15 N number, D divisor) {
16 return (static_cast<D>(number) + divisor - 1) / divisor;
17}
18
19/// Ceiled integer division with logarithmic divisor in base 2
20template <typename N, typename D>
21requires std::is_integral_v<N>&& std::is_unsigned_v<D>[[nodiscard]] constexpr auto DivCeilLog2(
22 N value, D alignment_log2) {
23 return (static_cast<D>(value) + (D(1) << alignment_log2) - 1) >> alignment_log2;
24}
25
26} // namespace Common
diff --git a/src/common/wall_clock.cpp b/src/common/wall_clock.cpp
index 452a2837e..a8c143f85 100644
--- a/src/common/wall_clock.cpp
+++ b/src/common/wall_clock.cpp
@@ -17,8 +17,8 @@ using base_time_point = std::chrono::time_point<base_timer>;
17 17
18class StandardWallClock final : public WallClock { 18class StandardWallClock final : public WallClock {
19public: 19public:
20 StandardWallClock(u64 emulated_cpu_frequency, u64 emulated_clock_frequency) 20 explicit StandardWallClock(u64 emulated_cpu_frequency_, u64 emulated_clock_frequency_)
21 : WallClock(emulated_cpu_frequency, emulated_clock_frequency, false) { 21 : WallClock(emulated_cpu_frequency_, emulated_clock_frequency_, false) {
22 start_time = base_timer::now(); 22 start_time = base_timer::now();
23 } 23 }
24 24
diff --git a/src/common/wall_clock.h b/src/common/wall_clock.h
index bc7adfbf8..cef3e9499 100644
--- a/src/common/wall_clock.h
+++ b/src/common/wall_clock.h
@@ -38,9 +38,9 @@ public:
38 } 38 }
39 39
40protected: 40protected:
41 WallClock(u64 emulated_cpu_frequency, u64 emulated_clock_frequency, bool is_native) 41 explicit WallClock(u64 emulated_cpu_frequency_, u64 emulated_clock_frequency_, bool is_native_)
42 : emulated_cpu_frequency{emulated_cpu_frequency}, 42 : emulated_cpu_frequency{emulated_cpu_frequency_},
43 emulated_clock_frequency{emulated_clock_frequency}, is_native{is_native} {} 43 emulated_clock_frequency{emulated_clock_frequency_}, is_native{is_native_} {}
44 44
45 u64 emulated_cpu_frequency; 45 u64 emulated_cpu_frequency;
46 u64 emulated_clock_frequency; 46 u64 emulated_clock_frequency;
diff --git a/src/common/x64/native_clock.cpp b/src/common/x64/native_clock.cpp
index 424b39b1f..eb8a7782f 100644
--- a/src/common/x64/native_clock.cpp
+++ b/src/common/x64/native_clock.cpp
@@ -43,10 +43,10 @@ u64 EstimateRDTSCFrequency() {
43} 43}
44 44
45namespace X64 { 45namespace X64 {
46NativeClock::NativeClock(u64 emulated_cpu_frequency, u64 emulated_clock_frequency, 46NativeClock::NativeClock(u64 emulated_cpu_frequency_, u64 emulated_clock_frequency_,
47 u64 rtsc_frequency) 47 u64 rtsc_frequency_)
48 : WallClock(emulated_cpu_frequency, emulated_clock_frequency, true), rtsc_frequency{ 48 : WallClock(emulated_cpu_frequency_, emulated_clock_frequency_, true), rtsc_frequency{
49 rtsc_frequency} { 49 rtsc_frequency_} {
50 _mm_mfence(); 50 _mm_mfence();
51 last_measure = __rdtsc(); 51 last_measure = __rdtsc();
52 accumulated_ticks = 0U; 52 accumulated_ticks = 0U;
diff --git a/src/common/x64/native_clock.h b/src/common/x64/native_clock.h
index 97aab6ac9..6d1e32ac8 100644
--- a/src/common/x64/native_clock.h
+++ b/src/common/x64/native_clock.h
@@ -14,7 +14,8 @@ namespace Common {
14namespace X64 { 14namespace X64 {
15class NativeClock final : public WallClock { 15class NativeClock final : public WallClock {
16public: 16public:
17 NativeClock(u64 emulated_cpu_frequency, u64 emulated_clock_frequency, u64 rtsc_frequency); 17 explicit NativeClock(u64 emulated_cpu_frequency_, u64 emulated_clock_frequency_,
18 u64 rtsc_frequency_);
18 19
19 std::chrono::nanoseconds GetTimeNS() override; 20 std::chrono::nanoseconds GetTimeNS() override;
20 21
diff --git a/src/core/core_timing.h b/src/core/core_timing.h
index b0b6036e4..77ff4c6fe 100644
--- a/src/core/core_timing.h
+++ b/src/core/core_timing.h
@@ -27,8 +27,8 @@ using TimedCallback =
27 27
28/// Contains the characteristics of a particular event. 28/// Contains the characteristics of a particular event.
29struct EventType { 29struct EventType {
30 EventType(TimedCallback&& callback, std::string&& name) 30 explicit EventType(TimedCallback&& callback_, std::string&& name_)
31 : callback{std::move(callback)}, name{std::move(name)} {} 31 : callback{std::move(callback_)}, name{std::move(name_)} {}
32 32
33 /// The event's callback function. 33 /// The event's callback function.
34 TimedCallback callback; 34 TimedCallback callback;
@@ -67,8 +67,8 @@ public:
67 void Shutdown(); 67 void Shutdown();
68 68
69 /// Sets if emulation is multicore or single core, must be set before Initialize 69 /// Sets if emulation is multicore or single core, must be set before Initialize
70 void SetMulticore(bool is_multicore) { 70 void SetMulticore(bool is_multicore_) {
71 this->is_multicore = is_multicore; 71 is_multicore = is_multicore_;
72 } 72 }
73 73
74 /// Check if it's using host timing. 74 /// Check if it's using host timing.
diff --git a/src/core/frontend/input.h b/src/core/frontend/input.h
index 11c2e96ca..de51a754e 100644
--- a/src/core/frontend/input.h
+++ b/src/core/frontend/input.h
@@ -163,10 +163,15 @@ using MotionStatus = std::tuple<Common::Vec3<float>, Common::Vec3<float>, Common
163using MotionDevice = InputDevice<MotionStatus>; 163using MotionDevice = InputDevice<MotionStatus>;
164 164
165/** 165/**
166 * A touch device is an input device that returns a tuple of two floats and a bool. The floats are 166 * A touch status is an object that returns a tuple of two floats and a bool. The floats are
167 * x and y coordinates in the range 0.0 - 1.0, and the bool indicates whether it is pressed. 167 * x and y coordinates in the range 0.0 - 1.0, and the bool indicates whether it is pressed.
168 */ 168 */
169using TouchDevice = InputDevice<std::tuple<float, float, bool>>; 169using TouchStatus = std::tuple<float, float, bool>;
170
171/**
172 * A touch device is an input device that returns a touch status object
173 */
174using TouchDevice = InputDevice<TouchStatus>;
170 175
171/** 176/**
172 * A mouse device is an input device that returns a tuple of two floats and four ints. 177 * A mouse device is an input device that returns a tuple of two floats and four ints.
diff --git a/src/core/hle/result.h b/src/core/hle/result.h
index b6bdbd988..8feda7ad7 100644
--- a/src/core/hle/result.h
+++ b/src/core/hle/result.h
@@ -119,7 +119,7 @@ union ResultCode {
119 BitField<0, 9, ErrorModule> module; 119 BitField<0, 9, ErrorModule> module;
120 BitField<9, 13, u32> description; 120 BitField<9, 13, u32> description;
121 121
122 constexpr explicit ResultCode(u32 raw) : raw(raw) {} 122 constexpr explicit ResultCode(u32 raw_) : raw(raw_) {}
123 123
124 constexpr ResultCode(ErrorModule module_, u32 description_) 124 constexpr ResultCode(ErrorModule module_, u32 description_)
125 : raw(module.FormatValue(module_) | description.FormatValue(description_)) {} 125 : raw(module.FormatValue(module_) | description.FormatValue(description_)) {}
diff --git a/src/core/settings.h b/src/core/settings.h
index 3df611d5b..8e076f7ef 100644
--- a/src/core/settings.h
+++ b/src/core/settings.h
@@ -178,9 +178,7 @@ struct Values {
178 178
179 Setting<bool> motion_enabled; 179 Setting<bool> motion_enabled;
180 std::string motion_device; 180 std::string motion_device;
181 std::string udp_input_address; 181 std::string udp_input_servers;
182 u16 udp_input_port;
183 u8 udp_pad_index;
184 182
185 bool mouse_enabled; 183 bool mouse_enabled;
186 std::string mouse_device; 184 std::string mouse_device;
diff --git a/src/input_common/CMakeLists.txt b/src/input_common/CMakeLists.txt
index 5682e5ca5..38ab31898 100644
--- a/src/input_common/CMakeLists.txt
+++ b/src/input_common/CMakeLists.txt
@@ -5,8 +5,6 @@ add_library(input_common STATIC
5 keyboard.h 5 keyboard.h
6 main.cpp 6 main.cpp
7 main.h 7 main.h
8 motion_emu.cpp
9 motion_emu.h
10 motion_from_button.cpp 8 motion_from_button.cpp
11 motion_from_button.h 9 motion_from_button.h
12 motion_input.cpp 10 motion_input.cpp
@@ -19,6 +17,10 @@ add_library(input_common STATIC
19 gcadapter/gc_adapter.h 17 gcadapter/gc_adapter.h
20 gcadapter/gc_poller.cpp 18 gcadapter/gc_poller.cpp
21 gcadapter/gc_poller.h 19 gcadapter/gc_poller.h
20 mouse/mouse_input.cpp
21 mouse/mouse_input.h
22 mouse/mouse_poller.cpp
23 mouse/mouse_poller.h
22 sdl/sdl.cpp 24 sdl/sdl.cpp
23 sdl/sdl.h 25 sdl/sdl.h
24 udp/client.cpp 26 udp/client.cpp
diff --git a/src/input_common/main.cpp b/src/input_common/main.cpp
index e59ad4ff5..7c4e7dd3b 100644
--- a/src/input_common/main.cpp
+++ b/src/input_common/main.cpp
@@ -10,8 +10,9 @@
10#include "input_common/gcadapter/gc_poller.h" 10#include "input_common/gcadapter/gc_poller.h"
11#include "input_common/keyboard.h" 11#include "input_common/keyboard.h"
12#include "input_common/main.h" 12#include "input_common/main.h"
13#include "input_common/motion_emu.h"
14#include "input_common/motion_from_button.h" 13#include "input_common/motion_from_button.h"
14#include "input_common/mouse/mouse_input.h"
15#include "input_common/mouse/mouse_poller.h"
15#include "input_common/touch_from_button.h" 16#include "input_common/touch_from_button.h"
16#include "input_common/udp/client.h" 17#include "input_common/udp/client.h"
17#include "input_common/udp/udp.h" 18#include "input_common/udp/udp.h"
@@ -37,8 +38,6 @@ struct InputSubsystem::Impl {
37 std::make_shared<AnalogFromButton>()); 38 std::make_shared<AnalogFromButton>());
38 Input::RegisterFactory<Input::MotionDevice>("keyboard", 39 Input::RegisterFactory<Input::MotionDevice>("keyboard",
39 std::make_shared<MotionFromButton>()); 40 std::make_shared<MotionFromButton>());
40 motion_emu = std::make_shared<MotionEmu>();
41 Input::RegisterFactory<Input::MotionDevice>("motion_emu", motion_emu);
42 Input::RegisterFactory<Input::TouchDevice>("touch_from_button", 41 Input::RegisterFactory<Input::TouchDevice>("touch_from_button",
43 std::make_shared<TouchFromButtonFactory>()); 42 std::make_shared<TouchFromButtonFactory>());
44 43
@@ -51,6 +50,16 @@ struct InputSubsystem::Impl {
51 Input::RegisterFactory<Input::MotionDevice>("cemuhookudp", udpmotion); 50 Input::RegisterFactory<Input::MotionDevice>("cemuhookudp", udpmotion);
52 udptouch = std::make_shared<UDPTouchFactory>(udp); 51 udptouch = std::make_shared<UDPTouchFactory>(udp);
53 Input::RegisterFactory<Input::TouchDevice>("cemuhookudp", udptouch); 52 Input::RegisterFactory<Input::TouchDevice>("cemuhookudp", udptouch);
53
54 mouse = std::make_shared<MouseInput::Mouse>();
55 mousebuttons = std::make_shared<MouseButtonFactory>(mouse);
56 Input::RegisterFactory<Input::ButtonDevice>("mouse", mousebuttons);
57 mouseanalog = std::make_shared<MouseAnalogFactory>(mouse);
58 Input::RegisterFactory<Input::AnalogDevice>("mouse", mouseanalog);
59 mousemotion = std::make_shared<MouseMotionFactory>(mouse);
60 Input::RegisterFactory<Input::MotionDevice>("mouse", mousemotion);
61 mousetouch = std::make_shared<MouseTouchFactory>(mouse);
62 Input::RegisterFactory<Input::TouchDevice>("mouse", mousetouch);
54 } 63 }
55 64
56 void Shutdown() { 65 void Shutdown() {
@@ -58,8 +67,6 @@ struct InputSubsystem::Impl {
58 Input::UnregisterFactory<Input::MotionDevice>("keyboard"); 67 Input::UnregisterFactory<Input::MotionDevice>("keyboard");
59 keyboard.reset(); 68 keyboard.reset();
60 Input::UnregisterFactory<Input::AnalogDevice>("analog_from_button"); 69 Input::UnregisterFactory<Input::AnalogDevice>("analog_from_button");
61 Input::UnregisterFactory<Input::MotionDevice>("motion_emu");
62 motion_emu.reset();
63 Input::UnregisterFactory<Input::TouchDevice>("touch_from_button"); 70 Input::UnregisterFactory<Input::TouchDevice>("touch_from_button");
64#ifdef HAVE_SDL2 71#ifdef HAVE_SDL2
65 sdl.reset(); 72 sdl.reset();
@@ -77,6 +84,16 @@ struct InputSubsystem::Impl {
77 84
78 udpmotion.reset(); 85 udpmotion.reset();
79 udptouch.reset(); 86 udptouch.reset();
87
88 Input::UnregisterFactory<Input::ButtonDevice>("mouse");
89 Input::UnregisterFactory<Input::AnalogDevice>("mouse");
90 Input::UnregisterFactory<Input::MotionDevice>("mouse");
91 Input::UnregisterFactory<Input::TouchDevice>("mouse");
92
93 mousebuttons.reset();
94 mouseanalog.reset();
95 mousemotion.reset();
96 mousetouch.reset();
80 } 97 }
81 98
82 [[nodiscard]] std::vector<Common::ParamPackage> GetInputDevices() const { 99 [[nodiscard]] std::vector<Common::ParamPackage> GetInputDevices() const {
@@ -140,7 +157,6 @@ struct InputSubsystem::Impl {
140 } 157 }
141 158
142 std::shared_ptr<Keyboard> keyboard; 159 std::shared_ptr<Keyboard> keyboard;
143 std::shared_ptr<MotionEmu> motion_emu;
144#ifdef HAVE_SDL2 160#ifdef HAVE_SDL2
145 std::unique_ptr<SDL::State> sdl; 161 std::unique_ptr<SDL::State> sdl;
146#endif 162#endif
@@ -149,8 +165,13 @@ struct InputSubsystem::Impl {
149 std::shared_ptr<GCVibrationFactory> gcvibration; 165 std::shared_ptr<GCVibrationFactory> gcvibration;
150 std::shared_ptr<UDPMotionFactory> udpmotion; 166 std::shared_ptr<UDPMotionFactory> udpmotion;
151 std::shared_ptr<UDPTouchFactory> udptouch; 167 std::shared_ptr<UDPTouchFactory> udptouch;
168 std::shared_ptr<MouseButtonFactory> mousebuttons;
169 std::shared_ptr<MouseAnalogFactory> mouseanalog;
170 std::shared_ptr<MouseMotionFactory> mousemotion;
171 std::shared_ptr<MouseTouchFactory> mousetouch;
152 std::shared_ptr<CemuhookUDP::Client> udp; 172 std::shared_ptr<CemuhookUDP::Client> udp;
153 std::shared_ptr<GCAdapter::Adapter> gcadapter; 173 std::shared_ptr<GCAdapter::Adapter> gcadapter;
174 std::shared_ptr<MouseInput::Mouse> mouse;
154}; 175};
155 176
156InputSubsystem::InputSubsystem() : impl{std::make_unique<Impl>()} {} 177InputSubsystem::InputSubsystem() : impl{std::make_unique<Impl>()} {}
@@ -173,12 +194,12 @@ const Keyboard* InputSubsystem::GetKeyboard() const {
173 return impl->keyboard.get(); 194 return impl->keyboard.get();
174} 195}
175 196
176MotionEmu* InputSubsystem::GetMotionEmu() { 197MouseInput::Mouse* InputSubsystem::GetMouse() {
177 return impl->motion_emu.get(); 198 return impl->mouse.get();
178} 199}
179 200
180const MotionEmu* InputSubsystem::GetMotionEmu() const { 201const MouseInput::Mouse* InputSubsystem::GetMouse() const {
181 return impl->motion_emu.get(); 202 return impl->mouse.get();
182} 203}
183 204
184std::vector<Common::ParamPackage> InputSubsystem::GetInputDevices() const { 205std::vector<Common::ParamPackage> InputSubsystem::GetInputDevices() const {
@@ -229,11 +250,43 @@ const UDPTouchFactory* InputSubsystem::GetUDPTouch() const {
229 return impl->udptouch.get(); 250 return impl->udptouch.get();
230} 251}
231 252
253MouseButtonFactory* InputSubsystem::GetMouseButtons() {
254 return impl->mousebuttons.get();
255}
256
257const MouseButtonFactory* InputSubsystem::GetMouseButtons() const {
258 return impl->mousebuttons.get();
259}
260
261MouseAnalogFactory* InputSubsystem::GetMouseAnalogs() {
262 return impl->mouseanalog.get();
263}
264
265const MouseAnalogFactory* InputSubsystem::GetMouseAnalogs() const {
266 return impl->mouseanalog.get();
267}
268
269MouseMotionFactory* InputSubsystem::GetMouseMotions() {
270 return impl->mousemotion.get();
271}
272
273const MouseMotionFactory* InputSubsystem::GetMouseMotions() const {
274 return impl->mousemotion.get();
275}
276
277MouseTouchFactory* InputSubsystem::GetMouseTouch() {
278 return impl->mousetouch.get();
279}
280
281const MouseTouchFactory* InputSubsystem::GetMouseTouch() const {
282 return impl->mousetouch.get();
283}
284
232void InputSubsystem::ReloadInputDevices() { 285void InputSubsystem::ReloadInputDevices() {
233 if (!impl->udp) { 286 if (!impl->udp) {
234 return; 287 return;
235 } 288 }
236 impl->udp->ReloadUDPClient(); 289 impl->udp->ReloadSockets();
237} 290}
238 291
239std::vector<std::unique_ptr<Polling::DevicePoller>> InputSubsystem::GetPollers( 292std::vector<std::unique_ptr<Polling::DevicePoller>> InputSubsystem::GetPollers(
diff --git a/src/input_common/main.h b/src/input_common/main.h
index dded3f1ef..5d6f26385 100644
--- a/src/input_common/main.h
+++ b/src/input_common/main.h
@@ -25,6 +25,10 @@ namespace Settings::NativeMotion {
25enum Values : int; 25enum Values : int;
26} 26}
27 27
28namespace MouseInput {
29class Mouse;
30}
31
28namespace InputCommon { 32namespace InputCommon {
29namespace Polling { 33namespace Polling {
30 34
@@ -56,8 +60,11 @@ class GCAnalogFactory;
56class GCButtonFactory; 60class GCButtonFactory;
57class UDPMotionFactory; 61class UDPMotionFactory;
58class UDPTouchFactory; 62class UDPTouchFactory;
63class MouseButtonFactory;
64class MouseAnalogFactory;
65class MouseMotionFactory;
66class MouseTouchFactory;
59class Keyboard; 67class Keyboard;
60class MotionEmu;
61 68
62/** 69/**
63 * Given a ParamPackage for a Device returned from `GetInputDevices`, attempt to get the default 70 * Given a ParamPackage for a Device returned from `GetInputDevices`, attempt to get the default
@@ -90,11 +97,11 @@ public:
90 /// Retrieves the underlying keyboard device. 97 /// Retrieves the underlying keyboard device.
91 [[nodiscard]] const Keyboard* GetKeyboard() const; 98 [[nodiscard]] const Keyboard* GetKeyboard() const;
92 99
93 /// Retrieves the underlying motion emulation factory. 100 /// Retrieves the underlying mouse device.
94 [[nodiscard]] MotionEmu* GetMotionEmu(); 101 [[nodiscard]] MouseInput::Mouse* GetMouse();
95 102
96 /// Retrieves the underlying motion emulation factory. 103 /// Retrieves the underlying mouse device.
97 [[nodiscard]] const MotionEmu* GetMotionEmu() const; 104 [[nodiscard]] const MouseInput::Mouse* GetMouse() const;
98 105
99 /** 106 /**
100 * Returns all available input devices that this Factory can create a new device with. 107 * Returns all available input devices that this Factory can create a new device with.
@@ -137,6 +144,30 @@ public:
137 /// Retrieves the underlying udp touch handler. 144 /// Retrieves the underlying udp touch handler.
138 [[nodiscard]] const UDPTouchFactory* GetUDPTouch() const; 145 [[nodiscard]] const UDPTouchFactory* GetUDPTouch() const;
139 146
147 /// Retrieves the underlying GameCube button handler.
148 [[nodiscard]] MouseButtonFactory* GetMouseButtons();
149
150 /// Retrieves the underlying GameCube button handler.
151 [[nodiscard]] const MouseButtonFactory* GetMouseButtons() const;
152
153 /// Retrieves the underlying udp touch handler.
154 [[nodiscard]] MouseAnalogFactory* GetMouseAnalogs();
155
156 /// Retrieves the underlying udp touch handler.
157 [[nodiscard]] const MouseAnalogFactory* GetMouseAnalogs() const;
158
159 /// Retrieves the underlying udp motion handler.
160 [[nodiscard]] MouseMotionFactory* GetMouseMotions();
161
162 /// Retrieves the underlying udp motion handler.
163 [[nodiscard]] const MouseMotionFactory* GetMouseMotions() const;
164
165 /// Retrieves the underlying udp touch handler.
166 [[nodiscard]] MouseTouchFactory* GetMouseTouch();
167
168 /// Retrieves the underlying udp touch handler.
169 [[nodiscard]] const MouseTouchFactory* GetMouseTouch() const;
170
140 /// Reloads the input devices 171 /// Reloads the input devices
141 void ReloadInputDevices(); 172 void ReloadInputDevices();
142 173
diff --git a/src/input_common/motion_emu.cpp b/src/input_common/motion_emu.cpp
deleted file mode 100644
index d4da5596b..000000000
--- a/src/input_common/motion_emu.cpp
+++ /dev/null
@@ -1,179 +0,0 @@
1// Copyright 2017 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include <algorithm>
6#include <chrono>
7#include <mutex>
8#include <thread>
9#include <tuple>
10#include "common/math_util.h"
11#include "common/quaternion.h"
12#include "common/thread.h"
13#include "common/vector_math.h"
14#include "input_common/motion_emu.h"
15
16namespace InputCommon {
17
18// Implementation class of the motion emulation device
19class MotionEmuDevice {
20public:
21 explicit MotionEmuDevice(int update_millisecond_, float sensitivity_)
22 : update_millisecond(update_millisecond_),
23 update_duration(std::chrono::duration_cast<std::chrono::steady_clock::duration>(
24 std::chrono::milliseconds(update_millisecond))),
25 sensitivity(sensitivity_), motion_emu_thread(&MotionEmuDevice::MotionEmuThread, this) {}
26
27 ~MotionEmuDevice() {
28 if (motion_emu_thread.joinable()) {
29 shutdown_event.Set();
30 motion_emu_thread.join();
31 }
32 }
33
34 void BeginTilt(int x, int y) {
35 mouse_origin = Common::MakeVec(x, y);
36 is_tilting = true;
37 }
38
39 void Tilt(int x, int y) {
40 if (!is_tilting) {
41 return;
42 }
43
44 std::lock_guard guard{tilt_mutex};
45 const auto mouse_move = Common::MakeVec(x, y) - mouse_origin;
46 if (mouse_move.x == 0 && mouse_move.y == 0) {
47 tilt_angle = 0;
48 } else {
49 tilt_direction = mouse_move.Cast<float>();
50 tilt_angle =
51 std::clamp(tilt_direction.Normalize() * sensitivity, 0.0f, Common::PI * 0.5f);
52 }
53 }
54
55 void EndTilt() {
56 std::lock_guard guard{tilt_mutex};
57 tilt_angle = 0;
58 is_tilting = false;
59 }
60
61 Input::MotionStatus GetStatus() {
62 std::lock_guard guard{status_mutex};
63 return status;
64 }
65
66private:
67 const int update_millisecond;
68 const std::chrono::steady_clock::duration update_duration;
69 const float sensitivity;
70
71 Common::Vec2<int> mouse_origin;
72
73 std::mutex tilt_mutex;
74 Common::Vec2<float> tilt_direction;
75 float tilt_angle = 0;
76
77 bool is_tilting = false;
78
79 Common::Event shutdown_event;
80
81 Input::MotionStatus status;
82 std::mutex status_mutex;
83
84 // Note: always keep the thread declaration at the end so that other objects are initialized
85 // before this!
86 std::thread motion_emu_thread;
87
88 void MotionEmuThread() {
89 auto update_time = std::chrono::steady_clock::now();
90 Common::Quaternion<float> q = Common::MakeQuaternion(Common::Vec3<float>(), 0);
91
92 while (!shutdown_event.WaitUntil(update_time)) {
93 update_time += update_duration;
94 const Common::Quaternion<float> old_q = q;
95
96 {
97 std::lock_guard guard{tilt_mutex};
98
99 // Find the quaternion describing current 3DS tilting
100 q = Common::MakeQuaternion(
101 Common::MakeVec(-tilt_direction.y, 0.0f, tilt_direction.x), tilt_angle);
102 }
103
104 const auto inv_q = q.Inverse();
105
106 // Set the gravity vector in world space
107 auto gravity = Common::MakeVec(0.0f, -1.0f, 0.0f);
108
109 // Find the angular rate vector in world space
110 auto angular_rate = ((q - old_q) * inv_q).xyz * 2;
111 angular_rate *= static_cast<float>(1000 / update_millisecond) / Common::PI * 180.0f;
112
113 // Transform the two vectors from world space to 3DS space
114 gravity = QuaternionRotate(inv_q, gravity);
115 angular_rate = QuaternionRotate(inv_q, angular_rate);
116
117 // TODO: Calculate the correct rotation vector and orientation matrix
118 const auto matrix4x4 = q.ToMatrix();
119 const auto rotation = Common::MakeVec(0.0f, 0.0f, 0.0f);
120 const std::array orientation{
121 Common::Vec3f(matrix4x4[0], matrix4x4[1], -matrix4x4[2]),
122 Common::Vec3f(matrix4x4[4], matrix4x4[5], -matrix4x4[6]),
123 Common::Vec3f(-matrix4x4[8], -matrix4x4[9], matrix4x4[10]),
124 };
125
126 // Update the sensor state
127 {
128 std::lock_guard guard{status_mutex};
129 status = std::make_tuple(gravity, angular_rate, rotation, orientation);
130 }
131 }
132 }
133};
134
135// Interface wrapper held by input receiver as a unique_ptr. It holds the implementation class as
136// a shared_ptr, which is also observed by the factory class as a weak_ptr. In this way the factory
137// can forward all the inputs to the implementation only when it is valid.
138class MotionEmuDeviceWrapper : public Input::MotionDevice {
139public:
140 explicit MotionEmuDeviceWrapper(int update_millisecond, float sensitivity) {
141 device = std::make_shared<MotionEmuDevice>(update_millisecond, sensitivity);
142 }
143
144 Input::MotionStatus GetStatus() const override {
145 return device->GetStatus();
146 }
147
148 std::shared_ptr<MotionEmuDevice> device;
149};
150
151std::unique_ptr<Input::MotionDevice> MotionEmu::Create(const Common::ParamPackage& params) {
152 const int update_period = params.Get("update_period", 100);
153 const float sensitivity = params.Get("sensitivity", 0.01f);
154 auto device_wrapper = std::make_unique<MotionEmuDeviceWrapper>(update_period, sensitivity);
155 // Previously created device is disconnected here. Having two motion devices for 3DS is not
156 // expected.
157 current_device = device_wrapper->device;
158 return device_wrapper;
159}
160
161void MotionEmu::BeginTilt(int x, int y) {
162 if (auto ptr = current_device.lock()) {
163 ptr->BeginTilt(x, y);
164 }
165}
166
167void MotionEmu::Tilt(int x, int y) {
168 if (auto ptr = current_device.lock()) {
169 ptr->Tilt(x, y);
170 }
171}
172
173void MotionEmu::EndTilt() {
174 if (auto ptr = current_device.lock()) {
175 ptr->EndTilt();
176 }
177}
178
179} // namespace InputCommon
diff --git a/src/input_common/motion_emu.h b/src/input_common/motion_emu.h
deleted file mode 100644
index 7a7e22467..000000000
--- a/src/input_common/motion_emu.h
+++ /dev/null
@@ -1,46 +0,0 @@
1// Copyright 2017 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include "core/frontend/input.h"
8
9namespace InputCommon {
10
11class MotionEmuDevice;
12
13class MotionEmu : public Input::Factory<Input::MotionDevice> {
14public:
15 /**
16 * Creates a motion device emulated from mouse input
17 * @param params contains parameters for creating the device:
18 * - "update_period": update period in milliseconds
19 * - "sensitivity": the coefficient converting mouse movement to tilting angle
20 */
21 std::unique_ptr<Input::MotionDevice> Create(const Common::ParamPackage& params) override;
22
23 /**
24 * Signals that a motion sensor tilt has begun.
25 * @param x the x-coordinate of the cursor
26 * @param y the y-coordinate of the cursor
27 */
28 void BeginTilt(int x, int y);
29
30 /**
31 * Signals that a motion sensor tilt is occurring.
32 * @param x the x-coordinate of the cursor
33 * @param y the y-coordinate of the cursor
34 */
35 void Tilt(int x, int y);
36
37 /**
38 * Signals that a motion sensor tilt has ended.
39 */
40 void EndTilt();
41
42private:
43 std::weak_ptr<MotionEmuDevice> current_device;
44};
45
46} // namespace InputCommon
diff --git a/src/input_common/mouse/mouse_input.cpp b/src/input_common/mouse/mouse_input.cpp
new file mode 100644
index 000000000..10786a541
--- /dev/null
+++ b/src/input_common/mouse/mouse_input.cpp
@@ -0,0 +1,129 @@
1// Copyright 2020 yuzu Emulator Project
2// Licensed under GPLv2+
3// Refer to the license.txt file included.
4
5#include "input_common/mouse/mouse_input.h"
6
7namespace MouseInput {
8
9Mouse::Mouse() {
10 update_thread = std::thread(&Mouse::UpdateThread, this);
11}
12
13Mouse::~Mouse() {
14 update_thread_running = false;
15 if (update_thread.joinable()) {
16 update_thread.join();
17 }
18}
19
20void Mouse::UpdateThread() {
21 constexpr int update_time = 10;
22 while (update_thread_running) {
23 for (MouseInfo& info : mouse_info) {
24 const Common::Vec3f angular_direction{
25 -info.tilt_direction.y,
26 0.0f,
27 -info.tilt_direction.x,
28 };
29
30 info.motion.SetGyroscope(angular_direction * info.tilt_speed);
31 info.motion.UpdateRotation(update_time * 1000);
32 info.motion.UpdateOrientation(update_time * 1000);
33 info.tilt_speed = 0;
34 info.data.motion = info.motion.GetMotion();
35 }
36 if (configuring) {
37 UpdateYuzuSettings();
38 }
39 std::this_thread::sleep_for(std::chrono::milliseconds(update_time));
40 }
41}
42
43void Mouse::UpdateYuzuSettings() {
44 if (buttons == 0) {
45 return;
46 }
47
48 mouse_queue.Push(MouseStatus{
49 .button = last_button,
50 });
51}
52
53void Mouse::PressButton(int x, int y, int button_) {
54 const auto button_index = static_cast<std::size_t>(button_);
55 if (button_index >= mouse_info.size()) {
56 return;
57 }
58
59 const auto button = 1U << button_index;
60 buttons |= static_cast<u16>(button);
61 last_button = static_cast<MouseButton>(button_index);
62
63 mouse_info[button_index].mouse_origin = Common::MakeVec(x, y);
64 mouse_info[button_index].last_mouse_position = Common::MakeVec(x, y);
65 mouse_info[button_index].data.pressed = true;
66}
67
68void Mouse::MouseMove(int x, int y) {
69 for (MouseInfo& info : mouse_info) {
70 if (info.data.pressed) {
71 const auto mouse_move = Common::MakeVec(x, y) - info.mouse_origin;
72 const auto mouse_change = Common::MakeVec(x, y) - info.last_mouse_position;
73 info.last_mouse_position = Common::MakeVec(x, y);
74 info.data.axis = {mouse_move.x, -mouse_move.y};
75
76 if (mouse_change.x == 0 && mouse_change.y == 0) {
77 info.tilt_speed = 0;
78 } else {
79 info.tilt_direction = mouse_change.Cast<float>();
80 info.tilt_speed = info.tilt_direction.Normalize() * info.sensitivity;
81 }
82 }
83 }
84}
85
86void Mouse::ReleaseButton(int button_) {
87 const auto button_index = static_cast<std::size_t>(button_);
88 if (button_index >= mouse_info.size()) {
89 return;
90 }
91
92 const auto button = 1U << button_index;
93 buttons &= static_cast<u16>(0xFF - button);
94
95 mouse_info[button_index].tilt_speed = 0;
96 mouse_info[button_index].data.pressed = false;
97 mouse_info[button_index].data.axis = {0, 0};
98}
99
100void Mouse::BeginConfiguration() {
101 buttons = 0;
102 last_button = MouseButton::Undefined;
103 mouse_queue.Clear();
104 configuring = true;
105}
106
107void Mouse::EndConfiguration() {
108 buttons = 0;
109 last_button = MouseButton::Undefined;
110 mouse_queue.Clear();
111 configuring = false;
112}
113
114Common::SPSCQueue<MouseStatus>& Mouse::GetMouseQueue() {
115 return mouse_queue;
116}
117
118const Common::SPSCQueue<MouseStatus>& Mouse::GetMouseQueue() const {
119 return mouse_queue;
120}
121
122MouseData& Mouse::GetMouseState(std::size_t button) {
123 return mouse_info[button].data;
124}
125
126const MouseData& Mouse::GetMouseState(std::size_t button) const {
127 return mouse_info[button].data;
128}
129} // namespace MouseInput
diff --git a/src/input_common/mouse/mouse_input.h b/src/input_common/mouse/mouse_input.h
new file mode 100644
index 000000000..65e64bee7
--- /dev/null
+++ b/src/input_common/mouse/mouse_input.h
@@ -0,0 +1,98 @@
1// Copyright 2020 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <array>
8#include <mutex>
9#include <thread>
10
11#include "common/common_types.h"
12#include "common/threadsafe_queue.h"
13#include "common/vector_math.h"
14#include "core/frontend/input.h"
15#include "input_common/motion_input.h"
16
17namespace MouseInput {
18
19enum class MouseButton {
20 Left,
21 Wheel,
22 Right,
23 Foward,
24 Backward,
25 Undefined,
26};
27
28struct MouseStatus {
29 MouseButton button{MouseButton::Undefined};
30};
31
32struct MouseData {
33 bool pressed{};
34 std::array<int, 2> axis{};
35 Input::MotionStatus motion{};
36 Input::TouchStatus touch{};
37};
38
39class Mouse {
40public:
41 Mouse();
42 ~Mouse();
43
44 /// Used for polling
45 void BeginConfiguration();
46 void EndConfiguration();
47
48 /**
49 * Signals that a button is pressed.
50 * @param x the x-coordinate of the cursor
51 * @param y the y-coordinate of the cursor
52 * @param button_ the button pressed
53 */
54 void PressButton(int x, int y, int button_);
55
56 /**
57 * Signals that mouse has moved.
58 * @param x the x-coordinate of the cursor
59 * @param y the y-coordinate of the cursor
60 */
61 void MouseMove(int x, int y);
62
63 /**
64 * Signals that a motion sensor tilt has ended.
65 */
66 void ReleaseButton(int button_);
67
68 [[nodiscard]] Common::SPSCQueue<MouseStatus>& GetMouseQueue();
69 [[nodiscard]] const Common::SPSCQueue<MouseStatus>& GetMouseQueue() const;
70
71 [[nodiscard]] MouseData& GetMouseState(std::size_t button);
72 [[nodiscard]] const MouseData& GetMouseState(std::size_t button) const;
73
74private:
75 void UpdateThread();
76 void UpdateYuzuSettings();
77
78 struct MouseInfo {
79 InputCommon::MotionInput motion{0.0f, 0.0f, 0.0f};
80 Common::Vec2<int> mouse_origin;
81 Common::Vec2<int> last_mouse_position;
82 bool is_tilting = false;
83 float sensitivity{0.120f};
84
85 float tilt_speed = 0;
86 Common::Vec2<float> tilt_direction;
87 MouseData data;
88 };
89
90 u16 buttons{};
91 std::thread update_thread;
92 MouseButton last_button{MouseButton::Undefined};
93 std::array<MouseInfo, 5> mouse_info;
94 Common::SPSCQueue<MouseStatus> mouse_queue;
95 bool configuring{false};
96 bool update_thread_running{true};
97};
98} // namespace MouseInput
diff --git a/src/input_common/mouse/mouse_poller.cpp b/src/input_common/mouse/mouse_poller.cpp
new file mode 100644
index 000000000..7445ad3ad
--- /dev/null
+++ b/src/input_common/mouse/mouse_poller.cpp
@@ -0,0 +1,259 @@
1// Copyright 2020 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include <mutex>
6#include <utility>
7
8#include "common/threadsafe_queue.h"
9#include "input_common/mouse/mouse_input.h"
10#include "input_common/mouse/mouse_poller.h"
11
12namespace InputCommon {
13
14class MouseButton final : public Input::ButtonDevice {
15public:
16 explicit MouseButton(u32 button_, const MouseInput::Mouse* mouse_input_)
17 : button(button_), mouse_input(mouse_input_) {}
18
19 bool GetStatus() const override {
20 return mouse_input->GetMouseState(button).pressed;
21 }
22
23private:
24 const u32 button;
25 const MouseInput::Mouse* mouse_input;
26};
27
28MouseButtonFactory::MouseButtonFactory(std::shared_ptr<MouseInput::Mouse> mouse_input_)
29 : mouse_input(std::move(mouse_input_)) {}
30
31std::unique_ptr<Input::ButtonDevice> MouseButtonFactory::Create(
32 const Common::ParamPackage& params) {
33 const auto button_id = params.Get("button", 0);
34
35 return std::make_unique<MouseButton>(button_id, mouse_input.get());
36}
37
38Common::ParamPackage MouseButtonFactory::GetNextInput() const {
39 MouseInput::MouseStatus pad;
40 Common::ParamPackage params;
41 auto& queue = mouse_input->GetMouseQueue();
42 while (queue.Pop(pad)) {
43 // This while loop will break on the earliest detected button
44 if (pad.button != MouseInput::MouseButton::Undefined) {
45 params.Set("engine", "mouse");
46 params.Set("button", static_cast<u16>(pad.button));
47 return params;
48 }
49 }
50 return params;
51}
52
53void MouseButtonFactory::BeginConfiguration() {
54 polling = true;
55 mouse_input->BeginConfiguration();
56}
57
58void MouseButtonFactory::EndConfiguration() {
59 polling = false;
60 mouse_input->EndConfiguration();
61}
62
63class MouseAnalog final : public Input::AnalogDevice {
64public:
65 explicit MouseAnalog(u32 port_, u32 axis_x_, u32 axis_y_, float deadzone_, float range_,
66 const MouseInput::Mouse* mouse_input_)
67 : button(port_), axis_x(axis_x_), axis_y(axis_y_), deadzone(deadzone_), range(range_),
68 mouse_input(mouse_input_) {}
69
70 float GetAxis(u32 axis) const {
71 std::lock_guard lock{mutex};
72 const auto axis_value =
73 static_cast<float>(mouse_input->GetMouseState(button).axis.at(axis));
74 return axis_value / (100.0f * range);
75 }
76
77 std::pair<float, float> GetAnalog(u32 analog_axis_x, u32 analog_axis_y) const {
78 float x = GetAxis(analog_axis_x);
79 float y = GetAxis(analog_axis_y);
80
81 // Make sure the coordinates are in the unit circle,
82 // otherwise normalize it.
83 float r = x * x + y * y;
84 if (r > 1.0f) {
85 r = std::sqrt(r);
86 x /= r;
87 y /= r;
88 }
89
90 return {x, y};
91 }
92
93 std::tuple<float, float> GetStatus() const override {
94 const auto [x, y] = GetAnalog(axis_x, axis_y);
95 const float r = std::sqrt((x * x) + (y * y));
96 if (r > deadzone) {
97 return {x / r * (r - deadzone) / (1 - deadzone),
98 y / r * (r - deadzone) / (1 - deadzone)};
99 }
100 return {0.0f, 0.0f};
101 }
102
103private:
104 const u32 button;
105 const u32 axis_x;
106 const u32 axis_y;
107 const float deadzone;
108 const float range;
109 const MouseInput::Mouse* mouse_input;
110 mutable std::mutex mutex;
111};
112
113/// An analog device factory that creates analog devices from GC Adapter
114MouseAnalogFactory::MouseAnalogFactory(std::shared_ptr<MouseInput::Mouse> mouse_input_)
115 : mouse_input(std::move(mouse_input_)) {}
116
117/**
118 * Creates analog device from joystick axes
119 * @param params contains parameters for creating the device:
120 * - "port": the nth gcpad on the adapter
121 * - "axis_x": the index of the axis to be bind as x-axis
122 * - "axis_y": the index of the axis to be bind as y-axis
123 */
124std::unique_ptr<Input::AnalogDevice> MouseAnalogFactory::Create(
125 const Common::ParamPackage& params) {
126 const auto port = static_cast<u32>(params.Get("port", 0));
127 const auto axis_x = static_cast<u32>(params.Get("axis_x", 0));
128 const auto axis_y = static_cast<u32>(params.Get("axis_y", 1));
129 const auto deadzone = std::clamp(params.Get("deadzone", 0.0f), 0.0f, 1.0f);
130 const auto range = std::clamp(params.Get("range", 1.0f), 0.50f, 1.50f);
131
132 return std::make_unique<MouseAnalog>(port, axis_x, axis_y, deadzone, range, mouse_input.get());
133}
134
135void MouseAnalogFactory::BeginConfiguration() {
136 polling = true;
137 mouse_input->BeginConfiguration();
138}
139
140void MouseAnalogFactory::EndConfiguration() {
141 polling = false;
142 mouse_input->EndConfiguration();
143}
144
145Common::ParamPackage MouseAnalogFactory::GetNextInput() const {
146 MouseInput::MouseStatus pad;
147 Common::ParamPackage params;
148 auto& queue = mouse_input->GetMouseQueue();
149 while (queue.Pop(pad)) {
150 // This while loop will break on the earliest detected button
151 if (pad.button != MouseInput::MouseButton::Undefined) {
152 params.Set("engine", "mouse");
153 params.Set("port", static_cast<u16>(pad.button));
154 params.Set("axis_x", 0);
155 params.Set("axis_y", 1);
156 return params;
157 }
158 }
159 return params;
160}
161
162class MouseMotion final : public Input::MotionDevice {
163public:
164 explicit MouseMotion(u32 button_, const MouseInput::Mouse* mouse_input_)
165 : button(button_), mouse_input(mouse_input_) {}
166
167 Input::MotionStatus GetStatus() const override {
168 return mouse_input->GetMouseState(button).motion;
169 }
170
171private:
172 const u32 button;
173 const MouseInput::Mouse* mouse_input;
174};
175
176MouseMotionFactory::MouseMotionFactory(std::shared_ptr<MouseInput::Mouse> mouse_input_)
177 : mouse_input(std::move(mouse_input_)) {}
178
179std::unique_ptr<Input::MotionDevice> MouseMotionFactory::Create(
180 const Common::ParamPackage& params) {
181 const auto button_id = params.Get("button", 0);
182
183 return std::make_unique<MouseMotion>(button_id, mouse_input.get());
184}
185
186Common::ParamPackage MouseMotionFactory::GetNextInput() const {
187 MouseInput::MouseStatus pad;
188 Common::ParamPackage params;
189 auto& queue = mouse_input->GetMouseQueue();
190 while (queue.Pop(pad)) {
191 // This while loop will break on the earliest detected button
192 if (pad.button != MouseInput::MouseButton::Undefined) {
193 params.Set("engine", "mouse");
194 params.Set("button", static_cast<u16>(pad.button));
195 return params;
196 }
197 }
198 return params;
199}
200
201void MouseMotionFactory::BeginConfiguration() {
202 polling = true;
203 mouse_input->BeginConfiguration();
204}
205
206void MouseMotionFactory::EndConfiguration() {
207 polling = false;
208 mouse_input->EndConfiguration();
209}
210
211class MouseTouch final : public Input::TouchDevice {
212public:
213 explicit MouseTouch(u32 button_, const MouseInput::Mouse* mouse_input_)
214 : button(button_), mouse_input(mouse_input_) {}
215
216 Input::TouchStatus GetStatus() const override {
217 return mouse_input->GetMouseState(button).touch;
218 }
219
220private:
221 const u32 button;
222 const MouseInput::Mouse* mouse_input;
223};
224
225MouseTouchFactory::MouseTouchFactory(std::shared_ptr<MouseInput::Mouse> mouse_input_)
226 : mouse_input(std::move(mouse_input_)) {}
227
228std::unique_ptr<Input::TouchDevice> MouseTouchFactory::Create(const Common::ParamPackage& params) {
229 const auto button_id = params.Get("button", 0);
230
231 return std::make_unique<MouseTouch>(button_id, mouse_input.get());
232}
233
234Common::ParamPackage MouseTouchFactory::GetNextInput() const {
235 MouseInput::MouseStatus pad;
236 Common::ParamPackage params;
237 auto& queue = mouse_input->GetMouseQueue();
238 while (queue.Pop(pad)) {
239 // This while loop will break on the earliest detected button
240 if (pad.button != MouseInput::MouseButton::Undefined) {
241 params.Set("engine", "mouse");
242 params.Set("button", static_cast<u16>(pad.button));
243 return params;
244 }
245 }
246 return params;
247}
248
249void MouseTouchFactory::BeginConfiguration() {
250 polling = true;
251 mouse_input->BeginConfiguration();
252}
253
254void MouseTouchFactory::EndConfiguration() {
255 polling = false;
256 mouse_input->EndConfiguration();
257}
258
259} // namespace InputCommon
diff --git a/src/input_common/mouse/mouse_poller.h b/src/input_common/mouse/mouse_poller.h
new file mode 100644
index 000000000..cf331293b
--- /dev/null
+++ b/src/input_common/mouse/mouse_poller.h
@@ -0,0 +1,109 @@
1// Copyright 2020 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <memory>
8#include "core/frontend/input.h"
9#include "input_common/mouse/mouse_input.h"
10
11namespace InputCommon {
12
13/**
14 * A button device factory representing a mouse. It receives mouse events and forward them
15 * to all button devices it created.
16 */
17class MouseButtonFactory final : public Input::Factory<Input::ButtonDevice> {
18public:
19 explicit MouseButtonFactory(std::shared_ptr<MouseInput::Mouse> mouse_input_);
20
21 /**
22 * Creates a button device from a button press
23 * @param params contains parameters for creating the device:
24 * - "code": the code of the key to bind with the button
25 */
26 std::unique_ptr<Input::ButtonDevice> Create(const Common::ParamPackage& params) override;
27
28 Common::ParamPackage GetNextInput() const;
29
30 /// For device input configuration/polling
31 void BeginConfiguration();
32 void EndConfiguration();
33
34 bool IsPolling() const {
35 return polling;
36 }
37
38private:
39 std::shared_ptr<MouseInput::Mouse> mouse_input;
40 bool polling = false;
41};
42
43/// An analog device factory that creates analog devices from mouse
44class MouseAnalogFactory final : public Input::Factory<Input::AnalogDevice> {
45public:
46 explicit MouseAnalogFactory(std::shared_ptr<MouseInput::Mouse> mouse_input_);
47
48 std::unique_ptr<Input::AnalogDevice> Create(const Common::ParamPackage& params) override;
49
50 Common::ParamPackage GetNextInput() const;
51
52 /// For device input configuration/polling
53 void BeginConfiguration();
54 void EndConfiguration();
55
56 bool IsPolling() const {
57 return polling;
58 }
59
60private:
61 std::shared_ptr<MouseInput::Mouse> mouse_input;
62 bool polling = false;
63};
64
65/// A motion device factory that creates motion devices from mouse
66class MouseMotionFactory final : public Input::Factory<Input::MotionDevice> {
67public:
68 explicit MouseMotionFactory(std::shared_ptr<MouseInput::Mouse> mouse_input_);
69
70 std::unique_ptr<Input::MotionDevice> Create(const Common::ParamPackage& params) override;
71
72 Common::ParamPackage GetNextInput() const;
73
74 /// For device input configuration/polling
75 void BeginConfiguration();
76 void EndConfiguration();
77
78 bool IsPolling() const {
79 return polling;
80 }
81
82private:
83 std::shared_ptr<MouseInput::Mouse> mouse_input;
84 bool polling = false;
85};
86
87/// An touch device factory that creates touch devices from mouse
88class MouseTouchFactory final : public Input::Factory<Input::TouchDevice> {
89public:
90 explicit MouseTouchFactory(std::shared_ptr<MouseInput::Mouse> mouse_input_);
91
92 std::unique_ptr<Input::TouchDevice> Create(const Common::ParamPackage& params) override;
93
94 Common::ParamPackage GetNextInput() const;
95
96 /// For device input configuration/polling
97 void BeginConfiguration();
98 void EndConfiguration();
99
100 bool IsPolling() const {
101 return polling;
102 }
103
104private:
105 std::shared_ptr<MouseInput::Mouse> mouse_input;
106 bool polling = false;
107};
108
109} // namespace InputCommon
diff --git a/src/input_common/udp/client.cpp b/src/input_common/udp/client.cpp
index c0bb90048..17a9225d7 100644
--- a/src/input_common/udp/client.cpp
+++ b/src/input_common/udp/client.cpp
@@ -136,15 +136,7 @@ static void SocketLoop(Socket* socket) {
136 136
137Client::Client() { 137Client::Client() {
138 LOG_INFO(Input, "Udp Initialization started"); 138 LOG_INFO(Input, "Udp Initialization started");
139 for (std::size_t client = 0; client < clients.size(); client++) { 139 ReloadSockets();
140 const auto pad = client % 4;
141 StartCommunication(client, Settings::values.udp_input_address,
142 Settings::values.udp_input_port, pad, 24872);
143 // Set motion parameters
144 // SetGyroThreshold value should be dependent on GyroscopeZeroDriftMode
145 // Real HW values are unknown, 0.0001 is an approximate to Standard
146 clients[client].motion.SetGyroThreshold(0.0001f);
147 }
148} 140}
149 141
150Client::~Client() { 142Client::~Client() {
@@ -167,26 +159,61 @@ std::vector<Common::ParamPackage> Client::GetInputDevices() const {
167 return devices; 159 return devices;
168} 160}
169 161
170bool Client::DeviceConnected(std::size_t pad) const { 162bool Client::DeviceConnected(std::size_t client) const {
171 // Use last timestamp to detect if the socket has stopped sending data 163 // Use last timestamp to detect if the socket has stopped sending data
172 const auto now = std::chrono::system_clock::now(); 164 const auto now = std::chrono::steady_clock::now();
173 const auto time_difference = static_cast<u64>( 165 const auto time_difference =
174 std::chrono::duration_cast<std::chrono::milliseconds>(now - clients[pad].last_motion_update) 166 static_cast<u64>(std::chrono::duration_cast<std::chrono::milliseconds>(
175 .count()); 167 now - clients[client].last_motion_update)
176 return time_difference < 1000 && clients[pad].active == 1; 168 .count());
169 return time_difference < 1000 && clients[client].active == 1;
177} 170}
178 171
179void Client::ReloadUDPClient() { 172void Client::ReloadSockets() {
180 for (std::size_t client = 0; client < clients.size(); client++) { 173 Reset();
181 ReloadSocket(Settings::values.udp_input_address, Settings::values.udp_input_port, client); 174
175 std::stringstream servers_ss(Settings::values.udp_input_servers);
176 std::string server_token;
177 std::size_t client = 0;
178 while (std::getline(servers_ss, server_token, ',')) {
179 if (client == max_udp_clients) {
180 break;
181 }
182 std::stringstream server_ss(server_token);
183 std::string token;
184 std::getline(server_ss, token, ':');
185 std::string udp_input_address = token;
186 std::getline(server_ss, token, ':');
187 char* temp;
188 const u16 udp_input_port = static_cast<u16>(std::strtol(token.c_str(), &temp, 0));
189 if (*temp != '\0') {
190 LOG_ERROR(Input, "Port number is not valid {}", token);
191 continue;
192 }
193
194 for (std::size_t pad = 0; pad < 4; ++pad) {
195 const std::size_t client_number =
196 GetClientNumber(udp_input_address, udp_input_port, pad);
197 if (client_number != max_udp_clients) {
198 LOG_ERROR(Input, "Duplicated UDP servers found");
199 continue;
200 }
201 StartCommunication(client++, udp_input_address, udp_input_port, pad, 24872);
202 }
182 } 203 }
183} 204}
184void Client::ReloadSocket(const std::string& host, u16 port, std::size_t pad_index, u32 client_id) { 205
185 // client number must be determined from host / port and pad index 206std::size_t Client::GetClientNumber(std::string_view host, u16 port, std::size_t pad) const {
186 const std::size_t client = pad_index; 207 for (std::size_t client = 0; client < clients.size(); client++) {
187 clients[client].socket->Stop(); 208 if (clients[client].active == -1) {
188 clients[client].thread.join(); 209 continue;
189 StartCommunication(client, host, port, pad_index, client_id); 210 }
211 if (clients[client].host == host && clients[client].port == port &&
212 clients[client].pad_index == pad) {
213 return client;
214 }
215 }
216 return max_udp_clients;
190} 217}
191 218
192void Client::OnVersion([[maybe_unused]] Response::Version data) { 219void Client::OnVersion([[maybe_unused]] Response::Version data) {
@@ -197,9 +224,7 @@ void Client::OnPortInfo([[maybe_unused]] Response::PortInfo data) {
197 LOG_TRACE(Input, "PortInfo packet received: {}", data.model); 224 LOG_TRACE(Input, "PortInfo packet received: {}", data.model);
198} 225}
199 226
200void Client::OnPadData(Response::PadData data) { 227void Client::OnPadData(Response::PadData data, std::size_t client) {
201 // Client number must be determined from host / port and pad index
202 const std::size_t client = data.info.id;
203 LOG_TRACE(Input, "PadData packet received"); 228 LOG_TRACE(Input, "PadData packet received");
204 if (data.packet_counter == clients[client].packet_sequence) { 229 if (data.packet_counter == clients[client].packet_sequence) {
205 LOG_WARNING( 230 LOG_WARNING(
@@ -208,9 +233,9 @@ void Client::OnPadData(Response::PadData data) {
208 clients[client].packet_sequence, data.packet_counter); 233 clients[client].packet_sequence, data.packet_counter);
209 return; 234 return;
210 } 235 }
211 clients[client].active = data.info.is_pad_active; 236 clients[client].active = static_cast<s8>(data.info.is_pad_active);
212 clients[client].packet_sequence = data.packet_counter; 237 clients[client].packet_sequence = data.packet_counter;
213 const auto now = std::chrono::system_clock::now(); 238 const auto now = std::chrono::steady_clock::now();
214 const auto time_difference = 239 const auto time_difference =
215 static_cast<u64>(std::chrono::duration_cast<std::chrono::microseconds>( 240 static_cast<u64>(std::chrono::duration_cast<std::chrono::microseconds>(
216 now - clients[client].last_motion_update) 241 now - clients[client].last_motion_update)
@@ -264,16 +289,28 @@ void Client::StartCommunication(std::size_t client, const std::string& host, u16
264 std::size_t pad_index, u32 client_id) { 289 std::size_t pad_index, u32 client_id) {
265 SocketCallback callback{[this](Response::Version version) { OnVersion(version); }, 290 SocketCallback callback{[this](Response::Version version) { OnVersion(version); },
266 [this](Response::PortInfo info) { OnPortInfo(info); }, 291 [this](Response::PortInfo info) { OnPortInfo(info); },
267 [this](Response::PadData data) { OnPadData(data); }}; 292 [this, client](Response::PadData data) { OnPadData(data, client); }};
268 LOG_INFO(Input, "Starting communication with UDP input server on {}:{}", host, port); 293 LOG_INFO(Input, "Starting communication with UDP input server on {}:{}:{}", host, port,
294 pad_index);
295 clients[client].host = host;
296 clients[client].port = port;
297 clients[client].pad_index = pad_index;
298 clients[client].active = 0;
269 clients[client].socket = std::make_unique<Socket>(host, port, pad_index, client_id, callback); 299 clients[client].socket = std::make_unique<Socket>(host, port, pad_index, client_id, callback);
270 clients[client].thread = std::thread{SocketLoop, clients[client].socket.get()}; 300 clients[client].thread = std::thread{SocketLoop, clients[client].socket.get()};
301 // Set motion parameters
302 // SetGyroThreshold value should be dependent on GyroscopeZeroDriftMode
303 // Real HW values are unknown, 0.0001 is an approximate to Standard
304 clients[client].motion.SetGyroThreshold(0.0001f);
271} 305}
272 306
273void Client::Reset() { 307void Client::Reset() {
274 for (auto& client : clients) { 308 for (auto& client : clients) {
275 client.socket->Stop(); 309 if (client.thread.joinable()) {
276 client.thread.join(); 310 client.active = -1;
311 client.socket->Stop();
312 client.thread.join();
313 }
277 } 314 }
278} 315}
279 316
@@ -283,52 +320,60 @@ void Client::UpdateYuzuSettings(std::size_t client, const Common::Vec3<float>& a
283 LOG_DEBUG(Input, "UDP Controller {}: gyro=({}, {}, {}), accel=({}, {}, {}), touch={}", 320 LOG_DEBUG(Input, "UDP Controller {}: gyro=({}, {}, {}), accel=({}, {}, {}), touch={}",
284 client, gyro[0], gyro[1], gyro[2], acc[0], acc[1], acc[2], touch); 321 client, gyro[0], gyro[1], gyro[2], acc[0], acc[1], acc[2], touch);
285 } 322 }
286 UDPPadStatus pad; 323 UDPPadStatus pad{
324 .host = clients[client].host,
325 .port = clients[client].port,
326 .pad_index = clients[client].pad_index,
327 };
287 if (touch) { 328 if (touch) {
288 pad.touch = PadTouch::Click; 329 pad.touch = PadTouch::Click;
289 pad_queue[client].Push(pad); 330 pad_queue.Push(pad);
290 } 331 }
291 for (size_t i = 0; i < 3; ++i) { 332 for (size_t i = 0; i < 3; ++i) {
292 if (gyro[i] > 5.0f || gyro[i] < -5.0f) { 333 if (gyro[i] > 5.0f || gyro[i] < -5.0f) {
293 pad.motion = static_cast<PadMotion>(i); 334 pad.motion = static_cast<PadMotion>(i);
294 pad.motion_value = gyro[i]; 335 pad.motion_value = gyro[i];
295 pad_queue[client].Push(pad); 336 pad_queue.Push(pad);
296 } 337 }
297 if (acc[i] > 1.75f || acc[i] < -1.75f) { 338 if (acc[i] > 1.75f || acc[i] < -1.75f) {
298 pad.motion = static_cast<PadMotion>(i + 3); 339 pad.motion = static_cast<PadMotion>(i + 3);
299 pad.motion_value = acc[i]; 340 pad.motion_value = acc[i];
300 pad_queue[client].Push(pad); 341 pad_queue.Push(pad);
301 } 342 }
302 } 343 }
303} 344}
304 345
305void Client::BeginConfiguration() { 346void Client::BeginConfiguration() {
306 for (auto& pq : pad_queue) { 347 pad_queue.Clear();
307 pq.Clear();
308 }
309 configuring = true; 348 configuring = true;
310} 349}
311 350
312void Client::EndConfiguration() { 351void Client::EndConfiguration() {
313 for (auto& pq : pad_queue) { 352 pad_queue.Clear();
314 pq.Clear();
315 }
316 configuring = false; 353 configuring = false;
317} 354}
318 355
319DeviceStatus& Client::GetPadState(std::size_t pad) { 356DeviceStatus& Client::GetPadState(const std::string& host, u16 port, std::size_t pad) {
320 return clients[pad].status; 357 const std::size_t client_number = GetClientNumber(host, port, pad);
358 if (client_number == max_udp_clients) {
359 return clients[0].status;
360 }
361 return clients[client_number].status;
321} 362}
322 363
323const DeviceStatus& Client::GetPadState(std::size_t pad) const { 364const DeviceStatus& Client::GetPadState(const std::string& host, u16 port, std::size_t pad) const {
324 return clients[pad].status; 365 const std::size_t client_number = GetClientNumber(host, port, pad);
366 if (client_number == max_udp_clients) {
367 return clients[0].status;
368 }
369 return clients[client_number].status;
325} 370}
326 371
327std::array<Common::SPSCQueue<UDPPadStatus>, 4>& Client::GetPadQueue() { 372Common::SPSCQueue<UDPPadStatus>& Client::GetPadQueue() {
328 return pad_queue; 373 return pad_queue;
329} 374}
330 375
331const std::array<Common::SPSCQueue<UDPPadStatus>, 4>& Client::GetPadQueue() const { 376const Common::SPSCQueue<UDPPadStatus>& Client::GetPadQueue() const {
332 return pad_queue; 377 return pad_queue;
333} 378}
334 379
diff --git a/src/input_common/udp/client.h b/src/input_common/udp/client.h
index 747e0c0a2..00c8b09f5 100644
--- a/src/input_common/udp/client.h
+++ b/src/input_common/udp/client.h
@@ -21,8 +21,7 @@
21 21
22namespace InputCommon::CemuhookUDP { 22namespace InputCommon::CemuhookUDP {
23 23
24constexpr u16 DEFAULT_PORT = 26760; 24constexpr char DEFAULT_SRV[] = "127.0.0.1:26760";
25constexpr char DEFAULT_ADDR[] = "127.0.0.1";
26 25
27class Socket; 26class Socket;
28 27
@@ -48,6 +47,9 @@ enum class PadTouch {
48}; 47};
49 48
50struct UDPPadStatus { 49struct UDPPadStatus {
50 std::string host{"127.0.0.1"};
51 u16 port{26760};
52 std::size_t pad_index{};
51 PadTouch touch{PadTouch::Undefined}; 53 PadTouch touch{PadTouch::Undefined};
52 PadMotion motion{PadMotion::Undefined}; 54 PadMotion motion{PadMotion::Undefined};
53 f32 motion_value{0.0f}; 55 f32 motion_value{0.0f};
@@ -82,37 +84,41 @@ public:
82 84
83 std::vector<Common::ParamPackage> GetInputDevices() const; 85 std::vector<Common::ParamPackage> GetInputDevices() const;
84 86
85 bool DeviceConnected(std::size_t pad) const; 87 bool DeviceConnected(std::size_t client) const;
86 void ReloadUDPClient(); 88 void ReloadSockets();
87 void ReloadSocket(const std::string& host = "127.0.0.1", u16 port = 26760,
88 std::size_t pad_index = 0, u32 client_id = 24872);
89 89
90 std::array<Common::SPSCQueue<UDPPadStatus>, 4>& GetPadQueue(); 90 Common::SPSCQueue<UDPPadStatus>& GetPadQueue();
91 const std::array<Common::SPSCQueue<UDPPadStatus>, 4>& GetPadQueue() const; 91 const Common::SPSCQueue<UDPPadStatus>& GetPadQueue() const;
92 92
93 DeviceStatus& GetPadState(std::size_t pad); 93 DeviceStatus& GetPadState(const std::string& host, u16 port, std::size_t pad);
94 const DeviceStatus& GetPadState(std::size_t pad) const; 94 const DeviceStatus& GetPadState(const std::string& host, u16 port, std::size_t pad) const;
95 95
96private: 96private:
97 struct ClientData { 97 struct ClientData {
98 std::string host{"127.0.0.1"};
99 u16 port{26760};
100 std::size_t pad_index{};
98 std::unique_ptr<Socket> socket; 101 std::unique_ptr<Socket> socket;
99 DeviceStatus status; 102 DeviceStatus status;
100 std::thread thread; 103 std::thread thread;
101 u64 packet_sequence = 0; 104 u64 packet_sequence{};
102 u8 active = 0; 105 s8 active{-1};
103 106
104 // Realtime values 107 // Realtime values
105 // motion is initalized with PID values for drift correction on joycons 108 // motion is initalized with PID values for drift correction on joycons
106 InputCommon::MotionInput motion{0.3f, 0.005f, 0.0f}; 109 InputCommon::MotionInput motion{0.3f, 0.005f, 0.0f};
107 std::chrono::time_point<std::chrono::system_clock> last_motion_update; 110 std::chrono::time_point<std::chrono::steady_clock> last_motion_update;
108 }; 111 };
109 112
110 // For shutting down, clear all data, join all threads, release usb 113 // For shutting down, clear all data, join all threads, release usb
111 void Reset(); 114 void Reset();
112 115
116 // Translates configuration to client number
117 std::size_t GetClientNumber(std::string_view host, u16 port, std::size_t pad) const;
118
113 void OnVersion(Response::Version); 119 void OnVersion(Response::Version);
114 void OnPortInfo(Response::PortInfo); 120 void OnPortInfo(Response::PortInfo);
115 void OnPadData(Response::PadData); 121 void OnPadData(Response::PadData, std::size_t client);
116 void StartCommunication(std::size_t client, const std::string& host, u16 port, 122 void StartCommunication(std::size_t client, const std::string& host, u16 port,
117 std::size_t pad_index, u32 client_id); 123 std::size_t pad_index, u32 client_id);
118 void UpdateYuzuSettings(std::size_t client, const Common::Vec3<float>& acc, 124 void UpdateYuzuSettings(std::size_t client, const Common::Vec3<float>& acc,
@@ -120,8 +126,10 @@ private:
120 126
121 bool configuring = false; 127 bool configuring = false;
122 128
123 std::array<ClientData, 4> clients; 129 // Allocate clients for 8 udp servers
124 std::array<Common::SPSCQueue<UDPPadStatus>, 4> pad_queue; 130 const std::size_t max_udp_clients = 32;
131 std::array<ClientData, 4 * 8> clients;
132 Common::SPSCQueue<UDPPadStatus> pad_queue;
125}; 133};
126 134
127/// An async job allowing configuration of the touchpad calibration. 135/// An async job allowing configuration of the touchpad calibration.
diff --git a/src/input_common/udp/udp.cpp b/src/input_common/udp/udp.cpp
index 71a76a7aa..8686a059c 100644
--- a/src/input_common/udp/udp.cpp
+++ b/src/input_common/udp/udp.cpp
@@ -13,17 +13,17 @@ namespace InputCommon {
13 13
14class UDPMotion final : public Input::MotionDevice { 14class UDPMotion final : public Input::MotionDevice {
15public: 15public:
16 explicit UDPMotion(std::string ip_, int port_, u32 pad_, CemuhookUDP::Client* client_) 16 explicit UDPMotion(std::string ip_, u16 port_, u16 pad_, CemuhookUDP::Client* client_)
17 : ip(std::move(ip_)), port(port_), pad(pad_), client(client_) {} 17 : ip(std::move(ip_)), port(port_), pad(pad_), client(client_) {}
18 18
19 Input::MotionStatus GetStatus() const override { 19 Input::MotionStatus GetStatus() const override {
20 return client->GetPadState(pad).motion_status; 20 return client->GetPadState(ip, port, pad).motion_status;
21 } 21 }
22 22
23private: 23private:
24 const std::string ip; 24 const std::string ip;
25 const int port; 25 const u16 port;
26 const u32 pad; 26 const u16 pad;
27 CemuhookUDP::Client* client; 27 CemuhookUDP::Client* client;
28 mutable std::mutex mutex; 28 mutable std::mutex mutex;
29}; 29};
@@ -39,8 +39,8 @@ UDPMotionFactory::UDPMotionFactory(std::shared_ptr<CemuhookUDP::Client> client_)
39 */ 39 */
40std::unique_ptr<Input::MotionDevice> UDPMotionFactory::Create(const Common::ParamPackage& params) { 40std::unique_ptr<Input::MotionDevice> UDPMotionFactory::Create(const Common::ParamPackage& params) {
41 auto ip = params.Get("ip", "127.0.0.1"); 41 auto ip = params.Get("ip", "127.0.0.1");
42 const auto port = params.Get("port", 26760); 42 const auto port = static_cast<u16>(params.Get("port", 26760));
43 const auto pad = static_cast<u32>(params.Get("pad_index", 0)); 43 const auto pad = static_cast<u16>(params.Get("pad_index", 0));
44 44
45 return std::make_unique<UDPMotion>(std::move(ip), port, pad, client.get()); 45 return std::make_unique<UDPMotion>(std::move(ip), port, pad, client.get());
46} 46}
@@ -59,35 +59,33 @@ Common::ParamPackage UDPMotionFactory::GetNextInput() {
59 Common::ParamPackage params; 59 Common::ParamPackage params;
60 CemuhookUDP::UDPPadStatus pad; 60 CemuhookUDP::UDPPadStatus pad;
61 auto& queue = client->GetPadQueue(); 61 auto& queue = client->GetPadQueue();
62 for (std::size_t pad_number = 0; pad_number < queue.size(); ++pad_number) { 62 while (queue.Pop(pad)) {
63 while (queue[pad_number].Pop(pad)) { 63 if (pad.motion == CemuhookUDP::PadMotion::Undefined || std::abs(pad.motion_value) < 1) {
64 if (pad.motion == CemuhookUDP::PadMotion::Undefined || std::abs(pad.motion_value) < 1) { 64 continue;
65 continue;
66 }
67 params.Set("engine", "cemuhookudp");
68 params.Set("ip", "127.0.0.1");
69 params.Set("port", 26760);
70 params.Set("pad_index", static_cast<int>(pad_number));
71 params.Set("motion", static_cast<u16>(pad.motion));
72 return params;
73 } 65 }
66 params.Set("engine", "cemuhookudp");
67 params.Set("ip", pad.host);
68 params.Set("port", static_cast<u16>(pad.port));
69 params.Set("pad_index", static_cast<u16>(pad.pad_index));
70 params.Set("motion", static_cast<u16>(pad.motion));
71 return params;
74 } 72 }
75 return params; 73 return params;
76} 74}
77 75
78class UDPTouch final : public Input::TouchDevice { 76class UDPTouch final : public Input::TouchDevice {
79public: 77public:
80 explicit UDPTouch(std::string ip_, int port_, u32 pad_, CemuhookUDP::Client* client_) 78 explicit UDPTouch(std::string ip_, u16 port_, u16 pad_, CemuhookUDP::Client* client_)
81 : ip(std::move(ip_)), port(port_), pad(pad_), client(client_) {} 79 : ip(std::move(ip_)), port(port_), pad(pad_), client(client_) {}
82 80
83 std::tuple<float, float, bool> GetStatus() const override { 81 std::tuple<float, float, bool> GetStatus() const override {
84 return client->GetPadState(pad).touch_status; 82 return client->GetPadState(ip, port, pad).touch_status;
85 } 83 }
86 84
87private: 85private:
88 const std::string ip; 86 const std::string ip;
89 const int port; 87 const u16 port;
90 const u32 pad; 88 const u16 pad;
91 CemuhookUDP::Client* client; 89 CemuhookUDP::Client* client;
92 mutable std::mutex mutex; 90 mutable std::mutex mutex;
93}; 91};
@@ -103,8 +101,8 @@ UDPTouchFactory::UDPTouchFactory(std::shared_ptr<CemuhookUDP::Client> client_)
103 */ 101 */
104std::unique_ptr<Input::TouchDevice> UDPTouchFactory::Create(const Common::ParamPackage& params) { 102std::unique_ptr<Input::TouchDevice> UDPTouchFactory::Create(const Common::ParamPackage& params) {
105 auto ip = params.Get("ip", "127.0.0.1"); 103 auto ip = params.Get("ip", "127.0.0.1");
106 const auto port = params.Get("port", 26760); 104 const auto port = static_cast<u16>(params.Get("port", 26760));
107 const auto pad = static_cast<u32>(params.Get("pad_index", 0)); 105 const auto pad = static_cast<u16>(params.Get("pad_index", 0));
108 106
109 return std::make_unique<UDPTouch>(std::move(ip), port, pad, client.get()); 107 return std::make_unique<UDPTouch>(std::move(ip), port, pad, client.get());
110} 108}
@@ -123,18 +121,16 @@ Common::ParamPackage UDPTouchFactory::GetNextInput() {
123 Common::ParamPackage params; 121 Common::ParamPackage params;
124 CemuhookUDP::UDPPadStatus pad; 122 CemuhookUDP::UDPPadStatus pad;
125 auto& queue = client->GetPadQueue(); 123 auto& queue = client->GetPadQueue();
126 for (std::size_t pad_number = 0; pad_number < queue.size(); ++pad_number) { 124 while (queue.Pop(pad)) {
127 while (queue[pad_number].Pop(pad)) { 125 if (pad.touch == CemuhookUDP::PadTouch::Undefined) {
128 if (pad.touch == CemuhookUDP::PadTouch::Undefined) { 126 continue;
129 continue;
130 }
131 params.Set("engine", "cemuhookudp");
132 params.Set("ip", "127.0.0.1");
133 params.Set("port", 26760);
134 params.Set("pad_index", static_cast<int>(pad_number));
135 params.Set("touch", static_cast<u16>(pad.touch));
136 return params;
137 } 127 }
128 params.Set("engine", "cemuhookudp");
129 params.Set("ip", pad.host);
130 params.Set("port", static_cast<u16>(pad.port));
131 params.Set("pad_index", static_cast<u16>(pad.pad_index));
132 params.Set("touch", static_cast<u16>(pad.touch));
133 return params;
138 } 134 }
139 return params; 135 return params;
140} 136}
diff --git a/src/video_core/command_classes/codecs/codec.cpp b/src/video_core/command_classes/codecs/codec.cpp
index 1adf3cd13..9a88f64e4 100644
--- a/src/video_core/command_classes/codecs/codec.cpp
+++ b/src/video_core/command_classes/codecs/codec.cpp
@@ -18,6 +18,11 @@ extern "C" {
18 18
19namespace Tegra { 19namespace Tegra {
20 20
21void AVFrameDeleter(AVFrame* ptr) {
22 av_frame_unref(ptr);
23 av_free(ptr);
24}
25
21Codec::Codec(GPU& gpu_) 26Codec::Codec(GPU& gpu_)
22 : gpu(gpu_), h264_decoder(std::make_unique<Decoder::H264>(gpu)), 27 : gpu(gpu_), h264_decoder(std::make_unique<Decoder::H264>(gpu)),
23 vp9_decoder(std::make_unique<Decoder::VP9>(gpu)) {} 28 vp9_decoder(std::make_unique<Decoder::VP9>(gpu)) {}
@@ -27,7 +32,9 @@ Codec::~Codec() {
27 return; 32 return;
28 } 33 }
29 // Free libav memory 34 // Free libav memory
35 AVFrame* av_frame{nullptr};
30 avcodec_send_packet(av_codec_ctx, nullptr); 36 avcodec_send_packet(av_codec_ctx, nullptr);
37 av_frame = av_frame_alloc();
31 avcodec_receive_frame(av_codec_ctx, av_frame); 38 avcodec_receive_frame(av_codec_ctx, av_frame);
32 avcodec_flush_buffers(av_codec_ctx); 39 avcodec_flush_buffers(av_codec_ctx);
33 40
@@ -60,7 +67,7 @@ void Codec::Decode() {
60 } 67 }
61 68
62 av_codec_ctx = avcodec_alloc_context3(av_codec); 69 av_codec_ctx = avcodec_alloc_context3(av_codec);
63 av_frame = av_frame_alloc(); 70 av_codec_ctx->refcounted_frames = 1;
64 av_opt_set(av_codec_ctx->priv_data, "tune", "zerolatency", 0); 71 av_opt_set(av_codec_ctx->priv_data, "tune", "zerolatency", 0);
65 72
66 // TODO(ameerj): libavcodec gpu hw acceleration 73 // TODO(ameerj): libavcodec gpu hw acceleration
@@ -68,8 +75,6 @@ void Codec::Decode() {
68 const auto av_error = avcodec_open2(av_codec_ctx, av_codec, nullptr); 75 const auto av_error = avcodec_open2(av_codec_ctx, av_codec, nullptr);
69 if (av_error < 0) { 76 if (av_error < 0) {
70 LOG_ERROR(Service_NVDRV, "avcodec_open2() Failed."); 77 LOG_ERROR(Service_NVDRV, "avcodec_open2() Failed.");
71 av_frame_unref(av_frame);
72 av_free(av_frame);
73 avcodec_close(av_codec_ctx); 78 avcodec_close(av_codec_ctx);
74 return; 79 return;
75 } 80 }
@@ -96,16 +101,26 @@ void Codec::Decode() {
96 101
97 if (!vp9_hidden_frame) { 102 if (!vp9_hidden_frame) {
98 // Only receive/store visible frames 103 // Only receive/store visible frames
99 avcodec_receive_frame(av_codec_ctx, av_frame); 104 AVFramePtr frame = AVFramePtr{av_frame_alloc(), AVFrameDeleter};
105 avcodec_receive_frame(av_codec_ctx, frame.get());
106 av_frames.push(std::move(frame));
107 // Limit queue to 10 frames. Workaround for ZLA decode and queue spam
108 if (av_frames.size() > 10) {
109 av_frames.pop();
110 }
100 } 111 }
101} 112}
102 113
103AVFrame* Codec::GetCurrentFrame() { 114AVFramePtr Codec::GetCurrentFrame() {
104 return av_frame; 115 // Sometimes VIC will request more frames than have been decoded.
105} 116 // in this case, return a nullptr and don't overwrite previous frame data
117 if (av_frames.empty()) {
118 return AVFramePtr{nullptr, AVFrameDeleter};
119 }
106 120
107const AVFrame* Codec::GetCurrentFrame() const { 121 AVFramePtr frame = std::move(av_frames.front());
108 return av_frame; 122 av_frames.pop();
123 return frame;
109} 124}
110 125
111NvdecCommon::VideoCodec Codec::GetCurrentCodec() const { 126NvdecCommon::VideoCodec Codec::GetCurrentCodec() const {
diff --git a/src/video_core/command_classes/codecs/codec.h b/src/video_core/command_classes/codecs/codec.h
index ee5d62540..8a2a6c360 100644
--- a/src/video_core/command_classes/codecs/codec.h
+++ b/src/video_core/command_classes/codecs/codec.h
@@ -5,6 +5,7 @@
5#pragma once 5#pragma once
6 6
7#include <memory> 7#include <memory>
8#include <queue>
8#include "common/common_types.h" 9#include "common/common_types.h"
9#include "video_core/command_classes/nvdec_common.h" 10#include "video_core/command_classes/nvdec_common.h"
10 11
@@ -23,6 +24,9 @@ namespace Tegra {
23class GPU; 24class GPU;
24struct VicRegisters; 25struct VicRegisters;
25 26
27void AVFrameDeleter(AVFrame* ptr);
28using AVFramePtr = std::unique_ptr<AVFrame, decltype(&AVFrameDeleter)>;
29
26namespace Decoder { 30namespace Decoder {
27class H264; 31class H264;
28class VP9; 32class VP9;
@@ -42,9 +46,8 @@ public:
42 /// Call decoders to construct headers, decode AVFrame with ffmpeg 46 /// Call decoders to construct headers, decode AVFrame with ffmpeg
43 void Decode(); 47 void Decode();
44 48
45 /// Returns most recently decoded frame 49 /// Returns next decoded frame
46 [[nodiscard]] AVFrame* GetCurrentFrame(); 50 [[nodiscard]] AVFramePtr GetCurrentFrame();
47 [[nodiscard]] const AVFrame* GetCurrentFrame() const;
48 51
49 /// Returns the value of current_codec 52 /// Returns the value of current_codec
50 [[nodiscard]] NvdecCommon::VideoCodec GetCurrentCodec() const; 53 [[nodiscard]] NvdecCommon::VideoCodec GetCurrentCodec() const;
@@ -55,13 +58,13 @@ private:
55 58
56 AVCodec* av_codec{nullptr}; 59 AVCodec* av_codec{nullptr};
57 AVCodecContext* av_codec_ctx{nullptr}; 60 AVCodecContext* av_codec_ctx{nullptr};
58 AVFrame* av_frame{nullptr};
59 61
60 GPU& gpu; 62 GPU& gpu;
61 std::unique_ptr<Decoder::H264> h264_decoder; 63 std::unique_ptr<Decoder::H264> h264_decoder;
62 std::unique_ptr<Decoder::VP9> vp9_decoder; 64 std::unique_ptr<Decoder::VP9> vp9_decoder;
63 65
64 NvdecCommon::NvdecRegisters state{}; 66 NvdecCommon::NvdecRegisters state{};
67 std::queue<AVFramePtr> av_frames{};
65}; 68};
66 69
67} // namespace Tegra 70} // namespace Tegra
diff --git a/src/video_core/command_classes/codecs/h264.cpp b/src/video_core/command_classes/codecs/h264.cpp
index 33e063e20..65bbeac78 100644
--- a/src/video_core/command_classes/codecs/h264.cpp
+++ b/src/video_core/command_classes/codecs/h264.cpp
@@ -43,7 +43,7 @@ H264::H264(GPU& gpu_) : gpu(gpu_) {}
43 43
44H264::~H264() = default; 44H264::~H264() = default;
45 45
46const std::vector<u8>& H264::ComposeFrameHeader(NvdecCommon::NvdecRegisters& state, 46const std::vector<u8>& H264::ComposeFrameHeader(const NvdecCommon::NvdecRegisters& state,
47 bool is_first_frame) { 47 bool is_first_frame) {
48 H264DecoderContext context{}; 48 H264DecoderContext context{};
49 gpu.MemoryManager().ReadBlock(state.picture_info_offset, &context, sizeof(H264DecoderContext)); 49 gpu.MemoryManager().ReadBlock(state.picture_info_offset, &context, sizeof(H264DecoderContext));
diff --git a/src/video_core/command_classes/codecs/h264.h b/src/video_core/command_classes/codecs/h264.h
index 273449495..0f3a1d9f3 100644
--- a/src/video_core/command_classes/codecs/h264.h
+++ b/src/video_core/command_classes/codecs/h264.h
@@ -74,8 +74,8 @@ public:
74 ~H264(); 74 ~H264();
75 75
76 /// Compose the H264 header of the frame for FFmpeg decoding 76 /// Compose the H264 header of the frame for FFmpeg decoding
77 [[nodiscard]] const std::vector<u8>& ComposeFrameHeader(NvdecCommon::NvdecRegisters& state, 77 [[nodiscard]] const std::vector<u8>& ComposeFrameHeader(
78 bool is_first_frame = false); 78 const NvdecCommon::NvdecRegisters& state, bool is_first_frame = false);
79 79
80private: 80private:
81 struct H264ParameterSet { 81 struct H264ParameterSet {
diff --git a/src/video_core/command_classes/codecs/vp9.cpp b/src/video_core/command_classes/codecs/vp9.cpp
index ab44fdc9e..b1d675cdb 100644
--- a/src/video_core/command_classes/codecs/vp9.cpp
+++ b/src/video_core/command_classes/codecs/vp9.cpp
@@ -23,122 +23,102 @@ constexpr Vp9EntropyProbs default_probs{
23 222, 34, 30, 0, 72, 16, 44, 0, 58, 32, 12, 0, 10, 7, 6, 0, 23 222, 34, 30, 0, 72, 16, 44, 0, 58, 32, 12, 0, 10, 7, 6, 0,
24 }, 24 },
25 .coef_probs{ 25 .coef_probs{
26 195, 29, 183, 0, 84, 49, 136, 0, 8, 42, 71, 0, 0, 0, 0, 0, 0, 0, 0, 0, 26 195, 29, 183, 84, 49, 136, 8, 42, 71, 0, 0, 0, 0, 0, 0, 0, 0, 0,
27 0, 0, 0, 0, 31, 107, 169, 0, 35, 99, 159, 0, 17, 82, 140, 0, 8, 66, 114, 0, 27 31, 107, 169, 35, 99, 159, 17, 82, 140, 8, 66, 114, 2, 44, 76, 1, 19, 32,
28 2, 44, 76, 0, 1, 19, 32, 0, 40, 132, 201, 0, 29, 114, 187, 0, 13, 91, 157, 0, 28 40, 132, 201, 29, 114, 187, 13, 91, 157, 7, 75, 127, 3, 58, 95, 1, 28, 47,
29 7, 75, 127, 0, 3, 58, 95, 0, 1, 28, 47, 0, 69, 142, 221, 0, 42, 122, 201, 0, 29 69, 142, 221, 42, 122, 201, 15, 91, 159, 6, 67, 121, 1, 42, 77, 1, 17, 31,
30 15, 91, 159, 0, 6, 67, 121, 0, 1, 42, 77, 0, 1, 17, 31, 0, 102, 148, 228, 0, 30 102, 148, 228, 67, 117, 204, 17, 82, 154, 6, 59, 114, 2, 39, 75, 1, 15, 29,
31 67, 117, 204, 0, 17, 82, 154, 0, 6, 59, 114, 0, 2, 39, 75, 0, 1, 15, 29, 0, 31 156, 57, 233, 119, 57, 212, 58, 48, 163, 29, 40, 124, 12, 30, 81, 3, 12, 31,
32 156, 57, 233, 0, 119, 57, 212, 0, 58, 48, 163, 0, 29, 40, 124, 0, 12, 30, 81, 0, 32 191, 107, 226, 124, 117, 204, 25, 99, 155, 0, 0, 0, 0, 0, 0, 0, 0, 0,
33 3, 12, 31, 0, 191, 107, 226, 0, 124, 117, 204, 0, 25, 99, 155, 0, 0, 0, 0, 0, 33 29, 148, 210, 37, 126, 194, 8, 93, 157, 2, 68, 118, 1, 39, 69, 1, 17, 33,
34 0, 0, 0, 0, 0, 0, 0, 0, 29, 148, 210, 0, 37, 126, 194, 0, 8, 93, 157, 0, 34 41, 151, 213, 27, 123, 193, 3, 82, 144, 1, 58, 105, 1, 32, 60, 1, 13, 26,
35 2, 68, 118, 0, 1, 39, 69, 0, 1, 17, 33, 0, 41, 151, 213, 0, 27, 123, 193, 0, 35 59, 159, 220, 23, 126, 198, 4, 88, 151, 1, 66, 114, 1, 38, 71, 1, 18, 34,
36 3, 82, 144, 0, 1, 58, 105, 0, 1, 32, 60, 0, 1, 13, 26, 0, 59, 159, 220, 0, 36 114, 136, 232, 51, 114, 207, 11, 83, 155, 3, 56, 105, 1, 33, 65, 1, 17, 34,
37 23, 126, 198, 0, 4, 88, 151, 0, 1, 66, 114, 0, 1, 38, 71, 0, 1, 18, 34, 0, 37 149, 65, 234, 121, 57, 215, 61, 49, 166, 28, 36, 114, 12, 25, 76, 3, 16, 42,
38 114, 136, 232, 0, 51, 114, 207, 0, 11, 83, 155, 0, 3, 56, 105, 0, 1, 33, 65, 0, 38 214, 49, 220, 132, 63, 188, 42, 65, 137, 0, 0, 0, 0, 0, 0, 0, 0, 0,
39 1, 17, 34, 0, 149, 65, 234, 0, 121, 57, 215, 0, 61, 49, 166, 0, 28, 36, 114, 0, 39 85, 137, 221, 104, 131, 216, 49, 111, 192, 21, 87, 155, 2, 49, 87, 1, 16, 28,
40 12, 25, 76, 0, 3, 16, 42, 0, 214, 49, 220, 0, 132, 63, 188, 0, 42, 65, 137, 0, 40 89, 163, 230, 90, 137, 220, 29, 100, 183, 10, 70, 135, 2, 42, 81, 1, 17, 33,
41 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 137, 221, 0, 104, 131, 216, 0, 41 108, 167, 237, 55, 133, 222, 15, 97, 179, 4, 72, 135, 1, 45, 85, 1, 19, 38,
42 49, 111, 192, 0, 21, 87, 155, 0, 2, 49, 87, 0, 1, 16, 28, 0, 89, 163, 230, 0, 42 124, 146, 240, 66, 124, 224, 17, 88, 175, 4, 58, 122, 1, 36, 75, 1, 18, 37,
43 90, 137, 220, 0, 29, 100, 183, 0, 10, 70, 135, 0, 2, 42, 81, 0, 1, 17, 33, 0, 43 141, 79, 241, 126, 70, 227, 66, 58, 182, 30, 44, 136, 12, 34, 96, 2, 20, 47,
44 108, 167, 237, 0, 55, 133, 222, 0, 15, 97, 179, 0, 4, 72, 135, 0, 1, 45, 85, 0, 44 229, 99, 249, 143, 111, 235, 46, 109, 192, 0, 0, 0, 0, 0, 0, 0, 0, 0,
45 1, 19, 38, 0, 124, 146, 240, 0, 66, 124, 224, 0, 17, 88, 175, 0, 4, 58, 122, 0, 45 82, 158, 236, 94, 146, 224, 25, 117, 191, 9, 87, 149, 3, 56, 99, 1, 33, 57,
46 1, 36, 75, 0, 1, 18, 37, 0, 141, 79, 241, 0, 126, 70, 227, 0, 66, 58, 182, 0, 46 83, 167, 237, 68, 145, 222, 10, 103, 177, 2, 72, 131, 1, 41, 79, 1, 20, 39,
47 30, 44, 136, 0, 12, 34, 96, 0, 2, 20, 47, 0, 229, 99, 249, 0, 143, 111, 235, 0, 47 99, 167, 239, 47, 141, 224, 10, 104, 178, 2, 73, 133, 1, 44, 85, 1, 22, 47,
48 46, 109, 192, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 82, 158, 236, 0, 48 127, 145, 243, 71, 129, 228, 17, 93, 177, 3, 61, 124, 1, 41, 84, 1, 21, 52,
49 94, 146, 224, 0, 25, 117, 191, 0, 9, 87, 149, 0, 3, 56, 99, 0, 1, 33, 57, 0, 49 157, 78, 244, 140, 72, 231, 69, 58, 184, 31, 44, 137, 14, 38, 105, 8, 23, 61,
50 83, 167, 237, 0, 68, 145, 222, 0, 10, 103, 177, 0, 2, 72, 131, 0, 1, 41, 79, 0, 50 125, 34, 187, 52, 41, 133, 6, 31, 56, 0, 0, 0, 0, 0, 0, 0, 0, 0,
51 1, 20, 39, 0, 99, 167, 239, 0, 47, 141, 224, 0, 10, 104, 178, 0, 2, 73, 133, 0, 51 37, 109, 153, 51, 102, 147, 23, 87, 128, 8, 67, 101, 1, 41, 63, 1, 19, 29,
52 1, 44, 85, 0, 1, 22, 47, 0, 127, 145, 243, 0, 71, 129, 228, 0, 17, 93, 177, 0, 52 31, 154, 185, 17, 127, 175, 6, 96, 145, 2, 73, 114, 1, 51, 82, 1, 28, 45,
53 3, 61, 124, 0, 1, 41, 84, 0, 1, 21, 52, 0, 157, 78, 244, 0, 140, 72, 231, 0, 53 23, 163, 200, 10, 131, 185, 2, 93, 148, 1, 67, 111, 1, 41, 69, 1, 14, 24,
54 69, 58, 184, 0, 31, 44, 137, 0, 14, 38, 105, 0, 8, 23, 61, 0, 125, 34, 187, 0, 54 29, 176, 217, 12, 145, 201, 3, 101, 156, 1, 69, 111, 1, 39, 63, 1, 14, 23,
55 52, 41, 133, 0, 6, 31, 56, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 55 57, 192, 233, 25, 154, 215, 6, 109, 167, 3, 78, 118, 1, 48, 69, 1, 21, 29,
56 37, 109, 153, 0, 51, 102, 147, 0, 23, 87, 128, 0, 8, 67, 101, 0, 1, 41, 63, 0, 56 202, 105, 245, 108, 106, 216, 18, 90, 144, 0, 0, 0, 0, 0, 0, 0, 0, 0,
57 1, 19, 29, 0, 31, 154, 185, 0, 17, 127, 175, 0, 6, 96, 145, 0, 2, 73, 114, 0, 57 33, 172, 219, 64, 149, 206, 14, 117, 177, 5, 90, 141, 2, 61, 95, 1, 37, 57,
58 1, 51, 82, 0, 1, 28, 45, 0, 23, 163, 200, 0, 10, 131, 185, 0, 2, 93, 148, 0, 58 33, 179, 220, 11, 140, 198, 1, 89, 148, 1, 60, 104, 1, 33, 57, 1, 12, 21,
59 1, 67, 111, 0, 1, 41, 69, 0, 1, 14, 24, 0, 29, 176, 217, 0, 12, 145, 201, 0, 59 30, 181, 221, 8, 141, 198, 1, 87, 145, 1, 58, 100, 1, 31, 55, 1, 12, 20,
60 3, 101, 156, 0, 1, 69, 111, 0, 1, 39, 63, 0, 1, 14, 23, 0, 57, 192, 233, 0, 60 32, 186, 224, 7, 142, 198, 1, 86, 143, 1, 58, 100, 1, 31, 55, 1, 12, 22,
61 25, 154, 215, 0, 6, 109, 167, 0, 3, 78, 118, 0, 1, 48, 69, 0, 1, 21, 29, 0, 61 57, 192, 227, 20, 143, 204, 3, 96, 154, 1, 68, 112, 1, 42, 69, 1, 19, 32,
62 202, 105, 245, 0, 108, 106, 216, 0, 18, 90, 144, 0, 0, 0, 0, 0, 0, 0, 0, 0, 62 212, 35, 215, 113, 47, 169, 29, 48, 105, 0, 0, 0, 0, 0, 0, 0, 0, 0,
63 0, 0, 0, 0, 33, 172, 219, 0, 64, 149, 206, 0, 14, 117, 177, 0, 5, 90, 141, 0, 63 74, 129, 203, 106, 120, 203, 49, 107, 178, 19, 84, 144, 4, 50, 84, 1, 15, 25,
64 2, 61, 95, 0, 1, 37, 57, 0, 33, 179, 220, 0, 11, 140, 198, 0, 1, 89, 148, 0, 64 71, 172, 217, 44, 141, 209, 15, 102, 173, 6, 76, 133, 2, 51, 89, 1, 24, 42,
65 1, 60, 104, 0, 1, 33, 57, 0, 1, 12, 21, 0, 30, 181, 221, 0, 8, 141, 198, 0, 65 64, 185, 231, 31, 148, 216, 8, 103, 175, 3, 74, 131, 1, 46, 81, 1, 18, 30,
66 1, 87, 145, 0, 1, 58, 100, 0, 1, 31, 55, 0, 1, 12, 20, 0, 32, 186, 224, 0, 66 65, 196, 235, 25, 157, 221, 5, 105, 174, 1, 67, 120, 1, 38, 69, 1, 15, 30,
67 7, 142, 198, 0, 1, 86, 143, 0, 1, 58, 100, 0, 1, 31, 55, 0, 1, 12, 22, 0, 67 65, 204, 238, 30, 156, 224, 7, 107, 177, 2, 70, 124, 1, 42, 73, 1, 18, 34,
68 57, 192, 227, 0, 20, 143, 204, 0, 3, 96, 154, 0, 1, 68, 112, 0, 1, 42, 69, 0, 68 225, 86, 251, 144, 104, 235, 42, 99, 181, 0, 0, 0, 0, 0, 0, 0, 0, 0,
69 1, 19, 32, 0, 212, 35, 215, 0, 113, 47, 169, 0, 29, 48, 105, 0, 0, 0, 0, 0, 69 85, 175, 239, 112, 165, 229, 29, 136, 200, 12, 103, 162, 6, 77, 123, 2, 53, 84,
70 0, 0, 0, 0, 0, 0, 0, 0, 74, 129, 203, 0, 106, 120, 203, 0, 49, 107, 178, 0, 70 75, 183, 239, 30, 155, 221, 3, 106, 171, 1, 74, 128, 1, 44, 76, 1, 17, 28,
71 19, 84, 144, 0, 4, 50, 84, 0, 1, 15, 25, 0, 71, 172, 217, 0, 44, 141, 209, 0, 71 73, 185, 240, 27, 159, 222, 2, 107, 172, 1, 75, 127, 1, 42, 73, 1, 17, 29,
72 15, 102, 173, 0, 6, 76, 133, 0, 2, 51, 89, 0, 1, 24, 42, 0, 64, 185, 231, 0, 72 62, 190, 238, 21, 159, 222, 2, 107, 172, 1, 72, 122, 1, 40, 71, 1, 18, 32,
73 31, 148, 216, 0, 8, 103, 175, 0, 3, 74, 131, 0, 1, 46, 81, 0, 1, 18, 30, 0, 73 61, 199, 240, 27, 161, 226, 4, 113, 180, 1, 76, 129, 1, 46, 80, 1, 23, 41,
74 65, 196, 235, 0, 25, 157, 221, 0, 5, 105, 174, 0, 1, 67, 120, 0, 1, 38, 69, 0, 74 7, 27, 153, 5, 30, 95, 1, 16, 30, 0, 0, 0, 0, 0, 0, 0, 0, 0,
75 1, 15, 30, 0, 65, 204, 238, 0, 30, 156, 224, 0, 7, 107, 177, 0, 2, 70, 124, 0, 75 50, 75, 127, 57, 75, 124, 27, 67, 108, 10, 54, 86, 1, 33, 52, 1, 12, 18,
76 1, 42, 73, 0, 1, 18, 34, 0, 225, 86, 251, 0, 144, 104, 235, 0, 42, 99, 181, 0, 76 43, 125, 151, 26, 108, 148, 7, 83, 122, 2, 59, 89, 1, 38, 60, 1, 17, 27,
77 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 175, 239, 0, 112, 165, 229, 0, 77 23, 144, 163, 13, 112, 154, 2, 75, 117, 1, 50, 81, 1, 31, 51, 1, 14, 23,
78 29, 136, 200, 0, 12, 103, 162, 0, 6, 77, 123, 0, 2, 53, 84, 0, 75, 183, 239, 0, 78 18, 162, 185, 6, 123, 171, 1, 78, 125, 1, 51, 86, 1, 31, 54, 1, 14, 23,
79 30, 155, 221, 0, 3, 106, 171, 0, 1, 74, 128, 0, 1, 44, 76, 0, 1, 17, 28, 0, 79 15, 199, 227, 3, 150, 204, 1, 91, 146, 1, 55, 95, 1, 30, 53, 1, 11, 20,
80 73, 185, 240, 0, 27, 159, 222, 0, 2, 107, 172, 0, 1, 75, 127, 0, 1, 42, 73, 0, 80 19, 55, 240, 19, 59, 196, 3, 52, 105, 0, 0, 0, 0, 0, 0, 0, 0, 0,
81 1, 17, 29, 0, 62, 190, 238, 0, 21, 159, 222, 0, 2, 107, 172, 0, 1, 72, 122, 0, 81 41, 166, 207, 104, 153, 199, 31, 123, 181, 14, 101, 152, 5, 72, 106, 1, 36, 52,
82 1, 40, 71, 0, 1, 18, 32, 0, 61, 199, 240, 0, 27, 161, 226, 0, 4, 113, 180, 0, 82 35, 176, 211, 12, 131, 190, 2, 88, 144, 1, 60, 101, 1, 36, 60, 1, 16, 28,
83 1, 76, 129, 0, 1, 46, 80, 0, 1, 23, 41, 0, 7, 27, 153, 0, 5, 30, 95, 0, 83 28, 183, 213, 8, 134, 191, 1, 86, 142, 1, 56, 96, 1, 30, 53, 1, 12, 20,
84 1, 16, 30, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 50, 75, 127, 0, 84 20, 190, 215, 4, 135, 192, 1, 84, 139, 1, 53, 91, 1, 28, 49, 1, 11, 20,
85 57, 75, 124, 0, 27, 67, 108, 0, 10, 54, 86, 0, 1, 33, 52, 0, 1, 12, 18, 0, 85 13, 196, 216, 2, 137, 192, 1, 86, 143, 1, 57, 99, 1, 32, 56, 1, 13, 24,
86 43, 125, 151, 0, 26, 108, 148, 0, 7, 83, 122, 0, 2, 59, 89, 0, 1, 38, 60, 0, 86 211, 29, 217, 96, 47, 156, 22, 43, 87, 0, 0, 0, 0, 0, 0, 0, 0, 0,
87 1, 17, 27, 0, 23, 144, 163, 0, 13, 112, 154, 0, 2, 75, 117, 0, 1, 50, 81, 0, 87 78, 120, 193, 111, 116, 186, 46, 102, 164, 15, 80, 128, 2, 49, 76, 1, 18, 28,
88 1, 31, 51, 0, 1, 14, 23, 0, 18, 162, 185, 0, 6, 123, 171, 0, 1, 78, 125, 0, 88 71, 161, 203, 42, 132, 192, 10, 98, 150, 3, 69, 109, 1, 44, 70, 1, 18, 29,
89 1, 51, 86, 0, 1, 31, 54, 0, 1, 14, 23, 0, 15, 199, 227, 0, 3, 150, 204, 0, 89 57, 186, 211, 30, 140, 196, 4, 93, 146, 1, 62, 102, 1, 38, 65, 1, 16, 27,
90 1, 91, 146, 0, 1, 55, 95, 0, 1, 30, 53, 0, 1, 11, 20, 0, 19, 55, 240, 0, 90 47, 199, 217, 14, 145, 196, 1, 88, 142, 1, 57, 98, 1, 36, 62, 1, 15, 26,
91 19, 59, 196, 0, 3, 52, 105, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 91 26, 219, 229, 5, 155, 207, 1, 94, 151, 1, 60, 104, 1, 36, 62, 1, 16, 28,
92 41, 166, 207, 0, 104, 153, 199, 0, 31, 123, 181, 0, 14, 101, 152, 0, 5, 72, 106, 0, 92 233, 29, 248, 146, 47, 220, 43, 52, 140, 0, 0, 0, 0, 0, 0, 0, 0, 0,
93 1, 36, 52, 0, 35, 176, 211, 0, 12, 131, 190, 0, 2, 88, 144, 0, 1, 60, 101, 0, 93 100, 163, 232, 179, 161, 222, 63, 142, 204, 37, 113, 174, 26, 89, 137, 18, 68, 97,
94 1, 36, 60, 0, 1, 16, 28, 0, 28, 183, 213, 0, 8, 134, 191, 0, 1, 86, 142, 0, 94 85, 181, 230, 32, 146, 209, 7, 100, 164, 3, 71, 121, 1, 45, 77, 1, 18, 30,
95 1, 56, 96, 0, 1, 30, 53, 0, 1, 12, 20, 0, 20, 190, 215, 0, 4, 135, 192, 0, 95 65, 187, 230, 20, 148, 207, 2, 97, 159, 1, 68, 116, 1, 40, 70, 1, 14, 29,
96 1, 84, 139, 0, 1, 53, 91, 0, 1, 28, 49, 0, 1, 11, 20, 0, 13, 196, 216, 0, 96 40, 194, 227, 8, 147, 204, 1, 94, 155, 1, 65, 112, 1, 39, 66, 1, 14, 26,
97 2, 137, 192, 0, 1, 86, 143, 0, 1, 57, 99, 0, 1, 32, 56, 0, 1, 13, 24, 0, 97 16, 208, 228, 3, 151, 207, 1, 98, 160, 1, 67, 117, 1, 41, 74, 1, 17, 31,
98 211, 29, 217, 0, 96, 47, 156, 0, 22, 43, 87, 0, 0, 0, 0, 0, 0, 0, 0, 0, 98 17, 38, 140, 7, 34, 80, 1, 17, 29, 0, 0, 0, 0, 0, 0, 0, 0, 0,
99 0, 0, 0, 0, 78, 120, 193, 0, 111, 116, 186, 0, 46, 102, 164, 0, 15, 80, 128, 0, 99 37, 75, 128, 41, 76, 128, 26, 66, 116, 12, 52, 94, 2, 32, 55, 1, 10, 16,
100 2, 49, 76, 0, 1, 18, 28, 0, 71, 161, 203, 0, 42, 132, 192, 0, 10, 98, 150, 0, 100 50, 127, 154, 37, 109, 152, 16, 82, 121, 5, 59, 85, 1, 35, 54, 1, 13, 20,
101 3, 69, 109, 0, 1, 44, 70, 0, 1, 18, 29, 0, 57, 186, 211, 0, 30, 140, 196, 0, 101 40, 142, 167, 17, 110, 157, 2, 71, 112, 1, 44, 72, 1, 27, 45, 1, 11, 17,
102 4, 93, 146, 0, 1, 62, 102, 0, 1, 38, 65, 0, 1, 16, 27, 0, 47, 199, 217, 0, 102 30, 175, 188, 9, 124, 169, 1, 74, 116, 1, 48, 78, 1, 30, 49, 1, 11, 18,
103 14, 145, 196, 0, 1, 88, 142, 0, 1, 57, 98, 0, 1, 36, 62, 0, 1, 15, 26, 0, 103 10, 222, 223, 2, 150, 194, 1, 83, 128, 1, 48, 79, 1, 27, 45, 1, 11, 17,
104 26, 219, 229, 0, 5, 155, 207, 0, 1, 94, 151, 0, 1, 60, 104, 0, 1, 36, 62, 0, 104 36, 41, 235, 29, 36, 193, 10, 27, 111, 0, 0, 0, 0, 0, 0, 0, 0, 0,
105 1, 16, 28, 0, 233, 29, 248, 0, 146, 47, 220, 0, 43, 52, 140, 0, 0, 0, 0, 0, 105 85, 165, 222, 177, 162, 215, 110, 135, 195, 57, 113, 168, 23, 83, 120, 10, 49, 61,
106 0, 0, 0, 0, 0, 0, 0, 0, 100, 163, 232, 0, 179, 161, 222, 0, 63, 142, 204, 0, 106 85, 190, 223, 36, 139, 200, 5, 90, 146, 1, 60, 103, 1, 38, 65, 1, 18, 30,
107 37, 113, 174, 0, 26, 89, 137, 0, 18, 68, 97, 0, 85, 181, 230, 0, 32, 146, 209, 0, 107 72, 202, 223, 23, 141, 199, 2, 86, 140, 1, 56, 97, 1, 36, 61, 1, 16, 27,
108 7, 100, 164, 0, 3, 71, 121, 0, 1, 45, 77, 0, 1, 18, 30, 0, 65, 187, 230, 0, 108 55, 218, 225, 13, 145, 200, 1, 86, 141, 1, 57, 99, 1, 35, 61, 1, 13, 22,
109 20, 148, 207, 0, 2, 97, 159, 0, 1, 68, 116, 0, 1, 40, 70, 0, 1, 14, 29, 0, 109 15, 235, 212, 1, 132, 184, 1, 84, 139, 1, 57, 97, 1, 34, 56, 1, 14, 23,
110 40, 194, 227, 0, 8, 147, 204, 0, 1, 94, 155, 0, 1, 65, 112, 0, 1, 39, 66, 0, 110 181, 21, 201, 61, 37, 123, 10, 38, 71, 0, 0, 0, 0, 0, 0, 0, 0, 0,
111 1, 14, 26, 0, 16, 208, 228, 0, 3, 151, 207, 0, 1, 98, 160, 0, 1, 67, 117, 0, 111 47, 106, 172, 95, 104, 173, 42, 93, 159, 18, 77, 131, 4, 50, 81, 1, 17, 23,
112 1, 41, 74, 0, 1, 17, 31, 0, 17, 38, 140, 0, 7, 34, 80, 0, 1, 17, 29, 0, 112 62, 147, 199, 44, 130, 189, 28, 102, 154, 18, 75, 115, 2, 44, 65, 1, 12, 19,
113 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 37, 75, 128, 0, 41, 76, 128, 0, 113 55, 153, 210, 24, 130, 194, 3, 93, 146, 1, 61, 97, 1, 31, 50, 1, 10, 16,
114 26, 66, 116, 0, 12, 52, 94, 0, 2, 32, 55, 0, 1, 10, 16, 0, 50, 127, 154, 0, 114 49, 186, 223, 17, 148, 204, 1, 96, 142, 1, 53, 83, 1, 26, 44, 1, 11, 17,
115 37, 109, 152, 0, 16, 82, 121, 0, 5, 59, 85, 0, 1, 35, 54, 0, 1, 13, 20, 0, 115 13, 217, 212, 2, 136, 180, 1, 78, 124, 1, 50, 83, 1, 29, 49, 1, 14, 23,
116 40, 142, 167, 0, 17, 110, 157, 0, 2, 71, 112, 0, 1, 44, 72, 0, 1, 27, 45, 0, 116 197, 13, 247, 82, 17, 222, 25, 17, 162, 0, 0, 0, 0, 0, 0, 0, 0, 0,
117 1, 11, 17, 0, 30, 175, 188, 0, 9, 124, 169, 0, 1, 74, 116, 0, 1, 48, 78, 0, 117 126, 186, 247, 234, 191, 243, 176, 177, 234, 104, 158, 220, 66, 128, 186, 55, 90, 137,
118 1, 30, 49, 0, 1, 11, 18, 0, 10, 222, 223, 0, 2, 150, 194, 0, 1, 83, 128, 0, 118 111, 197, 242, 46, 158, 219, 9, 104, 171, 2, 65, 125, 1, 44, 80, 1, 17, 91,
119 1, 48, 79, 0, 1, 27, 45, 0, 1, 11, 17, 0, 36, 41, 235, 0, 29, 36, 193, 0, 119 104, 208, 245, 39, 168, 224, 3, 109, 162, 1, 79, 124, 1, 50, 102, 1, 43, 102,
120 10, 27, 111, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 165, 222, 0, 120 84, 220, 246, 31, 177, 231, 2, 115, 180, 1, 79, 134, 1, 55, 77, 1, 60, 79,
121 177, 162, 215, 0, 110, 135, 195, 0, 57, 113, 168, 0, 23, 83, 120, 0, 10, 49, 61, 0, 121 43, 243, 240, 8, 180, 217, 1, 115, 166, 1, 84, 121, 1, 51, 67, 1, 16, 6,
122 85, 190, 223, 0, 36, 139, 200, 0, 5, 90, 146, 0, 1, 60, 103, 0, 1, 38, 65, 0,
123 1, 18, 30, 0, 72, 202, 223, 0, 23, 141, 199, 0, 2, 86, 140, 0, 1, 56, 97, 0,
124 1, 36, 61, 0, 1, 16, 27, 0, 55, 218, 225, 0, 13, 145, 200, 0, 1, 86, 141, 0,
125 1, 57, 99, 0, 1, 35, 61, 0, 1, 13, 22, 0, 15, 235, 212, 0, 1, 132, 184, 0,
126 1, 84, 139, 0, 1, 57, 97, 0, 1, 34, 56, 0, 1, 14, 23, 0, 181, 21, 201, 0,
127 61, 37, 123, 0, 10, 38, 71, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
128 47, 106, 172, 0, 95, 104, 173, 0, 42, 93, 159, 0, 18, 77, 131, 0, 4, 50, 81, 0,
129 1, 17, 23, 0, 62, 147, 199, 0, 44, 130, 189, 0, 28, 102, 154, 0, 18, 75, 115, 0,
130 2, 44, 65, 0, 1, 12, 19, 0, 55, 153, 210, 0, 24, 130, 194, 0, 3, 93, 146, 0,
131 1, 61, 97, 0, 1, 31, 50, 0, 1, 10, 16, 0, 49, 186, 223, 0, 17, 148, 204, 0,
132 1, 96, 142, 0, 1, 53, 83, 0, 1, 26, 44, 0, 1, 11, 17, 0, 13, 217, 212, 0,
133 2, 136, 180, 0, 1, 78, 124, 0, 1, 50, 83, 0, 1, 29, 49, 0, 1, 14, 23, 0,
134 197, 13, 247, 0, 82, 17, 222, 0, 25, 17, 162, 0, 0, 0, 0, 0, 0, 0, 0, 0,
135 0, 0, 0, 0, 126, 186, 247, 0, 234, 191, 243, 0, 176, 177, 234, 0, 104, 158, 220, 0,
136 66, 128, 186, 0, 55, 90, 137, 0, 111, 197, 242, 0, 46, 158, 219, 0, 9, 104, 171, 0,
137 2, 65, 125, 0, 1, 44, 80, 0, 1, 17, 91, 0, 104, 208, 245, 0, 39, 168, 224, 0,
138 3, 109, 162, 0, 1, 79, 124, 0, 1, 50, 102, 0, 1, 43, 102, 0, 84, 220, 246, 0,
139 31, 177, 231, 0, 2, 115, 180, 0, 1, 79, 134, 0, 1, 55, 77, 0, 1, 60, 79, 0,
140 43, 243, 240, 0, 8, 180, 217, 0, 1, 115, 166, 0, 1, 84, 121, 0, 1, 51, 67, 0,
141 1, 16, 6, 0,
142 }, 122 },
143 .switchable_interp_prob{235, 162, 36, 255, 34, 3, 149, 144}, 123 .switchable_interp_prob{235, 162, 36, 255, 34, 3, 149, 144},
144 .inter_mode_prob{ 124 .inter_mode_prob{
@@ -322,39 +302,23 @@ bool VP9::WriteLessThan(VpxRangeEncoder& writer, s32 value, s32 test) {
322} 302}
323 303
324void VP9::WriteCoefProbabilityUpdate(VpxRangeEncoder& writer, s32 tx_mode, 304void VP9::WriteCoefProbabilityUpdate(VpxRangeEncoder& writer, s32 tx_mode,
325 const std::array<u8, 2304>& new_prob, 305 const std::array<u8, 1728>& new_prob,
326 const std::array<u8, 2304>& old_prob) { 306 const std::array<u8, 1728>& old_prob) {
327 // Note: There's 1 byte added on each packet for alignment, 307 constexpr u32 block_bytes = 2 * 2 * 6 * 6 * 3;
328 // this byte is ignored when doing updates. 308
329 constexpr s32 block_bytes = 2 * 2 * 6 * 6 * 4; 309 const auto needs_update = [&](u32 base_index) {
330 310 return !std::equal(new_prob.begin() + base_index,
331 const auto needs_update = [&](s32 base_index) -> bool { 311 new_prob.begin() + base_index + block_bytes,
332 s32 index = base_index; 312 old_prob.begin() + base_index);
333 for (s32 i = 0; i < 2; i++) {
334 for (s32 j = 0; j < 2; j++) {
335 for (s32 k = 0; k < 6; k++) {
336 for (s32 l = 0; l < 6; l++) {
337 if (new_prob[index + 0] != old_prob[index + 0] ||
338 new_prob[index + 1] != old_prob[index + 1] ||
339 new_prob[index + 2] != old_prob[index + 2]) {
340 return true;
341 }
342
343 index += 4;
344 }
345 }
346 }
347 }
348 return false;
349 }; 313 };
350 314
351 for (s32 block_index = 0; block_index < 4; block_index++) { 315 for (u32 block_index = 0; block_index < 4; block_index++) {
352 const s32 base_index = block_index * block_bytes; 316 const u32 base_index = block_index * block_bytes;
353 const bool update = needs_update(base_index); 317 const bool update = needs_update(base_index);
354 writer.Write(update); 318 writer.Write(update);
355 319
356 if (update) { 320 if (update) {
357 s32 index = base_index; 321 u32 index = base_index;
358 for (s32 i = 0; i < 2; i++) { 322 for (s32 i = 0; i < 2; i++) {
359 for (s32 j = 0; j < 2; j++) { 323 for (s32 j = 0; j < 2; j++) {
360 for (s32 k = 0; k < 6; k++) { 324 for (s32 k = 0; k < 6; k++) {
@@ -367,14 +331,13 @@ void VP9::WriteCoefProbabilityUpdate(VpxRangeEncoder& writer, s32 tx_mode,
367 WriteProbabilityUpdate(writer, new_prob[index + 2], 331 WriteProbabilityUpdate(writer, new_prob[index + 2],
368 old_prob[index + 2]); 332 old_prob[index + 2]);
369 } 333 }
370 index += 4; 334 index += 3;
371 } 335 }
372 } 336 }
373 } 337 }
374 } 338 }
375 } 339 }
376 340 if (block_index == static_cast<u32>(tx_mode)) {
377 if (block_index == tx_mode) {
378 break; 341 break;
379 } 342 }
380 } 343 }
@@ -392,7 +355,7 @@ void VP9::WriteMvProbabilityUpdate(VpxRangeEncoder& writer, u8 new_prob, u8 old_
392Vp9PictureInfo VP9::GetVp9PictureInfo(const NvdecCommon::NvdecRegisters& state) { 355Vp9PictureInfo VP9::GetVp9PictureInfo(const NvdecCommon::NvdecRegisters& state) {
393 PictureInfo picture_info{}; 356 PictureInfo picture_info{};
394 gpu.MemoryManager().ReadBlock(state.picture_info_offset, &picture_info, sizeof(PictureInfo)); 357 gpu.MemoryManager().ReadBlock(state.picture_info_offset, &picture_info, sizeof(PictureInfo));
395 Vp9PictureInfo vp9_info = picture_info.Convert(); 358 Vp9PictureInfo vp9_info = std::move(picture_info.Convert());
396 359
397 InsertEntropy(state.vp9_entropy_probs_offset, vp9_info.entropy); 360 InsertEntropy(state.vp9_entropy_probs_offset, vp9_info.entropy);
398 361
@@ -414,8 +377,7 @@ Vp9FrameContainer VP9::GetCurrentFrame(const NvdecCommon::NvdecRegisters& state)
414 Vp9FrameContainer frame{}; 377 Vp9FrameContainer frame{};
415 { 378 {
416 gpu.SyncGuestHost(); 379 gpu.SyncGuestHost();
417 frame.info = GetVp9PictureInfo(state); 380 frame.info = std::move(GetVp9PictureInfo(state));
418
419 frame.bit_stream.resize(frame.info.bitstream_size); 381 frame.bit_stream.resize(frame.info.bitstream_size);
420 gpu.MemoryManager().ReadBlock(state.frame_bitstream_offset, frame.bit_stream.data(), 382 gpu.MemoryManager().ReadBlock(state.frame_bitstream_offset, frame.bit_stream.data(),
421 frame.info.bitstream_size); 383 frame.info.bitstream_size);
@@ -423,37 +385,37 @@ Vp9FrameContainer VP9::GetCurrentFrame(const NvdecCommon::NvdecRegisters& state)
423 // Buffer two frames, saving the last show frame info 385 // Buffer two frames, saving the last show frame info
424 if (!next_next_frame.bit_stream.empty()) { 386 if (!next_next_frame.bit_stream.empty()) {
425 Vp9FrameContainer temp{ 387 Vp9FrameContainer temp{
426 .info = frame.info, 388 .info = std::move(frame.info),
427 .bit_stream = frame.bit_stream, 389 .bit_stream = std::move(frame.bit_stream),
428 }; 390 };
429 next_next_frame.info.show_frame = frame.info.last_frame_shown; 391 next_next_frame.info.show_frame = frame.info.last_frame_shown;
430 frame.info = next_next_frame.info; 392 frame.info = std::move(next_next_frame.info);
431 frame.bit_stream = next_next_frame.bit_stream; 393 frame.bit_stream = std::move(next_next_frame.bit_stream);
432 next_next_frame = std::move(temp); 394 next_next_frame = std::move(temp);
433 395
434 if (!next_frame.bit_stream.empty()) { 396 if (!next_frame.bit_stream.empty()) {
435 Vp9FrameContainer temp2{ 397 Vp9FrameContainer temp2{
436 .info = frame.info, 398 .info = std::move(frame.info),
437 .bit_stream = frame.bit_stream, 399 .bit_stream = std::move(frame.bit_stream),
438 }; 400 };
439 next_frame.info.show_frame = frame.info.last_frame_shown; 401 next_frame.info.show_frame = frame.info.last_frame_shown;
440 frame.info = next_frame.info; 402 frame.info = std::move(next_frame.info);
441 frame.bit_stream = next_frame.bit_stream; 403 frame.bit_stream = std::move(next_frame.bit_stream);
442 next_frame = std::move(temp2); 404 next_frame = std::move(temp2);
443 } else { 405 } else {
444 next_frame.info = frame.info; 406 next_frame.info = std::move(frame.info);
445 next_frame.bit_stream = frame.bit_stream; 407 next_frame.bit_stream = std::move(frame.bit_stream);
446 } 408 }
447 } else { 409 } else {
448 next_next_frame.info = frame.info; 410 next_next_frame.info = std::move(frame.info);
449 next_next_frame.bit_stream = frame.bit_stream; 411 next_next_frame.bit_stream = std::move(frame.bit_stream);
450 } 412 }
451 return frame; 413 return frame;
452} 414}
453 415
454std::vector<u8> VP9::ComposeCompressedHeader() { 416std::vector<u8> VP9::ComposeCompressedHeader() {
455 VpxRangeEncoder writer{}; 417 VpxRangeEncoder writer{};
456 418 const bool update_probs = current_frame_info.show_frame && !current_frame_info.is_key_frame;
457 if (!current_frame_info.lossless) { 419 if (!current_frame_info.lossless) {
458 if (static_cast<u32>(current_frame_info.transform_mode) >= 3) { 420 if (static_cast<u32>(current_frame_info.transform_mode) >= 3) {
459 writer.Write(3, 2); 421 writer.Write(3, 2);
@@ -471,7 +433,7 @@ std::vector<u8> VP9::ComposeCompressedHeader() {
471 prev_frame_probs.tx_16x16_prob); 433 prev_frame_probs.tx_16x16_prob);
472 WriteProbabilityUpdate(writer, current_frame_info.entropy.tx_32x32_prob, 434 WriteProbabilityUpdate(writer, current_frame_info.entropy.tx_32x32_prob,
473 prev_frame_probs.tx_32x32_prob); 435 prev_frame_probs.tx_32x32_prob);
474 if (current_frame_info.show_frame && !current_frame_info.is_key_frame) { 436 if (update_probs) {
475 prev_frame_probs.tx_8x8_prob = current_frame_info.entropy.tx_8x8_prob; 437 prev_frame_probs.tx_8x8_prob = current_frame_info.entropy.tx_8x8_prob;
476 prev_frame_probs.tx_16x16_prob = current_frame_info.entropy.tx_16x16_prob; 438 prev_frame_probs.tx_16x16_prob = current_frame_info.entropy.tx_16x16_prob;
477 prev_frame_probs.tx_32x32_prob = current_frame_info.entropy.tx_32x32_prob; 439 prev_frame_probs.tx_32x32_prob = current_frame_info.entropy.tx_32x32_prob;
@@ -484,7 +446,7 @@ std::vector<u8> VP9::ComposeCompressedHeader() {
484 WriteProbabilityUpdate(writer, current_frame_info.entropy.skip_probs, 446 WriteProbabilityUpdate(writer, current_frame_info.entropy.skip_probs,
485 prev_frame_probs.skip_probs); 447 prev_frame_probs.skip_probs);
486 448
487 if (current_frame_info.show_frame && !current_frame_info.is_key_frame) { 449 if (update_probs) {
488 prev_frame_probs.coef_probs = current_frame_info.entropy.coef_probs; 450 prev_frame_probs.coef_probs = current_frame_info.entropy.coef_probs;
489 prev_frame_probs.skip_probs = current_frame_info.entropy.skip_probs; 451 prev_frame_probs.skip_probs = current_frame_info.entropy.skip_probs;
490 } 452 }
@@ -493,15 +455,12 @@ std::vector<u8> VP9::ComposeCompressedHeader() {
493 // read_inter_probs() in the spec 455 // read_inter_probs() in the spec
494 WriteProbabilityUpdateAligned4(writer, current_frame_info.entropy.inter_mode_prob, 456 WriteProbabilityUpdateAligned4(writer, current_frame_info.entropy.inter_mode_prob,
495 prev_frame_probs.inter_mode_prob); 457 prev_frame_probs.inter_mode_prob);
496 if (current_frame_info.show_frame && !current_frame_info.is_key_frame) {
497 prev_frame_probs.inter_mode_prob = current_frame_info.entropy.inter_mode_prob;
498 }
499 458
500 if (current_frame_info.interp_filter == 4) { 459 if (current_frame_info.interp_filter == 4) {
501 // read_interp_filter_probs() in the spec 460 // read_interp_filter_probs() in the spec
502 WriteProbabilityUpdate(writer, current_frame_info.entropy.switchable_interp_prob, 461 WriteProbabilityUpdate(writer, current_frame_info.entropy.switchable_interp_prob,
503 prev_frame_probs.switchable_interp_prob); 462 prev_frame_probs.switchable_interp_prob);
504 if (current_frame_info.show_frame && !current_frame_info.is_key_frame) { 463 if (update_probs) {
505 prev_frame_probs.switchable_interp_prob = 464 prev_frame_probs.switchable_interp_prob =
506 current_frame_info.entropy.switchable_interp_prob; 465 current_frame_info.entropy.switchable_interp_prob;
507 } 466 }
@@ -510,9 +469,7 @@ std::vector<u8> VP9::ComposeCompressedHeader() {
510 // read_is_inter_probs() in the spec 469 // read_is_inter_probs() in the spec
511 WriteProbabilityUpdate(writer, current_frame_info.entropy.intra_inter_prob, 470 WriteProbabilityUpdate(writer, current_frame_info.entropy.intra_inter_prob,
512 prev_frame_probs.intra_inter_prob); 471 prev_frame_probs.intra_inter_prob);
513 if (current_frame_info.show_frame && !current_frame_info.is_key_frame) { 472
514 prev_frame_probs.intra_inter_prob = current_frame_info.entropy.intra_inter_prob;
515 }
516 // frame_reference_mode() in the spec 473 // frame_reference_mode() in the spec
517 if ((current_frame_info.ref_frame_sign_bias[1] & 1) != 474 if ((current_frame_info.ref_frame_sign_bias[1] & 1) !=
518 (current_frame_info.ref_frame_sign_bias[2] & 1) || 475 (current_frame_info.ref_frame_sign_bias[2] & 1) ||
@@ -530,7 +487,7 @@ std::vector<u8> VP9::ComposeCompressedHeader() {
530 if (current_frame_info.reference_mode == 2) { 487 if (current_frame_info.reference_mode == 2) {
531 WriteProbabilityUpdate(writer, current_frame_info.entropy.comp_inter_prob, 488 WriteProbabilityUpdate(writer, current_frame_info.entropy.comp_inter_prob,
532 prev_frame_probs.comp_inter_prob); 489 prev_frame_probs.comp_inter_prob);
533 if (current_frame_info.show_frame && !current_frame_info.is_key_frame) { 490 if (update_probs) {
534 prev_frame_probs.comp_inter_prob = current_frame_info.entropy.comp_inter_prob; 491 prev_frame_probs.comp_inter_prob = current_frame_info.entropy.comp_inter_prob;
535 } 492 }
536 } 493 }
@@ -538,7 +495,7 @@ std::vector<u8> VP9::ComposeCompressedHeader() {
538 if (current_frame_info.reference_mode != 1) { 495 if (current_frame_info.reference_mode != 1) {
539 WriteProbabilityUpdate(writer, current_frame_info.entropy.single_ref_prob, 496 WriteProbabilityUpdate(writer, current_frame_info.entropy.single_ref_prob,
540 prev_frame_probs.single_ref_prob); 497 prev_frame_probs.single_ref_prob);
541 if (current_frame_info.show_frame && !current_frame_info.is_key_frame) { 498 if (update_probs) {
542 prev_frame_probs.single_ref_prob = current_frame_info.entropy.single_ref_prob; 499 prev_frame_probs.single_ref_prob = current_frame_info.entropy.single_ref_prob;
543 } 500 }
544 } 501 }
@@ -546,7 +503,7 @@ std::vector<u8> VP9::ComposeCompressedHeader() {
546 if (current_frame_info.reference_mode != 0) { 503 if (current_frame_info.reference_mode != 0) {
547 WriteProbabilityUpdate(writer, current_frame_info.entropy.comp_ref_prob, 504 WriteProbabilityUpdate(writer, current_frame_info.entropy.comp_ref_prob,
548 prev_frame_probs.comp_ref_prob); 505 prev_frame_probs.comp_ref_prob);
549 if (current_frame_info.show_frame && !current_frame_info.is_key_frame) { 506 if (update_probs) {
550 prev_frame_probs.comp_ref_prob = current_frame_info.entropy.comp_ref_prob; 507 prev_frame_probs.comp_ref_prob = current_frame_info.entropy.comp_ref_prob;
551 } 508 }
552 } 509 }
@@ -557,42 +514,37 @@ std::vector<u8> VP9::ComposeCompressedHeader() {
557 WriteProbabilityUpdate(writer, current_frame_info.entropy.y_mode_prob[index], 514 WriteProbabilityUpdate(writer, current_frame_info.entropy.y_mode_prob[index],
558 prev_frame_probs.y_mode_prob[index]); 515 prev_frame_probs.y_mode_prob[index]);
559 } 516 }
560 if (current_frame_info.show_frame && !current_frame_info.is_key_frame) { 517
561 prev_frame_probs.y_mode_prob = current_frame_info.entropy.y_mode_prob;
562 }
563 // read_partition_probs 518 // read_partition_probs
564 WriteProbabilityUpdateAligned4(writer, current_frame_info.entropy.partition_prob, 519 WriteProbabilityUpdateAligned4(writer, current_frame_info.entropy.partition_prob,
565 prev_frame_probs.partition_prob); 520 prev_frame_probs.partition_prob);
566 if (current_frame_info.show_frame && !current_frame_info.is_key_frame) {
567 prev_frame_probs.partition_prob = current_frame_info.entropy.partition_prob;
568 }
569 521
570 // mv_probs 522 // mv_probs
571 for (s32 i = 0; i < 3; i++) { 523 for (s32 i = 0; i < 3; i++) {
572 WriteMvProbabilityUpdate(writer, current_frame_info.entropy.joints[i], 524 WriteMvProbabilityUpdate(writer, current_frame_info.entropy.joints[i],
573 prev_frame_probs.joints[i]); 525 prev_frame_probs.joints[i]);
574 } 526 }
575 if (current_frame_info.show_frame && !current_frame_info.is_key_frame) { 527 if (update_probs) {
528 prev_frame_probs.inter_mode_prob = current_frame_info.entropy.inter_mode_prob;
529 prev_frame_probs.intra_inter_prob = current_frame_info.entropy.intra_inter_prob;
530 prev_frame_probs.y_mode_prob = current_frame_info.entropy.y_mode_prob;
531 prev_frame_probs.partition_prob = current_frame_info.entropy.partition_prob;
576 prev_frame_probs.joints = current_frame_info.entropy.joints; 532 prev_frame_probs.joints = current_frame_info.entropy.joints;
577 } 533 }
578 534
579 for (s32 i = 0; i < 2; i++) { 535 for (s32 i = 0; i < 2; i++) {
580 WriteMvProbabilityUpdate(writer, current_frame_info.entropy.sign[i], 536 WriteMvProbabilityUpdate(writer, current_frame_info.entropy.sign[i],
581 prev_frame_probs.sign[i]); 537 prev_frame_probs.sign[i]);
582
583 for (s32 j = 0; j < 10; j++) { 538 for (s32 j = 0; j < 10; j++) {
584 const int index = i * 10 + j; 539 const int index = i * 10 + j;
585
586 WriteMvProbabilityUpdate(writer, current_frame_info.entropy.classes[index], 540 WriteMvProbabilityUpdate(writer, current_frame_info.entropy.classes[index],
587 prev_frame_probs.classes[index]); 541 prev_frame_probs.classes[index]);
588 } 542 }
589
590 WriteMvProbabilityUpdate(writer, current_frame_info.entropy.class_0[i], 543 WriteMvProbabilityUpdate(writer, current_frame_info.entropy.class_0[i],
591 prev_frame_probs.class_0[i]); 544 prev_frame_probs.class_0[i]);
592 545
593 for (s32 j = 0; j < 10; j++) { 546 for (s32 j = 0; j < 10; j++) {
594 const int index = i * 10 + j; 547 const int index = i * 10 + j;
595
596 WriteMvProbabilityUpdate(writer, current_frame_info.entropy.prob_bits[index], 548 WriteMvProbabilityUpdate(writer, current_frame_info.entropy.prob_bits[index],
597 prev_frame_probs.prob_bits[index]); 549 prev_frame_probs.prob_bits[index]);
598 } 550 }
@@ -602,7 +554,6 @@ std::vector<u8> VP9::ComposeCompressedHeader() {
602 for (s32 j = 0; j < 2; j++) { 554 for (s32 j = 0; j < 2; j++) {
603 for (s32 k = 0; k < 3; k++) { 555 for (s32 k = 0; k < 3; k++) {
604 const int index = i * 2 * 3 + j * 3 + k; 556 const int index = i * 2 * 3 + j * 3 + k;
605
606 WriteMvProbabilityUpdate(writer, current_frame_info.entropy.class_0_fr[index], 557 WriteMvProbabilityUpdate(writer, current_frame_info.entropy.class_0_fr[index],
607 prev_frame_probs.class_0_fr[index]); 558 prev_frame_probs.class_0_fr[index]);
608 } 559 }
@@ -610,7 +561,6 @@ std::vector<u8> VP9::ComposeCompressedHeader() {
610 561
611 for (s32 j = 0; j < 3; j++) { 562 for (s32 j = 0; j < 3; j++) {
612 const int index = i * 3 + j; 563 const int index = i * 3 + j;
613
614 WriteMvProbabilityUpdate(writer, current_frame_info.entropy.fr[index], 564 WriteMvProbabilityUpdate(writer, current_frame_info.entropy.fr[index],
615 prev_frame_probs.fr[index]); 565 prev_frame_probs.fr[index]);
616 } 566 }
@@ -626,7 +576,7 @@ std::vector<u8> VP9::ComposeCompressedHeader() {
626 } 576 }
627 577
628 // save previous probs 578 // save previous probs
629 if (current_frame_info.show_frame && !current_frame_info.is_key_frame) { 579 if (update_probs) {
630 prev_frame_probs.sign = current_frame_info.entropy.sign; 580 prev_frame_probs.sign = current_frame_info.entropy.sign;
631 prev_frame_probs.classes = current_frame_info.entropy.classes; 581 prev_frame_probs.classes = current_frame_info.entropy.classes;
632 prev_frame_probs.class_0 = current_frame_info.entropy.class_0; 582 prev_frame_probs.class_0 = current_frame_info.entropy.class_0;
@@ -637,7 +587,6 @@ std::vector<u8> VP9::ComposeCompressedHeader() {
637 prev_frame_probs.high_precision = current_frame_info.entropy.high_precision; 587 prev_frame_probs.high_precision = current_frame_info.entropy.high_precision;
638 } 588 }
639 } 589 }
640
641 writer.End(); 590 writer.End();
642 return writer.GetBuffer(); 591 return writer.GetBuffer();
643} 592}
@@ -854,11 +803,11 @@ VpxBitStreamWriter VP9::ComposeUncompressedHeader() {
854 return uncomp_writer; 803 return uncomp_writer;
855} 804}
856 805
857const std::vector<u8>& VP9::ComposeFrameHeader(NvdecCommon::NvdecRegisters& state) { 806const std::vector<u8>& VP9::ComposeFrameHeader(const NvdecCommon::NvdecRegisters& state) {
858 std::vector<u8> bitstream; 807 std::vector<u8> bitstream;
859 { 808 {
860 Vp9FrameContainer curr_frame = GetCurrentFrame(state); 809 Vp9FrameContainer curr_frame = std::move(GetCurrentFrame(state));
861 current_frame_info = curr_frame.info; 810 current_frame_info = std::move(curr_frame.info);
862 bitstream = std::move(curr_frame.bit_stream); 811 bitstream = std::move(curr_frame.bit_stream);
863 } 812 }
864 813
diff --git a/src/video_core/command_classes/codecs/vp9.h b/src/video_core/command_classes/codecs/vp9.h
index e2504512c..9ebbbf59e 100644
--- a/src/video_core/command_classes/codecs/vp9.h
+++ b/src/video_core/command_classes/codecs/vp9.h
@@ -119,7 +119,8 @@ public:
119 119
120 /// Composes the VP9 frame from the GPU state information. Based on the official VP9 spec 120 /// Composes the VP9 frame from the GPU state information. Based on the official VP9 spec
121 /// documentation 121 /// documentation
122 [[nodiscard]] const std::vector<u8>& ComposeFrameHeader(NvdecCommon::NvdecRegisters& state); 122 [[nodiscard]] const std::vector<u8>& ComposeFrameHeader(
123 const NvdecCommon::NvdecRegisters& state);
123 124
124 /// Returns true if the most recent frame was a hidden frame. 125 /// Returns true if the most recent frame was a hidden frame.
125 [[nodiscard]] bool WasFrameHidden() const { 126 [[nodiscard]] bool WasFrameHidden() const {
@@ -147,8 +148,8 @@ private:
147 148
148 /// Writes probability updates for the Coef probabilities 149 /// Writes probability updates for the Coef probabilities
149 void WriteCoefProbabilityUpdate(VpxRangeEncoder& writer, s32 tx_mode, 150 void WriteCoefProbabilityUpdate(VpxRangeEncoder& writer, s32 tx_mode,
150 const std::array<u8, 2304>& new_prob, 151 const std::array<u8, 1728>& new_prob,
151 const std::array<u8, 2304>& old_prob); 152 const std::array<u8, 1728>& old_prob);
152 153
153 /// Write probabilities for 4-byte aligned structures 154 /// Write probabilities for 4-byte aligned structures
154 template <typename T, std::size_t N> 155 template <typename T, std::size_t N>
diff --git a/src/video_core/command_classes/codecs/vp9_types.h b/src/video_core/command_classes/codecs/vp9_types.h
index 4f0b05d22..139501a1c 100644
--- a/src/video_core/command_classes/codecs/vp9_types.h
+++ b/src/video_core/command_classes/codecs/vp9_types.h
@@ -31,62 +31,6 @@ enum FrameFlags : u32 {
31 IntraOnly = 1 << 5, 31 IntraOnly = 1 << 5,
32}; 32};
33 33
34enum class MvJointType {
35 MvJointZero = 0, /* Zero vector */
36 MvJointHnzvz = 1, /* Vert zero, hor nonzero */
37 MvJointHzvnz = 2, /* Hor zero, vert nonzero */
38 MvJointHnzvnz = 3, /* Both components nonzero */
39};
40enum class MvClassType {
41 MvClass0 = 0, /* (0, 2] integer pel */
42 MvClass1 = 1, /* (2, 4] integer pel */
43 MvClass2 = 2, /* (4, 8] integer pel */
44 MvClass3 = 3, /* (8, 16] integer pel */
45 MvClass4 = 4, /* (16, 32] integer pel */
46 MvClass5 = 5, /* (32, 64] integer pel */
47 MvClass6 = 6, /* (64, 128] integer pel */
48 MvClass7 = 7, /* (128, 256] integer pel */
49 MvClass8 = 8, /* (256, 512] integer pel */
50 MvClass9 = 9, /* (512, 1024] integer pel */
51 MvClass10 = 10, /* (1024,2048] integer pel */
52};
53
54enum class BlockSize {
55 Block4x4 = 0,
56 Block4x8 = 1,
57 Block8x4 = 2,
58 Block8x8 = 3,
59 Block8x16 = 4,
60 Block16x8 = 5,
61 Block16x16 = 6,
62 Block16x32 = 7,
63 Block32x16 = 8,
64 Block32x32 = 9,
65 Block32x64 = 10,
66 Block64x32 = 11,
67 Block64x64 = 12,
68 BlockSizes = 13,
69 BlockInvalid = BlockSizes
70};
71
72enum class PredictionMode {
73 DcPred = 0, // Average of above and left pixels
74 VPred = 1, // Vertical
75 HPred = 2, // Horizontal
76 D45Pred = 3, // Directional 45 deg = round(arctan(1 / 1) * 180 / pi)
77 D135Pred = 4, // Directional 135 deg = 180 - 45
78 D117Pred = 5, // Directional 117 deg = 180 - 63
79 D153Pred = 6, // Directional 153 deg = 180 - 27
80 D207Pred = 7, // Directional 207 deg = 180 + 27
81 D63Pred = 8, // Directional 63 deg = round(arctan(2 / 1) * 180 / pi)
82 TmPred = 9, // True-motion
83 NearestMv = 10,
84 NearMv = 11,
85 ZeroMv = 12,
86 NewMv = 13,
87 MbModeCount = 14
88};
89
90enum class TxSize { 34enum class TxSize {
91 Tx4x4 = 0, // 4x4 transform 35 Tx4x4 = 0, // 4x4 transform
92 Tx8x8 = 1, // 8x8 transform 36 Tx8x8 = 1, // 8x8 transform
@@ -104,13 +48,6 @@ enum class TxMode {
104 TxModes = 5 48 TxModes = 5
105}; 49};
106 50
107enum class reference_mode {
108 SingleReference = 0,
109 CompoundReference = 1,
110 ReferenceModeSelect = 2,
111 ReferenceModes = 3
112};
113
114struct Segmentation { 51struct Segmentation {
115 u8 enabled{}; 52 u8 enabled{};
116 u8 update_map{}; 53 u8 update_map{};
@@ -131,7 +68,7 @@ static_assert(sizeof(LoopFilter) == 0x7, "LoopFilter is an invalid size");
131struct Vp9EntropyProbs { 68struct Vp9EntropyProbs {
132 std::array<u8, 36> y_mode_prob{}; 69 std::array<u8, 36> y_mode_prob{};
133 std::array<u8, 64> partition_prob{}; 70 std::array<u8, 64> partition_prob{};
134 std::array<u8, 2304> coef_probs{}; 71 std::array<u8, 1728> coef_probs{};
135 std::array<u8, 8> switchable_interp_prob{}; 72 std::array<u8, 8> switchable_interp_prob{};
136 std::array<u8, 28> inter_mode_prob{}; 73 std::array<u8, 28> inter_mode_prob{};
137 std::array<u8, 4> intra_inter_prob{}; 74 std::array<u8, 4> intra_inter_prob{};
@@ -152,7 +89,7 @@ struct Vp9EntropyProbs {
152 std::array<u8, 2> class_0_hp{}; 89 std::array<u8, 2> class_0_hp{};
153 std::array<u8, 2> high_precision{}; 90 std::array<u8, 2> high_precision{};
154}; 91};
155static_assert(sizeof(Vp9EntropyProbs) == 0x9F4, "Vp9EntropyProbs is an invalid size"); 92static_assert(sizeof(Vp9EntropyProbs) == 0x7B4, "Vp9EntropyProbs is an invalid size");
156 93
157struct Vp9PictureInfo { 94struct Vp9PictureInfo {
158 bool is_key_frame{}; 95 bool is_key_frame{};
@@ -278,72 +215,71 @@ static_assert(sizeof(PictureInfo) == 0x100, "PictureInfo is an invalid size");
278 215
279struct EntropyProbs { 216struct EntropyProbs {
280 INSERT_PADDING_BYTES(1024); 217 INSERT_PADDING_BYTES(1024);
281 std::array<std::array<u8, 4>, 7> inter_mode_prob{}; 218 std::array<u8, 28> inter_mode_prob{};
282 std::array<u8, 4> intra_inter_prob{}; 219 std::array<u8, 4> intra_inter_prob{};
283 INSERT_PADDING_BYTES(80); 220 INSERT_PADDING_BYTES(80);
284 std::array<std::array<u8, 1>, 2> tx_8x8_prob{}; 221 std::array<u8, 2> tx_8x8_prob{};
285 std::array<std::array<u8, 2>, 2> tx_16x16_prob{}; 222 std::array<u8, 4> tx_16x16_prob{};
286 std::array<std::array<u8, 3>, 2> tx_32x32_prob{}; 223 std::array<u8, 6> tx_32x32_prob{};
287 std::array<u8, 4> y_mode_prob_e8{}; 224 std::array<u8, 4> y_mode_prob_e8{};
288 std::array<std::array<u8, 8>, 4> y_mode_prob_e0e7{}; 225 std::array<std::array<u8, 8>, 4> y_mode_prob_e0e7{};
289 INSERT_PADDING_BYTES(64); 226 INSERT_PADDING_BYTES(64);
290 std::array<std::array<u8, 4>, 16> partition_prob{}; 227 std::array<u8, 64> partition_prob{};
291 INSERT_PADDING_BYTES(10); 228 INSERT_PADDING_BYTES(10);
292 std::array<std::array<u8, 2>, 4> switchable_interp_prob{}; 229 std::array<u8, 8> switchable_interp_prob{};
293 std::array<u8, 5> comp_inter_prob{}; 230 std::array<u8, 5> comp_inter_prob{};
294 std::array<u8, 4> skip_probs{}; 231 std::array<u8, 3> skip_probs{};
232 INSERT_PADDING_BYTES(1);
295 std::array<u8, 3> joints{}; 233 std::array<u8, 3> joints{};
296 std::array<u8, 2> sign{}; 234 std::array<u8, 2> sign{};
297 std::array<std::array<u8, 1>, 2> class_0{}; 235 std::array<u8, 2> class_0{};
298 std::array<std::array<u8, 3>, 2> fr{}; 236 std::array<u8, 6> fr{};
299 std::array<u8, 2> class_0_hp{}; 237 std::array<u8, 2> class_0_hp{};
300 std::array<u8, 2> high_precision{}; 238 std::array<u8, 2> high_precision{};
301 std::array<std::array<u8, 10>, 2> classes{}; 239 std::array<u8, 20> classes{};
302 std::array<std::array<std::array<u8, 3>, 2>, 2> class_0_fr{}; 240 std::array<u8, 12> class_0_fr{};
303 std::array<std::array<u8, 10>, 2> pred_bits{}; 241 std::array<u8, 20> pred_bits{};
304 std::array<std::array<u8, 2>, 5> single_ref_prob{}; 242 std::array<u8, 10> single_ref_prob{};
305 std::array<u8, 5> comp_ref_prob{}; 243 std::array<u8, 5> comp_ref_prob{};
306 INSERT_PADDING_BYTES(17); 244 INSERT_PADDING_BYTES(17);
307 std::array<std::array<std::array<std::array<std::array<std::array<u8, 4>, 6>, 6>, 2>, 2>, 4> 245 std::array<u8, 2304> coef_probs{};
308 coef_probs{};
309 246
310 void Convert(Vp9EntropyProbs& fc) { 247 void Convert(Vp9EntropyProbs& fc) {
311 std::memcpy(fc.inter_mode_prob.data(), inter_mode_prob.data(), fc.inter_mode_prob.size()); 248 fc.inter_mode_prob = inter_mode_prob;
312 249 fc.intra_inter_prob = intra_inter_prob;
313 std::memcpy(fc.intra_inter_prob.data(), intra_inter_prob.data(), 250 fc.tx_8x8_prob = tx_8x8_prob;
314 fc.intra_inter_prob.size()); 251 fc.tx_16x16_prob = tx_16x16_prob;
315 252 fc.tx_32x32_prob = tx_32x32_prob;
316 std::memcpy(fc.tx_8x8_prob.data(), tx_8x8_prob.data(), fc.tx_8x8_prob.size()); 253
317 std::memcpy(fc.tx_16x16_prob.data(), tx_16x16_prob.data(), fc.tx_16x16_prob.size()); 254 for (std::size_t i = 0; i < 4; i++) {
318 std::memcpy(fc.tx_32x32_prob.data(), tx_32x32_prob.data(), fc.tx_32x32_prob.size()); 255 for (std::size_t j = 0; j < 9; j++) {
319
320 for (s32 i = 0; i < 4; i++) {
321 for (s32 j = 0; j < 9; j++) {
322 fc.y_mode_prob[j + 9 * i] = j < 8 ? y_mode_prob_e0e7[i][j] : y_mode_prob_e8[i]; 256 fc.y_mode_prob[j + 9 * i] = j < 8 ? y_mode_prob_e0e7[i][j] : y_mode_prob_e8[i];
323 } 257 }
324 } 258 }
325 259
326 std::memcpy(fc.partition_prob.data(), partition_prob.data(), fc.partition_prob.size()); 260 fc.partition_prob = partition_prob;
327 261 fc.switchable_interp_prob = switchable_interp_prob;
328 std::memcpy(fc.switchable_interp_prob.data(), switchable_interp_prob.data(), 262 fc.comp_inter_prob = comp_inter_prob;
329 fc.switchable_interp_prob.size()); 263 fc.skip_probs = skip_probs;
330 std::memcpy(fc.comp_inter_prob.data(), comp_inter_prob.data(), fc.comp_inter_prob.size()); 264 fc.joints = joints;
331 std::memcpy(fc.skip_probs.data(), skip_probs.data(), fc.skip_probs.size()); 265 fc.sign = sign;
332 266 fc.class_0 = class_0;
333 std::memcpy(fc.joints.data(), joints.data(), fc.joints.size()); 267 fc.fr = fr;
334 268 fc.class_0_hp = class_0_hp;
335 std::memcpy(fc.sign.data(), sign.data(), fc.sign.size()); 269 fc.high_precision = high_precision;
336 std::memcpy(fc.class_0.data(), class_0.data(), fc.class_0.size()); 270 fc.classes = classes;
337 std::memcpy(fc.fr.data(), fr.data(), fc.fr.size()); 271 fc.class_0_fr = class_0_fr;
338 std::memcpy(fc.class_0_hp.data(), class_0_hp.data(), fc.class_0_hp.size()); 272 fc.prob_bits = pred_bits;
339 std::memcpy(fc.high_precision.data(), high_precision.data(), fc.high_precision.size()); 273 fc.single_ref_prob = single_ref_prob;
340 std::memcpy(fc.classes.data(), classes.data(), fc.classes.size()); 274 fc.comp_ref_prob = comp_ref_prob;
341 std::memcpy(fc.class_0_fr.data(), class_0_fr.data(), fc.class_0_fr.size()); 275
342 std::memcpy(fc.prob_bits.data(), pred_bits.data(), fc.prob_bits.size()); 276 // Skip the 4th element as it goes unused
343 std::memcpy(fc.single_ref_prob.data(), single_ref_prob.data(), fc.single_ref_prob.size()); 277 for (std::size_t i = 0; i < coef_probs.size(); i += 4) {
344 std::memcpy(fc.comp_ref_prob.data(), comp_ref_prob.data(), fc.comp_ref_prob.size()); 278 const std::size_t j = i - i / 4;
345 279 fc.coef_probs[j] = coef_probs[i];
346 std::memcpy(fc.coef_probs.data(), coef_probs.data(), fc.coef_probs.size()); 280 fc.coef_probs[j + 1] = coef_probs[i + 1];
281 fc.coef_probs[j + 2] = coef_probs[i + 2];
282 }
347 } 283 }
348}; 284};
349static_assert(sizeof(EntropyProbs) == 0xEA0, "EntropyProbs is an invalid size"); 285static_assert(sizeof(EntropyProbs) == 0xEA0, "EntropyProbs is an invalid size");
diff --git a/src/video_core/command_classes/nvdec.cpp b/src/video_core/command_classes/nvdec.cpp
index 8ca7a7b06..79e1f4e13 100644
--- a/src/video_core/command_classes/nvdec.cpp
+++ b/src/video_core/command_classes/nvdec.cpp
@@ -29,11 +29,7 @@ void Nvdec::ProcessMethod(Method method, const std::vector<u32>& arguments) {
29 } 29 }
30} 30}
31 31
32AVFrame* Nvdec::GetFrame() { 32AVFramePtr Nvdec::GetFrame() {
33 return codec->GetCurrentFrame();
34}
35
36const AVFrame* Nvdec::GetFrame() const {
37 return codec->GetCurrentFrame(); 33 return codec->GetCurrentFrame();
38} 34}
39 35
diff --git a/src/video_core/command_classes/nvdec.h b/src/video_core/command_classes/nvdec.h
index eec4443f9..e4877c533 100644
--- a/src/video_core/command_classes/nvdec.h
+++ b/src/video_core/command_classes/nvdec.h
@@ -26,8 +26,7 @@ public:
26 void ProcessMethod(Method method, const std::vector<u32>& arguments); 26 void ProcessMethod(Method method, const std::vector<u32>& arguments);
27 27
28 /// Return most recently decoded frame 28 /// Return most recently decoded frame
29 [[nodiscard]] AVFrame* GetFrame(); 29 [[nodiscard]] AVFramePtr GetFrame();
30 [[nodiscard]] const AVFrame* GetFrame() const;
31 30
32private: 31private:
33 /// Invoke codec to decode a frame 32 /// Invoke codec to decode a frame
diff --git a/src/video_core/command_classes/vic.cpp b/src/video_core/command_classes/vic.cpp
index 5b52da277..248443027 100644
--- a/src/video_core/command_classes/vic.cpp
+++ b/src/video_core/command_classes/vic.cpp
@@ -58,17 +58,18 @@ void Vic::Execute() {
58 return; 58 return;
59 } 59 }
60 const VicConfig config{gpu.MemoryManager().Read<u64>(config_struct_address + 0x20)}; 60 const VicConfig config{gpu.MemoryManager().Read<u64>(config_struct_address + 0x20)};
61 const AVFramePtr frame_ptr = std::move(nvdec_processor->GetFrame());
62 const auto* frame = frame_ptr.get();
63 if (!frame || frame->width == 0 || frame->height == 0) {
64 return;
65 }
61 const VideoPixelFormat pixel_format = 66 const VideoPixelFormat pixel_format =
62 static_cast<VideoPixelFormat>(config.pixel_format.Value()); 67 static_cast<VideoPixelFormat>(config.pixel_format.Value());
63 switch (pixel_format) { 68 switch (pixel_format) {
64 case VideoPixelFormat::BGRA8: 69 case VideoPixelFormat::BGRA8:
65 case VideoPixelFormat::RGBA8: { 70 case VideoPixelFormat::RGBA8: {
66 LOG_TRACE(Service_NVDRV, "Writing RGB Frame"); 71 LOG_TRACE(Service_NVDRV, "Writing RGB Frame");
67 const auto* frame = nvdec_processor->GetFrame();
68 72
69 if (!frame || frame->width == 0 || frame->height == 0) {
70 return;
71 }
72 if (scaler_ctx == nullptr || frame->width != scaler_width || 73 if (scaler_ctx == nullptr || frame->width != scaler_width ||
73 frame->height != scaler_height) { 74 frame->height != scaler_height) {
74 const AVPixelFormat target_format = 75 const AVPixelFormat target_format =
@@ -121,12 +122,6 @@ void Vic::Execute() {
121 case VideoPixelFormat::Yuv420: { 122 case VideoPixelFormat::Yuv420: {
122 LOG_TRACE(Service_NVDRV, "Writing YUV420 Frame"); 123 LOG_TRACE(Service_NVDRV, "Writing YUV420 Frame");
123 124
124 const auto* frame = nvdec_processor->GetFrame();
125
126 if (!frame || frame->width == 0 || frame->height == 0) {
127 return;
128 }
129
130 const std::size_t surface_width = config.surface_width_minus1 + 1; 125 const std::size_t surface_width = config.surface_width_minus1 + 1;
131 const std::size_t surface_height = config.surface_height_minus1 + 1; 126 const std::size_t surface_height = config.surface_height_minus1 + 1;
132 const std::size_t half_width = surface_width / 2; 127 const std::size_t half_width = surface_width / 2;
diff --git a/src/video_core/engines/maxwell_3d.h b/src/video_core/engines/maxwell_3d.h
index 1cbe8fe67..b0d9559d0 100644
--- a/src/video_core/engines/maxwell_3d.h
+++ b/src/video_core/engines/maxwell_3d.h
@@ -755,7 +755,11 @@ public:
755 755
756 u32 data_upload; 756 u32 data_upload;
757 757
758 INSERT_UNION_PADDING_WORDS(0x44); 758 INSERT_UNION_PADDING_WORDS(0x16);
759
760 u32 force_early_fragment_tests;
761
762 INSERT_UNION_PADDING_WORDS(0x2D);
759 763
760 struct { 764 struct {
761 union { 765 union {
@@ -1572,6 +1576,7 @@ ASSERT_REG_POSITION(shadow_ram_control, 0x49);
1572ASSERT_REG_POSITION(upload, 0x60); 1576ASSERT_REG_POSITION(upload, 0x60);
1573ASSERT_REG_POSITION(exec_upload, 0x6C); 1577ASSERT_REG_POSITION(exec_upload, 0x6C);
1574ASSERT_REG_POSITION(data_upload, 0x6D); 1578ASSERT_REG_POSITION(data_upload, 0x6D);
1579ASSERT_REG_POSITION(force_early_fragment_tests, 0x84);
1575ASSERT_REG_POSITION(sync_info, 0xB2); 1580ASSERT_REG_POSITION(sync_info, 0xB2);
1576ASSERT_REG_POSITION(tess_mode, 0xC8); 1581ASSERT_REG_POSITION(tess_mode, 0xC8);
1577ASSERT_REG_POSITION(tess_level_outer, 0xC9); 1582ASSERT_REG_POSITION(tess_level_outer, 0xC9);
diff --git a/src/video_core/renderer_vulkan/fixed_pipeline_state.cpp b/src/video_core/renderer_vulkan/fixed_pipeline_state.cpp
index fffae528e..5ec43db11 100644
--- a/src/video_core/renderer_vulkan/fixed_pipeline_state.cpp
+++ b/src/video_core/renderer_vulkan/fixed_pipeline_state.cpp
@@ -46,7 +46,7 @@ void FixedPipelineState::Fill(const Maxwell& regs, bool has_extended_dynamic_sta
46 regs.polygon_offset_fill_enable}; 46 regs.polygon_offset_fill_enable};
47 const u32 topology_index = static_cast<u32>(regs.draw.topology.Value()); 47 const u32 topology_index = static_cast<u32>(regs.draw.topology.Value());
48 48
49 raw = 0; 49 raw1 = 0;
50 primitive_restart_enable.Assign(regs.primitive_restart.enabled != 0 ? 1 : 0); 50 primitive_restart_enable.Assign(regs.primitive_restart.enabled != 0 ? 1 : 0);
51 depth_bias_enable.Assign(enabled_lut[POLYGON_OFFSET_ENABLE_LUT[topology_index]] != 0 ? 1 : 0); 51 depth_bias_enable.Assign(enabled_lut[POLYGON_OFFSET_ENABLE_LUT[topology_index]] != 0 ? 1 : 0);
52 depth_clamp_disabled.Assign(regs.view_volume_clip_control.depth_clamp_disabled.Value()); 52 depth_clamp_disabled.Assign(regs.view_volume_clip_control.depth_clamp_disabled.Value());
@@ -61,12 +61,13 @@ void FixedPipelineState::Fill(const Maxwell& regs, bool has_extended_dynamic_sta
61 rasterize_enable.Assign(regs.rasterize_enable != 0 ? 1 : 0); 61 rasterize_enable.Assign(regs.rasterize_enable != 0 ? 1 : 0);
62 topology.Assign(regs.draw.topology); 62 topology.Assign(regs.draw.topology);
63 63
64 alpha_raw = 0; 64 raw2 = 0;
65 const auto test_func = 65 const auto test_func =
66 regs.alpha_test_enabled == 1 ? regs.alpha_test_func : Maxwell::ComparisonOp::Always; 66 regs.alpha_test_enabled == 1 ? regs.alpha_test_func : Maxwell::ComparisonOp::Always;
67 alpha_test_func.Assign(PackComparisonOp(test_func)); 67 alpha_test_func.Assign(PackComparisonOp(test_func));
68 alpha_test_ref = Common::BitCast<u32>(regs.alpha_test_ref); 68 early_z.Assign(regs.force_early_fragment_tests != 0 ? 1 : 0);
69 69
70 alpha_test_ref = Common::BitCast<u32>(regs.alpha_test_ref);
70 point_size = Common::BitCast<u32>(regs.point_size); 71 point_size = Common::BitCast<u32>(regs.point_size);
71 72
72 for (std::size_t index = 0; index < Maxwell::NumVertexArrays; ++index) { 73 for (std::size_t index = 0; index < Maxwell::NumVertexArrays; ++index) {
diff --git a/src/video_core/renderer_vulkan/fixed_pipeline_state.h b/src/video_core/renderer_vulkan/fixed_pipeline_state.h
index 42480e8d0..c26b77790 100644
--- a/src/video_core/renderer_vulkan/fixed_pipeline_state.h
+++ b/src/video_core/renderer_vulkan/fixed_pipeline_state.h
@@ -171,7 +171,7 @@ struct FixedPipelineState {
171 }; 171 };
172 172
173 union { 173 union {
174 u32 raw; 174 u32 raw1;
175 BitField<0, 1, u32> no_extended_dynamic_state; 175 BitField<0, 1, u32> no_extended_dynamic_state;
176 BitField<2, 1, u32> primitive_restart_enable; 176 BitField<2, 1, u32> primitive_restart_enable;
177 BitField<3, 1, u32> depth_bias_enable; 177 BitField<3, 1, u32> depth_bias_enable;
@@ -187,13 +187,13 @@ struct FixedPipelineState {
187 BitField<23, 1, u32> rasterize_enable; 187 BitField<23, 1, u32> rasterize_enable;
188 BitField<24, 4, Maxwell::PrimitiveTopology> topology; 188 BitField<24, 4, Maxwell::PrimitiveTopology> topology;
189 }; 189 };
190
191 u32 alpha_test_ref; ///< Alpha test reference value
192 union { 190 union {
193 u32 alpha_raw; 191 u32 raw2;
194 BitField<0, 3, u32> alpha_test_func; 192 BitField<0, 3, u32> alpha_test_func;
193 BitField<3, 1, u32> early_z;
195 }; 194 };
196 195
196 u32 alpha_test_ref;
197 u32 point_size; 197 u32 point_size;
198 std::array<u32, Maxwell::NumVertexArrays> binding_divisors; 198 std::array<u32, Maxwell::NumVertexArrays> binding_divisors;
199 std::array<VertexAttribute, Maxwell::NumVertexAttributes> attributes; 199 std::array<VertexAttribute, Maxwell::NumVertexAttributes> attributes;
diff --git a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp
index f9efe526d..df7e8c864 100644
--- a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp
+++ b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp
@@ -344,6 +344,7 @@ VKPipelineCache::DecompileShaders(const FixedPipelineState& fixed_state) {
344 specialization.attribute_types[i] = attribute.Type(); 344 specialization.attribute_types[i] = attribute.Type();
345 } 345 }
346 specialization.ndc_minus_one_to_one = fixed_state.ndc_minus_one_to_one; 346 specialization.ndc_minus_one_to_one = fixed_state.ndc_minus_one_to_one;
347 specialization.early_fragment_tests = fixed_state.early_z;
347 348
348 // Alpha test 349 // Alpha test
349 specialization.alpha_test_func = 350 specialization.alpha_test_func =
diff --git a/src/video_core/renderer_vulkan/vk_shader_decompiler.cpp b/src/video_core/renderer_vulkan/vk_shader_decompiler.cpp
index 1c52f40bb..fed9ebecd 100644
--- a/src/video_core/renderer_vulkan/vk_shader_decompiler.cpp
+++ b/src/video_core/renderer_vulkan/vk_shader_decompiler.cpp
@@ -315,7 +315,6 @@ public:
315 "supported on this device"); 315 "supported on this device");
316 } 316 }
317 } 317 }
318
319 if (ir.UsesLayer() || ir.UsesViewportIndex()) { 318 if (ir.UsesLayer() || ir.UsesViewportIndex()) {
320 if (ir.UsesViewportIndex()) { 319 if (ir.UsesViewportIndex()) {
321 AddCapability(spv::Capability::MultiViewport); 320 AddCapability(spv::Capability::MultiViewport);
@@ -325,11 +324,9 @@ public:
325 AddCapability(spv::Capability::ShaderViewportIndexLayerEXT); 324 AddCapability(spv::Capability::ShaderViewportIndexLayerEXT);
326 } 325 }
327 } 326 }
328
329 if (device.IsFormatlessImageLoadSupported()) { 327 if (device.IsFormatlessImageLoadSupported()) {
330 AddCapability(spv::Capability::StorageImageReadWithoutFormat); 328 AddCapability(spv::Capability::StorageImageReadWithoutFormat);
331 } 329 }
332
333 if (device.IsFloat16Supported()) { 330 if (device.IsFloat16Supported()) {
334 AddCapability(spv::Capability::Float16); 331 AddCapability(spv::Capability::Float16);
335 } 332 }
@@ -377,6 +374,9 @@ public:
377 if (header.ps.omap.depth) { 374 if (header.ps.omap.depth) {
378 AddExecutionMode(main, spv::ExecutionMode::DepthReplacing); 375 AddExecutionMode(main, spv::ExecutionMode::DepthReplacing);
379 } 376 }
377 if (specialization.early_fragment_tests) {
378 AddExecutionMode(main, spv::ExecutionMode::EarlyFragmentTests);
379 }
380 break; 380 break;
381 case ShaderType::Compute: 381 case ShaderType::Compute:
382 const auto workgroup_size = specialization.workgroup_size; 382 const auto workgroup_size = specialization.workgroup_size;
diff --git a/src/video_core/renderer_vulkan/vk_shader_decompiler.h b/src/video_core/renderer_vulkan/vk_shader_decompiler.h
index cd3d0a415..110848922 100644
--- a/src/video_core/renderer_vulkan/vk_shader_decompiler.h
+++ b/src/video_core/renderer_vulkan/vk_shader_decompiler.h
@@ -95,6 +95,7 @@ struct Specialization final {
95 std::bitset<Maxwell::NumVertexAttributes> enabled_attributes; 95 std::bitset<Maxwell::NumVertexAttributes> enabled_attributes;
96 std::array<Maxwell::VertexAttribute::Type, Maxwell::NumVertexAttributes> attribute_types{}; 96 std::array<Maxwell::VertexAttribute::Type, Maxwell::NumVertexAttributes> attribute_types{};
97 bool ndc_minus_one_to_one{}; 97 bool ndc_minus_one_to_one{};
98 bool early_fragment_tests{};
98 float alpha_test_ref{}; 99 float alpha_test_ref{};
99 Maxwell::ComparisonOp alpha_test_func{}; 100 Maxwell::ComparisonOp alpha_test_func{};
100}; 101};
diff --git a/src/yuzu/bootmanager.cpp b/src/yuzu/bootmanager.cpp
index ea8f0d7b1..489104d5f 100644
--- a/src/yuzu/bootmanager.cpp
+++ b/src/yuzu/bootmanager.cpp
@@ -35,7 +35,7 @@
35#include "core/settings.h" 35#include "core/settings.h"
36#include "input_common/keyboard.h" 36#include "input_common/keyboard.h"
37#include "input_common/main.h" 37#include "input_common/main.h"
38#include "input_common/motion_emu.h" 38#include "input_common/mouse/mouse_input.h"
39#include "video_core/renderer_base.h" 39#include "video_core/renderer_base.h"
40#include "video_core/video_core.h" 40#include "video_core/video_core.h"
41#include "yuzu/bootmanager.h" 41#include "yuzu/bootmanager.h"
@@ -388,23 +388,19 @@ void GRenderWindow::keyReleaseEvent(QKeyEvent* event) {
388} 388}
389 389
390void GRenderWindow::mousePressEvent(QMouseEvent* event) { 390void GRenderWindow::mousePressEvent(QMouseEvent* event) {
391 if (!Settings::values.touchscreen.enabled) {
392 input_subsystem->GetKeyboard()->PressKey(event->button());
393 return;
394 }
395
396 // Touch input is handled in TouchBeginEvent 391 // Touch input is handled in TouchBeginEvent
397 if (event->source() == Qt::MouseEventSynthesizedBySystem) { 392 if (event->source() == Qt::MouseEventSynthesizedBySystem) {
398 return; 393 return;
399 } 394 }
400 395
401 auto pos = event->pos(); 396 auto pos = event->pos();
397 const auto [x, y] = ScaleTouch(pos);
398 input_subsystem->GetMouse()->PressButton(x, y, event->button());
399
402 if (event->button() == Qt::LeftButton) { 400 if (event->button() == Qt::LeftButton) {
403 const auto [x, y] = ScaleTouch(pos);
404 this->TouchPressed(x, y); 401 this->TouchPressed(x, y);
405 } else if (event->button() == Qt::RightButton) {
406 input_subsystem->GetMotionEmu()->BeginTilt(pos.x(), pos.y());
407 } 402 }
403
408 QWidget::mousePressEvent(event); 404 QWidget::mousePressEvent(event);
409} 405}
410 406
@@ -416,26 +412,22 @@ void GRenderWindow::mouseMoveEvent(QMouseEvent* event) {
416 412
417 auto pos = event->pos(); 413 auto pos = event->pos();
418 const auto [x, y] = ScaleTouch(pos); 414 const auto [x, y] = ScaleTouch(pos);
415 input_subsystem->GetMouse()->MouseMove(x, y);
419 this->TouchMoved(x, y); 416 this->TouchMoved(x, y);
420 input_subsystem->GetMotionEmu()->Tilt(pos.x(), pos.y()); 417
421 QWidget::mouseMoveEvent(event); 418 QWidget::mouseMoveEvent(event);
422} 419}
423 420
424void GRenderWindow::mouseReleaseEvent(QMouseEvent* event) { 421void GRenderWindow::mouseReleaseEvent(QMouseEvent* event) {
425 if (!Settings::values.touchscreen.enabled) {
426 input_subsystem->GetKeyboard()->ReleaseKey(event->button());
427 return;
428 }
429
430 // Touch input is handled in TouchEndEvent 422 // Touch input is handled in TouchEndEvent
431 if (event->source() == Qt::MouseEventSynthesizedBySystem) { 423 if (event->source() == Qt::MouseEventSynthesizedBySystem) {
432 return; 424 return;
433 } 425 }
434 426
427 input_subsystem->GetMouse()->ReleaseButton(event->button());
428
435 if (event->button() == Qt::LeftButton) { 429 if (event->button() == Qt::LeftButton) {
436 this->TouchReleased(); 430 this->TouchReleased();
437 } else if (event->button() == Qt::RightButton) {
438 input_subsystem->GetMotionEmu()->EndTilt();
439 } 431 }
440} 432}
441 433
diff --git a/src/yuzu/configuration/config.cpp b/src/yuzu/configuration/config.cpp
index 8be9e93c3..fcc38b3af 100644
--- a/src/yuzu/configuration/config.cpp
+++ b/src/yuzu/configuration/config.cpp
@@ -569,16 +569,11 @@ void Config::ReadMotionTouchValues() {
569 ReadSetting(QStringLiteral("touch_from_button_map"), 0).toInt(); 569 ReadSetting(QStringLiteral("touch_from_button_map"), 0).toInt();
570 Settings::values.touch_from_button_map_index = 570 Settings::values.touch_from_button_map_index =
571 std::clamp(Settings::values.touch_from_button_map_index, 0, num_touch_from_button_maps - 1); 571 std::clamp(Settings::values.touch_from_button_map_index, 0, num_touch_from_button_maps - 1);
572 Settings::values.udp_input_address = 572 Settings::values.udp_input_servers =
573 ReadSetting(QStringLiteral("udp_input_address"), 573 ReadSetting(QStringLiteral("udp_input_servers"),
574 QString::fromUtf8(InputCommon::CemuhookUDP::DEFAULT_ADDR)) 574 QString::fromUtf8(InputCommon::CemuhookUDP::DEFAULT_SRV))
575 .toString() 575 .toString()
576 .toStdString(); 576 .toStdString();
577 Settings::values.udp_input_port = static_cast<u16>(
578 ReadSetting(QStringLiteral("udp_input_port"), InputCommon::CemuhookUDP::DEFAULT_PORT)
579 .toInt());
580 Settings::values.udp_pad_index =
581 static_cast<u8>(ReadSetting(QStringLiteral("udp_pad_index"), 0).toUInt());
582} 577}
583 578
584void Config::ReadCoreValues() { 579void Config::ReadCoreValues() {
@@ -1109,12 +1104,9 @@ void Config::SaveMotionTouchValues() {
1109 false); 1104 false);
1110 WriteSetting(QStringLiteral("touch_from_button_map"), 1105 WriteSetting(QStringLiteral("touch_from_button_map"),
1111 Settings::values.touch_from_button_map_index, 0); 1106 Settings::values.touch_from_button_map_index, 0);
1112 WriteSetting(QStringLiteral("udp_input_address"), 1107 WriteSetting(QStringLiteral("udp_input_servers"),
1113 QString::fromStdString(Settings::values.udp_input_address), 1108 QString::fromStdString(Settings::values.udp_input_servers),
1114 QString::fromUtf8(InputCommon::CemuhookUDP::DEFAULT_ADDR)); 1109 QString::fromUtf8(InputCommon::CemuhookUDP::DEFAULT_SRV));
1115 WriteSetting(QStringLiteral("udp_input_port"), Settings::values.udp_input_port,
1116 InputCommon::CemuhookUDP::DEFAULT_PORT);
1117 WriteSetting(QStringLiteral("udp_pad_index"), Settings::values.udp_pad_index, 0);
1118 1110
1119 qt_config->beginWriteArray(QStringLiteral("touch_from_button_maps")); 1111 qt_config->beginWriteArray(QStringLiteral("touch_from_button_maps"));
1120 for (std::size_t p = 0; p < Settings::values.touch_from_button_maps.size(); ++p) { 1112 for (std::size_t p = 0; p < Settings::values.touch_from_button_maps.size(); ++p) {
diff --git a/src/yuzu/configuration/configure_input_player.cpp b/src/yuzu/configuration/configure_input_player.cpp
index 918bfb56b..f9915fb7a 100644
--- a/src/yuzu/configuration/configure_input_player.cpp
+++ b/src/yuzu/configuration/configure_input_player.cpp
@@ -19,6 +19,7 @@
19#include "core/hle/service/sm/sm.h" 19#include "core/hle/service/sm/sm.h"
20#include "input_common/gcadapter/gc_poller.h" 20#include "input_common/gcadapter/gc_poller.h"
21#include "input_common/main.h" 21#include "input_common/main.h"
22#include "input_common/mouse/mouse_poller.h"
22#include "input_common/udp/udp.h" 23#include "input_common/udp/udp.h"
23#include "ui_configure_input_player.h" 24#include "ui_configure_input_player.h"
24#include "yuzu/configuration/config.h" 25#include "yuzu/configuration/config.h"
@@ -152,6 +153,14 @@ QString ButtonToText(const Common::ParamPackage& param) {
152 return {}; 153 return {};
153 } 154 }
154 155
156 if (param.Get("engine", "") == "mouse") {
157 if (param.Has("button")) {
158 const QString button_str = QString::number(int(param.Get("button", 0)));
159 return QObject::tr("Click %1").arg(button_str);
160 }
161 return GetKeyName(param.Get("code", 0));
162 }
163
155 return QObject::tr("[unknown]"); 164 return QObject::tr("[unknown]");
156} 165}
157 166
@@ -203,6 +212,26 @@ QString AnalogToText(const Common::ParamPackage& param, const std::string& dir)
203 212
204 return {}; 213 return {};
205 } 214 }
215
216 if (param.Get("engine", "") == "mouse") {
217 if (dir == "modifier") {
218 return QObject::tr("[unused]");
219 }
220
221 if (dir == "left" || dir == "right") {
222 const QString axis_x_str = QString::fromStdString(param.Get("axis_x", ""));
223
224 return QObject::tr("Mouse %1").arg(axis_x_str);
225 }
226
227 if (dir == "up" || dir == "down") {
228 const QString axis_y_str = QString::fromStdString(param.Get("axis_y", ""));
229
230 return QObject::tr("Mouse %1").arg(axis_y_str);
231 }
232
233 return {};
234 }
206 return QObject::tr("[unknown]"); 235 return QObject::tr("[unknown]");
207} 236}
208} // namespace 237} // namespace
@@ -484,6 +513,34 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i
484 return; 513 return;
485 } 514 }
486 } 515 }
516 if (input_subsystem->GetMouseButtons()->IsPolling()) {
517 params = input_subsystem->GetMouseButtons()->GetNextInput();
518 if (params.Has("engine") && IsInputAcceptable(params)) {
519 SetPollingResult(params, false);
520 return;
521 }
522 }
523 if (input_subsystem->GetMouseAnalogs()->IsPolling()) {
524 params = input_subsystem->GetMouseAnalogs()->GetNextInput();
525 if (params.Has("engine") && IsInputAcceptable(params)) {
526 SetPollingResult(params, false);
527 return;
528 }
529 }
530 if (input_subsystem->GetMouseMotions()->IsPolling()) {
531 params = input_subsystem->GetMouseMotions()->GetNextInput();
532 if (params.Has("engine") && IsInputAcceptable(params)) {
533 SetPollingResult(params, false);
534 return;
535 }
536 }
537 if (input_subsystem->GetMouseTouch()->IsPolling()) {
538 params = input_subsystem->GetMouseTouch()->GetNextInput();
539 if (params.Has("engine") && IsInputAcceptable(params)) {
540 SetPollingResult(params, false);
541 return;
542 }
543 }
487 for (auto& poller : device_pollers) { 544 for (auto& poller : device_pollers) {
488 params = poller->GetNextInput(); 545 params = poller->GetNextInput();
489 if (params.Has("engine") && IsInputAcceptable(params)) { 546 if (params.Has("engine") && IsInputAcceptable(params)) {
@@ -761,8 +818,9 @@ void ConfigureInputPlayer::UpdateUI() {
761 818
762 int slider_value; 819 int slider_value;
763 auto& param = analogs_param[analog_id]; 820 auto& param = analogs_param[analog_id];
764 const bool is_controller = 821 const bool is_controller = param.Get("engine", "") == "sdl" ||
765 param.Get("engine", "") == "sdl" || param.Get("engine", "") == "gcpad"; 822 param.Get("engine", "") == "gcpad" ||
823 param.Get("engine", "") == "mouse";
766 824
767 if (is_controller) { 825 if (is_controller) {
768 if (!param.Has("deadzone")) { 826 if (!param.Has("deadzone")) {
@@ -1078,6 +1136,16 @@ void ConfigureInputPlayer::HandleClick(
1078 input_subsystem->GetUDPMotions()->BeginConfiguration(); 1136 input_subsystem->GetUDPMotions()->BeginConfiguration();
1079 } 1137 }
1080 1138
1139 if (type == InputCommon::Polling::DeviceType::Button) {
1140 input_subsystem->GetMouseButtons()->BeginConfiguration();
1141 } else if (type == InputCommon::Polling::DeviceType::AnalogPreferred) {
1142 input_subsystem->GetMouseAnalogs()->BeginConfiguration();
1143 } else if (type == InputCommon::Polling::DeviceType::Motion) {
1144 input_subsystem->GetMouseMotions()->BeginConfiguration();
1145 } else {
1146 input_subsystem->GetMouseTouch()->BeginConfiguration();
1147 }
1148
1081 timeout_timer->start(2500); // Cancel after 2.5 seconds 1149 timeout_timer->start(2500); // Cancel after 2.5 seconds
1082 poll_timer->start(50); // Check for new inputs every 50ms 1150 poll_timer->start(50); // Check for new inputs every 50ms
1083} 1151}
@@ -1097,6 +1165,11 @@ void ConfigureInputPlayer::SetPollingResult(const Common::ParamPackage& params,
1097 1165
1098 input_subsystem->GetUDPMotions()->EndConfiguration(); 1166 input_subsystem->GetUDPMotions()->EndConfiguration();
1099 1167
1168 input_subsystem->GetMouseButtons()->EndConfiguration();
1169 input_subsystem->GetMouseAnalogs()->EndConfiguration();
1170 input_subsystem->GetMouseMotions()->EndConfiguration();
1171 input_subsystem->GetMouseTouch()->EndConfiguration();
1172
1100 if (!abort) { 1173 if (!abort) {
1101 (*input_setter)(params); 1174 (*input_setter)(params);
1102 } 1175 }
@@ -1128,15 +1201,7 @@ void ConfigureInputPlayer::mousePressEvent(QMouseEvent* event) {
1128 return; 1201 return;
1129 } 1202 }
1130 1203
1131 if (want_keyboard_mouse) { 1204 input_subsystem->GetMouse()->PressButton(0, 0, event->button());
1132 SetPollingResult(Common::ParamPackage{InputCommon::GenerateKeyboardParam(event->button())},
1133 false);
1134 } else {
1135 // We don't want any mouse buttons, so don't stop polling
1136 return;
1137 }
1138
1139 SetPollingResult({}, true);
1140} 1205}
1141 1206
1142void ConfigureInputPlayer::keyPressEvent(QKeyEvent* event) { 1207void ConfigureInputPlayer::keyPressEvent(QKeyEvent* event) {
diff --git a/src/yuzu/configuration/configure_motion_touch.cpp b/src/yuzu/configuration/configure_motion_touch.cpp
index 170574d9b..2afac591a 100644
--- a/src/yuzu/configuration/configure_motion_touch.cpp
+++ b/src/yuzu/configuration/configure_motion_touch.cpp
@@ -3,10 +3,12 @@
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <array> 5#include <array>
6#include <sstream>
6#include <QCloseEvent> 7#include <QCloseEvent>
7#include <QLabel> 8#include <QLabel>
8#include <QMessageBox> 9#include <QMessageBox>
9#include <QPushButton> 10#include <QPushButton>
11#include <QStringListModel>
10#include <QVBoxLayout> 12#include <QVBoxLayout>
11#include "common/logging/log.h" 13#include "common/logging/log.h"
12#include "core/settings.h" 14#include "core/settings.h"
@@ -74,11 +76,6 @@ void CalibrationConfigurationDialog::UpdateButtonText(const QString& text) {
74 cancel_button->setText(text); 76 cancel_button->setText(text);
75} 77}
76 78
77constexpr std::array<std::pair<const char*, const char*>, 2> MotionProviders = {{
78 {"motion_emu", QT_TRANSLATE_NOOP("ConfigureMotionTouch", "Mouse (Right Click)")},
79 {"cemuhookudp", QT_TRANSLATE_NOOP("ConfigureMotionTouch", "CemuhookUDP")},
80}};
81
82constexpr std::array<std::pair<const char*, const char*>, 2> TouchProviders = {{ 79constexpr std::array<std::pair<const char*, const char*>, 2> TouchProviders = {{
83 {"emu_window", QT_TRANSLATE_NOOP("ConfigureMotionTouch", "Emulator Window")}, 80 {"emu_window", QT_TRANSLATE_NOOP("ConfigureMotionTouch", "Emulator Window")},
84 {"cemuhookudp", QT_TRANSLATE_NOOP("ConfigureMotionTouch", "CemuhookUDP")}, 81 {"cemuhookudp", QT_TRANSLATE_NOOP("ConfigureMotionTouch", "CemuhookUDP")},
@@ -89,9 +86,6 @@ ConfigureMotionTouch::ConfigureMotionTouch(QWidget* parent,
89 : QDialog(parent), input_subsystem{input_subsystem_}, 86 : QDialog(parent), input_subsystem{input_subsystem_},
90 ui(std::make_unique<Ui::ConfigureMotionTouch>()) { 87 ui(std::make_unique<Ui::ConfigureMotionTouch>()) {
91 ui->setupUi(this); 88 ui->setupUi(this);
92 for (const auto& [provider, name] : MotionProviders) {
93 ui->motion_provider->addItem(tr(name), QString::fromUtf8(provider));
94 }
95 for (const auto& [provider, name] : TouchProviders) { 89 for (const auto& [provider, name] : TouchProviders) {
96 ui->touch_provider->addItem(tr(name), QString::fromUtf8(provider)); 90 ui->touch_provider->addItem(tr(name), QString::fromUtf8(provider));
97 } 91 }
@@ -116,8 +110,6 @@ void ConfigureMotionTouch::SetConfiguration() {
116 const std::string motion_engine = motion_param.Get("engine", "motion_emu"); 110 const std::string motion_engine = motion_param.Get("engine", "motion_emu");
117 const std::string touch_engine = touch_param.Get("engine", "emu_window"); 111 const std::string touch_engine = touch_param.Get("engine", "emu_window");
118 112
119 ui->motion_provider->setCurrentIndex(
120 ui->motion_provider->findData(QString::fromStdString(motion_engine)));
121 ui->touch_provider->setCurrentIndex( 113 ui->touch_provider->setCurrentIndex(
122 ui->touch_provider->findData(QString::fromStdString(touch_engine))); 114 ui->touch_provider->findData(QString::fromStdString(touch_engine)));
123 ui->touch_from_button_checkbox->setChecked(Settings::values.use_touch_from_button); 115 ui->touch_from_button_checkbox->setChecked(Settings::values.use_touch_from_button);
@@ -133,23 +125,30 @@ void ConfigureMotionTouch::SetConfiguration() {
133 max_x = touch_param.Get("max_x", 1800); 125 max_x = touch_param.Get("max_x", 1800);
134 max_y = touch_param.Get("max_y", 850); 126 max_y = touch_param.Get("max_y", 850);
135 127
136 ui->udp_server->setText(QString::fromStdString(Settings::values.udp_input_address)); 128 ui->udp_server->setText(QString::fromStdString("127.0.0.1"));
137 ui->udp_port->setText(QString::number(Settings::values.udp_input_port)); 129 ui->udp_port->setText(QString::number(26760));
138 ui->udp_pad_index->setCurrentIndex(Settings::values.udp_pad_index); 130
131 udp_server_list_model = new QStringListModel(this);
132 udp_server_list_model->setStringList({});
133 ui->udp_server_list->setModel(udp_server_list_model);
134
135 std::stringstream ss(Settings::values.udp_input_servers);
136 std::string token;
137
138 while (std::getline(ss, token, ',')) {
139 const int row = udp_server_list_model->rowCount();
140 udp_server_list_model->insertRows(row, 1);
141 const QModelIndex index = udp_server_list_model->index(row);
142 udp_server_list_model->setData(index, QString::fromStdString(token));
143 }
139} 144}
140 145
141void ConfigureMotionTouch::UpdateUiDisplay() { 146void ConfigureMotionTouch::UpdateUiDisplay() {
142 const QString motion_engine = ui->motion_provider->currentData().toString();
143 const QString touch_engine = ui->touch_provider->currentData().toString(); 147 const QString touch_engine = ui->touch_provider->currentData().toString();
144 const QString cemuhook_udp = QStringLiteral("cemuhookudp"); 148 const QString cemuhook_udp = QStringLiteral("cemuhookudp");
145 149
146 if (motion_engine == QStringLiteral("motion_emu")) { 150 ui->motion_sensitivity_label->setVisible(true);
147 ui->motion_sensitivity_label->setVisible(true); 151 ui->motion_sensitivity->setVisible(true);
148 ui->motion_sensitivity->setVisible(true);
149 } else {
150 ui->motion_sensitivity_label->setVisible(false);
151 ui->motion_sensitivity->setVisible(false);
152 }
153 152
154 if (touch_engine == cemuhook_udp) { 153 if (touch_engine == cemuhook_udp) {
155 ui->touch_calibration->setVisible(true); 154 ui->touch_calibration->setVisible(true);
@@ -163,19 +162,15 @@ void ConfigureMotionTouch::UpdateUiDisplay() {
163 ui->touch_calibration_label->setVisible(false); 162 ui->touch_calibration_label->setVisible(false);
164 } 163 }
165 164
166 if (motion_engine == cemuhook_udp || touch_engine == cemuhook_udp) { 165 ui->udp_config_group_box->setVisible(true);
167 ui->udp_config_group_box->setVisible(true);
168 } else {
169 ui->udp_config_group_box->setVisible(false);
170 }
171} 166}
172 167
173void ConfigureMotionTouch::ConnectEvents() { 168void ConfigureMotionTouch::ConnectEvents() {
174 connect(ui->motion_provider, qOverload<int>(&QComboBox::currentIndexChanged), this,
175 [this](int index) { UpdateUiDisplay(); });
176 connect(ui->touch_provider, qOverload<int>(&QComboBox::currentIndexChanged), this, 169 connect(ui->touch_provider, qOverload<int>(&QComboBox::currentIndexChanged), this,
177 [this](int index) { UpdateUiDisplay(); }); 170 [this](int index) { UpdateUiDisplay(); });
178 connect(ui->udp_test, &QPushButton::clicked, this, &ConfigureMotionTouch::OnCemuhookUDPTest); 171 connect(ui->udp_test, &QPushButton::clicked, this, &ConfigureMotionTouch::OnCemuhookUDPTest);
172 connect(ui->udp_add, &QPushButton::clicked, this, &ConfigureMotionTouch::OnUDPAddServer);
173 connect(ui->udp_remove, &QPushButton::clicked, this, &ConfigureMotionTouch::OnUDPDeleteServer);
179 connect(ui->touch_calibration_config, &QPushButton::clicked, this, 174 connect(ui->touch_calibration_config, &QPushButton::clicked, this,
180 &ConfigureMotionTouch::OnConfigureTouchCalibration); 175 &ConfigureMotionTouch::OnConfigureTouchCalibration);
181 connect(ui->touch_from_button_config_btn, &QPushButton::clicked, this, 176 connect(ui->touch_from_button_config_btn, &QPushButton::clicked, this,
@@ -187,13 +182,58 @@ void ConfigureMotionTouch::ConnectEvents() {
187 }); 182 });
188} 183}
189 184
185void ConfigureMotionTouch::OnUDPAddServer() {
186 QRegExp re(tr("^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?["
187 "0-9][0-9]?)$")); // a valid ip address
188 bool ok;
189 QString port_text = ui->udp_port->text();
190 QString server_text = ui->udp_server->text();
191 const QString server_string = tr("%1:%2").arg(server_text, port_text);
192 int port_number = port_text.toInt(&ok, 10);
193 int row = udp_server_list_model->rowCount();
194
195 if (!ok) {
196 QMessageBox::warning(this, tr("yuzu"), tr("Port number has invalid characters"));
197 return;
198 }
199 if (port_number < 0 || port_number > 65353) {
200 QMessageBox::warning(this, tr("yuzu"), tr("Port has to be in range 0 and 65353"));
201 return;
202 }
203 if (!re.exactMatch(server_text)) {
204 QMessageBox::warning(this, tr("yuzu"), tr("IP address is not valid"));
205 return;
206 }
207 // Search for duplicates
208 for (const auto& item : udp_server_list_model->stringList()) {
209 if (item == server_string) {
210 QMessageBox::warning(this, tr("yuzu"), tr("This UDP server already exists"));
211 return;
212 }
213 }
214 // Limit server count to 8
215 if (row == 8) {
216 QMessageBox::warning(this, tr("yuzu"), tr("Unable to add more than 8 servers"));
217 return;
218 }
219
220 udp_server_list_model->insertRows(row, 1);
221 QModelIndex index = udp_server_list_model->index(row);
222 udp_server_list_model->setData(index, server_string);
223 ui->udp_server_list->setCurrentIndex(index);
224}
225
226void ConfigureMotionTouch::OnUDPDeleteServer() {
227 udp_server_list_model->removeRows(ui->udp_server_list->currentIndex().row(), 1);
228}
229
190void ConfigureMotionTouch::OnCemuhookUDPTest() { 230void ConfigureMotionTouch::OnCemuhookUDPTest() {
191 ui->udp_test->setEnabled(false); 231 ui->udp_test->setEnabled(false);
192 ui->udp_test->setText(tr("Testing")); 232 ui->udp_test->setText(tr("Testing"));
193 udp_test_in_progress = true; 233 udp_test_in_progress = true;
194 InputCommon::CemuhookUDP::TestCommunication( 234 InputCommon::CemuhookUDP::TestCommunication(
195 ui->udp_server->text().toStdString(), static_cast<u16>(ui->udp_port->text().toInt()), 235 ui->udp_server->text().toStdString(), static_cast<u16>(ui->udp_port->text().toInt()), 0,
196 static_cast<u32>(ui->udp_pad_index->currentIndex()), 24872, 236 24872,
197 [this] { 237 [this] {
198 LOG_INFO(Frontend, "UDP input test success"); 238 LOG_INFO(Frontend, "UDP input test success");
199 QMetaObject::invokeMethod(this, "ShowUDPTestResult", Q_ARG(bool, true)); 239 QMetaObject::invokeMethod(this, "ShowUDPTestResult", Q_ARG(bool, true));
@@ -207,9 +247,9 @@ void ConfigureMotionTouch::OnCemuhookUDPTest() {
207void ConfigureMotionTouch::OnConfigureTouchCalibration() { 247void ConfigureMotionTouch::OnConfigureTouchCalibration() {
208 ui->touch_calibration_config->setEnabled(false); 248 ui->touch_calibration_config->setEnabled(false);
209 ui->touch_calibration_config->setText(tr("Configuring")); 249 ui->touch_calibration_config->setText(tr("Configuring"));
210 CalibrationConfigurationDialog dialog( 250 CalibrationConfigurationDialog dialog(this, ui->udp_server->text().toStdString(),
211 this, ui->udp_server->text().toStdString(), static_cast<u16>(ui->udp_port->text().toUInt()), 251 static_cast<u16>(ui->udp_port->text().toUInt()), 0,
212 static_cast<u8>(ui->udp_pad_index->currentIndex()), 24872); 252 24872);
213 dialog.exec(); 253 dialog.exec();
214 if (dialog.completed) { 254 if (dialog.completed) {
215 min_x = dialog.min_x; 255 min_x = dialog.min_x;
@@ -269,7 +309,7 @@ void ConfigureMotionTouch::OnConfigureTouchFromButton() {
269 309
270bool ConfigureMotionTouch::CanCloseDialog() { 310bool ConfigureMotionTouch::CanCloseDialog() {
271 if (udp_test_in_progress) { 311 if (udp_test_in_progress) {
272 QMessageBox::warning(this, tr("Citra"), 312 QMessageBox::warning(this, tr("yuzu"),
273 tr("UDP Test or calibration configuration is in progress.<br>Please " 313 tr("UDP Test or calibration configuration is in progress.<br>Please "
274 "wait for them to finish.")); 314 "wait for them to finish."));
275 return false; 315 return false;
@@ -282,17 +322,11 @@ void ConfigureMotionTouch::ApplyConfiguration() {
282 return; 322 return;
283 } 323 }
284 324
285 std::string motion_engine = ui->motion_provider->currentData().toString().toStdString();
286 std::string touch_engine = ui->touch_provider->currentData().toString().toStdString(); 325 std::string touch_engine = ui->touch_provider->currentData().toString().toStdString();
287 326
288 Common::ParamPackage motion_param{}, touch_param{}; 327 Common::ParamPackage touch_param{};
289 motion_param.Set("engine", std::move(motion_engine));
290 touch_param.Set("engine", std::move(touch_engine)); 328 touch_param.Set("engine", std::move(touch_engine));
291 329
292 if (motion_engine == "motion_emu") {
293 motion_param.Set("sensitivity", static_cast<float>(ui->motion_sensitivity->value()));
294 }
295
296 if (touch_engine == "cemuhookudp") { 330 if (touch_engine == "cemuhookudp") {
297 touch_param.Set("min_x", min_x); 331 touch_param.Set("min_x", min_x);
298 touch_param.Set("min_y", min_y); 332 touch_param.Set("min_y", min_y);
@@ -300,15 +334,25 @@ void ConfigureMotionTouch::ApplyConfiguration() {
300 touch_param.Set("max_y", max_y); 334 touch_param.Set("max_y", max_y);
301 } 335 }
302 336
303 Settings::values.motion_device = motion_param.Serialize();
304 Settings::values.touch_device = touch_param.Serialize(); 337 Settings::values.touch_device = touch_param.Serialize();
305 Settings::values.use_touch_from_button = ui->touch_from_button_checkbox->isChecked(); 338 Settings::values.use_touch_from_button = ui->touch_from_button_checkbox->isChecked();
306 Settings::values.touch_from_button_map_index = ui->touch_from_button_map->currentIndex(); 339 Settings::values.touch_from_button_map_index = ui->touch_from_button_map->currentIndex();
307 Settings::values.touch_from_button_maps = touch_from_button_maps; 340 Settings::values.touch_from_button_maps = touch_from_button_maps;
308 Settings::values.udp_input_address = ui->udp_server->text().toStdString(); 341 Settings::values.udp_input_servers = GetUDPServerString();
309 Settings::values.udp_input_port = static_cast<u16>(ui->udp_port->text().toInt());
310 Settings::values.udp_pad_index = static_cast<u8>(ui->udp_pad_index->currentIndex());
311 input_subsystem->ReloadInputDevices(); 342 input_subsystem->ReloadInputDevices();
312 343
313 accept(); 344 accept();
314} 345}
346
347std::string ConfigureMotionTouch::GetUDPServerString() const {
348 QString input_servers;
349
350 for (const auto& item : udp_server_list_model->stringList()) {
351 input_servers += item;
352 input_servers += QLatin1Char{','};
353 }
354
355 // Remove last comma
356 input_servers.chop(1);
357 return input_servers.toStdString();
358}
diff --git a/src/yuzu/configuration/configure_motion_touch.h b/src/yuzu/configuration/configure_motion_touch.h
index 3d4b5d659..15d61e8ba 100644
--- a/src/yuzu/configuration/configure_motion_touch.h
+++ b/src/yuzu/configuration/configure_motion_touch.h
@@ -10,6 +10,7 @@
10 10
11class QLabel; 11class QLabel;
12class QPushButton; 12class QPushButton;
13class QStringListModel;
13class QVBoxLayout; 14class QVBoxLayout;
14 15
15namespace InputCommon { 16namespace InputCommon {
@@ -62,6 +63,8 @@ public slots:
62 void ApplyConfiguration(); 63 void ApplyConfiguration();
63 64
64private slots: 65private slots:
66 void OnUDPAddServer();
67 void OnUDPDeleteServer();
65 void OnCemuhookUDPTest(); 68 void OnCemuhookUDPTest();
66 void OnConfigureTouchCalibration(); 69 void OnConfigureTouchCalibration();
67 void OnConfigureTouchFromButton(); 70 void OnConfigureTouchFromButton();
@@ -73,10 +76,12 @@ private:
73 void UpdateUiDisplay(); 76 void UpdateUiDisplay();
74 void ConnectEvents(); 77 void ConnectEvents();
75 bool CanCloseDialog(); 78 bool CanCloseDialog();
79 std::string GetUDPServerString() const;
76 80
77 InputCommon::InputSubsystem* input_subsystem; 81 InputCommon::InputSubsystem* input_subsystem;
78 82
79 std::unique_ptr<Ui::ConfigureMotionTouch> ui; 83 std::unique_ptr<Ui::ConfigureMotionTouch> ui;
84 QStringListModel* udp_server_list_model;
80 85
81 // Coordinate system of the CemuhookUDP touch provider 86 // Coordinate system of the CemuhookUDP touch provider
82 int min_x{}; 87 int min_x{};
diff --git a/src/yuzu/configuration/configure_motion_touch.ui b/src/yuzu/configuration/configure_motion_touch.ui
index 5b78c5a4b..ebca835ac 100644
--- a/src/yuzu/configuration/configure_motion_touch.ui
+++ b/src/yuzu/configuration/configure_motion_touch.ui
@@ -2,41 +2,30 @@
2<ui version="4.0"> 2<ui version="4.0">
3 <class>ConfigureMotionTouch</class> 3 <class>ConfigureMotionTouch</class>
4 <widget class="QDialog" name="ConfigureMotionTouch"> 4 <widget class="QDialog" name="ConfigureMotionTouch">
5 <property name="windowTitle">
6 <string>Configure Motion / Touch</string>
7 </property>
8 <property name="geometry"> 5 <property name="geometry">
9 <rect> 6 <rect>
10 <x>0</x> 7 <x>0</x>
11 <y>0</y> 8 <y>0</y>
12 <width>500</width> 9 <width>500</width>
13 <height>450</height> 10 <height>482</height>
14 </rect> 11 </rect>
15 </property> 12 </property>
13 <property name="windowTitle">
14 <string>Configure Motion / Touch</string>
15 </property>
16 <property name="styleSheet">
17 <string notr="true"/>
18 </property>
16 <layout class="QVBoxLayout"> 19 <layout class="QVBoxLayout">
17 <item> 20 <item>
18 <widget class="QGroupBox" name="motion_group_box"> 21 <widget class="QGroupBox" name="motion_group_box">
19 <property name="title"> 22 <property name="title">
20 <string>Motion</string> 23 <string>Mouse Motion</string>
21 </property> 24 </property>
22 <layout class="QVBoxLayout"> 25 <layout class="QVBoxLayout">
23 <item> 26 <item>
24 <layout class="QHBoxLayout"> 27 <layout class="QHBoxLayout">
25 <item> 28 <item>
26 <widget class="QLabel" name="motion_provider_label">
27 <property name="text">
28 <string>Motion Provider:</string>
29 </property>
30 </widget>
31 </item>
32 <item>
33 <widget class="QComboBox" name="motion_provider"/>
34 </item>
35 </layout>
36 </item>
37 <item>
38 <layout class="QHBoxLayout">
39 <item>
40 <widget class="QLabel" name="motion_sensitivity_label"> 29 <widget class="QLabel" name="motion_sensitivity_label">
41 <property name="text"> 30 <property name="text">
42 <string>Sensitivity:</string> 31 <string>Sensitivity:</string>
@@ -180,103 +169,171 @@
180 </widget> 169 </widget>
181 </item> 170 </item>
182 <item> 171 <item>
183 <layout class="QHBoxLayout"> 172 <layout class="QHBoxLayout" name="horizontalLayout">
184 <item> 173 <item>
185 <widget class="QLabel" name="udp_server_label"> 174 <widget class="QListView" name="udp_server_list"/>
186 <property name="text">
187 <string>Server:</string>
188 </property>
189 </widget>
190 </item> 175 </item>
191 <item> 176 <item>
192 <widget class="QLineEdit" name="udp_server"> 177 <layout class="QVBoxLayout" name="verticalLayout">
193 <property name="sizePolicy"> 178 <property name="leftMargin">
194 <sizepolicy hsizetype="Minimum" vsizetype="Fixed"> 179 <number>0</number>
195 <horstretch>0</horstretch>
196 <verstretch>0</verstretch>
197 </sizepolicy>
198 </property> 180 </property>
199 </widget> 181 <property name="topMargin">
200 </item> 182 <number>0</number>
201 </layout>
202 </item>
203 <item>
204 <layout class="QHBoxLayout">
205 <item>
206 <widget class="QLabel" name="udp_port_label">
207 <property name="text">
208 <string>Port:</string>
209 </property> 183 </property>
210 </widget> 184 <property name="rightMargin">
211 </item> 185 <number>0</number>
212 <item>
213 <widget class="QLineEdit" name="udp_port">
214 <property name="sizePolicy">
215 <sizepolicy hsizetype="Minimum" vsizetype="Fixed">
216 <horstretch>0</horstretch>
217 <verstretch>0</verstretch>
218 </sizepolicy>
219 </property> 186 </property>
220 </widget> 187 <property name="bottomMargin">
221 </item> 188 <number>0</number>
222 </layout>
223 </item>
224 <item>
225 <layout class="QHBoxLayout">
226 <item>
227 <widget class="QLabel" name="udp_pad_index_label">
228 <property name="text">
229 <string>Pad:</string>
230 </property> 189 </property>
231 </widget>
232 </item>
233 <item>
234 <widget class="QComboBox" name="udp_pad_index">
235 <item> 190 <item>
236 <property name="text"> 191 <layout class="QHBoxLayout">
237 <string>Pad 1</string> 192 <property name="leftMargin">
238 </property> 193 <number>3</number>
194 </property>
195 <property name="topMargin">
196 <number>3</number>
197 </property>
198 <property name="rightMargin">
199 <number>0</number>
200 </property>
201 <item>
202 <widget class="QLabel" name="udp_server_label">
203 <property name="text">
204 <string>Server:</string>
205 </property>
206 </widget>
207 </item>
208 <item>
209 <widget class="QLineEdit" name="udp_server">
210 <property name="sizePolicy">
211 <sizepolicy hsizetype="Minimum" vsizetype="Fixed">
212 <horstretch>0</horstretch>
213 <verstretch>0</verstretch>
214 </sizepolicy>
215 </property>
216 </widget>
217 </item>
218 </layout>
239 </item> 219 </item>
240 <item> 220 <item>
241 <property name="text"> 221 <layout class="QHBoxLayout">
242 <string>Pad 2</string> 222 <property name="leftMargin">
243 </property> 223 <number>3</number>
224 </property>
225 <property name="rightMargin">
226 <number>0</number>
227 </property>
228 <item>
229 <widget class="QLabel" name="udp_port_label">
230 <property name="text">
231 <string>Port:</string>
232 </property>
233 </widget>
234 </item>
235 <item>
236 <widget class="QLineEdit" name="udp_port">
237 <property name="sizePolicy">
238 <sizepolicy hsizetype="Minimum" vsizetype="Fixed">
239 <horstretch>0</horstretch>
240 <verstretch>0</verstretch>
241 </sizepolicy>
242 </property>
243 </widget>
244 </item>
245 </layout>
244 </item> 246 </item>
245 <item> 247 <item>
246 <property name="text"> 248 <layout class="QHBoxLayout">
247 <string>Pad 3</string> 249 <property name="leftMargin">
248 </property> 250 <number>3</number>
251 </property>
252 <property name="rightMargin">
253 <number>0</number>
254 </property>
255 <item>
256 <widget class="QLabel" name="udp_learn_more">
257 <property name="text">
258 <string>Learn More</string>
259 </property>
260 </widget>
261 </item>
262 <item>
263 <widget class="QPushButton" name="udp_test">
264 <property name="sizePolicy">
265 <sizepolicy hsizetype="Maximum" vsizetype="Fixed">
266 <horstretch>0</horstretch>
267 <verstretch>0</verstretch>
268 </sizepolicy>
269 </property>
270 <property name="text">
271 <string>Test</string>
272 </property>
273 </widget>
274 </item>
275 <item>
276 <widget class="QPushButton" name="udp_add">
277 <property name="sizePolicy">
278 <sizepolicy hsizetype="Maximum" vsizetype="Fixed">
279 <horstretch>0</horstretch>
280 <verstretch>0</verstretch>
281 </sizepolicy>
282 </property>
283 <property name="text">
284 <string>Add Server</string>
285 </property>
286 </widget>
287 </item>
288 </layout>
249 </item> 289 </item>
250 <item> 290 <item>
251 <property name="text"> 291 <spacer name="verticalSpacer_3">
252 <string>Pad 4</string> 292 <property name="orientation">
253 </property> 293 <enum>Qt::Vertical</enum>
294 </property>
295 <property name="sizeHint" stdset="0">
296 <size>
297 <width>20</width>
298 <height>40</height>
299 </size>
300 </property>
301 </spacer>
254 </item> 302 </item>
255 </widget> 303 <item>
256 </item> 304 <layout class="QHBoxLayout" name="horizontalLayout_2">
257 </layout> 305 <property name="topMargin">
258 </item> 306 <number>0</number>
259 <item> 307 </property>
260 <layout class="QHBoxLayout"> 308 <item>
261 <item> 309 <widget class="QPushButton" name="udp_remove">
262 <widget class="QLabel" name="udp_learn_more"> 310 <property name="sizePolicy">
263 <property name="text"> 311 <sizepolicy hsizetype="Maximum" vsizetype="Fixed">
264 <string>Learn More</string> 312 <horstretch>0</horstretch>
265 </property> 313 <verstretch>0</verstretch>
266 </widget> 314 </sizepolicy>
267 </item> 315 </property>
268 <item> 316 <property name="text">
269 <widget class="QPushButton" name="udp_test"> 317 <string>Remove Server</string>
270 <property name="sizePolicy"> 318 </property>
271 <sizepolicy hsizetype="Maximum" vsizetype="Fixed"> 319 </widget>
272 <horstretch>0</horstretch> 320 </item>
273 <verstretch>0</verstretch> 321 <item>
274 </sizepolicy> 322 <spacer name="horizontalSpacer_2">
275 </property> 323 <property name="orientation">
276 <property name="text"> 324 <enum>Qt::Horizontal</enum>
277 <string>Test</string> 325 </property>
278 </property> 326 <property name="sizeHint" stdset="0">
279 </widget> 327 <size>
328 <width>40</width>
329 <height>20</height>
330 </size>
331 </property>
332 </spacer>
333 </item>
334 </layout>
335 </item>
336 </layout>
280 </item> 337 </item>
281 </layout> 338 </layout>
282 </item> 339 </item>
@@ -312,6 +369,16 @@
312 <signal>accepted()</signal> 369 <signal>accepted()</signal>
313 <receiver>ConfigureMotionTouch</receiver> 370 <receiver>ConfigureMotionTouch</receiver>
314 <slot>ApplyConfiguration()</slot> 371 <slot>ApplyConfiguration()</slot>
372 <hints>
373 <hint type="sourcelabel">
374 <x>20</x>
375 <y>20</y>
376 </hint>
377 <hint type="destinationlabel">
378 <x>20</x>
379 <y>20</y>
380 </hint>
381 </hints>
315 </connection> 382 </connection>
316 </connections> 383 </connections>
317</ui> 384</ui>
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp
index 871ff4ae4..26f5e42ed 100644
--- a/src/yuzu/main.cpp
+++ b/src/yuzu/main.cpp
@@ -477,11 +477,13 @@ void GMainWindow::WebBrowserOpenPage(std::string_view filename, std::string_view
477#else 477#else
478 478
479void GMainWindow::WebBrowserOpenPage(std::string_view filename, std::string_view additional_args) { 479void GMainWindow::WebBrowserOpenPage(std::string_view filename, std::string_view additional_args) {
480#ifndef __linux__
480 QMessageBox::warning( 481 QMessageBox::warning(
481 this, tr("Web Applet"), 482 this, tr("Web Applet"),
482 tr("This version of yuzu was built without QtWebEngine support, meaning that yuzu cannot " 483 tr("This version of yuzu was built without QtWebEngine support, meaning that yuzu cannot "
483 "properly display the game manual or web page requested."), 484 "properly display the game manual or web page requested."),
484 QMessageBox::Ok, QMessageBox::Ok); 485 QMessageBox::Ok, QMessageBox::Ok);
486#endif
485 487
486 LOG_INFO(Frontend, 488 LOG_INFO(Frontend,
487 "(STUBBED) called - Missing QtWebEngine dependency needed to open website page at " 489 "(STUBBED) called - Missing QtWebEngine dependency needed to open website page at "
diff --git a/src/yuzu_cmd/config.cpp b/src/yuzu_cmd/config.cpp
index e1adbbf2b..34c9673bc 100644
--- a/src/yuzu_cmd/config.cpp
+++ b/src/yuzu_cmd/config.cpp
@@ -306,10 +306,8 @@ void Config::ReadValues() {
306 sdl2_config->GetInteger("ControlsGeneral", "touch_diameter_x", 15); 306 sdl2_config->GetInteger("ControlsGeneral", "touch_diameter_x", 15);
307 Settings::values.touchscreen.diameter_y = 307 Settings::values.touchscreen.diameter_y =
308 sdl2_config->GetInteger("ControlsGeneral", "touch_diameter_y", 15); 308 sdl2_config->GetInteger("ControlsGeneral", "touch_diameter_y", 15);
309 Settings::values.udp_input_address = 309 Settings::values.udp_input_servers =
310 sdl2_config->Get("Controls", "udp_input_address", InputCommon::CemuhookUDP::DEFAULT_ADDR); 310 sdl2_config->Get("Controls", "udp_input_address", InputCommon::CemuhookUDP::DEFAULT_SRV);
311 Settings::values.udp_input_port = static_cast<u16>(sdl2_config->GetInteger(
312 "Controls", "udp_input_port", InputCommon::CemuhookUDP::DEFAULT_PORT));
313 311
314 std::transform(keyboard_keys.begin(), keyboard_keys.end(), 312 std::transform(keyboard_keys.begin(), keyboard_keys.end(),
315 Settings::values.keyboard_keys.begin(), InputCommon::GenerateKeyboardParam); 313 Settings::values.keyboard_keys.begin(), InputCommon::GenerateKeyboardParam);
diff --git a/src/yuzu_cmd/emu_window/emu_window_sdl2.cpp b/src/yuzu_cmd/emu_window/emu_window_sdl2.cpp
index c4a4a36be..e32bed5e6 100644
--- a/src/yuzu_cmd/emu_window/emu_window_sdl2.cpp
+++ b/src/yuzu_cmd/emu_window/emu_window_sdl2.cpp
@@ -9,7 +9,7 @@
9#include "core/perf_stats.h" 9#include "core/perf_stats.h"
10#include "input_common/keyboard.h" 10#include "input_common/keyboard.h"
11#include "input_common/main.h" 11#include "input_common/main.h"
12#include "input_common/motion_emu.h" 12#include "input_common/mouse/mouse_input.h"
13#include "input_common/sdl/sdl.h" 13#include "input_common/sdl/sdl.h"
14#include "yuzu_cmd/emu_window/emu_window_sdl2.h" 14#include "yuzu_cmd/emu_window/emu_window_sdl2.h"
15 15
@@ -30,7 +30,7 @@ EmuWindow_SDL2::~EmuWindow_SDL2() {
30 30
31void EmuWindow_SDL2::OnMouseMotion(s32 x, s32 y) { 31void EmuWindow_SDL2::OnMouseMotion(s32 x, s32 y) {
32 TouchMoved((unsigned)std::max(x, 0), (unsigned)std::max(y, 0)); 32 TouchMoved((unsigned)std::max(x, 0), (unsigned)std::max(y, 0));
33 input_subsystem->GetMotionEmu()->Tilt(x, y); 33 input_subsystem->GetMouse()->MouseMove(x, y);
34} 34}
35 35
36void EmuWindow_SDL2::OnMouseButton(u32 button, u8 state, s32 x, s32 y) { 36void EmuWindow_SDL2::OnMouseButton(u32 button, u8 state, s32 x, s32 y) {
@@ -42,9 +42,9 @@ void EmuWindow_SDL2::OnMouseButton(u32 button, u8 state, s32 x, s32 y) {
42 } 42 }
43 } else if (button == SDL_BUTTON_RIGHT) { 43 } else if (button == SDL_BUTTON_RIGHT) {
44 if (state == SDL_PRESSED) { 44 if (state == SDL_PRESSED) {
45 input_subsystem->GetMotionEmu()->BeginTilt(x, y); 45 input_subsystem->GetMouse()->PressButton(x, y, button);
46 } else { 46 } else {
47 input_subsystem->GetMotionEmu()->EndTilt(); 47 input_subsystem->GetMouse()->ReleaseButton(button);
48 } 48 }
49 } 49 }
50} 50}
diff --git a/src/yuzu_cmd/emu_window/emu_window_sdl2_gl.cpp b/src/yuzu_cmd/emu_window/emu_window_sdl2_gl.cpp
index 5f35233b5..a103b04bd 100644
--- a/src/yuzu_cmd/emu_window/emu_window_sdl2_gl.cpp
+++ b/src/yuzu_cmd/emu_window/emu_window_sdl2_gl.cpp
@@ -17,7 +17,6 @@
17#include "core/settings.h" 17#include "core/settings.h"
18#include "input_common/keyboard.h" 18#include "input_common/keyboard.h"
19#include "input_common/main.h" 19#include "input_common/main.h"
20#include "input_common/motion_emu.h"
21#include "video_core/renderer_base.h" 20#include "video_core/renderer_base.h"
22#include "yuzu_cmd/emu_window/emu_window_sdl2_gl.h" 21#include "yuzu_cmd/emu_window/emu_window_sdl2_gl.h"
23 22