diff options
72 files changed, 1660 insertions, 1050 deletions
diff --git a/.ci/scripts/linux/docker.sh b/.ci/scripts/linux/docker.sh index 277775ef6..05f6ffe7d 100755 --- a/.ci/scripts/linux/docker.sh +++ b/.ci/scripts/linux/docker.sh @@ -5,7 +5,7 @@ cd /yuzu ccache -s mkdir build || true && cd build -cmake .. -G Ninja -DDISPLAY_VERSION=$1 -DYUZU_USE_BUNDLED_UNICORN=ON -DYUZU_USE_QT_WEB_ENGINE=ON -DCMAKE_BUILD_TYPE=Release -DCMAKE_C_COMPILER=/usr/lib/ccache/gcc -DCMAKE_CXX_COMPILER=/usr/lib/ccache/g++ -DYUZU_ENABLE_COMPATIBILITY_REPORTING=${ENABLE_COMPATIBILITY_REPORTING:-"OFF"} -DENABLE_COMPATIBILITY_LIST_DOWNLOAD=ON -DUSE_DISCORD_PRESENCE=ON -DENABLE_QT_TRANSLATION=ON +cmake .. -G Ninja -DDISPLAY_VERSION=$1 -DYUZU_USE_BUNDLED_UNICORN=ON -DCMAKE_BUILD_TYPE=Release -DCMAKE_C_COMPILER=/usr/lib/ccache/gcc -DCMAKE_CXX_COMPILER=/usr/lib/ccache/g++ -DYUZU_ENABLE_COMPATIBILITY_REPORTING=${ENABLE_COMPATIBILITY_REPORTING:-"OFF"} -DENABLE_COMPATIBILITY_LIST_DOWNLOAD=ON -DUSE_DISCORD_PRESENCE=ON -DENABLE_QT_TRANSLATION=ON ninja 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) -Werror=implicit-fallthrough -Werror=reorder -Werror=sign-compare + -Werror=shadow + -Werror=unused-parameter -Werror=unused-variable $<$<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) { Filter::Filter() : Filter(1.0, 0.0, 0.0, 1.0, 0.0, 0.0) {} -Filter::Filter(double a0, double a1, double a2, double b0, double b1, double b2) - : a1(a1 / a0), a2(a2 / a0), b0(b0 / a0), b1(b1 / a0), b2(b2 / a0) {} +Filter::Filter(double a0_, double a1_, double a2_, double b0_, double b1_, double b2_) + : a1(a1_ / a0_), a2(a2_ / a0_), b0(b0_ / a0_), b1(b1_ / a0_), b2(b2_ / a0_) {} void Filter::Process(std::vector<s16>& signal) { const std::size_t num_frames = signal.size() / 2; @@ -69,7 +69,7 @@ CascadingFilter CascadingFilter::LowPass(double cutoff, std::size_t cascade_size } CascadingFilter::CascadingFilter() = default; -CascadingFilter::CascadingFilter(std::vector<Filter> filters) : filters(std::move(filters)) {} +CascadingFilter::CascadingFilter(std::vector<Filter> filters_) : filters(std::move(filters_)) {} void CascadingFilter::Process(std::vector<s16>& signal) { 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: /// Passthrough filter. Filter(); - Filter(double a0, double a1, double a2, double b0, double b1, double b2); + Filter(double a0_, double a1_, double a2_, double b0_, double b1_, double b2_); void Process(std::vector<s16>& signal); @@ -51,7 +51,7 @@ public: /// Passthrough. CascadingFilter(); - explicit CascadingFilter(std::vector<Filter> filters); + explicit CascadingFilter(std::vector<Filter> filters_); void Process(std::vector<s16>& signal); 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 { namespace AudioCore { AudioRenderer::AudioRenderer(Core::Timing::CoreTiming& core_timing, Core::Memory::Memory& memory_, AudioCommon::AudioRendererParameter params, - std::shared_ptr<Kernel::WritableEvent> buffer_event, + std::shared_ptr<Kernel::WritableEvent> buffer_event_, std::size_t instance_number) - : worker_params{params}, buffer_event{buffer_event}, + : worker_params{params}, buffer_event{buffer_event_}, memory_pool_info(params.effect_count + params.voice_count * 4), voice_context(params.voice_count), effect_context(params.effect_count), mix_context(), sink_context(params.sink_count), splitter_context(), @@ -88,7 +88,7 @@ AudioRenderer::AudioRenderer(Core::Timing::CoreTiming& core_timing, Core::Memory stream = audio_out->OpenStream(core_timing, params.sample_rate, AudioCommon::STREAM_NUM_CHANNELS, fmt::format("AudioRenderer-Instance{}", instance_number), - [=]() { buffer_event->Signal(); }); + [=]() { buffer_event_->Signal(); }); audio_out->StartStream(stream); 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 { public: AudioRenderer(Core::Timing::CoreTiming& core_timing, Core::Memory::Memory& memory_, AudioCommon::AudioRendererParameter params, - std::shared_ptr<Kernel::WritableEvent> buffer_event, std::size_t instance_number); + std::shared_ptr<Kernel::WritableEvent> buffer_event_, + std::size_t instance_number); ~AudioRenderer(); [[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 { public: using Tag = u64; - Buffer(Tag tag, std::vector<s16>&& samples) : tag{tag}, samples{std::move(samples)} {} + Buffer(Tag tag_, std::vector<s16>&& samples_) : tag{tag_}, samples{std::move(samples_)} {} /// Returns the raw audio data for the buffer 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) { } // namespace -CommandGenerator::CommandGenerator(AudioCommon::AudioRendererParameter& worker_params, - VoiceContext& voice_context, MixContext& mix_context, - SplitterContext& splitter_context, EffectContext& effect_context, - Core::Memory::Memory& memory) - : worker_params(worker_params), voice_context(voice_context), mix_context(mix_context), - splitter_context(splitter_context), effect_context(effect_context), memory(memory), +CommandGenerator::CommandGenerator(AudioCommon::AudioRendererParameter& worker_params_, + VoiceContext& voice_context_, MixContext& mix_context_, + SplitterContext& splitter_context_, + EffectContext& effect_context_, Core::Memory::Memory& memory_) + : worker_params(worker_params_), voice_context(voice_context_), mix_context(mix_context_), + splitter_context(splitter_context_), effect_context(effect_context_), memory(memory_), mix_buffer((worker_params.mix_buffer_count + AudioCommon::MAX_CHANNEL_COUNT) * worker_params.sample_count), sample_buffer(MIX_BUFFER_SIZE), @@ -255,7 +255,8 @@ void CommandGenerator::GenerateDataSourceCommand(ServerVoiceInfo& voice_info, Vo void CommandGenerator::GenerateBiquadFilterCommandForVoice(ServerVoiceInfo& voice_info, VoiceState& dsp_state, - s32 mix_buffer_count, s32 channel) { + [[maybe_unused]] s32 mix_buffer_count, + [[maybe_unused]] s32 channel) { for (std::size_t i = 0; i < AudioCommon::MAX_BIQUAD_FILTERS; i++) { const auto& in_params = voice_info.GetInParams(); auto& biquad_filter = in_params.biquad_filter[i]; @@ -278,9 +279,12 @@ void CommandGenerator::GenerateBiquadFilterCommandForVoice(ServerVoiceInfo& voic } } -void AudioCore::CommandGenerator::GenerateBiquadFilterCommand( - s32 mix_buffer, const BiquadFilterParameter& params, std::array<s64, 2>& state, - std::size_t input_offset, std::size_t output_offset, s32 sample_count, s32 node_id) { +void CommandGenerator::GenerateBiquadFilterCommand([[maybe_unused]] s32 mix_buffer_id, + const BiquadFilterParameter& params, + std::array<s64, 2>& state, + std::size_t input_offset, + std::size_t output_offset, s32 sample_count, + s32 node_id) { if (dumping_frame) { LOG_DEBUG(Audio, "(DSP_TRACE) GenerateBiquadFilterCommand node_id={}, " @@ -714,7 +718,8 @@ s32 CommandGenerator::DecodePcm16(ServerVoiceInfo& voice_info, VoiceState& dsp_s } s32 CommandGenerator::DecodeAdpcm(ServerVoiceInfo& voice_info, VoiceState& dsp_state, - s32 sample_count, s32 channel, std::size_t mix_offset) { + s32 sample_count, [[maybe_unused]] s32 channel, + std::size_t mix_offset) { const auto& in_params = voice_info.GetInParams(); const auto& wave_buffer = in_params.wave_buffer[dsp_state.wave_buffer_index]; 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>; class CommandGenerator { public: - explicit CommandGenerator(AudioCommon::AudioRendererParameter& worker_params, - VoiceContext& voice_context, MixContext& mix_context, - SplitterContext& splitter_context, EffectContext& effect_context, - Core::Memory::Memory& memory); + explicit CommandGenerator(AudioCommon::AudioRendererParameter& worker_params_, + VoiceContext& voice_context_, MixContext& mix_context_, + SplitterContext& splitter_context_, EffectContext& effect_context_, + Core::Memory::Memory& memory_); ~CommandGenerator(); 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 { class CubebSinkStream final : public SinkStream { public: - CubebSinkStream(cubeb* ctx, u32 sample_rate, u32 num_channels_, cubeb_devid output_device, + CubebSinkStream(cubeb* ctx_, u32 sample_rate, u32 num_channels_, cubeb_devid output_device, const std::string& name) - : ctx{ctx}, num_channels{std::min(num_channels_, 6u)}, time_stretch{sample_rate, - num_channels} { + : ctx{ctx_}, num_channels{std::min(num_channels_, 6u)}, time_stretch{sample_rate, + num_channels} { cubeb_stream_params params{}; params.rate = sample_rate; @@ -192,8 +192,9 @@ SinkStream& CubebSink::AcquireSinkStream(u32 sample_rate, u32 num_channels, return *sink_streams.back(); } -long CubebSinkStream::DataCallback(cubeb_stream* stream, void* user_data, const void* input_buffer, - void* output_buffer, long num_frames) { +long CubebSinkStream::DataCallback([[maybe_unused]] cubeb_stream* stream, void* user_data, + [[maybe_unused]] const void* input_buffer, void* output_buffer, + long num_frames) { auto* impl = static_cast<CubebSinkStream*>(user_data); auto* buffer = static_cast<u8*>(output_buffer); @@ -236,7 +237,9 @@ long CubebSinkStream::DataCallback(cubeb_stream* stream, void* user_data, const return num_frames; } -void CubebSinkStream::StateCallback(cubeb_stream* stream, void* user_data, cubeb_state state) {} +void CubebSinkStream::StateCallback([[maybe_unused]] cubeb_stream* stream, + [[maybe_unused]] void* user_data, + [[maybe_unused]] cubeb_state state) {} std::vector<std::string> ListCubebSinkDevices() { 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) { } } // namespace -EffectContext::EffectContext(std::size_t effect_count) : effect_count(effect_count) { +EffectContext::EffectContext(std::size_t effect_count_) : effect_count(effect_count_) { effects.reserve(effect_count); std::generate_n(std::back_inserter(effects), effect_count, [] { return std::make_unique<EffectStubbed>(); }); @@ -61,13 +61,13 @@ const EffectBase* EffectContext::GetInfo(std::size_t i) const { return effects.at(i).get(); } -EffectStubbed::EffectStubbed() : EffectBase::EffectBase(EffectType::Invalid) {} +EffectStubbed::EffectStubbed() : EffectBase(EffectType::Invalid) {} EffectStubbed::~EffectStubbed() = default; -void EffectStubbed::Update(EffectInfo::InParams& in_params) {} +void EffectStubbed::Update([[maybe_unused]] EffectInfo::InParams& in_params) {} void EffectStubbed::UpdateForCommandGeneration() {} -EffectBase::EffectBase(EffectType effect_type) : effect_type(effect_type) {} +EffectBase::EffectBase(EffectType effect_type_) : effect_type(effect_type_) {} EffectBase::~EffectBase() = default; UsageState EffectBase::GetUsage() const { @@ -90,32 +90,32 @@ s32 EffectBase::GetProcessingOrder() const { return processing_order; } -EffectI3dl2Reverb::EffectI3dl2Reverb() : EffectGeneric::EffectGeneric(EffectType::I3dl2Reverb) {} +EffectI3dl2Reverb::EffectI3dl2Reverb() : EffectGeneric(EffectType::I3dl2Reverb) {} EffectI3dl2Reverb::~EffectI3dl2Reverb() = default; void EffectI3dl2Reverb::Update(EffectInfo::InParams& in_params) { - auto& internal_params = GetParams(); + auto& params = GetParams(); const auto* reverb_params = reinterpret_cast<I3dl2ReverbParams*>(in_params.raw.data()); if (!ValidChannelCountForEffect(reverb_params->max_channels)) { UNREACHABLE_MSG("Invalid reverb max channel count {}", reverb_params->max_channels); return; } - const auto last_status = internal_params.status; + const auto last_status = params.status; mix_id = in_params.mix_id; processing_order = in_params.processing_order; - internal_params = *reverb_params; + params = *reverb_params; if (!ValidChannelCountForEffect(reverb_params->channel_count)) { - internal_params.channel_count = internal_params.max_channels; + params.channel_count = params.max_channels; } enabled = in_params.is_enabled; if (last_status != ParameterStatus::Updated) { - internal_params.status = last_status; + params.status = last_status; } if (in_params.is_new || skipped) { usage = UsageState::Initialized; - internal_params.status = ParameterStatus::Initialized; + params.status = ParameterStatus::Initialized; skipped = in_params.buffer_address == 0 || in_params.buffer_size == 0; } } @@ -129,15 +129,15 @@ void EffectI3dl2Reverb::UpdateForCommandGeneration() { GetParams().status = ParameterStatus::Updated; } -EffectBiquadFilter::EffectBiquadFilter() : EffectGeneric::EffectGeneric(EffectType::BiquadFilter) {} +EffectBiquadFilter::EffectBiquadFilter() : EffectGeneric(EffectType::BiquadFilter) {} EffectBiquadFilter::~EffectBiquadFilter() = default; void EffectBiquadFilter::Update(EffectInfo::InParams& in_params) { - auto& internal_params = GetParams(); + auto& params = GetParams(); const auto* biquad_params = reinterpret_cast<BiquadFilterParams*>(in_params.raw.data()); mix_id = in_params.mix_id; processing_order = in_params.processing_order; - internal_params = *biquad_params; + params = *biquad_params; enabled = in_params.is_enabled; } @@ -150,7 +150,7 @@ void EffectBiquadFilter::UpdateForCommandGeneration() { GetParams().status = ParameterStatus::Updated; } -EffectAuxInfo::EffectAuxInfo() : EffectGeneric::EffectGeneric(EffectType::Aux) {} +EffectAuxInfo::EffectAuxInfo() : EffectGeneric(EffectType::Aux) {} EffectAuxInfo::~EffectAuxInfo() = default; void EffectAuxInfo::Update(EffectInfo::InParams& in_params) { @@ -200,32 +200,32 @@ VAddr EffectAuxInfo::GetRecvBuffer() const { return recv_buffer; } -EffectDelay::EffectDelay() : EffectGeneric::EffectGeneric(EffectType::Delay) {} +EffectDelay::EffectDelay() : EffectGeneric(EffectType::Delay) {} EffectDelay::~EffectDelay() = default; void EffectDelay::Update(EffectInfo::InParams& in_params) { const auto* delay_params = reinterpret_cast<DelayParams*>(in_params.raw.data()); - auto& internal_params = GetParams(); + auto& params = GetParams(); if (!ValidChannelCountForEffect(delay_params->max_channels)) { return; } - const auto last_status = internal_params.status; + const auto last_status = params.status; mix_id = in_params.mix_id; processing_order = in_params.processing_order; - internal_params = *delay_params; + params = *delay_params; if (!ValidChannelCountForEffect(delay_params->channels)) { - internal_params.channels = internal_params.max_channels; + params.channels = params.max_channels; } enabled = in_params.is_enabled; if (last_status != ParameterStatus::Updated) { - internal_params.status = last_status; + params.status = last_status; } if (in_params.is_new || skipped) { usage = UsageState::Initialized; - internal_params.status = ParameterStatus::Initialized; + params.status = ParameterStatus::Initialized; skipped = in_params.buffer_address == 0 || in_params.buffer_size == 0; } } @@ -239,7 +239,7 @@ void EffectDelay::UpdateForCommandGeneration() { GetParams().status = ParameterStatus::Updated; } -EffectBufferMixer::EffectBufferMixer() : EffectGeneric::EffectGeneric(EffectType::BufferMixer) {} +EffectBufferMixer::EffectBufferMixer() : EffectGeneric(EffectType::BufferMixer) {} EffectBufferMixer::~EffectBufferMixer() = default; void EffectBufferMixer::Update(EffectInfo::InParams& in_params) { @@ -257,32 +257,32 @@ void EffectBufferMixer::UpdateForCommandGeneration() { } } -EffectReverb::EffectReverb() : EffectGeneric::EffectGeneric(EffectType::Reverb) {} +EffectReverb::EffectReverb() : EffectGeneric(EffectType::Reverb) {} EffectReverb::~EffectReverb() = default; void EffectReverb::Update(EffectInfo::InParams& in_params) { const auto* reverb_params = reinterpret_cast<ReverbParams*>(in_params.raw.data()); - auto& internal_params = GetParams(); + auto& params = GetParams(); if (!ValidChannelCountForEffect(reverb_params->max_channels)) { return; } - const auto last_status = internal_params.status; + const auto last_status = params.status; mix_id = in_params.mix_id; processing_order = in_params.processing_order; - internal_params = *reverb_params; + params = *reverb_params; if (!ValidChannelCountForEffect(reverb_params->channels)) { - internal_params.channels = internal_params.max_channels; + params.channels = params.max_channels; } enabled = in_params.is_enabled; if (last_status != ParameterStatus::Updated) { - internal_params.status = last_status; + params.status = last_status; } if (in_params.is_new || skipped) { usage = UsageState::Initialized; - internal_params.status = ParameterStatus::Initialized; + params.status = ParameterStatus::Initialized; skipped = in_params.buffer_address == 0 || in_params.buffer_size == 0; } } 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 { class EffectBase { public: - explicit EffectBase(EffectType effect_type); + explicit EffectBase(EffectType effect_type_); virtual ~EffectBase(); virtual void Update(EffectInfo::InParams& in_params) = 0; @@ -206,7 +206,7 @@ protected: template <typename T> class EffectGeneric : public EffectBase { public: - explicit EffectGeneric(EffectType effect_type) : EffectBase(effect_type) {} + explicit EffectGeneric(EffectType effect_type_) : EffectBase(effect_type_) {} T& GetParams() { return internal_params; @@ -306,7 +306,7 @@ private: class EffectContext { public: - explicit EffectContext(std::size_t effect_count); + explicit EffectContext(std::size_t effect_count_); ~EffectContext(); [[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 @@ namespace AudioCore { -InfoUpdater::InfoUpdater(const std::vector<u8>& in_params, std::vector<u8>& out_params, - BehaviorInfo& behavior_info) - : in_params(in_params), out_params(out_params), behavior_info(behavior_info) { +InfoUpdater::InfoUpdater(const std::vector<u8>& in_params_, std::vector<u8>& out_params_, + BehaviorInfo& behavior_info_) + : in_params(in_params_), out_params(out_params_), behavior_info(behavior_info_) { ASSERT( AudioCommon::CanConsumeBuffer(in_params.size(), 0, sizeof(AudioCommon::UpdateDataHeader))); std::memcpy(&input_header, in_params.data(), sizeof(AudioCommon::UpdateDataHeader)); @@ -135,8 +135,8 @@ bool InfoUpdater::UpdateVoiceChannelResources(VoiceContext& voice_context) { } bool InfoUpdater::UpdateVoices(VoiceContext& voice_context, - std::vector<ServerMemoryPoolInfo>& memory_pool_info, - VAddr audio_codec_dsp_addr) { + [[maybe_unused]] std::vector<ServerMemoryPoolInfo>& memory_pool_info, + [[maybe_unused]] VAddr audio_codec_dsp_addr) { const auto voice_count = voice_context.GetVoiceCount(); std::vector<VoiceInfo::InParams> voice_in(voice_count); std::vector<VoiceInfo::OutParams> voice_out(voice_count); @@ -165,28 +165,28 @@ bool InfoUpdater::UpdateVoices(VoiceContext& voice_context, // Update our voices for (std::size_t i = 0; i < voice_count; i++) { - auto& in_params = voice_in[i]; - const auto channel_count = static_cast<std::size_t>(in_params.channel_count); + auto& voice_in_params = voice_in[i]; + const auto channel_count = static_cast<std::size_t>(voice_in_params.channel_count); // Skip if it's not currently in use - if (!in_params.is_in_use) { + if (!voice_in_params.is_in_use) { continue; } // Voice states for each channel std::array<VoiceState*, AudioCommon::MAX_CHANNEL_COUNT> voice_states{}; - ASSERT(static_cast<std::size_t>(in_params.id) < voice_count); + ASSERT(static_cast<std::size_t>(voice_in_params.id) < voice_count); // Grab our current voice info - auto& voice_info = voice_context.GetInfo(static_cast<std::size_t>(in_params.id)); + auto& voice_info = voice_context.GetInfo(static_cast<std::size_t>(voice_in_params.id)); ASSERT(channel_count <= AudioCommon::MAX_CHANNEL_COUNT); // Get all our channel voice states for (std::size_t channel = 0; channel < channel_count; channel++) { voice_states[channel] = - &voice_context.GetState(in_params.voice_channel_resource_ids[channel]); + &voice_context.GetState(voice_in_params.voice_channel_resource_ids[channel]); } - if (in_params.is_new) { + if (voice_in_params.is_new) { // Default our values for our voice voice_info.Initialize(); if (channel_count == 0 || channel_count > AudioCommon::MAX_CHANNEL_COUNT) { @@ -200,12 +200,12 @@ bool InfoUpdater::UpdateVoices(VoiceContext& voice_context, } // Update our voice - voice_info.UpdateParameters(in_params, behavior_info); + voice_info.UpdateParameters(voice_in_params, behavior_info); // TODO(ogniK): Handle mapping errors with behavior info based on in params response // Update our wave buffers - voice_info.UpdateWaveBuffers(in_params, voice_states, behavior_info); - voice_info.WriteOutStatus(voice_out[i], in_params, voice_states); + voice_info.UpdateWaveBuffers(voice_in_params, voice_states, behavior_info); + voice_info.WriteOutStatus(voice_out[i], voice_in_params, voice_states); } if (!AudioCommon::CanConsumeBuffer(out_params.size(), output_offset, voice_out_size)) { @@ -445,7 +445,7 @@ bool InfoUpdater::UpdatePerformanceBuffer() { return true; } -bool InfoUpdater::UpdateErrorInfo(BehaviorInfo& in_behavior_info) { +bool InfoUpdater::UpdateErrorInfo([[maybe_unused]] BehaviorInfo& in_behavior_info) { const auto total_beahvior_info_out = sizeof(BehaviorInfo::OutParams); 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; class InfoUpdater { public: // TODO(ogniK): Pass process handle when we support it - InfoUpdater(const std::vector<u8>& in_params, std::vector<u8>& out_params, - BehaviorInfo& behavior_info); + InfoUpdater(const std::vector<u8>& in_params_, std::vector<u8>& out_params_, + BehaviorInfo& behavior_info_); ~InfoUpdater(); 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 { ServerMemoryPoolInfo::ServerMemoryPoolInfo() = default; ServerMemoryPoolInfo::~ServerMemoryPoolInfo() = default; -bool ServerMemoryPoolInfo::Update(const ServerMemoryPoolInfo::InParams& in_params, - ServerMemoryPoolInfo::OutParams& out_params) { + +bool ServerMemoryPoolInfo::Update(const InParams& in_params, OutParams& out_params) { // Our state does not need to be changed - if (in_params.state != ServerMemoryPoolInfo::State::RequestAttach && - in_params.state != ServerMemoryPoolInfo::State::RequestDetach) { + if (in_params.state != State::RequestAttach && in_params.state != State::RequestDetach) { return true; } @@ -32,11 +31,11 @@ bool ServerMemoryPoolInfo::Update(const ServerMemoryPoolInfo::InParams& in_param return false; } - if (in_params.state == ServerMemoryPoolInfo::State::RequestAttach) { + if (in_params.state == State::RequestAttach) { cpu_address = in_params.address; size = in_params.size; used = true; - out_params.state = ServerMemoryPoolInfo::State::Attached; + out_params.state = State::Attached; } else { // Unexpected address if (cpu_address != in_params.address) { @@ -54,7 +53,7 @@ bool ServerMemoryPoolInfo::Update(const ServerMemoryPoolInfo::InParams& in_param cpu_address = 0; size = 0; used = false; - out_params.state = ServerMemoryPoolInfo::State::Detached; + out_params.state = State::Detached; } return true; } 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: struct InParams { u64_le address{}; u64_le size{}; - ServerMemoryPoolInfo::State state{}; + State state{}; INSERT_PADDING_WORDS(3); }; - static_assert(sizeof(ServerMemoryPoolInfo::InParams) == 0x20, "InParams are an invalid size"); + static_assert(sizeof(InParams) == 0x20, "InParams are an invalid size"); struct OutParams { - ServerMemoryPoolInfo::State state{}; + State state{}; INSERT_PADDING_WORDS(3); }; - static_assert(sizeof(ServerMemoryPoolInfo::OutParams) == 0x10, "OutParams are an invalid size"); + static_assert(sizeof(OutParams) == 0x10, "OutParams are an invalid size"); - bool Update(const ServerMemoryPoolInfo::InParams& in_params, - ServerMemoryPoolInfo::OutParams& out_params); + bool Update(const InParams& in_params, OutParams& out_params); private: // 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 @@ #include "audio_core/sink_context.h" namespace AudioCore { -SinkContext::SinkContext(std::size_t sink_count) : sink_count(sink_count) {} +SinkContext::SinkContext(std::size_t sink_count_) : sink_count{sink_count_} {} SinkContext::~SinkContext() = default; std::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: bool in_use; INSERT_UNION_PADDING_BYTES(5); }; - static_assert(sizeof(SinkInfo::CircularBufferIn) == 0x28, + static_assert(sizeof(CircularBufferIn) == 0x28, "SinkInfo::CircularBufferIn is in invalid size"); struct DeviceIn { @@ -54,7 +54,7 @@ public: bool down_matrix_enabled; DownmixCoefficients down_matrix_coef; }; - static_assert(sizeof(SinkInfo::DeviceIn) == 0x11c, "SinkInfo::DeviceIn is an invalid size"); + static_assert(sizeof(DeviceIn) == 0x11c, "SinkInfo::DeviceIn is an invalid size"); struct InParams { SinkTypes type{}; @@ -64,16 +64,16 @@ public: INSERT_PADDING_WORDS(6); union { // std::array<u8, 0x120> raw{}; - SinkInfo::DeviceIn device; - SinkInfo::CircularBufferIn circular_buffer; + DeviceIn device; + CircularBufferIn circular_buffer; }; }; - static_assert(sizeof(SinkInfo::InParams) == 0x140, "SinkInfo::InParams are an invalid size!"); + static_assert(sizeof(InParams) == 0x140, "SinkInfo::InParams are an invalid size!"); }; class SinkContext { public: - explicit SinkContext(std::size_t sink_count); + explicit SinkContext(std::size_t sink_count_); ~SinkContext(); [[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 @@ namespace AudioCore { -ServerSplitterDestinationData::ServerSplitterDestinationData(s32 id) : id(id) {} +ServerSplitterDestinationData::ServerSplitterDestinationData(s32 id_) : id{id_} {} ServerSplitterDestinationData::~ServerSplitterDestinationData() = default; void ServerSplitterDestinationData::Update(SplitterInfo::InDestinationParams& header) { @@ -87,7 +87,7 @@ void ServerSplitterDestinationData::UpdateInternalState() { needs_update = false; } -ServerSplitterInfo::ServerSplitterInfo(s32 id) : id(id) {} +ServerSplitterInfo::ServerSplitterInfo(s32 id_) : id(id_) {} ServerSplitterInfo::~ServerSplitterInfo() = default; void ServerSplitterInfo::InitializeInfos() { @@ -121,7 +121,7 @@ const ServerSplitterDestinationData* ServerSplitterInfo::GetHead() const { } ServerSplitterDestinationData* ServerSplitterInfo::GetData(std::size_t depth) { - auto current_head = head; + auto* current_head = head; for (std::size_t i = 0; i < depth; i++) { if (current_head == nullptr) { return nullptr; @@ -132,7 +132,7 @@ ServerSplitterDestinationData* ServerSplitterInfo::GetData(std::size_t depth) { } const ServerSplitterDestinationData* ServerSplitterInfo::GetData(std::size_t depth) const { - auto current_head = head; + auto* current_head = head; for (std::size_t i = 0; i < depth; i++) { if (current_head == nullptr) { return nullptr; @@ -245,7 +245,7 @@ ServerSplitterDestinationData* SplitterContext::GetDestinationData(std::size_t i const ServerSplitterDestinationData* SplitterContext::GetDestinationData(std::size_t info, std::size_t data) const { ASSERT(info < info_count); - auto& cur_info = GetInfo(info); + const auto& cur_info = GetInfo(info); return cur_info.GetData(data); } @@ -267,11 +267,11 @@ std::size_t SplitterContext::GetDataCount() const { return data_count; } -void SplitterContext::Setup(std::size_t _info_count, std::size_t _data_count, +void SplitterContext::Setup(std::size_t info_count_, std::size_t data_count_, bool is_splitter_bug_fixed) { - info_count = _info_count; - data_count = _data_count; + info_count = info_count_; + data_count = data_count_; for (std::size_t i = 0; i < info_count; i++) { auto& splitter = infos.emplace_back(static_cast<s32>(i)); @@ -364,7 +364,7 @@ bool SplitterContext::RecomposeDestination(ServerSplitterInfo& info, // Clear our current destinations auto* current_head = info.GetHead(); while (current_head != nullptr) { - auto next_head = current_head->GetNextDestination(); + auto* next_head = current_head->GetNextDestination(); current_head->SetNextDestination(nullptr); current_head = next_head; } @@ -471,8 +471,8 @@ bool NodeStates::DepthFirstSearch(EdgeMatrix& edge_matrix) { continue; } - const auto node_count = edge_matrix.GetNodeCount(); - for (s32 j = 0; j < static_cast<s32>(node_count); j++) { + const auto edge_node_count = edge_matrix.GetNodeCount(); + for (s32 j = 0; j < static_cast<s32>(edge_node_count); j++) { // Check if our node is connected to our edge matrix if (!edge_matrix.Connected(current_stack_index, j)) { 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: NodeStates(); ~NodeStates(); - void Initialize(std::size_t _node_count); + void Initialize(std::size_t node_count_); bool Tsort(EdgeMatrix& edge_matrix); std::size_t GetIndexPos() const; const std::vector<s32>& GetIndexList() const; @@ -72,15 +72,15 @@ private: void PushTsortResult(s32 index); bool DepthFirstSearch(EdgeMatrix& edge_matrix); void ResetState(); - void UpdateState(NodeStates::State state, std::size_t i); - NodeStates::State GetState(std::size_t i); + void UpdateState(State state, std::size_t i); + State GetState(std::size_t i); std::size_t node_count{}; std::vector<bool> was_node_found{}; std::vector<bool> was_node_completed{}; std::size_t index_pos{}; std::vector<s32> index_list{}; - NodeStates::Stack index_stack{}; + Stack index_stack{}; }; enum class SplitterMagic : u32_le { @@ -97,8 +97,7 @@ public: s32_le data_count{}; INSERT_PADDING_WORDS(5); }; - static_assert(sizeof(SplitterInfo::InHeader) == 0x20, - "SplitterInfo::InHeader is an invalid size"); + static_assert(sizeof(InHeader) == 0x20, "SplitterInfo::InHeader is an invalid size"); struct InInfoPrams { SplitterMagic magic{}; @@ -107,8 +106,7 @@ public: s32_le length{}; s32_le resource_id_base{}; }; - static_assert(sizeof(SplitterInfo::InInfoPrams) == 0x14, - "SplitterInfo::InInfoPrams is an invalid size"); + static_assert(sizeof(InInfoPrams) == 0x14, "SplitterInfo::InInfoPrams is an invalid size"); struct InDestinationParams { SplitterMagic magic{}; @@ -118,13 +116,13 @@ public: bool in_use{}; INSERT_PADDING_BYTES(3); }; - static_assert(sizeof(SplitterInfo::InDestinationParams) == 0x70, + static_assert(sizeof(InDestinationParams) == 0x70, "SplitterInfo::InDestinationParams is an invalid size"); }; class ServerSplitterDestinationData { public: - explicit ServerSplitterDestinationData(s32 id); + explicit ServerSplitterDestinationData(s32 id_); ~ServerSplitterDestinationData(); void Update(SplitterInfo::InDestinationParams& header); @@ -153,7 +151,7 @@ private: class ServerSplitterInfo { public: - explicit ServerSplitterInfo(s32 id); + explicit ServerSplitterInfo(s32 id_); ~ServerSplitterInfo(); 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 { return {}; } -Stream::Stream(Core::Timing::CoreTiming& core_timing, u32 sample_rate, Format format, - ReleaseCallback&& release_callback, SinkStream& sink_stream, std::string&& name_) - : sample_rate{sample_rate}, format{format}, release_callback{std::move(release_callback)}, - sink_stream{sink_stream}, core_timing{core_timing}, name{std::move(name_)} { +Stream::Stream(Core::Timing::CoreTiming& core_timing_, u32 sample_rate_, Format format_, + ReleaseCallback&& release_callback_, SinkStream& sink_stream_, std::string&& name_) + : sample_rate{sample_rate_}, format{format_}, release_callback{std::move(release_callback_)}, + sink_stream{sink_stream_}, core_timing{core_timing_}, name{std::move(name_)} { release_event = Core::Timing::CreateEvent(name, [this](std::uintptr_t, std::chrono::nanoseconds ns_late) { ReleaseActiveBuffer(ns_late); @@ -122,7 +122,7 @@ bool Stream::QueueBuffer(BufferPtr&& buffer) { return false; } -bool Stream::ContainsBuffer(Buffer::Tag tag) const { +bool Stream::ContainsBuffer([[maybe_unused]] Buffer::Tag tag) const { UNIMPLEMENTED(); return {}; } 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: /// Callback function type, used to change guest state on a buffer being released using ReleaseCallback = std::function<void()>; - Stream(Core::Timing::CoreTiming& core_timing, u32 sample_rate, Format format, - ReleaseCallback&& release_callback, SinkStream& sink_stream, std::string&& name_); + Stream(Core::Timing::CoreTiming& core_timing_, u32 sample_rate_, Format format_, + ReleaseCallback&& release_callback_, SinkStream& sink_stream_, std::string&& name_); /// Plays the audio stream 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 @@ namespace AudioCore { -ServerVoiceChannelResource::ServerVoiceChannelResource(s32 id) : id(id) {} +ServerVoiceChannelResource::ServerVoiceChannelResource(s32 id_) : id(id_) {} ServerVoiceChannelResource::~ServerVoiceChannelResource() = default; bool ServerVoiceChannelResource::InUse() const { @@ -209,7 +209,8 @@ void ServerVoiceInfo::UpdateWaveBuffers( void ServerVoiceInfo::UpdateWaveBuffer(ServerWaveBuffer& out_wavebuffer, const WaveBuffer& in_wave_buffer, SampleFormat sample_format, - bool is_buffer_valid, BehaviorInfo& behavior_info) { + bool is_buffer_valid, + [[maybe_unused]] BehaviorInfo& behavior_info) { if (!is_buffer_valid && out_wavebuffer.sent_to_dsp) { out_wavebuffer.buffer_address = 0; out_wavebuffer.buffer_size = 0; @@ -400,7 +401,7 @@ bool ServerVoiceInfo::HasValidWaveBuffer(const VoiceState* state) const { return std::find(valid_wb.begin(), valid_wb.end(), true) != valid_wb.end(); } -VoiceContext::VoiceContext(std::size_t voice_count) : voice_count(voice_count) { +VoiceContext::VoiceContext(std::size_t voice_count_) : voice_count{voice_count_} { for (std::size_t i = 0; i < voice_count; i++) { voice_channel_resources.emplace_back(static_cast<s32>(i)); 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: bool in_use{}; INSERT_PADDING_BYTES(11); }; - static_assert(sizeof(VoiceChannelResource::InParams) == 0x70, "InParams is an invalid size"); + static_assert(sizeof(InParams) == 0x70, "InParams is an invalid size"); }; class ServerVoiceChannelResource { public: - explicit ServerVoiceChannelResource(s32 id); + explicit ServerVoiceChannelResource(s32 id_); ~ServerVoiceChannelResource(); bool InUse() const; @@ -174,7 +174,7 @@ public: BehaviorFlags behavior_flags{}; INSERT_PADDING_BYTES(16); }; - static_assert(sizeof(VoiceInfo::InParams) == 0x170, "InParams is an invalid size"); + static_assert(sizeof(InParams) == 0x170, "InParams is an invalid size"); struct OutParams { u64_le played_sample_count{}; @@ -182,7 +182,7 @@ public: u8 voice_dropped{}; INSERT_PADDING_BYTES(3); }; - static_assert(sizeof(VoiceInfo::OutParams) == 0x10, "OutParams is an invalid size"); + static_assert(sizeof(OutParams) == 0x10, "OutParams is an invalid size"); }; class ServerVoiceInfo { @@ -263,7 +263,7 @@ private: class VoiceContext { public: - VoiceContext(std::size_t voice_count); + explicit VoiceContext(std::size_t voice_count_); ~VoiceContext(); 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 common_paths.h common_types.h concepts.h + div_ceil.h dynamic_library.cpp dynamic_library.h 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 @@ +// Copyright 2020 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include <cstddef> +#include <type_traits> + +namespace Common { + +/// Ceiled integer division. +template <typename N, typename D> +requires std::is_integral_v<N>&& std::is_unsigned_v<D>[[nodiscard]] constexpr auto DivCeil( + N number, D divisor) { + return (static_cast<D>(number) + divisor - 1) / divisor; +} + +/// Ceiled integer division with logarithmic divisor in base 2 +template <typename N, typename D> +requires std::is_integral_v<N>&& std::is_unsigned_v<D>[[nodiscard]] constexpr auto DivCeilLog2( + N value, D alignment_log2) { + return (static_cast<D>(value) + (D(1) << alignment_log2) - 1) >> alignment_log2; +} + +} // 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>; class StandardWallClock final : public WallClock { public: - StandardWallClock(u64 emulated_cpu_frequency, u64 emulated_clock_frequency) - : WallClock(emulated_cpu_frequency, emulated_clock_frequency, false) { + explicit StandardWallClock(u64 emulated_cpu_frequency_, u64 emulated_clock_frequency_) + : WallClock(emulated_cpu_frequency_, emulated_clock_frequency_, false) { start_time = base_timer::now(); } 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: } protected: - WallClock(u64 emulated_cpu_frequency, u64 emulated_clock_frequency, bool is_native) - : emulated_cpu_frequency{emulated_cpu_frequency}, - emulated_clock_frequency{emulated_clock_frequency}, is_native{is_native} {} + explicit WallClock(u64 emulated_cpu_frequency_, u64 emulated_clock_frequency_, bool is_native_) + : emulated_cpu_frequency{emulated_cpu_frequency_}, + emulated_clock_frequency{emulated_clock_frequency_}, is_native{is_native_} {} u64 emulated_cpu_frequency; 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() { } namespace X64 { -NativeClock::NativeClock(u64 emulated_cpu_frequency, u64 emulated_clock_frequency, - u64 rtsc_frequency) - : WallClock(emulated_cpu_frequency, emulated_clock_frequency, true), rtsc_frequency{ - rtsc_frequency} { +NativeClock::NativeClock(u64 emulated_cpu_frequency_, u64 emulated_clock_frequency_, + u64 rtsc_frequency_) + : WallClock(emulated_cpu_frequency_, emulated_clock_frequency_, true), rtsc_frequency{ + rtsc_frequency_} { _mm_mfence(); last_measure = __rdtsc(); 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 { namespace X64 { class NativeClock final : public WallClock { public: - NativeClock(u64 emulated_cpu_frequency, u64 emulated_clock_frequency, u64 rtsc_frequency); + explicit NativeClock(u64 emulated_cpu_frequency_, u64 emulated_clock_frequency_, + u64 rtsc_frequency_); std::chrono::nanoseconds GetTimeNS() override; 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 = /// Contains the characteristics of a particular event. struct EventType { - EventType(TimedCallback&& callback, std::string&& name) - : callback{std::move(callback)}, name{std::move(name)} {} + explicit EventType(TimedCallback&& callback_, std::string&& name_) + : callback{std::move(callback_)}, name{std::move(name_)} {} /// The event's callback function. TimedCallback callback; @@ -67,8 +67,8 @@ public: void Shutdown(); /// Sets if emulation is multicore or single core, must be set before Initialize - void SetMulticore(bool is_multicore) { - this->is_multicore = is_multicore; + void SetMulticore(bool is_multicore_) { + is_multicore = is_multicore_; } /// 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 using MotionDevice = InputDevice<MotionStatus>; /** - * A touch device is an input device that returns a tuple of two floats and a bool. The floats are + * A touch status is an object that returns a tuple of two floats and a bool. The floats are * x and y coordinates in the range 0.0 - 1.0, and the bool indicates whether it is pressed. */ -using TouchDevice = InputDevice<std::tuple<float, float, bool>>; +using TouchStatus = std::tuple<float, float, bool>; + +/** + * A touch device is an input device that returns a touch status object + */ +using TouchDevice = InputDevice<TouchStatus>; /** * 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 { BitField<0, 9, ErrorModule> module; BitField<9, 13, u32> description; - constexpr explicit ResultCode(u32 raw) : raw(raw) {} + constexpr explicit ResultCode(u32 raw_) : raw(raw_) {} constexpr ResultCode(ErrorModule module_, u32 description_) : 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 { Setting<bool> motion_enabled; std::string motion_device; - std::string udp_input_address; - u16 udp_input_port; - u8 udp_pad_index; + std::string udp_input_servers; bool mouse_enabled; 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 keyboard.h main.cpp main.h - motion_emu.cpp - motion_emu.h motion_from_button.cpp motion_from_button.h motion_input.cpp @@ -19,6 +17,10 @@ add_library(input_common STATIC gcadapter/gc_adapter.h gcadapter/gc_poller.cpp gcadapter/gc_poller.h + mouse/mouse_input.cpp + mouse/mouse_input.h + mouse/mouse_poller.cpp + mouse/mouse_poller.h sdl/sdl.cpp sdl/sdl.h 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 @@ #include "input_common/gcadapter/gc_poller.h" #include "input_common/keyboard.h" #include "input_common/main.h" -#include "input_common/motion_emu.h" #include "input_common/motion_from_button.h" +#include "input_common/mouse/mouse_input.h" +#include "input_common/mouse/mouse_poller.h" #include "input_common/touch_from_button.h" #include "input_common/udp/client.h" #include "input_common/udp/udp.h" @@ -37,8 +38,6 @@ struct InputSubsystem::Impl { std::make_shared<AnalogFromButton>()); Input::RegisterFactory<Input::MotionDevice>("keyboard", std::make_shared<MotionFromButton>()); - motion_emu = std::make_shared<MotionEmu>(); - Input::RegisterFactory<Input::MotionDevice>("motion_emu", motion_emu); Input::RegisterFactory<Input::TouchDevice>("touch_from_button", std::make_shared<TouchFromButtonFactory>()); @@ -51,6 +50,16 @@ struct InputSubsystem::Impl { Input::RegisterFactory<Input::MotionDevice>("cemuhookudp", udpmotion); udptouch = std::make_shared<UDPTouchFactory>(udp); Input::RegisterFactory<Input::TouchDevice>("cemuhookudp", udptouch); + + mouse = std::make_shared<MouseInput::Mouse>(); + mousebuttons = std::make_shared<MouseButtonFactory>(mouse); + Input::RegisterFactory<Input::ButtonDevice>("mouse", mousebuttons); + mouseanalog = std::make_shared<MouseAnalogFactory>(mouse); + Input::RegisterFactory<Input::AnalogDevice>("mouse", mouseanalog); + mousemotion = std::make_shared<MouseMotionFactory>(mouse); + Input::RegisterFactory<Input::MotionDevice>("mouse", mousemotion); + mousetouch = std::make_shared<MouseTouchFactory>(mouse); + Input::RegisterFactory<Input::TouchDevice>("mouse", mousetouch); } void Shutdown() { @@ -58,8 +67,6 @@ struct InputSubsystem::Impl { Input::UnregisterFactory<Input::MotionDevice>("keyboard"); keyboard.reset(); Input::UnregisterFactory<Input::AnalogDevice>("analog_from_button"); - Input::UnregisterFactory<Input::MotionDevice>("motion_emu"); - motion_emu.reset(); Input::UnregisterFactory<Input::TouchDevice>("touch_from_button"); #ifdef HAVE_SDL2 sdl.reset(); @@ -77,6 +84,16 @@ struct InputSubsystem::Impl { udpmotion.reset(); udptouch.reset(); + + Input::UnregisterFactory<Input::ButtonDevice>("mouse"); + Input::UnregisterFactory<Input::AnalogDevice>("mouse"); + Input::UnregisterFactory<Input::MotionDevice>("mouse"); + Input::UnregisterFactory<Input::TouchDevice>("mouse"); + + mousebuttons.reset(); + mouseanalog.reset(); + mousemotion.reset(); + mousetouch.reset(); } [[nodiscard]] std::vector<Common::ParamPackage> GetInputDevices() const { @@ -140,7 +157,6 @@ struct InputSubsystem::Impl { } std::shared_ptr<Keyboard> keyboard; - std::shared_ptr<MotionEmu> motion_emu; #ifdef HAVE_SDL2 std::unique_ptr<SDL::State> sdl; #endif @@ -149,8 +165,13 @@ struct InputSubsystem::Impl { std::shared_ptr<GCVibrationFactory> gcvibration; std::shared_ptr<UDPMotionFactory> udpmotion; std::shared_ptr<UDPTouchFactory> udptouch; + std::shared_ptr<MouseButtonFactory> mousebuttons; + std::shared_ptr<MouseAnalogFactory> mouseanalog; + std::shared_ptr<MouseMotionFactory> mousemotion; + std::shared_ptr<MouseTouchFactory> mousetouch; std::shared_ptr<CemuhookUDP::Client> udp; std::shared_ptr<GCAdapter::Adapter> gcadapter; + std::shared_ptr<MouseInput::Mouse> mouse; }; InputSubsystem::InputSubsystem() : impl{std::make_unique<Impl>()} {} @@ -173,12 +194,12 @@ const Keyboard* InputSubsystem::GetKeyboard() const { return impl->keyboard.get(); } -MotionEmu* InputSubsystem::GetMotionEmu() { - return impl->motion_emu.get(); +MouseInput::Mouse* InputSubsystem::GetMouse() { + return impl->mouse.get(); } -const MotionEmu* InputSubsystem::GetMotionEmu() const { - return impl->motion_emu.get(); +const MouseInput::Mouse* InputSubsystem::GetMouse() const { + return impl->mouse.get(); } std::vector<Common::ParamPackage> InputSubsystem::GetInputDevices() const { @@ -229,11 +250,43 @@ const UDPTouchFactory* InputSubsystem::GetUDPTouch() const { return impl->udptouch.get(); } +MouseButtonFactory* InputSubsystem::GetMouseButtons() { + return impl->mousebuttons.get(); +} + +const MouseButtonFactory* InputSubsystem::GetMouseButtons() const { + return impl->mousebuttons.get(); +} + +MouseAnalogFactory* InputSubsystem::GetMouseAnalogs() { + return impl->mouseanalog.get(); +} + +const MouseAnalogFactory* InputSubsystem::GetMouseAnalogs() const { + return impl->mouseanalog.get(); +} + +MouseMotionFactory* InputSubsystem::GetMouseMotions() { + return impl->mousemotion.get(); +} + +const MouseMotionFactory* InputSubsystem::GetMouseMotions() const { + return impl->mousemotion.get(); +} + +MouseTouchFactory* InputSubsystem::GetMouseTouch() { + return impl->mousetouch.get(); +} + +const MouseTouchFactory* InputSubsystem::GetMouseTouch() const { + return impl->mousetouch.get(); +} + void InputSubsystem::ReloadInputDevices() { if (!impl->udp) { return; } - impl->udp->ReloadUDPClient(); + impl->udp->ReloadSockets(); } std::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 { enum Values : int; } +namespace MouseInput { +class Mouse; +} + namespace InputCommon { namespace Polling { @@ -56,8 +60,11 @@ class GCAnalogFactory; class GCButtonFactory; class UDPMotionFactory; class UDPTouchFactory; +class MouseButtonFactory; +class MouseAnalogFactory; +class MouseMotionFactory; +class MouseTouchFactory; class Keyboard; -class MotionEmu; /** * Given a ParamPackage for a Device returned from `GetInputDevices`, attempt to get the default @@ -90,11 +97,11 @@ public: /// Retrieves the underlying keyboard device. [[nodiscard]] const Keyboard* GetKeyboard() const; - /// Retrieves the underlying motion emulation factory. - [[nodiscard]] MotionEmu* GetMotionEmu(); + /// Retrieves the underlying mouse device. + [[nodiscard]] MouseInput::Mouse* GetMouse(); - /// Retrieves the underlying motion emulation factory. - [[nodiscard]] const MotionEmu* GetMotionEmu() const; + /// Retrieves the underlying mouse device. + [[nodiscard]] const MouseInput::Mouse* GetMouse() const; /** * Returns all available input devices that this Factory can create a new device with. @@ -137,6 +144,30 @@ public: /// Retrieves the underlying udp touch handler. [[nodiscard]] const UDPTouchFactory* GetUDPTouch() const; + /// Retrieves the underlying GameCube button handler. + [[nodiscard]] MouseButtonFactory* GetMouseButtons(); + + /// Retrieves the underlying GameCube button handler. + [[nodiscard]] const MouseButtonFactory* GetMouseButtons() const; + + /// Retrieves the underlying udp touch handler. + [[nodiscard]] MouseAnalogFactory* GetMouseAnalogs(); + + /// Retrieves the underlying udp touch handler. + [[nodiscard]] const MouseAnalogFactory* GetMouseAnalogs() const; + + /// Retrieves the underlying udp motion handler. + [[nodiscard]] MouseMotionFactory* GetMouseMotions(); + + /// Retrieves the underlying udp motion handler. + [[nodiscard]] const MouseMotionFactory* GetMouseMotions() const; + + /// Retrieves the underlying udp touch handler. + [[nodiscard]] MouseTouchFactory* GetMouseTouch(); + + /// Retrieves the underlying udp touch handler. + [[nodiscard]] const MouseTouchFactory* GetMouseTouch() const; + /// Reloads the input devices void ReloadInputDevices(); 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 @@ -// Copyright 2017 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#include <algorithm> -#include <chrono> -#include <mutex> -#include <thread> -#include <tuple> -#include "common/math_util.h" -#include "common/quaternion.h" -#include "common/thread.h" -#include "common/vector_math.h" -#include "input_common/motion_emu.h" - -namespace InputCommon { - -// Implementation class of the motion emulation device -class MotionEmuDevice { -public: - explicit MotionEmuDevice(int update_millisecond_, float sensitivity_) - : update_millisecond(update_millisecond_), - update_duration(std::chrono::duration_cast<std::chrono::steady_clock::duration>( - std::chrono::milliseconds(update_millisecond))), - sensitivity(sensitivity_), motion_emu_thread(&MotionEmuDevice::MotionEmuThread, this) {} - - ~MotionEmuDevice() { - if (motion_emu_thread.joinable()) { - shutdown_event.Set(); - motion_emu_thread.join(); - } - } - - void BeginTilt(int x, int y) { - mouse_origin = Common::MakeVec(x, y); - is_tilting = true; - } - - void Tilt(int x, int y) { - if (!is_tilting) { - return; - } - - std::lock_guard guard{tilt_mutex}; - const auto mouse_move = Common::MakeVec(x, y) - mouse_origin; - if (mouse_move.x == 0 && mouse_move.y == 0) { - tilt_angle = 0; - } else { - tilt_direction = mouse_move.Cast<float>(); - tilt_angle = - std::clamp(tilt_direction.Normalize() * sensitivity, 0.0f, Common::PI * 0.5f); - } - } - - void EndTilt() { - std::lock_guard guard{tilt_mutex}; - tilt_angle = 0; - is_tilting = false; - } - - Input::MotionStatus GetStatus() { - std::lock_guard guard{status_mutex}; - return status; - } - -private: - const int update_millisecond; - const std::chrono::steady_clock::duration update_duration; - const float sensitivity; - - Common::Vec2<int> mouse_origin; - - std::mutex tilt_mutex; - Common::Vec2<float> tilt_direction; - float tilt_angle = 0; - - bool is_tilting = false; - - Common::Event shutdown_event; - - Input::MotionStatus status; - std::mutex status_mutex; - - // Note: always keep the thread declaration at the end so that other objects are initialized - // before this! - std::thread motion_emu_thread; - - void MotionEmuThread() { - auto update_time = std::chrono::steady_clock::now(); - Common::Quaternion<float> q = Common::MakeQuaternion(Common::Vec3<float>(), 0); - - while (!shutdown_event.WaitUntil(update_time)) { - update_time += update_duration; - const Common::Quaternion<float> old_q = q; - - { - std::lock_guard guard{tilt_mutex}; - - // Find the quaternion describing current 3DS tilting - q = Common::MakeQuaternion( - Common::MakeVec(-tilt_direction.y, 0.0f, tilt_direction.x), tilt_angle); - } - - const auto inv_q = q.Inverse(); - - // Set the gravity vector in world space - auto gravity = Common::MakeVec(0.0f, -1.0f, 0.0f); - - // Find the angular rate vector in world space - auto angular_rate = ((q - old_q) * inv_q).xyz * 2; - angular_rate *= static_cast<float>(1000 / update_millisecond) / Common::PI * 180.0f; - - // Transform the two vectors from world space to 3DS space - gravity = QuaternionRotate(inv_q, gravity); - angular_rate = QuaternionRotate(inv_q, angular_rate); - - // TODO: Calculate the correct rotation vector and orientation matrix - const auto matrix4x4 = q.ToMatrix(); - const auto rotation = Common::MakeVec(0.0f, 0.0f, 0.0f); - const std::array orientation{ - Common::Vec3f(matrix4x4[0], matrix4x4[1], -matrix4x4[2]), - Common::Vec3f(matrix4x4[4], matrix4x4[5], -matrix4x4[6]), - Common::Vec3f(-matrix4x4[8], -matrix4x4[9], matrix4x4[10]), - }; - - // Update the sensor state - { - std::lock_guard guard{status_mutex}; - status = std::make_tuple(gravity, angular_rate, rotation, orientation); - } - } - } -}; - -// Interface wrapper held by input receiver as a unique_ptr. It holds the implementation class as -// a shared_ptr, which is also observed by the factory class as a weak_ptr. In this way the factory -// can forward all the inputs to the implementation only when it is valid. -class MotionEmuDeviceWrapper : public Input::MotionDevice { -public: - explicit MotionEmuDeviceWrapper(int update_millisecond, float sensitivity) { - device = std::make_shared<MotionEmuDevice>(update_millisecond, sensitivity); - } - - Input::MotionStatus GetStatus() const override { - return device->GetStatus(); - } - - std::shared_ptr<MotionEmuDevice> device; -}; - -std::unique_ptr<Input::MotionDevice> MotionEmu::Create(const Common::ParamPackage& params) { - const int update_period = params.Get("update_period", 100); - const float sensitivity = params.Get("sensitivity", 0.01f); - auto device_wrapper = std::make_unique<MotionEmuDeviceWrapper>(update_period, sensitivity); - // Previously created device is disconnected here. Having two motion devices for 3DS is not - // expected. - current_device = device_wrapper->device; - return device_wrapper; -} - -void MotionEmu::BeginTilt(int x, int y) { - if (auto ptr = current_device.lock()) { - ptr->BeginTilt(x, y); - } -} - -void MotionEmu::Tilt(int x, int y) { - if (auto ptr = current_device.lock()) { - ptr->Tilt(x, y); - } -} - -void MotionEmu::EndTilt() { - if (auto ptr = current_device.lock()) { - ptr->EndTilt(); - } -} - -} // 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 @@ -// Copyright 2017 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#pragma once - -#include "core/frontend/input.h" - -namespace InputCommon { - -class MotionEmuDevice; - -class MotionEmu : public Input::Factory<Input::MotionDevice> { -public: - /** - * Creates a motion device emulated from mouse input - * @param params contains parameters for creating the device: - * - "update_period": update period in milliseconds - * - "sensitivity": the coefficient converting mouse movement to tilting angle - */ - std::unique_ptr<Input::MotionDevice> Create(const Common::ParamPackage& params) override; - - /** - * Signals that a motion sensor tilt has begun. - * @param x the x-coordinate of the cursor - * @param y the y-coordinate of the cursor - */ - void BeginTilt(int x, int y); - - /** - * Signals that a motion sensor tilt is occurring. - * @param x the x-coordinate of the cursor - * @param y the y-coordinate of the cursor - */ - void Tilt(int x, int y); - - /** - * Signals that a motion sensor tilt has ended. - */ - void EndTilt(); - -private: - std::weak_ptr<MotionEmuDevice> current_device; -}; - -} // 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 @@ +// Copyright 2020 yuzu Emulator Project +// Licensed under GPLv2+ +// Refer to the license.txt file included. + +#include "input_common/mouse/mouse_input.h" + +namespace MouseInput { + +Mouse::Mouse() { + update_thread = std::thread(&Mouse::UpdateThread, this); +} + +Mouse::~Mouse() { + update_thread_running = false; + if (update_thread.joinable()) { + update_thread.join(); + } +} + +void Mouse::UpdateThread() { + constexpr int update_time = 10; + while (update_thread_running) { + for (MouseInfo& info : mouse_info) { + const Common::Vec3f angular_direction{ + -info.tilt_direction.y, + 0.0f, + -info.tilt_direction.x, + }; + + info.motion.SetGyroscope(angular_direction * info.tilt_speed); + info.motion.UpdateRotation(update_time * 1000); + info.motion.UpdateOrientation(update_time * 1000); + info.tilt_speed = 0; + info.data.motion = info.motion.GetMotion(); + } + if (configuring) { + UpdateYuzuSettings(); + } + std::this_thread::sleep_for(std::chrono::milliseconds(update_time)); + } +} + +void Mouse::UpdateYuzuSettings() { + if (buttons == 0) { + return; + } + + mouse_queue.Push(MouseStatus{ + .button = last_button, + }); +} + +void Mouse::PressButton(int x, int y, int button_) { + const auto button_index = static_cast<std::size_t>(button_); + if (button_index >= mouse_info.size()) { + return; + } + + const auto button = 1U << button_index; + buttons |= static_cast<u16>(button); + last_button = static_cast<MouseButton>(button_index); + + mouse_info[button_index].mouse_origin = Common::MakeVec(x, y); + mouse_info[button_index].last_mouse_position = Common::MakeVec(x, y); + mouse_info[button_index].data.pressed = true; +} + +void Mouse::MouseMove(int x, int y) { + for (MouseInfo& info : mouse_info) { + if (info.data.pressed) { + const auto mouse_move = Common::MakeVec(x, y) - info.mouse_origin; + const auto mouse_change = Common::MakeVec(x, y) - info.last_mouse_position; + info.last_mouse_position = Common::MakeVec(x, y); + info.data.axis = {mouse_move.x, -mouse_move.y}; + + if (mouse_change.x == 0 && mouse_change.y == 0) { + info.tilt_speed = 0; + } else { + info.tilt_direction = mouse_change.Cast<float>(); + info.tilt_speed = info.tilt_direction.Normalize() * info.sensitivity; + } + } + } +} + +void Mouse::ReleaseButton(int button_) { + const auto button_index = static_cast<std::size_t>(button_); + if (button_index >= mouse_info.size()) { + return; + } + + const auto button = 1U << button_index; + buttons &= static_cast<u16>(0xFF - button); + + mouse_info[button_index].tilt_speed = 0; + mouse_info[button_index].data.pressed = false; + mouse_info[button_index].data.axis = {0, 0}; +} + +void Mouse::BeginConfiguration() { + buttons = 0; + last_button = MouseButton::Undefined; + mouse_queue.Clear(); + configuring = true; +} + +void Mouse::EndConfiguration() { + buttons = 0; + last_button = MouseButton::Undefined; + mouse_queue.Clear(); + configuring = false; +} + +Common::SPSCQueue<MouseStatus>& Mouse::GetMouseQueue() { + return mouse_queue; +} + +const Common::SPSCQueue<MouseStatus>& Mouse::GetMouseQueue() const { + return mouse_queue; +} + +MouseData& Mouse::GetMouseState(std::size_t button) { + return mouse_info[button].data; +} + +const MouseData& Mouse::GetMouseState(std::size_t button) const { + return mouse_info[button].data; +} +} // 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 @@ +// Copyright 2020 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include <array> +#include <mutex> +#include <thread> + +#include "common/common_types.h" +#include "common/threadsafe_queue.h" +#include "common/vector_math.h" +#include "core/frontend/input.h" +#include "input_common/motion_input.h" + +namespace MouseInput { + +enum class MouseButton { + Left, + Wheel, + Right, + Foward, + Backward, + Undefined, +}; + +struct MouseStatus { + MouseButton button{MouseButton::Undefined}; +}; + +struct MouseData { + bool pressed{}; + std::array<int, 2> axis{}; + Input::MotionStatus motion{}; + Input::TouchStatus touch{}; +}; + +class Mouse { +public: + Mouse(); + ~Mouse(); + + /// Used for polling + void BeginConfiguration(); + void EndConfiguration(); + + /** + * Signals that a button is pressed. + * @param x the x-coordinate of the cursor + * @param y the y-coordinate of the cursor + * @param button_ the button pressed + */ + void PressButton(int x, int y, int button_); + + /** + * Signals that mouse has moved. + * @param x the x-coordinate of the cursor + * @param y the y-coordinate of the cursor + */ + void MouseMove(int x, int y); + + /** + * Signals that a motion sensor tilt has ended. + */ + void ReleaseButton(int button_); + + [[nodiscard]] Common::SPSCQueue<MouseStatus>& GetMouseQueue(); + [[nodiscard]] const Common::SPSCQueue<MouseStatus>& GetMouseQueue() const; + + [[nodiscard]] MouseData& GetMouseState(std::size_t button); + [[nodiscard]] const MouseData& GetMouseState(std::size_t button) const; + +private: + void UpdateThread(); + void UpdateYuzuSettings(); + + struct MouseInfo { + InputCommon::MotionInput motion{0.0f, 0.0f, 0.0f}; + Common::Vec2<int> mouse_origin; + Common::Vec2<int> last_mouse_position; + bool is_tilting = false; + float sensitivity{0.120f}; + + float tilt_speed = 0; + Common::Vec2<float> tilt_direction; + MouseData data; + }; + + u16 buttons{}; + std::thread update_thread; + MouseButton last_button{MouseButton::Undefined}; + std::array<MouseInfo, 5> mouse_info; + Common::SPSCQueue<MouseStatus> mouse_queue; + bool configuring{false}; + bool update_thread_running{true}; +}; +} // 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 @@ +// Copyright 2020 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include <mutex> +#include <utility> + +#include "common/threadsafe_queue.h" +#include "input_common/mouse/mouse_input.h" +#include "input_common/mouse/mouse_poller.h" + +namespace InputCommon { + +class MouseButton final : public Input::ButtonDevice { +public: + explicit MouseButton(u32 button_, const MouseInput::Mouse* mouse_input_) + : button(button_), mouse_input(mouse_input_) {} + + bool GetStatus() const override { + return mouse_input->GetMouseState(button).pressed; + } + +private: + const u32 button; + const MouseInput::Mouse* mouse_input; +}; + +MouseButtonFactory::MouseButtonFactory(std::shared_ptr<MouseInput::Mouse> mouse_input_) + : mouse_input(std::move(mouse_input_)) {} + +std::unique_ptr<Input::ButtonDevice> MouseButtonFactory::Create( + const Common::ParamPackage& params) { + const auto button_id = params.Get("button", 0); + + return std::make_unique<MouseButton>(button_id, mouse_input.get()); +} + +Common::ParamPackage MouseButtonFactory::GetNextInput() const { + MouseInput::MouseStatus pad; + Common::ParamPackage params; + auto& queue = mouse_input->GetMouseQueue(); + while (queue.Pop(pad)) { + // This while loop will break on the earliest detected button + if (pad.button != MouseInput::MouseButton::Undefined) { + params.Set("engine", "mouse"); + params.Set("button", static_cast<u16>(pad.button)); + return params; + } + } + return params; +} + +void MouseButtonFactory::BeginConfiguration() { + polling = true; + mouse_input->BeginConfiguration(); +} + +void MouseButtonFactory::EndConfiguration() { + polling = false; + mouse_input->EndConfiguration(); +} + +class MouseAnalog final : public Input::AnalogDevice { +public: + explicit MouseAnalog(u32 port_, u32 axis_x_, u32 axis_y_, float deadzone_, float range_, + const MouseInput::Mouse* mouse_input_) + : button(port_), axis_x(axis_x_), axis_y(axis_y_), deadzone(deadzone_), range(range_), + mouse_input(mouse_input_) {} + + float GetAxis(u32 axis) const { + std::lock_guard lock{mutex}; + const auto axis_value = + static_cast<float>(mouse_input->GetMouseState(button).axis.at(axis)); + return axis_value / (100.0f * range); + } + + std::pair<float, float> GetAnalog(u32 analog_axis_x, u32 analog_axis_y) const { + float x = GetAxis(analog_axis_x); + float y = GetAxis(analog_axis_y); + + // Make sure the coordinates are in the unit circle, + // otherwise normalize it. + float r = x * x + y * y; + if (r > 1.0f) { + r = std::sqrt(r); + x /= r; + y /= r; + } + + return {x, y}; + } + + std::tuple<float, float> GetStatus() const override { + const auto [x, y] = GetAnalog(axis_x, axis_y); + const float r = std::sqrt((x * x) + (y * y)); + if (r > deadzone) { + return {x / r * (r - deadzone) / (1 - deadzone), + y / r * (r - deadzone) / (1 - deadzone)}; + } + return {0.0f, 0.0f}; + } + +private: + const u32 button; + const u32 axis_x; + const u32 axis_y; + const float deadzone; + const float range; + const MouseInput::Mouse* mouse_input; + mutable std::mutex mutex; +}; + +/// An analog device factory that creates analog devices from GC Adapter +MouseAnalogFactory::MouseAnalogFactory(std::shared_ptr<MouseInput::Mouse> mouse_input_) + : mouse_input(std::move(mouse_input_)) {} + +/** + * Creates analog device from joystick axes + * @param params contains parameters for creating the device: + * - "port": the nth gcpad on the adapter + * - "axis_x": the index of the axis to be bind as x-axis + * - "axis_y": the index of the axis to be bind as y-axis + */ +std::unique_ptr<Input::AnalogDevice> MouseAnalogFactory::Create( + const Common::ParamPackage& params) { + const auto port = static_cast<u32>(params.Get("port", 0)); + const auto axis_x = static_cast<u32>(params.Get("axis_x", 0)); + const auto axis_y = static_cast<u32>(params.Get("axis_y", 1)); + const auto deadzone = std::clamp(params.Get("deadzone", 0.0f), 0.0f, 1.0f); + const auto range = std::clamp(params.Get("range", 1.0f), 0.50f, 1.50f); + + return std::make_unique<MouseAnalog>(port, axis_x, axis_y, deadzone, range, mouse_input.get()); +} + +void MouseAnalogFactory::BeginConfiguration() { + polling = true; + mouse_input->BeginConfiguration(); +} + +void MouseAnalogFactory::EndConfiguration() { + polling = false; + mouse_input->EndConfiguration(); +} + +Common::ParamPackage MouseAnalogFactory::GetNextInput() const { + MouseInput::MouseStatus pad; + Common::ParamPackage params; + auto& queue = mouse_input->GetMouseQueue(); + while (queue.Pop(pad)) { + // This while loop will break on the earliest detected button + if (pad.button != MouseInput::MouseButton::Undefined) { + params.Set("engine", "mouse"); + params.Set("port", static_cast<u16>(pad.button)); + params.Set("axis_x", 0); + params.Set("axis_y", 1); + return params; + } + } + return params; +} + +class MouseMotion final : public Input::MotionDevice { +public: + explicit MouseMotion(u32 button_, const MouseInput::Mouse* mouse_input_) + : button(button_), mouse_input(mouse_input_) {} + + Input::MotionStatus GetStatus() const override { + return mouse_input->GetMouseState(button).motion; + } + +private: + const u32 button; + const MouseInput::Mouse* mouse_input; +}; + +MouseMotionFactory::MouseMotionFactory(std::shared_ptr<MouseInput::Mouse> mouse_input_) + : mouse_input(std::move(mouse_input_)) {} + +std::unique_ptr<Input::MotionDevice> MouseMotionFactory::Create( + const Common::ParamPackage& params) { + const auto button_id = params.Get("button", 0); + + return std::make_unique<MouseMotion>(button_id, mouse_input.get()); +} + +Common::ParamPackage MouseMotionFactory::GetNextInput() const { + MouseInput::MouseStatus pad; + Common::ParamPackage params; + auto& queue = mouse_input->GetMouseQueue(); + while (queue.Pop(pad)) { + // This while loop will break on the earliest detected button + if (pad.button != MouseInput::MouseButton::Undefined) { + params.Set("engine", "mouse"); + params.Set("button", static_cast<u16>(pad.button)); + return params; + } + } + return params; +} + +void MouseMotionFactory::BeginConfiguration() { + polling = true; + mouse_input->BeginConfiguration(); +} + +void MouseMotionFactory::EndConfiguration() { + polling = false; + mouse_input->EndConfiguration(); +} + +class MouseTouch final : public Input::TouchDevice { +public: + explicit MouseTouch(u32 button_, const MouseInput::Mouse* mouse_input_) + : button(button_), mouse_input(mouse_input_) {} + + Input::TouchStatus GetStatus() const override { + return mouse_input->GetMouseState(button).touch; + } + +private: + const u32 button; + const MouseInput::Mouse* mouse_input; +}; + +MouseTouchFactory::MouseTouchFactory(std::shared_ptr<MouseInput::Mouse> mouse_input_) + : mouse_input(std::move(mouse_input_)) {} + +std::unique_ptr<Input::TouchDevice> MouseTouchFactory::Create(const Common::ParamPackage& params) { + const auto button_id = params.Get("button", 0); + + return std::make_unique<MouseTouch>(button_id, mouse_input.get()); +} + +Common::ParamPackage MouseTouchFactory::GetNextInput() const { + MouseInput::MouseStatus pad; + Common::ParamPackage params; + auto& queue = mouse_input->GetMouseQueue(); + while (queue.Pop(pad)) { + // This while loop will break on the earliest detected button + if (pad.button != MouseInput::MouseButton::Undefined) { + params.Set("engine", "mouse"); + params.Set("button", static_cast<u16>(pad.button)); + return params; + } + } + return params; +} + +void MouseTouchFactory::BeginConfiguration() { + polling = true; + mouse_input->BeginConfiguration(); +} + +void MouseTouchFactory::EndConfiguration() { + polling = false; + mouse_input->EndConfiguration(); +} + +} // 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 @@ +// Copyright 2020 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include <memory> +#include "core/frontend/input.h" +#include "input_common/mouse/mouse_input.h" + +namespace InputCommon { + +/** + * A button device factory representing a mouse. It receives mouse events and forward them + * to all button devices it created. + */ +class MouseButtonFactory final : public Input::Factory<Input::ButtonDevice> { +public: + explicit MouseButtonFactory(std::shared_ptr<MouseInput::Mouse> mouse_input_); + + /** + * Creates a button device from a button press + * @param params contains parameters for creating the device: + * - "code": the code of the key to bind with the button + */ + std::unique_ptr<Input::ButtonDevice> Create(const Common::ParamPackage& params) override; + + Common::ParamPackage GetNextInput() const; + + /// For device input configuration/polling + void BeginConfiguration(); + void EndConfiguration(); + + bool IsPolling() const { + return polling; + } + +private: + std::shared_ptr<MouseInput::Mouse> mouse_input; + bool polling = false; +}; + +/// An analog device factory that creates analog devices from mouse +class MouseAnalogFactory final : public Input::Factory<Input::AnalogDevice> { +public: + explicit MouseAnalogFactory(std::shared_ptr<MouseInput::Mouse> mouse_input_); + + std::unique_ptr<Input::AnalogDevice> Create(const Common::ParamPackage& params) override; + + Common::ParamPackage GetNextInput() const; + + /// For device input configuration/polling + void BeginConfiguration(); + void EndConfiguration(); + + bool IsPolling() const { + return polling; + } + +private: + std::shared_ptr<MouseInput::Mouse> mouse_input; + bool polling = false; +}; + +/// A motion device factory that creates motion devices from mouse +class MouseMotionFactory final : public Input::Factory<Input::MotionDevice> { +public: + explicit MouseMotionFactory(std::shared_ptr<MouseInput::Mouse> mouse_input_); + + std::unique_ptr<Input::MotionDevice> Create(const Common::ParamPackage& params) override; + + Common::ParamPackage GetNextInput() const; + + /// For device input configuration/polling + void BeginConfiguration(); + void EndConfiguration(); + + bool IsPolling() const { + return polling; + } + +private: + std::shared_ptr<MouseInput::Mouse> mouse_input; + bool polling = false; +}; + +/// An touch device factory that creates touch devices from mouse +class MouseTouchFactory final : public Input::Factory<Input::TouchDevice> { +public: + explicit MouseTouchFactory(std::shared_ptr<MouseInput::Mouse> mouse_input_); + + std::unique_ptr<Input::TouchDevice> Create(const Common::ParamPackage& params) override; + + Common::ParamPackage GetNextInput() const; + + /// For device input configuration/polling + void BeginConfiguration(); + void EndConfiguration(); + + bool IsPolling() const { + return polling; + } + +private: + std::shared_ptr<MouseInput::Mouse> mouse_input; + bool polling = false; +}; + +} // 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) { Client::Client() { LOG_INFO(Input, "Udp Initialization started"); - for (std::size_t client = 0; client < clients.size(); client++) { - const auto pad = client % 4; - StartCommunication(client, Settings::values.udp_input_address, - Settings::values.udp_input_port, pad, 24872); - // Set motion parameters - // SetGyroThreshold value should be dependent on GyroscopeZeroDriftMode - // Real HW values are unknown, 0.0001 is an approximate to Standard - clients[client].motion.SetGyroThreshold(0.0001f); - } + ReloadSockets(); } Client::~Client() { @@ -167,26 +159,61 @@ std::vector<Common::ParamPackage> Client::GetInputDevices() const { return devices; } -bool Client::DeviceConnected(std::size_t pad) const { +bool Client::DeviceConnected(std::size_t client) const { // Use last timestamp to detect if the socket has stopped sending data - const auto now = std::chrono::system_clock::now(); - const auto time_difference = static_cast<u64>( - std::chrono::duration_cast<std::chrono::milliseconds>(now - clients[pad].last_motion_update) - .count()); - return time_difference < 1000 && clients[pad].active == 1; + const auto now = std::chrono::steady_clock::now(); + const auto time_difference = + static_cast<u64>(std::chrono::duration_cast<std::chrono::milliseconds>( + now - clients[client].last_motion_update) + .count()); + return time_difference < 1000 && clients[client].active == 1; } -void Client::ReloadUDPClient() { - for (std::size_t client = 0; client < clients.size(); client++) { - ReloadSocket(Settings::values.udp_input_address, Settings::values.udp_input_port, client); +void Client::ReloadSockets() { + Reset(); + + std::stringstream servers_ss(Settings::values.udp_input_servers); + std::string server_token; + std::size_t client = 0; + while (std::getline(servers_ss, server_token, ',')) { + if (client == max_udp_clients) { + break; + } + std::stringstream server_ss(server_token); + std::string token; + std::getline(server_ss, token, ':'); + std::string udp_input_address = token; + std::getline(server_ss, token, ':'); + char* temp; + const u16 udp_input_port = static_cast<u16>(std::strtol(token.c_str(), &temp, 0)); + if (*temp != '\0') { + LOG_ERROR(Input, "Port number is not valid {}", token); + continue; + } + + for (std::size_t pad = 0; pad < 4; ++pad) { + const std::size_t client_number = + GetClientNumber(udp_input_address, udp_input_port, pad); + if (client_number != max_udp_clients) { + LOG_ERROR(Input, "Duplicated UDP servers found"); + continue; + } + StartCommunication(client++, udp_input_address, udp_input_port, pad, 24872); + } } } -void Client::ReloadSocket(const std::string& host, u16 port, std::size_t pad_index, u32 client_id) { - // client number must be determined from host / port and pad index - const std::size_t client = pad_index; - clients[client].socket->Stop(); - clients[client].thread.join(); - StartCommunication(client, host, port, pad_index, client_id); + +std::size_t Client::GetClientNumber(std::string_view host, u16 port, std::size_t pad) const { + for (std::size_t client = 0; client < clients.size(); client++) { + if (clients[client].active == -1) { + continue; + } + if (clients[client].host == host && clients[client].port == port && + clients[client].pad_index == pad) { + return client; + } + } + return max_udp_clients; } void Client::OnVersion([[maybe_unused]] Response::Version data) { @@ -197,9 +224,7 @@ void Client::OnPortInfo([[maybe_unused]] Response::PortInfo data) { LOG_TRACE(Input, "PortInfo packet received: {}", data.model); } -void Client::OnPadData(Response::PadData data) { - // Client number must be determined from host / port and pad index - const std::size_t client = data.info.id; +void Client::OnPadData(Response::PadData data, std::size_t client) { LOG_TRACE(Input, "PadData packet received"); if (data.packet_counter == clients[client].packet_sequence) { LOG_WARNING( @@ -208,9 +233,9 @@ void Client::OnPadData(Response::PadData data) { clients[client].packet_sequence, data.packet_counter); return; } - clients[client].active = data.info.is_pad_active; + clients[client].active = static_cast<s8>(data.info.is_pad_active); clients[client].packet_sequence = data.packet_counter; - const auto now = std::chrono::system_clock::now(); + const auto now = std::chrono::steady_clock::now(); const auto time_difference = static_cast<u64>(std::chrono::duration_cast<std::chrono::microseconds>( now - clients[client].last_motion_update) @@ -264,16 +289,28 @@ void Client::StartCommunication(std::size_t client, const std::string& host, u16 std::size_t pad_index, u32 client_id) { SocketCallback callback{[this](Response::Version version) { OnVersion(version); }, [this](Response::PortInfo info) { OnPortInfo(info); }, - [this](Response::PadData data) { OnPadData(data); }}; - LOG_INFO(Input, "Starting communication with UDP input server on {}:{}", host, port); + [this, client](Response::PadData data) { OnPadData(data, client); }}; + LOG_INFO(Input, "Starting communication with UDP input server on {}:{}:{}", host, port, + pad_index); + clients[client].host = host; + clients[client].port = port; + clients[client].pad_index = pad_index; + clients[client].active = 0; clients[client].socket = std::make_unique<Socket>(host, port, pad_index, client_id, callback); clients[client].thread = std::thread{SocketLoop, clients[client].socket.get()}; + // Set motion parameters + // SetGyroThreshold value should be dependent on GyroscopeZeroDriftMode + // Real HW values are unknown, 0.0001 is an approximate to Standard + clients[client].motion.SetGyroThreshold(0.0001f); } void Client::Reset() { for (auto& client : clients) { - client.socket->Stop(); - client.thread.join(); + if (client.thread.joinable()) { + client.active = -1; + client.socket->Stop(); + client.thread.join(); + } } } @@ -283,52 +320,60 @@ void Client::UpdateYuzuSettings(std::size_t client, const Common::Vec3<float>& a LOG_DEBUG(Input, "UDP Controller {}: gyro=({}, {}, {}), accel=({}, {}, {}), touch={}", client, gyro[0], gyro[1], gyro[2], acc[0], acc[1], acc[2], touch); } - UDPPadStatus pad; + UDPPadStatus pad{ + .host = clients[client].host, + .port = clients[client].port, + .pad_index = clients[client].pad_index, + }; if (touch) { pad.touch = PadTouch::Click; - pad_queue[client].Push(pad); + pad_queue.Push(pad); } for (size_t i = 0; i < 3; ++i) { if (gyro[i] > 5.0f || gyro[i] < -5.0f) { pad.motion = static_cast<PadMotion>(i); pad.motion_value = gyro[i]; - pad_queue[client].Push(pad); + pad_queue.Push(pad); } if (acc[i] > 1.75f || acc[i] < -1.75f) { pad.motion = static_cast<PadMotion>(i + 3); pad.motion_value = acc[i]; - pad_queue[client].Push(pad); + pad_queue.Push(pad); } } } void Client::BeginConfiguration() { - for (auto& pq : pad_queue) { - pq.Clear(); - } + pad_queue.Clear(); configuring = true; } void Client::EndConfiguration() { - for (auto& pq : pad_queue) { - pq.Clear(); - } + pad_queue.Clear(); configuring = false; } -DeviceStatus& Client::GetPadState(std::size_t pad) { - return clients[pad].status; +DeviceStatus& Client::GetPadState(const std::string& host, u16 port, std::size_t pad) { + const std::size_t client_number = GetClientNumber(host, port, pad); + if (client_number == max_udp_clients) { + return clients[0].status; + } + return clients[client_number].status; } -const DeviceStatus& Client::GetPadState(std::size_t pad) const { - return clients[pad].status; +const DeviceStatus& Client::GetPadState(const std::string& host, u16 port, std::size_t pad) const { + const std::size_t client_number = GetClientNumber(host, port, pad); + if (client_number == max_udp_clients) { + return clients[0].status; + } + return clients[client_number].status; } -std::array<Common::SPSCQueue<UDPPadStatus>, 4>& Client::GetPadQueue() { +Common::SPSCQueue<UDPPadStatus>& Client::GetPadQueue() { return pad_queue; } -const std::array<Common::SPSCQueue<UDPPadStatus>, 4>& Client::GetPadQueue() const { +const Common::SPSCQueue<UDPPadStatus>& Client::GetPadQueue() const { return pad_queue; } 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 @@ namespace InputCommon::CemuhookUDP { -constexpr u16 DEFAULT_PORT = 26760; -constexpr char DEFAULT_ADDR[] = "127.0.0.1"; +constexpr char DEFAULT_SRV[] = "127.0.0.1:26760"; class Socket; @@ -48,6 +47,9 @@ enum class PadTouch { }; struct UDPPadStatus { + std::string host{"127.0.0.1"}; + u16 port{26760}; + std::size_t pad_index{}; PadTouch touch{PadTouch::Undefined}; PadMotion motion{PadMotion::Undefined}; f32 motion_value{0.0f}; @@ -82,37 +84,41 @@ public: std::vector<Common::ParamPackage> GetInputDevices() const; - bool DeviceConnected(std::size_t pad) const; - void ReloadUDPClient(); - void ReloadSocket(const std::string& host = "127.0.0.1", u16 port = 26760, - std::size_t pad_index = 0, u32 client_id = 24872); + bool DeviceConnected(std::size_t client) const; + void ReloadSockets(); - std::array<Common::SPSCQueue<UDPPadStatus>, 4>& GetPadQueue(); - const std::array<Common::SPSCQueue<UDPPadStatus>, 4>& GetPadQueue() const; + Common::SPSCQueue<UDPPadStatus>& GetPadQueue(); + const Common::SPSCQueue<UDPPadStatus>& GetPadQueue() const; - DeviceStatus& GetPadState(std::size_t pad); - const DeviceStatus& GetPadState(std::size_t pad) const; + DeviceStatus& GetPadState(const std::string& host, u16 port, std::size_t pad); + const DeviceStatus& GetPadState(const std::string& host, u16 port, std::size_t pad) const; private: struct ClientData { + std::string host{"127.0.0.1"}; + u16 port{26760}; + std::size_t pad_index{}; std::unique_ptr<Socket> socket; DeviceStatus status; std::thread thread; - u64 packet_sequence = 0; - u8 active = 0; + u64 packet_sequence{}; + s8 active{-1}; // Realtime values // motion is initalized with PID values for drift correction on joycons InputCommon::MotionInput motion{0.3f, 0.005f, 0.0f}; - std::chrono::time_point<std::chrono::system_clock> last_motion_update; + std::chrono::time_point<std::chrono::steady_clock> last_motion_update; }; // For shutting down, clear all data, join all threads, release usb void Reset(); + // Translates configuration to client number + std::size_t GetClientNumber(std::string_view host, u16 port, std::size_t pad) const; + void OnVersion(Response::Version); void OnPortInfo(Response::PortInfo); - void OnPadData(Response::PadData); + void OnPadData(Response::PadData, std::size_t client); void StartCommunication(std::size_t client, const std::string& host, u16 port, std::size_t pad_index, u32 client_id); void UpdateYuzuSettings(std::size_t client, const Common::Vec3<float>& acc, @@ -120,8 +126,10 @@ private: bool configuring = false; - std::array<ClientData, 4> clients; - std::array<Common::SPSCQueue<UDPPadStatus>, 4> pad_queue; + // Allocate clients for 8 udp servers + const std::size_t max_udp_clients = 32; + std::array<ClientData, 4 * 8> clients; + Common::SPSCQueue<UDPPadStatus> pad_queue; }; /// 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 { class UDPMotion final : public Input::MotionDevice { public: - explicit UDPMotion(std::string ip_, int port_, u32 pad_, CemuhookUDP::Client* client_) + explicit UDPMotion(std::string ip_, u16 port_, u16 pad_, CemuhookUDP::Client* client_) : ip(std::move(ip_)), port(port_), pad(pad_), client(client_) {} Input::MotionStatus GetStatus() const override { - return client->GetPadState(pad).motion_status; + return client->GetPadState(ip, port, pad).motion_status; } private: const std::string ip; - const int port; - const u32 pad; + const u16 port; + const u16 pad; CemuhookUDP::Client* client; mutable std::mutex mutex; }; @@ -39,8 +39,8 @@ UDPMotionFactory::UDPMotionFactory(std::shared_ptr<CemuhookUDP::Client> client_) */ std::unique_ptr<Input::MotionDevice> UDPMotionFactory::Create(const Common::ParamPackage& params) { auto ip = params.Get("ip", "127.0.0.1"); - const auto port = params.Get("port", 26760); - const auto pad = static_cast<u32>(params.Get("pad_index", 0)); + const auto port = static_cast<u16>(params.Get("port", 26760)); + const auto pad = static_cast<u16>(params.Get("pad_index", 0)); return std::make_unique<UDPMotion>(std::move(ip), port, pad, client.get()); } @@ -59,35 +59,33 @@ Common::ParamPackage UDPMotionFactory::GetNextInput() { Common::ParamPackage params; CemuhookUDP::UDPPadStatus pad; auto& queue = client->GetPadQueue(); - for (std::size_t pad_number = 0; pad_number < queue.size(); ++pad_number) { - while (queue[pad_number].Pop(pad)) { - if (pad.motion == CemuhookUDP::PadMotion::Undefined || std::abs(pad.motion_value) < 1) { - continue; - } - params.Set("engine", "cemuhookudp"); - params.Set("ip", "127.0.0.1"); - params.Set("port", 26760); - params.Set("pad_index", static_cast<int>(pad_number)); - params.Set("motion", static_cast<u16>(pad.motion)); - return params; + while (queue.Pop(pad)) { + if (pad.motion == CemuhookUDP::PadMotion::Undefined || std::abs(pad.motion_value) < 1) { + continue; } + params.Set("engine", "cemuhookudp"); + params.Set("ip", pad.host); + params.Set("port", static_cast<u16>(pad.port)); + params.Set("pad_index", static_cast<u16>(pad.pad_index)); + params.Set("motion", static_cast<u16>(pad.motion)); + return params; } return params; } class UDPTouch final : public Input::TouchDevice { public: - explicit UDPTouch(std::string ip_, int port_, u32 pad_, CemuhookUDP::Client* client_) + explicit UDPTouch(std::string ip_, u16 port_, u16 pad_, CemuhookUDP::Client* client_) : ip(std::move(ip_)), port(port_), pad(pad_), client(client_) {} std::tuple<float, float, bool> GetStatus() const override { - return client->GetPadState(pad).touch_status; + return client->GetPadState(ip, port, pad).touch_status; } private: const std::string ip; - const int port; - const u32 pad; + const u16 port; + const u16 pad; CemuhookUDP::Client* client; mutable std::mutex mutex; }; @@ -103,8 +101,8 @@ UDPTouchFactory::UDPTouchFactory(std::shared_ptr<CemuhookUDP::Client> client_) */ std::unique_ptr<Input::TouchDevice> UDPTouchFactory::Create(const Common::ParamPackage& params) { auto ip = params.Get("ip", "127.0.0.1"); - const auto port = params.Get("port", 26760); - const auto pad = static_cast<u32>(params.Get("pad_index", 0)); + const auto port = static_cast<u16>(params.Get("port", 26760)); + const auto pad = static_cast<u16>(params.Get("pad_index", 0)); return std::make_unique<UDPTouch>(std::move(ip), port, pad, client.get()); } @@ -123,18 +121,16 @@ Common::ParamPackage UDPTouchFactory::GetNextInput() { Common::ParamPackage params; CemuhookUDP::UDPPadStatus pad; auto& queue = client->GetPadQueue(); - for (std::size_t pad_number = 0; pad_number < queue.size(); ++pad_number) { - while (queue[pad_number].Pop(pad)) { - if (pad.touch == CemuhookUDP::PadTouch::Undefined) { - continue; - } - params.Set("engine", "cemuhookudp"); - params.Set("ip", "127.0.0.1"); - params.Set("port", 26760); - params.Set("pad_index", static_cast<int>(pad_number)); - params.Set("touch", static_cast<u16>(pad.touch)); - return params; + while (queue.Pop(pad)) { + if (pad.touch == CemuhookUDP::PadTouch::Undefined) { + continue; } + params.Set("engine", "cemuhookudp"); + params.Set("ip", pad.host); + params.Set("port", static_cast<u16>(pad.port)); + params.Set("pad_index", static_cast<u16>(pad.pad_index)); + params.Set("touch", static_cast<u16>(pad.touch)); + return params; } return params; } 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" { namespace Tegra { +void AVFrameDeleter(AVFrame* ptr) { + av_frame_unref(ptr); + av_free(ptr); +} + Codec::Codec(GPU& gpu_) : gpu(gpu_), h264_decoder(std::make_unique<Decoder::H264>(gpu)), vp9_decoder(std::make_unique<Decoder::VP9>(gpu)) {} @@ -27,7 +32,9 @@ Codec::~Codec() { return; } // Free libav memory + AVFrame* av_frame{nullptr}; avcodec_send_packet(av_codec_ctx, nullptr); + av_frame = av_frame_alloc(); avcodec_receive_frame(av_codec_ctx, av_frame); avcodec_flush_buffers(av_codec_ctx); @@ -60,7 +67,7 @@ void Codec::Decode() { } av_codec_ctx = avcodec_alloc_context3(av_codec); - av_frame = av_frame_alloc(); + av_codec_ctx->refcounted_frames = 1; av_opt_set(av_codec_ctx->priv_data, "tune", "zerolatency", 0); // TODO(ameerj): libavcodec gpu hw acceleration @@ -68,8 +75,6 @@ void Codec::Decode() { const auto av_error = avcodec_open2(av_codec_ctx, av_codec, nullptr); if (av_error < 0) { LOG_ERROR(Service_NVDRV, "avcodec_open2() Failed."); - av_frame_unref(av_frame); - av_free(av_frame); avcodec_close(av_codec_ctx); return; } @@ -96,16 +101,26 @@ void Codec::Decode() { if (!vp9_hidden_frame) { // Only receive/store visible frames - avcodec_receive_frame(av_codec_ctx, av_frame); + AVFramePtr frame = AVFramePtr{av_frame_alloc(), AVFrameDeleter}; + avcodec_receive_frame(av_codec_ctx, frame.get()); + av_frames.push(std::move(frame)); + // Limit queue to 10 frames. Workaround for ZLA decode and queue spam + if (av_frames.size() > 10) { + av_frames.pop(); + } } } -AVFrame* Codec::GetCurrentFrame() { - return av_frame; -} +AVFramePtr Codec::GetCurrentFrame() { + // Sometimes VIC will request more frames than have been decoded. + // in this case, return a nullptr and don't overwrite previous frame data + if (av_frames.empty()) { + return AVFramePtr{nullptr, AVFrameDeleter}; + } -const AVFrame* Codec::GetCurrentFrame() const { - return av_frame; + AVFramePtr frame = std::move(av_frames.front()); + av_frames.pop(); + return frame; } NvdecCommon::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 @@ #pragma once #include <memory> +#include <queue> #include "common/common_types.h" #include "video_core/command_classes/nvdec_common.h" @@ -23,6 +24,9 @@ namespace Tegra { class GPU; struct VicRegisters; +void AVFrameDeleter(AVFrame* ptr); +using AVFramePtr = std::unique_ptr<AVFrame, decltype(&AVFrameDeleter)>; + namespace Decoder { class H264; class VP9; @@ -42,9 +46,8 @@ public: /// Call decoders to construct headers, decode AVFrame with ffmpeg void Decode(); - /// Returns most recently decoded frame - [[nodiscard]] AVFrame* GetCurrentFrame(); - [[nodiscard]] const AVFrame* GetCurrentFrame() const; + /// Returns next decoded frame + [[nodiscard]] AVFramePtr GetCurrentFrame(); /// Returns the value of current_codec [[nodiscard]] NvdecCommon::VideoCodec GetCurrentCodec() const; @@ -55,13 +58,13 @@ private: AVCodec* av_codec{nullptr}; AVCodecContext* av_codec_ctx{nullptr}; - AVFrame* av_frame{nullptr}; GPU& gpu; std::unique_ptr<Decoder::H264> h264_decoder; std::unique_ptr<Decoder::VP9> vp9_decoder; NvdecCommon::NvdecRegisters state{}; + std::queue<AVFramePtr> av_frames{}; }; } // 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_) {} H264::~H264() = default; -const std::vector<u8>& H264::ComposeFrameHeader(NvdecCommon::NvdecRegisters& state, +const std::vector<u8>& H264::ComposeFrameHeader(const NvdecCommon::NvdecRegisters& state, bool is_first_frame) { H264DecoderContext context{}; 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: ~H264(); /// Compose the H264 header of the frame for FFmpeg decoding - [[nodiscard]] const std::vector<u8>& ComposeFrameHeader(NvdecCommon::NvdecRegisters& state, - bool is_first_frame = false); + [[nodiscard]] const std::vector<u8>& ComposeFrameHeader( + const NvdecCommon::NvdecRegisters& state, bool is_first_frame = false); private: 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{ 222, 34, 30, 0, 72, 16, 44, 0, 58, 32, 12, 0, 10, 7, 6, 0, }, .coef_probs{ - 195, 29, 183, 0, 84, 49, 136, 0, 8, 42, 71, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 31, 107, 169, 0, 35, 99, 159, 0, 17, 82, 140, 0, 8, 66, 114, 0, - 2, 44, 76, 0, 1, 19, 32, 0, 40, 132, 201, 0, 29, 114, 187, 0, 13, 91, 157, 0, - 7, 75, 127, 0, 3, 58, 95, 0, 1, 28, 47, 0, 69, 142, 221, 0, 42, 122, 201, 0, - 15, 91, 159, 0, 6, 67, 121, 0, 1, 42, 77, 0, 1, 17, 31, 0, 102, 148, 228, 0, - 67, 117, 204, 0, 17, 82, 154, 0, 6, 59, 114, 0, 2, 39, 75, 0, 1, 15, 29, 0, - 156, 57, 233, 0, 119, 57, 212, 0, 58, 48, 163, 0, 29, 40, 124, 0, 12, 30, 81, 0, - 3, 12, 31, 0, 191, 107, 226, 0, 124, 117, 204, 0, 25, 99, 155, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 29, 148, 210, 0, 37, 126, 194, 0, 8, 93, 157, 0, - 2, 68, 118, 0, 1, 39, 69, 0, 1, 17, 33, 0, 41, 151, 213, 0, 27, 123, 193, 0, - 3, 82, 144, 0, 1, 58, 105, 0, 1, 32, 60, 0, 1, 13, 26, 0, 59, 159, 220, 0, - 23, 126, 198, 0, 4, 88, 151, 0, 1, 66, 114, 0, 1, 38, 71, 0, 1, 18, 34, 0, - 114, 136, 232, 0, 51, 114, 207, 0, 11, 83, 155, 0, 3, 56, 105, 0, 1, 33, 65, 0, - 1, 17, 34, 0, 149, 65, 234, 0, 121, 57, 215, 0, 61, 49, 166, 0, 28, 36, 114, 0, - 12, 25, 76, 0, 3, 16, 42, 0, 214, 49, 220, 0, 132, 63, 188, 0, 42, 65, 137, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 137, 221, 0, 104, 131, 216, 0, - 49, 111, 192, 0, 21, 87, 155, 0, 2, 49, 87, 0, 1, 16, 28, 0, 89, 163, 230, 0, - 90, 137, 220, 0, 29, 100, 183, 0, 10, 70, 135, 0, 2, 42, 81, 0, 1, 17, 33, 0, - 108, 167, 237, 0, 55, 133, 222, 0, 15, 97, 179, 0, 4, 72, 135, 0, 1, 45, 85, 0, - 1, 19, 38, 0, 124, 146, 240, 0, 66, 124, 224, 0, 17, 88, 175, 0, 4, 58, 122, 0, - 1, 36, 75, 0, 1, 18, 37, 0, 141, 79, 241, 0, 126, 70, 227, 0, 66, 58, 182, 0, - 30, 44, 136, 0, 12, 34, 96, 0, 2, 20, 47, 0, 229, 99, 249, 0, 143, 111, 235, 0, - 46, 109, 192, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 82, 158, 236, 0, - 94, 146, 224, 0, 25, 117, 191, 0, 9, 87, 149, 0, 3, 56, 99, 0, 1, 33, 57, 0, - 83, 167, 237, 0, 68, 145, 222, 0, 10, 103, 177, 0, 2, 72, 131, 0, 1, 41, 79, 0, - 1, 20, 39, 0, 99, 167, 239, 0, 47, 141, 224, 0, 10, 104, 178, 0, 2, 73, 133, 0, - 1, 44, 85, 0, 1, 22, 47, 0, 127, 145, 243, 0, 71, 129, 228, 0, 17, 93, 177, 0, - 3, 61, 124, 0, 1, 41, 84, 0, 1, 21, 52, 0, 157, 78, 244, 0, 140, 72, 231, 0, - 69, 58, 184, 0, 31, 44, 137, 0, 14, 38, 105, 0, 8, 23, 61, 0, 125, 34, 187, 0, - 52, 41, 133, 0, 6, 31, 56, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 37, 109, 153, 0, 51, 102, 147, 0, 23, 87, 128, 0, 8, 67, 101, 0, 1, 41, 63, 0, - 1, 19, 29, 0, 31, 154, 185, 0, 17, 127, 175, 0, 6, 96, 145, 0, 2, 73, 114, 0, - 1, 51, 82, 0, 1, 28, 45, 0, 23, 163, 200, 0, 10, 131, 185, 0, 2, 93, 148, 0, - 1, 67, 111, 0, 1, 41, 69, 0, 1, 14, 24, 0, 29, 176, 217, 0, 12, 145, 201, 0, - 3, 101, 156, 0, 1, 69, 111, 0, 1, 39, 63, 0, 1, 14, 23, 0, 57, 192, 233, 0, - 25, 154, 215, 0, 6, 109, 167, 0, 3, 78, 118, 0, 1, 48, 69, 0, 1, 21, 29, 0, - 202, 105, 245, 0, 108, 106, 216, 0, 18, 90, 144, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 33, 172, 219, 0, 64, 149, 206, 0, 14, 117, 177, 0, 5, 90, 141, 0, - 2, 61, 95, 0, 1, 37, 57, 0, 33, 179, 220, 0, 11, 140, 198, 0, 1, 89, 148, 0, - 1, 60, 104, 0, 1, 33, 57, 0, 1, 12, 21, 0, 30, 181, 221, 0, 8, 141, 198, 0, - 1, 87, 145, 0, 1, 58, 100, 0, 1, 31, 55, 0, 1, 12, 20, 0, 32, 186, 224, 0, - 7, 142, 198, 0, 1, 86, 143, 0, 1, 58, 100, 0, 1, 31, 55, 0, 1, 12, 22, 0, - 57, 192, 227, 0, 20, 143, 204, 0, 3, 96, 154, 0, 1, 68, 112, 0, 1, 42, 69, 0, - 1, 19, 32, 0, 212, 35, 215, 0, 113, 47, 169, 0, 29, 48, 105, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 74, 129, 203, 0, 106, 120, 203, 0, 49, 107, 178, 0, - 19, 84, 144, 0, 4, 50, 84, 0, 1, 15, 25, 0, 71, 172, 217, 0, 44, 141, 209, 0, - 15, 102, 173, 0, 6, 76, 133, 0, 2, 51, 89, 0, 1, 24, 42, 0, 64, 185, 231, 0, - 31, 148, 216, 0, 8, 103, 175, 0, 3, 74, 131, 0, 1, 46, 81, 0, 1, 18, 30, 0, - 65, 196, 235, 0, 25, 157, 221, 0, 5, 105, 174, 0, 1, 67, 120, 0, 1, 38, 69, 0, - 1, 15, 30, 0, 65, 204, 238, 0, 30, 156, 224, 0, 7, 107, 177, 0, 2, 70, 124, 0, - 1, 42, 73, 0, 1, 18, 34, 0, 225, 86, 251, 0, 144, 104, 235, 0, 42, 99, 181, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 175, 239, 0, 112, 165, 229, 0, - 29, 136, 200, 0, 12, 103, 162, 0, 6, 77, 123, 0, 2, 53, 84, 0, 75, 183, 239, 0, - 30, 155, 221, 0, 3, 106, 171, 0, 1, 74, 128, 0, 1, 44, 76, 0, 1, 17, 28, 0, - 73, 185, 240, 0, 27, 159, 222, 0, 2, 107, 172, 0, 1, 75, 127, 0, 1, 42, 73, 0, - 1, 17, 29, 0, 62, 190, 238, 0, 21, 159, 222, 0, 2, 107, 172, 0, 1, 72, 122, 0, - 1, 40, 71, 0, 1, 18, 32, 0, 61, 199, 240, 0, 27, 161, 226, 0, 4, 113, 180, 0, - 1, 76, 129, 0, 1, 46, 80, 0, 1, 23, 41, 0, 7, 27, 153, 0, 5, 30, 95, 0, - 1, 16, 30, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 50, 75, 127, 0, - 57, 75, 124, 0, 27, 67, 108, 0, 10, 54, 86, 0, 1, 33, 52, 0, 1, 12, 18, 0, - 43, 125, 151, 0, 26, 108, 148, 0, 7, 83, 122, 0, 2, 59, 89, 0, 1, 38, 60, 0, - 1, 17, 27, 0, 23, 144, 163, 0, 13, 112, 154, 0, 2, 75, 117, 0, 1, 50, 81, 0, - 1, 31, 51, 0, 1, 14, 23, 0, 18, 162, 185, 0, 6, 123, 171, 0, 1, 78, 125, 0, - 1, 51, 86, 0, 1, 31, 54, 0, 1, 14, 23, 0, 15, 199, 227, 0, 3, 150, 204, 0, - 1, 91, 146, 0, 1, 55, 95, 0, 1, 30, 53, 0, 1, 11, 20, 0, 19, 55, 240, 0, - 19, 59, 196, 0, 3, 52, 105, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 41, 166, 207, 0, 104, 153, 199, 0, 31, 123, 181, 0, 14, 101, 152, 0, 5, 72, 106, 0, - 1, 36, 52, 0, 35, 176, 211, 0, 12, 131, 190, 0, 2, 88, 144, 0, 1, 60, 101, 0, - 1, 36, 60, 0, 1, 16, 28, 0, 28, 183, 213, 0, 8, 134, 191, 0, 1, 86, 142, 0, - 1, 56, 96, 0, 1, 30, 53, 0, 1, 12, 20, 0, 20, 190, 215, 0, 4, 135, 192, 0, - 1, 84, 139, 0, 1, 53, 91, 0, 1, 28, 49, 0, 1, 11, 20, 0, 13, 196, 216, 0, - 2, 137, 192, 0, 1, 86, 143, 0, 1, 57, 99, 0, 1, 32, 56, 0, 1, 13, 24, 0, - 211, 29, 217, 0, 96, 47, 156, 0, 22, 43, 87, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 78, 120, 193, 0, 111, 116, 186, 0, 46, 102, 164, 0, 15, 80, 128, 0, - 2, 49, 76, 0, 1, 18, 28, 0, 71, 161, 203, 0, 42, 132, 192, 0, 10, 98, 150, 0, - 3, 69, 109, 0, 1, 44, 70, 0, 1, 18, 29, 0, 57, 186, 211, 0, 30, 140, 196, 0, - 4, 93, 146, 0, 1, 62, 102, 0, 1, 38, 65, 0, 1, 16, 27, 0, 47, 199, 217, 0, - 14, 145, 196, 0, 1, 88, 142, 0, 1, 57, 98, 0, 1, 36, 62, 0, 1, 15, 26, 0, - 26, 219, 229, 0, 5, 155, 207, 0, 1, 94, 151, 0, 1, 60, 104, 0, 1, 36, 62, 0, - 1, 16, 28, 0, 233, 29, 248, 0, 146, 47, 220, 0, 43, 52, 140, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 100, 163, 232, 0, 179, 161, 222, 0, 63, 142, 204, 0, - 37, 113, 174, 0, 26, 89, 137, 0, 18, 68, 97, 0, 85, 181, 230, 0, 32, 146, 209, 0, - 7, 100, 164, 0, 3, 71, 121, 0, 1, 45, 77, 0, 1, 18, 30, 0, 65, 187, 230, 0, - 20, 148, 207, 0, 2, 97, 159, 0, 1, 68, 116, 0, 1, 40, 70, 0, 1, 14, 29, 0, - 40, 194, 227, 0, 8, 147, 204, 0, 1, 94, 155, 0, 1, 65, 112, 0, 1, 39, 66, 0, - 1, 14, 26, 0, 16, 208, 228, 0, 3, 151, 207, 0, 1, 98, 160, 0, 1, 67, 117, 0, - 1, 41, 74, 0, 1, 17, 31, 0, 17, 38, 140, 0, 7, 34, 80, 0, 1, 17, 29, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 37, 75, 128, 0, 41, 76, 128, 0, - 26, 66, 116, 0, 12, 52, 94, 0, 2, 32, 55, 0, 1, 10, 16, 0, 50, 127, 154, 0, - 37, 109, 152, 0, 16, 82, 121, 0, 5, 59, 85, 0, 1, 35, 54, 0, 1, 13, 20, 0, - 40, 142, 167, 0, 17, 110, 157, 0, 2, 71, 112, 0, 1, 44, 72, 0, 1, 27, 45, 0, - 1, 11, 17, 0, 30, 175, 188, 0, 9, 124, 169, 0, 1, 74, 116, 0, 1, 48, 78, 0, - 1, 30, 49, 0, 1, 11, 18, 0, 10, 222, 223, 0, 2, 150, 194, 0, 1, 83, 128, 0, - 1, 48, 79, 0, 1, 27, 45, 0, 1, 11, 17, 0, 36, 41, 235, 0, 29, 36, 193, 0, - 10, 27, 111, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 165, 222, 0, - 177, 162, 215, 0, 110, 135, 195, 0, 57, 113, 168, 0, 23, 83, 120, 0, 10, 49, 61, 0, - 85, 190, 223, 0, 36, 139, 200, 0, 5, 90, 146, 0, 1, 60, 103, 0, 1, 38, 65, 0, - 1, 18, 30, 0, 72, 202, 223, 0, 23, 141, 199, 0, 2, 86, 140, 0, 1, 56, 97, 0, - 1, 36, 61, 0, 1, 16, 27, 0, 55, 218, 225, 0, 13, 145, 200, 0, 1, 86, 141, 0, - 1, 57, 99, 0, 1, 35, 61, 0, 1, 13, 22, 0, 15, 235, 212, 0, 1, 132, 184, 0, - 1, 84, 139, 0, 1, 57, 97, 0, 1, 34, 56, 0, 1, 14, 23, 0, 181, 21, 201, 0, - 61, 37, 123, 0, 10, 38, 71, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 47, 106, 172, 0, 95, 104, 173, 0, 42, 93, 159, 0, 18, 77, 131, 0, 4, 50, 81, 0, - 1, 17, 23, 0, 62, 147, 199, 0, 44, 130, 189, 0, 28, 102, 154, 0, 18, 75, 115, 0, - 2, 44, 65, 0, 1, 12, 19, 0, 55, 153, 210, 0, 24, 130, 194, 0, 3, 93, 146, 0, - 1, 61, 97, 0, 1, 31, 50, 0, 1, 10, 16, 0, 49, 186, 223, 0, 17, 148, 204, 0, - 1, 96, 142, 0, 1, 53, 83, 0, 1, 26, 44, 0, 1, 11, 17, 0, 13, 217, 212, 0, - 2, 136, 180, 0, 1, 78, 124, 0, 1, 50, 83, 0, 1, 29, 49, 0, 1, 14, 23, 0, - 197, 13, 247, 0, 82, 17, 222, 0, 25, 17, 162, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 126, 186, 247, 0, 234, 191, 243, 0, 176, 177, 234, 0, 104, 158, 220, 0, - 66, 128, 186, 0, 55, 90, 137, 0, 111, 197, 242, 0, 46, 158, 219, 0, 9, 104, 171, 0, - 2, 65, 125, 0, 1, 44, 80, 0, 1, 17, 91, 0, 104, 208, 245, 0, 39, 168, 224, 0, - 3, 109, 162, 0, 1, 79, 124, 0, 1, 50, 102, 0, 1, 43, 102, 0, 84, 220, 246, 0, - 31, 177, 231, 0, 2, 115, 180, 0, 1, 79, 134, 0, 1, 55, 77, 0, 1, 60, 79, 0, - 43, 243, 240, 0, 8, 180, 217, 0, 1, 115, 166, 0, 1, 84, 121, 0, 1, 51, 67, 0, - 1, 16, 6, 0, + 195, 29, 183, 84, 49, 136, 8, 42, 71, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 31, 107, 169, 35, 99, 159, 17, 82, 140, 8, 66, 114, 2, 44, 76, 1, 19, 32, + 40, 132, 201, 29, 114, 187, 13, 91, 157, 7, 75, 127, 3, 58, 95, 1, 28, 47, + 69, 142, 221, 42, 122, 201, 15, 91, 159, 6, 67, 121, 1, 42, 77, 1, 17, 31, + 102, 148, 228, 67, 117, 204, 17, 82, 154, 6, 59, 114, 2, 39, 75, 1, 15, 29, + 156, 57, 233, 119, 57, 212, 58, 48, 163, 29, 40, 124, 12, 30, 81, 3, 12, 31, + 191, 107, 226, 124, 117, 204, 25, 99, 155, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 29, 148, 210, 37, 126, 194, 8, 93, 157, 2, 68, 118, 1, 39, 69, 1, 17, 33, + 41, 151, 213, 27, 123, 193, 3, 82, 144, 1, 58, 105, 1, 32, 60, 1, 13, 26, + 59, 159, 220, 23, 126, 198, 4, 88, 151, 1, 66, 114, 1, 38, 71, 1, 18, 34, + 114, 136, 232, 51, 114, 207, 11, 83, 155, 3, 56, 105, 1, 33, 65, 1, 17, 34, + 149, 65, 234, 121, 57, 215, 61, 49, 166, 28, 36, 114, 12, 25, 76, 3, 16, 42, + 214, 49, 220, 132, 63, 188, 42, 65, 137, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 85, 137, 221, 104, 131, 216, 49, 111, 192, 21, 87, 155, 2, 49, 87, 1, 16, 28, + 89, 163, 230, 90, 137, 220, 29, 100, 183, 10, 70, 135, 2, 42, 81, 1, 17, 33, + 108, 167, 237, 55, 133, 222, 15, 97, 179, 4, 72, 135, 1, 45, 85, 1, 19, 38, + 124, 146, 240, 66, 124, 224, 17, 88, 175, 4, 58, 122, 1, 36, 75, 1, 18, 37, + 141, 79, 241, 126, 70, 227, 66, 58, 182, 30, 44, 136, 12, 34, 96, 2, 20, 47, + 229, 99, 249, 143, 111, 235, 46, 109, 192, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 82, 158, 236, 94, 146, 224, 25, 117, 191, 9, 87, 149, 3, 56, 99, 1, 33, 57, + 83, 167, 237, 68, 145, 222, 10, 103, 177, 2, 72, 131, 1, 41, 79, 1, 20, 39, + 99, 167, 239, 47, 141, 224, 10, 104, 178, 2, 73, 133, 1, 44, 85, 1, 22, 47, + 127, 145, 243, 71, 129, 228, 17, 93, 177, 3, 61, 124, 1, 41, 84, 1, 21, 52, + 157, 78, 244, 140, 72, 231, 69, 58, 184, 31, 44, 137, 14, 38, 105, 8, 23, 61, + 125, 34, 187, 52, 41, 133, 6, 31, 56, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 37, 109, 153, 51, 102, 147, 23, 87, 128, 8, 67, 101, 1, 41, 63, 1, 19, 29, + 31, 154, 185, 17, 127, 175, 6, 96, 145, 2, 73, 114, 1, 51, 82, 1, 28, 45, + 23, 163, 200, 10, 131, 185, 2, 93, 148, 1, 67, 111, 1, 41, 69, 1, 14, 24, + 29, 176, 217, 12, 145, 201, 3, 101, 156, 1, 69, 111, 1, 39, 63, 1, 14, 23, + 57, 192, 233, 25, 154, 215, 6, 109, 167, 3, 78, 118, 1, 48, 69, 1, 21, 29, + 202, 105, 245, 108, 106, 216, 18, 90, 144, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 33, 172, 219, 64, 149, 206, 14, 117, 177, 5, 90, 141, 2, 61, 95, 1, 37, 57, + 33, 179, 220, 11, 140, 198, 1, 89, 148, 1, 60, 104, 1, 33, 57, 1, 12, 21, + 30, 181, 221, 8, 141, 198, 1, 87, 145, 1, 58, 100, 1, 31, 55, 1, 12, 20, + 32, 186, 224, 7, 142, 198, 1, 86, 143, 1, 58, 100, 1, 31, 55, 1, 12, 22, + 57, 192, 227, 20, 143, 204, 3, 96, 154, 1, 68, 112, 1, 42, 69, 1, 19, 32, + 212, 35, 215, 113, 47, 169, 29, 48, 105, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 74, 129, 203, 106, 120, 203, 49, 107, 178, 19, 84, 144, 4, 50, 84, 1, 15, 25, + 71, 172, 217, 44, 141, 209, 15, 102, 173, 6, 76, 133, 2, 51, 89, 1, 24, 42, + 64, 185, 231, 31, 148, 216, 8, 103, 175, 3, 74, 131, 1, 46, 81, 1, 18, 30, + 65, 196, 235, 25, 157, 221, 5, 105, 174, 1, 67, 120, 1, 38, 69, 1, 15, 30, + 65, 204, 238, 30, 156, 224, 7, 107, 177, 2, 70, 124, 1, 42, 73, 1, 18, 34, + 225, 86, 251, 144, 104, 235, 42, 99, 181, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 85, 175, 239, 112, 165, 229, 29, 136, 200, 12, 103, 162, 6, 77, 123, 2, 53, 84, + 75, 183, 239, 30, 155, 221, 3, 106, 171, 1, 74, 128, 1, 44, 76, 1, 17, 28, + 73, 185, 240, 27, 159, 222, 2, 107, 172, 1, 75, 127, 1, 42, 73, 1, 17, 29, + 62, 190, 238, 21, 159, 222, 2, 107, 172, 1, 72, 122, 1, 40, 71, 1, 18, 32, + 61, 199, 240, 27, 161, 226, 4, 113, 180, 1, 76, 129, 1, 46, 80, 1, 23, 41, + 7, 27, 153, 5, 30, 95, 1, 16, 30, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 50, 75, 127, 57, 75, 124, 27, 67, 108, 10, 54, 86, 1, 33, 52, 1, 12, 18, + 43, 125, 151, 26, 108, 148, 7, 83, 122, 2, 59, 89, 1, 38, 60, 1, 17, 27, + 23, 144, 163, 13, 112, 154, 2, 75, 117, 1, 50, 81, 1, 31, 51, 1, 14, 23, + 18, 162, 185, 6, 123, 171, 1, 78, 125, 1, 51, 86, 1, 31, 54, 1, 14, 23, + 15, 199, 227, 3, 150, 204, 1, 91, 146, 1, 55, 95, 1, 30, 53, 1, 11, 20, + 19, 55, 240, 19, 59, 196, 3, 52, 105, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 41, 166, 207, 104, 153, 199, 31, 123, 181, 14, 101, 152, 5, 72, 106, 1, 36, 52, + 35, 176, 211, 12, 131, 190, 2, 88, 144, 1, 60, 101, 1, 36, 60, 1, 16, 28, + 28, 183, 213, 8, 134, 191, 1, 86, 142, 1, 56, 96, 1, 30, 53, 1, 12, 20, + 20, 190, 215, 4, 135, 192, 1, 84, 139, 1, 53, 91, 1, 28, 49, 1, 11, 20, + 13, 196, 216, 2, 137, 192, 1, 86, 143, 1, 57, 99, 1, 32, 56, 1, 13, 24, + 211, 29, 217, 96, 47, 156, 22, 43, 87, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 78, 120, 193, 111, 116, 186, 46, 102, 164, 15, 80, 128, 2, 49, 76, 1, 18, 28, + 71, 161, 203, 42, 132, 192, 10, 98, 150, 3, 69, 109, 1, 44, 70, 1, 18, 29, + 57, 186, 211, 30, 140, 196, 4, 93, 146, 1, 62, 102, 1, 38, 65, 1, 16, 27, + 47, 199, 217, 14, 145, 196, 1, 88, 142, 1, 57, 98, 1, 36, 62, 1, 15, 26, + 26, 219, 229, 5, 155, 207, 1, 94, 151, 1, 60, 104, 1, 36, 62, 1, 16, 28, + 233, 29, 248, 146, 47, 220, 43, 52, 140, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 100, 163, 232, 179, 161, 222, 63, 142, 204, 37, 113, 174, 26, 89, 137, 18, 68, 97, + 85, 181, 230, 32, 146, 209, 7, 100, 164, 3, 71, 121, 1, 45, 77, 1, 18, 30, + 65, 187, 230, 20, 148, 207, 2, 97, 159, 1, 68, 116, 1, 40, 70, 1, 14, 29, + 40, 194, 227, 8, 147, 204, 1, 94, 155, 1, 65, 112, 1, 39, 66, 1, 14, 26, + 16, 208, 228, 3, 151, 207, 1, 98, 160, 1, 67, 117, 1, 41, 74, 1, 17, 31, + 17, 38, 140, 7, 34, 80, 1, 17, 29, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 37, 75, 128, 41, 76, 128, 26, 66, 116, 12, 52, 94, 2, 32, 55, 1, 10, 16, + 50, 127, 154, 37, 109, 152, 16, 82, 121, 5, 59, 85, 1, 35, 54, 1, 13, 20, + 40, 142, 167, 17, 110, 157, 2, 71, 112, 1, 44, 72, 1, 27, 45, 1, 11, 17, + 30, 175, 188, 9, 124, 169, 1, 74, 116, 1, 48, 78, 1, 30, 49, 1, 11, 18, + 10, 222, 223, 2, 150, 194, 1, 83, 128, 1, 48, 79, 1, 27, 45, 1, 11, 17, + 36, 41, 235, 29, 36, 193, 10, 27, 111, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 85, 165, 222, 177, 162, 215, 110, 135, 195, 57, 113, 168, 23, 83, 120, 10, 49, 61, + 85, 190, 223, 36, 139, 200, 5, 90, 146, 1, 60, 103, 1, 38, 65, 1, 18, 30, + 72, 202, 223, 23, 141, 199, 2, 86, 140, 1, 56, 97, 1, 36, 61, 1, 16, 27, + 55, 218, 225, 13, 145, 200, 1, 86, 141, 1, 57, 99, 1, 35, 61, 1, 13, 22, + 15, 235, 212, 1, 132, 184, 1, 84, 139, 1, 57, 97, 1, 34, 56, 1, 14, 23, + 181, 21, 201, 61, 37, 123, 10, 38, 71, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 47, 106, 172, 95, 104, 173, 42, 93, 159, 18, 77, 131, 4, 50, 81, 1, 17, 23, + 62, 147, 199, 44, 130, 189, 28, 102, 154, 18, 75, 115, 2, 44, 65, 1, 12, 19, + 55, 153, 210, 24, 130, 194, 3, 93, 146, 1, 61, 97, 1, 31, 50, 1, 10, 16, + 49, 186, 223, 17, 148, 204, 1, 96, 142, 1, 53, 83, 1, 26, 44, 1, 11, 17, + 13, 217, 212, 2, 136, 180, 1, 78, 124, 1, 50, 83, 1, 29, 49, 1, 14, 23, + 197, 13, 247, 82, 17, 222, 25, 17, 162, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 126, 186, 247, 234, 191, 243, 176, 177, 234, 104, 158, 220, 66, 128, 186, 55, 90, 137, + 111, 197, 242, 46, 158, 219, 9, 104, 171, 2, 65, 125, 1, 44, 80, 1, 17, 91, + 104, 208, 245, 39, 168, 224, 3, 109, 162, 1, 79, 124, 1, 50, 102, 1, 43, 102, + 84, 220, 246, 31, 177, 231, 2, 115, 180, 1, 79, 134, 1, 55, 77, 1, 60, 79, + 43, 243, 240, 8, 180, 217, 1, 115, 166, 1, 84, 121, 1, 51, 67, 1, 16, 6, }, .switchable_interp_prob{235, 162, 36, 255, 34, 3, 149, 144}, .inter_mode_prob{ @@ -322,39 +302,23 @@ bool VP9::WriteLessThan(VpxRangeEncoder& writer, s32 value, s32 test) { } void VP9::WriteCoefProbabilityUpdate(VpxRangeEncoder& writer, s32 tx_mode, - const std::array<u8, 2304>& new_prob, - const std::array<u8, 2304>& old_prob) { - // Note: There's 1 byte added on each packet for alignment, - // this byte is ignored when doing updates. - constexpr s32 block_bytes = 2 * 2 * 6 * 6 * 4; - - const auto needs_update = [&](s32 base_index) -> bool { - s32 index = base_index; - for (s32 i = 0; i < 2; i++) { - for (s32 j = 0; j < 2; j++) { - for (s32 k = 0; k < 6; k++) { - for (s32 l = 0; l < 6; l++) { - if (new_prob[index + 0] != old_prob[index + 0] || - new_prob[index + 1] != old_prob[index + 1] || - new_prob[index + 2] != old_prob[index + 2]) { - return true; - } - - index += 4; - } - } - } - } - return false; + const std::array<u8, 1728>& new_prob, + const std::array<u8, 1728>& old_prob) { + constexpr u32 block_bytes = 2 * 2 * 6 * 6 * 3; + + const auto needs_update = [&](u32 base_index) { + return !std::equal(new_prob.begin() + base_index, + new_prob.begin() + base_index + block_bytes, + old_prob.begin() + base_index); }; - for (s32 block_index = 0; block_index < 4; block_index++) { - const s32 base_index = block_index * block_bytes; + for (u32 block_index = 0; block_index < 4; block_index++) { + const u32 base_index = block_index * block_bytes; const bool update = needs_update(base_index); writer.Write(update); if (update) { - s32 index = base_index; + u32 index = base_index; for (s32 i = 0; i < 2; i++) { for (s32 j = 0; j < 2; j++) { for (s32 k = 0; k < 6; k++) { @@ -367,14 +331,13 @@ void VP9::WriteCoefProbabilityUpdate(VpxRangeEncoder& writer, s32 tx_mode, WriteProbabilityUpdate(writer, new_prob[index + 2], old_prob[index + 2]); } - index += 4; + index += 3; } } } } } - - if (block_index == tx_mode) { + if (block_index == static_cast<u32>(tx_mode)) { break; } } @@ -392,7 +355,7 @@ void VP9::WriteMvProbabilityUpdate(VpxRangeEncoder& writer, u8 new_prob, u8 old_ Vp9PictureInfo VP9::GetVp9PictureInfo(const NvdecCommon::NvdecRegisters& state) { PictureInfo picture_info{}; gpu.MemoryManager().ReadBlock(state.picture_info_offset, &picture_info, sizeof(PictureInfo)); - Vp9PictureInfo vp9_info = picture_info.Convert(); + Vp9PictureInfo vp9_info = std::move(picture_info.Convert()); InsertEntropy(state.vp9_entropy_probs_offset, vp9_info.entropy); @@ -414,8 +377,7 @@ Vp9FrameContainer VP9::GetCurrentFrame(const NvdecCommon::NvdecRegisters& state) Vp9FrameContainer frame{}; { gpu.SyncGuestHost(); - frame.info = GetVp9PictureInfo(state); - + frame.info = std::move(GetVp9PictureInfo(state)); frame.bit_stream.resize(frame.info.bitstream_size); gpu.MemoryManager().ReadBlock(state.frame_bitstream_offset, frame.bit_stream.data(), frame.info.bitstream_size); @@ -423,37 +385,37 @@ Vp9FrameContainer VP9::GetCurrentFrame(const NvdecCommon::NvdecRegisters& state) // Buffer two frames, saving the last show frame info if (!next_next_frame.bit_stream.empty()) { Vp9FrameContainer temp{ - .info = frame.info, - .bit_stream = frame.bit_stream, + .info = std::move(frame.info), + .bit_stream = std::move(frame.bit_stream), }; next_next_frame.info.show_frame = frame.info.last_frame_shown; - frame.info = next_next_frame.info; - frame.bit_stream = next_next_frame.bit_stream; + frame.info = std::move(next_next_frame.info); + frame.bit_stream = std::move(next_next_frame.bit_stream); next_next_frame = std::move(temp); if (!next_frame.bit_stream.empty()) { Vp9FrameContainer temp2{ - .info = frame.info, - .bit_stream = frame.bit_stream, + .info = std::move(frame.info), + .bit_stream = std::move(frame.bit_stream), }; next_frame.info.show_frame = frame.info.last_frame_shown; - frame.info = next_frame.info; - frame.bit_stream = next_frame.bit_stream; + frame.info = std::move(next_frame.info); + frame.bit_stream = std::move(next_frame.bit_stream); next_frame = std::move(temp2); } else { - next_frame.info = frame.info; - next_frame.bit_stream = frame.bit_stream; + next_frame.info = std::move(frame.info); + next_frame.bit_stream = std::move(frame.bit_stream); } } else { - next_next_frame.info = frame.info; - next_next_frame.bit_stream = frame.bit_stream; + next_next_frame.info = std::move(frame.info); + next_next_frame.bit_stream = std::move(frame.bit_stream); } return frame; } std::vector<u8> VP9::ComposeCompressedHeader() { VpxRangeEncoder writer{}; - + const bool update_probs = current_frame_info.show_frame && !current_frame_info.is_key_frame; if (!current_frame_info.lossless) { if (static_cast<u32>(current_frame_info.transform_mode) >= 3) { writer.Write(3, 2); @@ -471,7 +433,7 @@ std::vector<u8> VP9::ComposeCompressedHeader() { prev_frame_probs.tx_16x16_prob); WriteProbabilityUpdate(writer, current_frame_info.entropy.tx_32x32_prob, prev_frame_probs.tx_32x32_prob); - if (current_frame_info.show_frame && !current_frame_info.is_key_frame) { + if (update_probs) { prev_frame_probs.tx_8x8_prob = current_frame_info.entropy.tx_8x8_prob; prev_frame_probs.tx_16x16_prob = current_frame_info.entropy.tx_16x16_prob; prev_frame_probs.tx_32x32_prob = current_frame_info.entropy.tx_32x32_prob; @@ -484,7 +446,7 @@ std::vector<u8> VP9::ComposeCompressedHeader() { WriteProbabilityUpdate(writer, current_frame_info.entropy.skip_probs, prev_frame_probs.skip_probs); - if (current_frame_info.show_frame && !current_frame_info.is_key_frame) { + if (update_probs) { prev_frame_probs.coef_probs = current_frame_info.entropy.coef_probs; prev_frame_probs.skip_probs = current_frame_info.entropy.skip_probs; } @@ -493,15 +455,12 @@ std::vector<u8> VP9::ComposeCompressedHeader() { // read_inter_probs() in the spec WriteProbabilityUpdateAligned4(writer, current_frame_info.entropy.inter_mode_prob, prev_frame_probs.inter_mode_prob); - if (current_frame_info.show_frame && !current_frame_info.is_key_frame) { - prev_frame_probs.inter_mode_prob = current_frame_info.entropy.inter_mode_prob; - } if (current_frame_info.interp_filter == 4) { // read_interp_filter_probs() in the spec WriteProbabilityUpdate(writer, current_frame_info.entropy.switchable_interp_prob, prev_frame_probs.switchable_interp_prob); - if (current_frame_info.show_frame && !current_frame_info.is_key_frame) { + if (update_probs) { prev_frame_probs.switchable_interp_prob = current_frame_info.entropy.switchable_interp_prob; } @@ -510,9 +469,7 @@ std::vector<u8> VP9::ComposeCompressedHeader() { // read_is_inter_probs() in the spec WriteProbabilityUpdate(writer, current_frame_info.entropy.intra_inter_prob, prev_frame_probs.intra_inter_prob); - if (current_frame_info.show_frame && !current_frame_info.is_key_frame) { - prev_frame_probs.intra_inter_prob = current_frame_info.entropy.intra_inter_prob; - } + // frame_reference_mode() in the spec if ((current_frame_info.ref_frame_sign_bias[1] & 1) != (current_frame_info.ref_frame_sign_bias[2] & 1) || @@ -530,7 +487,7 @@ std::vector<u8> VP9::ComposeCompressedHeader() { if (current_frame_info.reference_mode == 2) { WriteProbabilityUpdate(writer, current_frame_info.entropy.comp_inter_prob, prev_frame_probs.comp_inter_prob); - if (current_frame_info.show_frame && !current_frame_info.is_key_frame) { + if (update_probs) { prev_frame_probs.comp_inter_prob = current_frame_info.entropy.comp_inter_prob; } } @@ -538,7 +495,7 @@ std::vector<u8> VP9::ComposeCompressedHeader() { if (current_frame_info.reference_mode != 1) { WriteProbabilityUpdate(writer, current_frame_info.entropy.single_ref_prob, prev_frame_probs.single_ref_prob); - if (current_frame_info.show_frame && !current_frame_info.is_key_frame) { + if (update_probs) { prev_frame_probs.single_ref_prob = current_frame_info.entropy.single_ref_prob; } } @@ -546,7 +503,7 @@ std::vector<u8> VP9::ComposeCompressedHeader() { if (current_frame_info.reference_mode != 0) { WriteProbabilityUpdate(writer, current_frame_info.entropy.comp_ref_prob, prev_frame_probs.comp_ref_prob); - if (current_frame_info.show_frame && !current_frame_info.is_key_frame) { + if (update_probs) { prev_frame_probs.comp_ref_prob = current_frame_info.entropy.comp_ref_prob; } } @@ -557,42 +514,37 @@ std::vector<u8> VP9::ComposeCompressedHeader() { WriteProbabilityUpdate(writer, current_frame_info.entropy.y_mode_prob[index], prev_frame_probs.y_mode_prob[index]); } - if (current_frame_info.show_frame && !current_frame_info.is_key_frame) { - prev_frame_probs.y_mode_prob = current_frame_info.entropy.y_mode_prob; - } + // read_partition_probs WriteProbabilityUpdateAligned4(writer, current_frame_info.entropy.partition_prob, prev_frame_probs.partition_prob); - if (current_frame_info.show_frame && !current_frame_info.is_key_frame) { - prev_frame_probs.partition_prob = current_frame_info.entropy.partition_prob; - } // mv_probs for (s32 i = 0; i < 3; i++) { WriteMvProbabilityUpdate(writer, current_frame_info.entropy.joints[i], prev_frame_probs.joints[i]); } - if (current_frame_info.show_frame && !current_frame_info.is_key_frame) { + if (update_probs) { + prev_frame_probs.inter_mode_prob = current_frame_info.entropy.inter_mode_prob; + prev_frame_probs.intra_inter_prob = current_frame_info.entropy.intra_inter_prob; + prev_frame_probs.y_mode_prob = current_frame_info.entropy.y_mode_prob; + prev_frame_probs.partition_prob = current_frame_info.entropy.partition_prob; prev_frame_probs.joints = current_frame_info.entropy.joints; } for (s32 i = 0; i < 2; i++) { WriteMvProbabilityUpdate(writer, current_frame_info.entropy.sign[i], prev_frame_probs.sign[i]); - for (s32 j = 0; j < 10; j++) { const int index = i * 10 + j; - WriteMvProbabilityUpdate(writer, current_frame_info.entropy.classes[index], prev_frame_probs.classes[index]); } - WriteMvProbabilityUpdate(writer, current_frame_info.entropy.class_0[i], prev_frame_probs.class_0[i]); for (s32 j = 0; j < 10; j++) { const int index = i * 10 + j; - WriteMvProbabilityUpdate(writer, current_frame_info.entropy.prob_bits[index], prev_frame_probs.prob_bits[index]); } @@ -602,7 +554,6 @@ std::vector<u8> VP9::ComposeCompressedHeader() { for (s32 j = 0; j < 2; j++) { for (s32 k = 0; k < 3; k++) { const int index = i * 2 * 3 + j * 3 + k; - WriteMvProbabilityUpdate(writer, current_frame_info.entropy.class_0_fr[index], prev_frame_probs.class_0_fr[index]); } @@ -610,7 +561,6 @@ std::vector<u8> VP9::ComposeCompressedHeader() { for (s32 j = 0; j < 3; j++) { const int index = i * 3 + j; - WriteMvProbabilityUpdate(writer, current_frame_info.entropy.fr[index], prev_frame_probs.fr[index]); } @@ -626,7 +576,7 @@ std::vector<u8> VP9::ComposeCompressedHeader() { } // save previous probs - if (current_frame_info.show_frame && !current_frame_info.is_key_frame) { + if (update_probs) { prev_frame_probs.sign = current_frame_info.entropy.sign; prev_frame_probs.classes = current_frame_info.entropy.classes; prev_frame_probs.class_0 = current_frame_info.entropy.class_0; @@ -637,7 +587,6 @@ std::vector<u8> VP9::ComposeCompressedHeader() { prev_frame_probs.high_precision = current_frame_info.entropy.high_precision; } } - writer.End(); return writer.GetBuffer(); } @@ -854,11 +803,11 @@ VpxBitStreamWriter VP9::ComposeUncompressedHeader() { return uncomp_writer; } -const std::vector<u8>& VP9::ComposeFrameHeader(NvdecCommon::NvdecRegisters& state) { +const std::vector<u8>& VP9::ComposeFrameHeader(const NvdecCommon::NvdecRegisters& state) { std::vector<u8> bitstream; { - Vp9FrameContainer curr_frame = GetCurrentFrame(state); - current_frame_info = curr_frame.info; + Vp9FrameContainer curr_frame = std::move(GetCurrentFrame(state)); + current_frame_info = std::move(curr_frame.info); bitstream = std::move(curr_frame.bit_stream); } 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: /// Composes the VP9 frame from the GPU state information. Based on the official VP9 spec /// documentation - [[nodiscard]] const std::vector<u8>& ComposeFrameHeader(NvdecCommon::NvdecRegisters& state); + [[nodiscard]] const std::vector<u8>& ComposeFrameHeader( + const NvdecCommon::NvdecRegisters& state); /// Returns true if the most recent frame was a hidden frame. [[nodiscard]] bool WasFrameHidden() const { @@ -147,8 +148,8 @@ private: /// Writes probability updates for the Coef probabilities void WriteCoefProbabilityUpdate(VpxRangeEncoder& writer, s32 tx_mode, - const std::array<u8, 2304>& new_prob, - const std::array<u8, 2304>& old_prob); + const std::array<u8, 1728>& new_prob, + const std::array<u8, 1728>& old_prob); /// Write probabilities for 4-byte aligned structures 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 { IntraOnly = 1 << 5, }; -enum class MvJointType { - MvJointZero = 0, /* Zero vector */ - MvJointHnzvz = 1, /* Vert zero, hor nonzero */ - MvJointHzvnz = 2, /* Hor zero, vert nonzero */ - MvJointHnzvnz = 3, /* Both components nonzero */ -}; -enum class MvClassType { - MvClass0 = 0, /* (0, 2] integer pel */ - MvClass1 = 1, /* (2, 4] integer pel */ - MvClass2 = 2, /* (4, 8] integer pel */ - MvClass3 = 3, /* (8, 16] integer pel */ - MvClass4 = 4, /* (16, 32] integer pel */ - MvClass5 = 5, /* (32, 64] integer pel */ - MvClass6 = 6, /* (64, 128] integer pel */ - MvClass7 = 7, /* (128, 256] integer pel */ - MvClass8 = 8, /* (256, 512] integer pel */ - MvClass9 = 9, /* (512, 1024] integer pel */ - MvClass10 = 10, /* (1024,2048] integer pel */ -}; - -enum class BlockSize { - Block4x4 = 0, - Block4x8 = 1, - Block8x4 = 2, - Block8x8 = 3, - Block8x16 = 4, - Block16x8 = 5, - Block16x16 = 6, - Block16x32 = 7, - Block32x16 = 8, - Block32x32 = 9, - Block32x64 = 10, - Block64x32 = 11, - Block64x64 = 12, - BlockSizes = 13, - BlockInvalid = BlockSizes -}; - -enum class PredictionMode { - DcPred = 0, // Average of above and left pixels - VPred = 1, // Vertical - HPred = 2, // Horizontal - D45Pred = 3, // Directional 45 deg = round(arctan(1 / 1) * 180 / pi) - D135Pred = 4, // Directional 135 deg = 180 - 45 - D117Pred = 5, // Directional 117 deg = 180 - 63 - D153Pred = 6, // Directional 153 deg = 180 - 27 - D207Pred = 7, // Directional 207 deg = 180 + 27 - D63Pred = 8, // Directional 63 deg = round(arctan(2 / 1) * 180 / pi) - TmPred = 9, // True-motion - NearestMv = 10, - NearMv = 11, - ZeroMv = 12, - NewMv = 13, - MbModeCount = 14 -}; - enum class TxSize { Tx4x4 = 0, // 4x4 transform Tx8x8 = 1, // 8x8 transform @@ -104,13 +48,6 @@ enum class TxMode { TxModes = 5 }; -enum class reference_mode { - SingleReference = 0, - CompoundReference = 1, - ReferenceModeSelect = 2, - ReferenceModes = 3 -}; - struct Segmentation { u8 enabled{}; u8 update_map{}; @@ -131,7 +68,7 @@ static_assert(sizeof(LoopFilter) == 0x7, "LoopFilter is an invalid size"); struct Vp9EntropyProbs { std::array<u8, 36> y_mode_prob{}; std::array<u8, 64> partition_prob{}; - std::array<u8, 2304> coef_probs{}; + std::array<u8, 1728> coef_probs{}; std::array<u8, 8> switchable_interp_prob{}; std::array<u8, 28> inter_mode_prob{}; std::array<u8, 4> intra_inter_prob{}; @@ -152,7 +89,7 @@ struct Vp9EntropyProbs { std::array<u8, 2> class_0_hp{}; std::array<u8, 2> high_precision{}; }; -static_assert(sizeof(Vp9EntropyProbs) == 0x9F4, "Vp9EntropyProbs is an invalid size"); +static_assert(sizeof(Vp9EntropyProbs) == 0x7B4, "Vp9EntropyProbs is an invalid size"); struct Vp9PictureInfo { bool is_key_frame{}; @@ -278,72 +215,71 @@ static_assert(sizeof(PictureInfo) == 0x100, "PictureInfo is an invalid size"); struct EntropyProbs { INSERT_PADDING_BYTES(1024); - std::array<std::array<u8, 4>, 7> inter_mode_prob{}; + std::array<u8, 28> inter_mode_prob{}; std::array<u8, 4> intra_inter_prob{}; INSERT_PADDING_BYTES(80); - std::array<std::array<u8, 1>, 2> tx_8x8_prob{}; - std::array<std::array<u8, 2>, 2> tx_16x16_prob{}; - std::array<std::array<u8, 3>, 2> tx_32x32_prob{}; + std::array<u8, 2> tx_8x8_prob{}; + std::array<u8, 4> tx_16x16_prob{}; + std::array<u8, 6> tx_32x32_prob{}; std::array<u8, 4> y_mode_prob_e8{}; std::array<std::array<u8, 8>, 4> y_mode_prob_e0e7{}; INSERT_PADDING_BYTES(64); - std::array<std::array<u8, 4>, 16> partition_prob{}; + std::array<u8, 64> partition_prob{}; INSERT_PADDING_BYTES(10); - std::array<std::array<u8, 2>, 4> switchable_interp_prob{}; + std::array<u8, 8> switchable_interp_prob{}; std::array<u8, 5> comp_inter_prob{}; - std::array<u8, 4> skip_probs{}; + std::array<u8, 3> skip_probs{}; + INSERT_PADDING_BYTES(1); std::array<u8, 3> joints{}; std::array<u8, 2> sign{}; - std::array<std::array<u8, 1>, 2> class_0{}; - std::array<std::array<u8, 3>, 2> fr{}; + std::array<u8, 2> class_0{}; + std::array<u8, 6> fr{}; std::array<u8, 2> class_0_hp{}; std::array<u8, 2> high_precision{}; - std::array<std::array<u8, 10>, 2> classes{}; - std::array<std::array<std::array<u8, 3>, 2>, 2> class_0_fr{}; - std::array<std::array<u8, 10>, 2> pred_bits{}; - std::array<std::array<u8, 2>, 5> single_ref_prob{}; + std::array<u8, 20> classes{}; + std::array<u8, 12> class_0_fr{}; + std::array<u8, 20> pred_bits{}; + std::array<u8, 10> single_ref_prob{}; std::array<u8, 5> comp_ref_prob{}; INSERT_PADDING_BYTES(17); - std::array<std::array<std::array<std::array<std::array<std::array<u8, 4>, 6>, 6>, 2>, 2>, 4> - coef_probs{}; + std::array<u8, 2304> coef_probs{}; void Convert(Vp9EntropyProbs& fc) { - std::memcpy(fc.inter_mode_prob.data(), inter_mode_prob.data(), fc.inter_mode_prob.size()); - - std::memcpy(fc.intra_inter_prob.data(), intra_inter_prob.data(), - fc.intra_inter_prob.size()); - - std::memcpy(fc.tx_8x8_prob.data(), tx_8x8_prob.data(), fc.tx_8x8_prob.size()); - std::memcpy(fc.tx_16x16_prob.data(), tx_16x16_prob.data(), fc.tx_16x16_prob.size()); - std::memcpy(fc.tx_32x32_prob.data(), tx_32x32_prob.data(), fc.tx_32x32_prob.size()); - - for (s32 i = 0; i < 4; i++) { - for (s32 j = 0; j < 9; j++) { + fc.inter_mode_prob = inter_mode_prob; + fc.intra_inter_prob = intra_inter_prob; + fc.tx_8x8_prob = tx_8x8_prob; + fc.tx_16x16_prob = tx_16x16_prob; + fc.tx_32x32_prob = tx_32x32_prob; + + for (std::size_t i = 0; i < 4; i++) { + for (std::size_t j = 0; j < 9; j++) { fc.y_mode_prob[j + 9 * i] = j < 8 ? y_mode_prob_e0e7[i][j] : y_mode_prob_e8[i]; } } - std::memcpy(fc.partition_prob.data(), partition_prob.data(), fc.partition_prob.size()); - - std::memcpy(fc.switchable_interp_prob.data(), switchable_interp_prob.data(), - fc.switchable_interp_prob.size()); - std::memcpy(fc.comp_inter_prob.data(), comp_inter_prob.data(), fc.comp_inter_prob.size()); - std::memcpy(fc.skip_probs.data(), skip_probs.data(), fc.skip_probs.size()); - - std::memcpy(fc.joints.data(), joints.data(), fc.joints.size()); - - std::memcpy(fc.sign.data(), sign.data(), fc.sign.size()); - std::memcpy(fc.class_0.data(), class_0.data(), fc.class_0.size()); - std::memcpy(fc.fr.data(), fr.data(), fc.fr.size()); - std::memcpy(fc.class_0_hp.data(), class_0_hp.data(), fc.class_0_hp.size()); - std::memcpy(fc.high_precision.data(), high_precision.data(), fc.high_precision.size()); - std::memcpy(fc.classes.data(), classes.data(), fc.classes.size()); - std::memcpy(fc.class_0_fr.data(), class_0_fr.data(), fc.class_0_fr.size()); - std::memcpy(fc.prob_bits.data(), pred_bits.data(), fc.prob_bits.size()); - std::memcpy(fc.single_ref_prob.data(), single_ref_prob.data(), fc.single_ref_prob.size()); - std::memcpy(fc.comp_ref_prob.data(), comp_ref_prob.data(), fc.comp_ref_prob.size()); - - std::memcpy(fc.coef_probs.data(), coef_probs.data(), fc.coef_probs.size()); + fc.partition_prob = partition_prob; + fc.switchable_interp_prob = switchable_interp_prob; + fc.comp_inter_prob = comp_inter_prob; + fc.skip_probs = skip_probs; + fc.joints = joints; + fc.sign = sign; + fc.class_0 = class_0; + fc.fr = fr; + fc.class_0_hp = class_0_hp; + fc.high_precision = high_precision; + fc.classes = classes; + fc.class_0_fr = class_0_fr; + fc.prob_bits = pred_bits; + fc.single_ref_prob = single_ref_prob; + fc.comp_ref_prob = comp_ref_prob; + + // Skip the 4th element as it goes unused + for (std::size_t i = 0; i < coef_probs.size(); i += 4) { + const std::size_t j = i - i / 4; + fc.coef_probs[j] = coef_probs[i]; + fc.coef_probs[j + 1] = coef_probs[i + 1]; + fc.coef_probs[j + 2] = coef_probs[i + 2]; + } } }; static_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) { } } -AVFrame* Nvdec::GetFrame() { - return codec->GetCurrentFrame(); -} - -const AVFrame* Nvdec::GetFrame() const { +AVFramePtr Nvdec::GetFrame() { return codec->GetCurrentFrame(); } 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: void ProcessMethod(Method method, const std::vector<u32>& arguments); /// Return most recently decoded frame - [[nodiscard]] AVFrame* GetFrame(); - [[nodiscard]] const AVFrame* GetFrame() const; + [[nodiscard]] AVFramePtr GetFrame(); private: /// 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() { return; } const VicConfig config{gpu.MemoryManager().Read<u64>(config_struct_address + 0x20)}; + const AVFramePtr frame_ptr = std::move(nvdec_processor->GetFrame()); + const auto* frame = frame_ptr.get(); + if (!frame || frame->width == 0 || frame->height == 0) { + return; + } const VideoPixelFormat pixel_format = static_cast<VideoPixelFormat>(config.pixel_format.Value()); switch (pixel_format) { case VideoPixelFormat::BGRA8: case VideoPixelFormat::RGBA8: { LOG_TRACE(Service_NVDRV, "Writing RGB Frame"); - const auto* frame = nvdec_processor->GetFrame(); - if (!frame || frame->width == 0 || frame->height == 0) { - return; - } if (scaler_ctx == nullptr || frame->width != scaler_width || frame->height != scaler_height) { const AVPixelFormat target_format = @@ -121,12 +122,6 @@ void Vic::Execute() { case VideoPixelFormat::Yuv420: { LOG_TRACE(Service_NVDRV, "Writing YUV420 Frame"); - const auto* frame = nvdec_processor->GetFrame(); - - if (!frame || frame->width == 0 || frame->height == 0) { - return; - } - const std::size_t surface_width = config.surface_width_minus1 + 1; const std::size_t surface_height = config.surface_height_minus1 + 1; 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: u32 data_upload; - INSERT_UNION_PADDING_WORDS(0x44); + INSERT_UNION_PADDING_WORDS(0x16); + + u32 force_early_fragment_tests; + + INSERT_UNION_PADDING_WORDS(0x2D); struct { union { @@ -1572,6 +1576,7 @@ ASSERT_REG_POSITION(shadow_ram_control, 0x49); ASSERT_REG_POSITION(upload, 0x60); ASSERT_REG_POSITION(exec_upload, 0x6C); ASSERT_REG_POSITION(data_upload, 0x6D); +ASSERT_REG_POSITION(force_early_fragment_tests, 0x84); ASSERT_REG_POSITION(sync_info, 0xB2); ASSERT_REG_POSITION(tess_mode, 0xC8); ASSERT_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 regs.polygon_offset_fill_enable}; const u32 topology_index = static_cast<u32>(regs.draw.topology.Value()); - raw = 0; + raw1 = 0; primitive_restart_enable.Assign(regs.primitive_restart.enabled != 0 ? 1 : 0); depth_bias_enable.Assign(enabled_lut[POLYGON_OFFSET_ENABLE_LUT[topology_index]] != 0 ? 1 : 0); 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 rasterize_enable.Assign(regs.rasterize_enable != 0 ? 1 : 0); topology.Assign(regs.draw.topology); - alpha_raw = 0; + raw2 = 0; const auto test_func = regs.alpha_test_enabled == 1 ? regs.alpha_test_func : Maxwell::ComparisonOp::Always; alpha_test_func.Assign(PackComparisonOp(test_func)); - alpha_test_ref = Common::BitCast<u32>(regs.alpha_test_ref); + early_z.Assign(regs.force_early_fragment_tests != 0 ? 1 : 0); + alpha_test_ref = Common::BitCast<u32>(regs.alpha_test_ref); point_size = Common::BitCast<u32>(regs.point_size); 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 { }; union { - u32 raw; + u32 raw1; BitField<0, 1, u32> no_extended_dynamic_state; BitField<2, 1, u32> primitive_restart_enable; BitField<3, 1, u32> depth_bias_enable; @@ -187,13 +187,13 @@ struct FixedPipelineState { BitField<23, 1, u32> rasterize_enable; BitField<24, 4, Maxwell::PrimitiveTopology> topology; }; - - u32 alpha_test_ref; ///< Alpha test reference value union { - u32 alpha_raw; + u32 raw2; BitField<0, 3, u32> alpha_test_func; + BitField<3, 1, u32> early_z; }; + u32 alpha_test_ref; u32 point_size; std::array<u32, Maxwell::NumVertexArrays> binding_divisors; 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) { specialization.attribute_types[i] = attribute.Type(); } specialization.ndc_minus_one_to_one = fixed_state.ndc_minus_one_to_one; + specialization.early_fragment_tests = fixed_state.early_z; // Alpha test 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: "supported on this device"); } } - if (ir.UsesLayer() || ir.UsesViewportIndex()) { if (ir.UsesViewportIndex()) { AddCapability(spv::Capability::MultiViewport); @@ -325,11 +324,9 @@ public: AddCapability(spv::Capability::ShaderViewportIndexLayerEXT); } } - if (device.IsFormatlessImageLoadSupported()) { AddCapability(spv::Capability::StorageImageReadWithoutFormat); } - if (device.IsFloat16Supported()) { AddCapability(spv::Capability::Float16); } @@ -377,6 +374,9 @@ public: if (header.ps.omap.depth) { AddExecutionMode(main, spv::ExecutionMode::DepthReplacing); } + if (specialization.early_fragment_tests) { + AddExecutionMode(main, spv::ExecutionMode::EarlyFragmentTests); + } break; case ShaderType::Compute: 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 { std::bitset<Maxwell::NumVertexAttributes> enabled_attributes; std::array<Maxwell::VertexAttribute::Type, Maxwell::NumVertexAttributes> attribute_types{}; bool ndc_minus_one_to_one{}; + bool early_fragment_tests{}; float alpha_test_ref{}; Maxwell::ComparisonOp alpha_test_func{}; }; 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 @@ #include "core/settings.h" #include "input_common/keyboard.h" #include "input_common/main.h" -#include "input_common/motion_emu.h" +#include "input_common/mouse/mouse_input.h" #include "video_core/renderer_base.h" #include "video_core/video_core.h" #include "yuzu/bootmanager.h" @@ -388,23 +388,19 @@ void GRenderWindow::keyReleaseEvent(QKeyEvent* event) { } void GRenderWindow::mousePressEvent(QMouseEvent* event) { - if (!Settings::values.touchscreen.enabled) { - input_subsystem->GetKeyboard()->PressKey(event->button()); - return; - } - // Touch input is handled in TouchBeginEvent if (event->source() == Qt::MouseEventSynthesizedBySystem) { return; } auto pos = event->pos(); + const auto [x, y] = ScaleTouch(pos); + input_subsystem->GetMouse()->PressButton(x, y, event->button()); + if (event->button() == Qt::LeftButton) { - const auto [x, y] = ScaleTouch(pos); this->TouchPressed(x, y); - } else if (event->button() == Qt::RightButton) { - input_subsystem->GetMotionEmu()->BeginTilt(pos.x(), pos.y()); } + QWidget::mousePressEvent(event); } @@ -416,26 +412,22 @@ void GRenderWindow::mouseMoveEvent(QMouseEvent* event) { auto pos = event->pos(); const auto [x, y] = ScaleTouch(pos); + input_subsystem->GetMouse()->MouseMove(x, y); this->TouchMoved(x, y); - input_subsystem->GetMotionEmu()->Tilt(pos.x(), pos.y()); + QWidget::mouseMoveEvent(event); } void GRenderWindow::mouseReleaseEvent(QMouseEvent* event) { - if (!Settings::values.touchscreen.enabled) { - input_subsystem->GetKeyboard()->ReleaseKey(event->button()); - return; - } - // Touch input is handled in TouchEndEvent if (event->source() == Qt::MouseEventSynthesizedBySystem) { return; } + input_subsystem->GetMouse()->ReleaseButton(event->button()); + if (event->button() == Qt::LeftButton) { this->TouchReleased(); - } else if (event->button() == Qt::RightButton) { - input_subsystem->GetMotionEmu()->EndTilt(); } } 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() { ReadSetting(QStringLiteral("touch_from_button_map"), 0).toInt(); Settings::values.touch_from_button_map_index = std::clamp(Settings::values.touch_from_button_map_index, 0, num_touch_from_button_maps - 1); - Settings::values.udp_input_address = - ReadSetting(QStringLiteral("udp_input_address"), - QString::fromUtf8(InputCommon::CemuhookUDP::DEFAULT_ADDR)) + Settings::values.udp_input_servers = + ReadSetting(QStringLiteral("udp_input_servers"), + QString::fromUtf8(InputCommon::CemuhookUDP::DEFAULT_SRV)) .toString() .toStdString(); - Settings::values.udp_input_port = static_cast<u16>( - ReadSetting(QStringLiteral("udp_input_port"), InputCommon::CemuhookUDP::DEFAULT_PORT) - .toInt()); - Settings::values.udp_pad_index = - static_cast<u8>(ReadSetting(QStringLiteral("udp_pad_index"), 0).toUInt()); } void Config::ReadCoreValues() { @@ -1109,12 +1104,9 @@ void Config::SaveMotionTouchValues() { false); WriteSetting(QStringLiteral("touch_from_button_map"), Settings::values.touch_from_button_map_index, 0); - WriteSetting(QStringLiteral("udp_input_address"), - QString::fromStdString(Settings::values.udp_input_address), - QString::fromUtf8(InputCommon::CemuhookUDP::DEFAULT_ADDR)); - WriteSetting(QStringLiteral("udp_input_port"), Settings::values.udp_input_port, - InputCommon::CemuhookUDP::DEFAULT_PORT); - WriteSetting(QStringLiteral("udp_pad_index"), Settings::values.udp_pad_index, 0); + WriteSetting(QStringLiteral("udp_input_servers"), + QString::fromStdString(Settings::values.udp_input_servers), + QString::fromUtf8(InputCommon::CemuhookUDP::DEFAULT_SRV)); qt_config->beginWriteArray(QStringLiteral("touch_from_button_maps")); 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 @@ #include "core/hle/service/sm/sm.h" #include "input_common/gcadapter/gc_poller.h" #include "input_common/main.h" +#include "input_common/mouse/mouse_poller.h" #include "input_common/udp/udp.h" #include "ui_configure_input_player.h" #include "yuzu/configuration/config.h" @@ -152,6 +153,14 @@ QString ButtonToText(const Common::ParamPackage& param) { return {}; } + if (param.Get("engine", "") == "mouse") { + if (param.Has("button")) { + const QString button_str = QString::number(int(param.Get("button", 0))); + return QObject::tr("Click %1").arg(button_str); + } + return GetKeyName(param.Get("code", 0)); + } + return QObject::tr("[unknown]"); } @@ -203,6 +212,26 @@ QString AnalogToText(const Common::ParamPackage& param, const std::string& dir) return {}; } + + if (param.Get("engine", "") == "mouse") { + if (dir == "modifier") { + return QObject::tr("[unused]"); + } + + if (dir == "left" || dir == "right") { + const QString axis_x_str = QString::fromStdString(param.Get("axis_x", "")); + + return QObject::tr("Mouse %1").arg(axis_x_str); + } + + if (dir == "up" || dir == "down") { + const QString axis_y_str = QString::fromStdString(param.Get("axis_y", "")); + + return QObject::tr("Mouse %1").arg(axis_y_str); + } + + return {}; + } return QObject::tr("[unknown]"); } } // namespace @@ -484,6 +513,34 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i return; } } + if (input_subsystem->GetMouseButtons()->IsPolling()) { + params = input_subsystem->GetMouseButtons()->GetNextInput(); + if (params.Has("engine") && IsInputAcceptable(params)) { + SetPollingResult(params, false); + return; + } + } + if (input_subsystem->GetMouseAnalogs()->IsPolling()) { + params = input_subsystem->GetMouseAnalogs()->GetNextInput(); + if (params.Has("engine") && IsInputAcceptable(params)) { + SetPollingResult(params, false); + return; + } + } + if (input_subsystem->GetMouseMotions()->IsPolling()) { + params = input_subsystem->GetMouseMotions()->GetNextInput(); + if (params.Has("engine") && IsInputAcceptable(params)) { + SetPollingResult(params, false); + return; + } + } + if (input_subsystem->GetMouseTouch()->IsPolling()) { + params = input_subsystem->GetMouseTouch()->GetNextInput(); + if (params.Has("engine") && IsInputAcceptable(params)) { + SetPollingResult(params, false); + return; + } + } for (auto& poller : device_pollers) { params = poller->GetNextInput(); if (params.Has("engine") && IsInputAcceptable(params)) { @@ -761,8 +818,9 @@ void ConfigureInputPlayer::UpdateUI() { int slider_value; auto& param = analogs_param[analog_id]; - const bool is_controller = - param.Get("engine", "") == "sdl" || param.Get("engine", "") == "gcpad"; + const bool is_controller = param.Get("engine", "") == "sdl" || + param.Get("engine", "") == "gcpad" || + param.Get("engine", "") == "mouse"; if (is_controller) { if (!param.Has("deadzone")) { @@ -1078,6 +1136,16 @@ void ConfigureInputPlayer::HandleClick( input_subsystem->GetUDPMotions()->BeginConfiguration(); } + if (type == InputCommon::Polling::DeviceType::Button) { + input_subsystem->GetMouseButtons()->BeginConfiguration(); + } else if (type == InputCommon::Polling::DeviceType::AnalogPreferred) { + input_subsystem->GetMouseAnalogs()->BeginConfiguration(); + } else if (type == InputCommon::Polling::DeviceType::Motion) { + input_subsystem->GetMouseMotions()->BeginConfiguration(); + } else { + input_subsystem->GetMouseTouch()->BeginConfiguration(); + } + timeout_timer->start(2500); // Cancel after 2.5 seconds poll_timer->start(50); // Check for new inputs every 50ms } @@ -1097,6 +1165,11 @@ void ConfigureInputPlayer::SetPollingResult(const Common::ParamPackage& params, input_subsystem->GetUDPMotions()->EndConfiguration(); + input_subsystem->GetMouseButtons()->EndConfiguration(); + input_subsystem->GetMouseAnalogs()->EndConfiguration(); + input_subsystem->GetMouseMotions()->EndConfiguration(); + input_subsystem->GetMouseTouch()->EndConfiguration(); + if (!abort) { (*input_setter)(params); } @@ -1128,15 +1201,7 @@ void ConfigureInputPlayer::mousePressEvent(QMouseEvent* event) { return; } - if (want_keyboard_mouse) { - SetPollingResult(Common::ParamPackage{InputCommon::GenerateKeyboardParam(event->button())}, - false); - } else { - // We don't want any mouse buttons, so don't stop polling - return; - } - - SetPollingResult({}, true); + input_subsystem->GetMouse()->PressButton(0, 0, event->button()); } void 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 @@ // Refer to the license.txt file included. #include <array> +#include <sstream> #include <QCloseEvent> #include <QLabel> #include <QMessageBox> #include <QPushButton> +#include <QStringListModel> #include <QVBoxLayout> #include "common/logging/log.h" #include "core/settings.h" @@ -74,11 +76,6 @@ void CalibrationConfigurationDialog::UpdateButtonText(const QString& text) { cancel_button->setText(text); } -constexpr std::array<std::pair<const char*, const char*>, 2> MotionProviders = {{ - {"motion_emu", QT_TRANSLATE_NOOP("ConfigureMotionTouch", "Mouse (Right Click)")}, - {"cemuhookudp", QT_TRANSLATE_NOOP("ConfigureMotionTouch", "CemuhookUDP")}, -}}; - constexpr std::array<std::pair<const char*, const char*>, 2> TouchProviders = {{ {"emu_window", QT_TRANSLATE_NOOP("ConfigureMotionTouch", "Emulator Window")}, {"cemuhookudp", QT_TRANSLATE_NOOP("ConfigureMotionTouch", "CemuhookUDP")}, @@ -89,9 +86,6 @@ ConfigureMotionTouch::ConfigureMotionTouch(QWidget* parent, : QDialog(parent), input_subsystem{input_subsystem_}, ui(std::make_unique<Ui::ConfigureMotionTouch>()) { ui->setupUi(this); - for (const auto& [provider, name] : MotionProviders) { - ui->motion_provider->addItem(tr(name), QString::fromUtf8(provider)); - } for (const auto& [provider, name] : TouchProviders) { ui->touch_provider->addItem(tr(name), QString::fromUtf8(provider)); } @@ -116,8 +110,6 @@ void ConfigureMotionTouch::SetConfiguration() { const std::string motion_engine = motion_param.Get("engine", "motion_emu"); const std::string touch_engine = touch_param.Get("engine", "emu_window"); - ui->motion_provider->setCurrentIndex( - ui->motion_provider->findData(QString::fromStdString(motion_engine))); ui->touch_provider->setCurrentIndex( ui->touch_provider->findData(QString::fromStdString(touch_engine))); ui->touch_from_button_checkbox->setChecked(Settings::values.use_touch_from_button); @@ -133,23 +125,30 @@ void ConfigureMotionTouch::SetConfiguration() { max_x = touch_param.Get("max_x", 1800); max_y = touch_param.Get("max_y", 850); - ui->udp_server->setText(QString::fromStdString(Settings::values.udp_input_address)); - ui->udp_port->setText(QString::number(Settings::values.udp_input_port)); - ui->udp_pad_index->setCurrentIndex(Settings::values.udp_pad_index); + ui->udp_server->setText(QString::fromStdString("127.0.0.1")); + ui->udp_port->setText(QString::number(26760)); + + udp_server_list_model = new QStringListModel(this); + udp_server_list_model->setStringList({}); + ui->udp_server_list->setModel(udp_server_list_model); + + std::stringstream ss(Settings::values.udp_input_servers); + std::string token; + + while (std::getline(ss, token, ',')) { + const int row = udp_server_list_model->rowCount(); + udp_server_list_model->insertRows(row, 1); + const QModelIndex index = udp_server_list_model->index(row); + udp_server_list_model->setData(index, QString::fromStdString(token)); + } } void ConfigureMotionTouch::UpdateUiDisplay() { - const QString motion_engine = ui->motion_provider->currentData().toString(); const QString touch_engine = ui->touch_provider->currentData().toString(); const QString cemuhook_udp = QStringLiteral("cemuhookudp"); - if (motion_engine == QStringLiteral("motion_emu")) { - ui->motion_sensitivity_label->setVisible(true); - ui->motion_sensitivity->setVisible(true); - } else { - ui->motion_sensitivity_label->setVisible(false); - ui->motion_sensitivity->setVisible(false); - } + ui->motion_sensitivity_label->setVisible(true); + ui->motion_sensitivity->setVisible(true); if (touch_engine == cemuhook_udp) { ui->touch_calibration->setVisible(true); @@ -163,19 +162,15 @@ void ConfigureMotionTouch::UpdateUiDisplay() { ui->touch_calibration_label->setVisible(false); } - if (motion_engine == cemuhook_udp || touch_engine == cemuhook_udp) { - ui->udp_config_group_box->setVisible(true); - } else { - ui->udp_config_group_box->setVisible(false); - } + ui->udp_config_group_box->setVisible(true); } void ConfigureMotionTouch::ConnectEvents() { - connect(ui->motion_provider, qOverload<int>(&QComboBox::currentIndexChanged), this, - [this](int index) { UpdateUiDisplay(); }); connect(ui->touch_provider, qOverload<int>(&QComboBox::currentIndexChanged), this, [this](int index) { UpdateUiDisplay(); }); connect(ui->udp_test, &QPushButton::clicked, this, &ConfigureMotionTouch::OnCemuhookUDPTest); + connect(ui->udp_add, &QPushButton::clicked, this, &ConfigureMotionTouch::OnUDPAddServer); + connect(ui->udp_remove, &QPushButton::clicked, this, &ConfigureMotionTouch::OnUDPDeleteServer); connect(ui->touch_calibration_config, &QPushButton::clicked, this, &ConfigureMotionTouch::OnConfigureTouchCalibration); connect(ui->touch_from_button_config_btn, &QPushButton::clicked, this, @@ -187,13 +182,58 @@ void ConfigureMotionTouch::ConnectEvents() { }); } +void ConfigureMotionTouch::OnUDPAddServer() { + 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]?[" + "0-9][0-9]?)$")); // a valid ip address + bool ok; + QString port_text = ui->udp_port->text(); + QString server_text = ui->udp_server->text(); + const QString server_string = tr("%1:%2").arg(server_text, port_text); + int port_number = port_text.toInt(&ok, 10); + int row = udp_server_list_model->rowCount(); + + if (!ok) { + QMessageBox::warning(this, tr("yuzu"), tr("Port number has invalid characters")); + return; + } + if (port_number < 0 || port_number > 65353) { + QMessageBox::warning(this, tr("yuzu"), tr("Port has to be in range 0 and 65353")); + return; + } + if (!re.exactMatch(server_text)) { + QMessageBox::warning(this, tr("yuzu"), tr("IP address is not valid")); + return; + } + // Search for duplicates + for (const auto& item : udp_server_list_model->stringList()) { + if (item == server_string) { + QMessageBox::warning(this, tr("yuzu"), tr("This UDP server already exists")); + return; + } + } + // Limit server count to 8 + if (row == 8) { + QMessageBox::warning(this, tr("yuzu"), tr("Unable to add more than 8 servers")); + return; + } + + udp_server_list_model->insertRows(row, 1); + QModelIndex index = udp_server_list_model->index(row); + udp_server_list_model->setData(index, server_string); + ui->udp_server_list->setCurrentIndex(index); +} + +void ConfigureMotionTouch::OnUDPDeleteServer() { + udp_server_list_model->removeRows(ui->udp_server_list->currentIndex().row(), 1); +} + void ConfigureMotionTouch::OnCemuhookUDPTest() { ui->udp_test->setEnabled(false); ui->udp_test->setText(tr("Testing")); udp_test_in_progress = true; InputCommon::CemuhookUDP::TestCommunication( - ui->udp_server->text().toStdString(), static_cast<u16>(ui->udp_port->text().toInt()), - static_cast<u32>(ui->udp_pad_index->currentIndex()), 24872, + ui->udp_server->text().toStdString(), static_cast<u16>(ui->udp_port->text().toInt()), 0, + 24872, [this] { LOG_INFO(Frontend, "UDP input test success"); QMetaObject::invokeMethod(this, "ShowUDPTestResult", Q_ARG(bool, true)); @@ -207,9 +247,9 @@ void ConfigureMotionTouch::OnCemuhookUDPTest() { void ConfigureMotionTouch::OnConfigureTouchCalibration() { ui->touch_calibration_config->setEnabled(false); ui->touch_calibration_config->setText(tr("Configuring")); - CalibrationConfigurationDialog dialog( - this, ui->udp_server->text().toStdString(), static_cast<u16>(ui->udp_port->text().toUInt()), - static_cast<u8>(ui->udp_pad_index->currentIndex()), 24872); + CalibrationConfigurationDialog dialog(this, ui->udp_server->text().toStdString(), + static_cast<u16>(ui->udp_port->text().toUInt()), 0, + 24872); dialog.exec(); if (dialog.completed) { min_x = dialog.min_x; @@ -269,7 +309,7 @@ void ConfigureMotionTouch::OnConfigureTouchFromButton() { bool ConfigureMotionTouch::CanCloseDialog() { if (udp_test_in_progress) { - QMessageBox::warning(this, tr("Citra"), + QMessageBox::warning(this, tr("yuzu"), tr("UDP Test or calibration configuration is in progress.<br>Please " "wait for them to finish.")); return false; @@ -282,17 +322,11 @@ void ConfigureMotionTouch::ApplyConfiguration() { return; } - std::string motion_engine = ui->motion_provider->currentData().toString().toStdString(); std::string touch_engine = ui->touch_provider->currentData().toString().toStdString(); - Common::ParamPackage motion_param{}, touch_param{}; - motion_param.Set("engine", std::move(motion_engine)); + Common::ParamPackage touch_param{}; touch_param.Set("engine", std::move(touch_engine)); - if (motion_engine == "motion_emu") { - motion_param.Set("sensitivity", static_cast<float>(ui->motion_sensitivity->value())); - } - if (touch_engine == "cemuhookudp") { touch_param.Set("min_x", min_x); touch_param.Set("min_y", min_y); @@ -300,15 +334,25 @@ void ConfigureMotionTouch::ApplyConfiguration() { touch_param.Set("max_y", max_y); } - Settings::values.motion_device = motion_param.Serialize(); Settings::values.touch_device = touch_param.Serialize(); Settings::values.use_touch_from_button = ui->touch_from_button_checkbox->isChecked(); Settings::values.touch_from_button_map_index = ui->touch_from_button_map->currentIndex(); Settings::values.touch_from_button_maps = touch_from_button_maps; - Settings::values.udp_input_address = ui->udp_server->text().toStdString(); - Settings::values.udp_input_port = static_cast<u16>(ui->udp_port->text().toInt()); - Settings::values.udp_pad_index = static_cast<u8>(ui->udp_pad_index->currentIndex()); + Settings::values.udp_input_servers = GetUDPServerString(); input_subsystem->ReloadInputDevices(); accept(); } + +std::string ConfigureMotionTouch::GetUDPServerString() const { + QString input_servers; + + for (const auto& item : udp_server_list_model->stringList()) { + input_servers += item; + input_servers += QLatin1Char{','}; + } + + // Remove last comma + input_servers.chop(1); + return input_servers.toStdString(); +} 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 @@ class QLabel; class QPushButton; +class QStringListModel; class QVBoxLayout; namespace InputCommon { @@ -62,6 +63,8 @@ public slots: void ApplyConfiguration(); private slots: + void OnUDPAddServer(); + void OnUDPDeleteServer(); void OnCemuhookUDPTest(); void OnConfigureTouchCalibration(); void OnConfigureTouchFromButton(); @@ -73,10 +76,12 @@ private: void UpdateUiDisplay(); void ConnectEvents(); bool CanCloseDialog(); + std::string GetUDPServerString() const; InputCommon::InputSubsystem* input_subsystem; std::unique_ptr<Ui::ConfigureMotionTouch> ui; + QStringListModel* udp_server_list_model; // Coordinate system of the CemuhookUDP touch provider 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 @@ <ui version="4.0"> <class>ConfigureMotionTouch</class> <widget class="QDialog" name="ConfigureMotionTouch"> - <property name="windowTitle"> - <string>Configure Motion / Touch</string> - </property> <property name="geometry"> <rect> <x>0</x> <y>0</y> <width>500</width> - <height>450</height> + <height>482</height> </rect> </property> + <property name="windowTitle"> + <string>Configure Motion / Touch</string> + </property> + <property name="styleSheet"> + <string notr="true"/> + </property> <layout class="QVBoxLayout"> <item> <widget class="QGroupBox" name="motion_group_box"> <property name="title"> - <string>Motion</string> + <string>Mouse Motion</string> </property> <layout class="QVBoxLayout"> <item> <layout class="QHBoxLayout"> <item> - <widget class="QLabel" name="motion_provider_label"> - <property name="text"> - <string>Motion Provider:</string> - </property> - </widget> - </item> - <item> - <widget class="QComboBox" name="motion_provider"/> - </item> - </layout> - </item> - <item> - <layout class="QHBoxLayout"> - <item> <widget class="QLabel" name="motion_sensitivity_label"> <property name="text"> <string>Sensitivity:</string> @@ -180,103 +169,171 @@ </widget> </item> <item> - <layout class="QHBoxLayout"> + <layout class="QHBoxLayout" name="horizontalLayout"> <item> - <widget class="QLabel" name="udp_server_label"> - <property name="text"> - <string>Server:</string> - </property> - </widget> + <widget class="QListView" name="udp_server_list"/> </item> <item> - <widget class="QLineEdit" name="udp_server"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Minimum" vsizetype="Fixed"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> + <layout class="QVBoxLayout" name="verticalLayout"> + <property name="leftMargin"> + <number>0</number> </property> - </widget> - </item> - </layout> - </item> - <item> - <layout class="QHBoxLayout"> - <item> - <widget class="QLabel" name="udp_port_label"> - <property name="text"> - <string>Port:</string> + <property name="topMargin"> + <number>0</number> </property> - </widget> - </item> - <item> - <widget class="QLineEdit" name="udp_port"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Minimum" vsizetype="Fixed"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> + <property name="rightMargin"> + <number>0</number> </property> - </widget> - </item> - </layout> - </item> - <item> - <layout class="QHBoxLayout"> - <item> - <widget class="QLabel" name="udp_pad_index_label"> - <property name="text"> - <string>Pad:</string> + <property name="bottomMargin"> + <number>0</number> </property> - </widget> - </item> - <item> - <widget class="QComboBox" name="udp_pad_index"> <item> - <property name="text"> - <string>Pad 1</string> - </property> + <layout class="QHBoxLayout"> + <property name="leftMargin"> + <number>3</number> + </property> + <property name="topMargin"> + <number>3</number> + </property> + <property name="rightMargin"> + <number>0</number> + </property> + <item> + <widget class="QLabel" name="udp_server_label"> + <property name="text"> + <string>Server:</string> + </property> + </widget> + </item> + <item> + <widget class="QLineEdit" name="udp_server"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Minimum" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + </widget> + </item> + </layout> </item> <item> - <property name="text"> - <string>Pad 2</string> - </property> + <layout class="QHBoxLayout"> + <property name="leftMargin"> + <number>3</number> + </property> + <property name="rightMargin"> + <number>0</number> + </property> + <item> + <widget class="QLabel" name="udp_port_label"> + <property name="text"> + <string>Port:</string> + </property> + </widget> + </item> + <item> + <widget class="QLineEdit" name="udp_port"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Minimum" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + </widget> + </item> + </layout> </item> <item> - <property name="text"> - <string>Pad 3</string> - </property> + <layout class="QHBoxLayout"> + <property name="leftMargin"> + <number>3</number> + </property> + <property name="rightMargin"> + <number>0</number> + </property> + <item> + <widget class="QLabel" name="udp_learn_more"> + <property name="text"> + <string>Learn More</string> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="udp_test"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Maximum" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>Test</string> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="udp_add"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Maximum" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>Add Server</string> + </property> + </widget> + </item> + </layout> </item> <item> - <property name="text"> - <string>Pad 4</string> - </property> + <spacer name="verticalSpacer_3"> + <property name="orientation"> + <enum>Qt::Vertical</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>20</width> + <height>40</height> + </size> + </property> + </spacer> </item> - </widget> - </item> - </layout> - </item> - <item> - <layout class="QHBoxLayout"> - <item> - <widget class="QLabel" name="udp_learn_more"> - <property name="text"> - <string>Learn More</string> - </property> - </widget> - </item> - <item> - <widget class="QPushButton" name="udp_test"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Maximum" vsizetype="Fixed"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="text"> - <string>Test</string> - </property> - </widget> + <item> + <layout class="QHBoxLayout" name="horizontalLayout_2"> + <property name="topMargin"> + <number>0</number> + </property> + <item> + <widget class="QPushButton" name="udp_remove"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Maximum" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>Remove Server</string> + </property> + </widget> + </item> + <item> + <spacer name="horizontalSpacer_2"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + </layout> + </item> + </layout> </item> </layout> </item> @@ -312,6 +369,16 @@ <signal>accepted()</signal> <receiver>ConfigureMotionTouch</receiver> <slot>ApplyConfiguration()</slot> + <hints> + <hint type="sourcelabel"> + <x>20</x> + <y>20</y> + </hint> + <hint type="destinationlabel"> + <x>20</x> + <y>20</y> + </hint> + </hints> </connection> </connections> </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 #else void GMainWindow::WebBrowserOpenPage(std::string_view filename, std::string_view additional_args) { +#ifndef __linux__ QMessageBox::warning( this, tr("Web Applet"), tr("This version of yuzu was built without QtWebEngine support, meaning that yuzu cannot " "properly display the game manual or web page requested."), QMessageBox::Ok, QMessageBox::Ok); +#endif LOG_INFO(Frontend, "(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() { sdl2_config->GetInteger("ControlsGeneral", "touch_diameter_x", 15); Settings::values.touchscreen.diameter_y = sdl2_config->GetInteger("ControlsGeneral", "touch_diameter_y", 15); - Settings::values.udp_input_address = - sdl2_config->Get("Controls", "udp_input_address", InputCommon::CemuhookUDP::DEFAULT_ADDR); - Settings::values.udp_input_port = static_cast<u16>(sdl2_config->GetInteger( - "Controls", "udp_input_port", InputCommon::CemuhookUDP::DEFAULT_PORT)); + Settings::values.udp_input_servers = + sdl2_config->Get("Controls", "udp_input_address", InputCommon::CemuhookUDP::DEFAULT_SRV); std::transform(keyboard_keys.begin(), keyboard_keys.end(), 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 @@ #include "core/perf_stats.h" #include "input_common/keyboard.h" #include "input_common/main.h" -#include "input_common/motion_emu.h" +#include "input_common/mouse/mouse_input.h" #include "input_common/sdl/sdl.h" #include "yuzu_cmd/emu_window/emu_window_sdl2.h" @@ -30,7 +30,7 @@ EmuWindow_SDL2::~EmuWindow_SDL2() { void EmuWindow_SDL2::OnMouseMotion(s32 x, s32 y) { TouchMoved((unsigned)std::max(x, 0), (unsigned)std::max(y, 0)); - input_subsystem->GetMotionEmu()->Tilt(x, y); + input_subsystem->GetMouse()->MouseMove(x, y); } void 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) { } } else if (button == SDL_BUTTON_RIGHT) { if (state == SDL_PRESSED) { - input_subsystem->GetMotionEmu()->BeginTilt(x, y); + input_subsystem->GetMouse()->PressButton(x, y, button); } else { - input_subsystem->GetMotionEmu()->EndTilt(); + input_subsystem->GetMouse()->ReleaseButton(button); } } } 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 @@ #include "core/settings.h" #include "input_common/keyboard.h" #include "input_common/main.h" -#include "input_common/motion_emu.h" #include "video_core/renderer_base.h" #include "yuzu_cmd/emu_window/emu_window_sdl2_gl.h" |