Compare commits
116 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 62c6c9f6a6 | |||
| 4c348f4069 | |||
| 419a59a7b1 | |||
| f250011ba0 | |||
| e1600b0962 | |||
| 61b246a3a9 | |||
| 06e65de93c | |||
| 7a99226785 | |||
| dffaffaac1 | |||
| 3446eb79b5 | |||
| 92adb69fa7 | |||
| cd3e959f23 | |||
| cc0dc3280d | |||
| 32b4627a9c | |||
| e9b81e9f01 | |||
| 614bd0ee8c | |||
| a54aee290f | |||
| de4cadca1f | |||
| a220d8799e | |||
| 2a24b1c973 | |||
| 182cf7d631 | |||
| 2f47b27654 | |||
| 283616dbd8 | |||
| 4d0ae1a17a | |||
| f7808f5658 | |||
| 91bd2281bf | |||
| 7d287a6fb0 | |||
| 9a251339dc | |||
| 6380731486 | |||
| 1ba0b077fc | |||
| cb56eaee41 | |||
| 3665a05488 | |||
| 392c1b96bc | |||
| 6ee1a784b8 | |||
| d7843b8ef2 | |||
| 771a9c21cc | |||
| 385b5602e4 | |||
| a1e3f6e27b | |||
| 09609dd50e | |||
| 2a82f1b08b | |||
| 02ea62568f | |||
| ae6df703f5 | |||
| ab88c2f611 | |||
| 2cbce77b92 | |||
| 9d665cb8db | |||
| a8be822e8e | |||
| e5a1e0a76d | |||
| 442096298e | |||
| 86e4aa81e9 | |||
| fbb5ca2633 | |||
| 891090799c | |||
| ad76b00f1e | |||
| 5c4e237902 | |||
| 3e4a0a13cb | |||
| 2978232390 | |||
| 03b574ae22 | |||
| 90c6141164 | |||
| ca26fd0f42 | |||
| dc83ca8914 | |||
| 4073931305 | |||
| 7c0908f301 | |||
| 966966dc02 | |||
| 8b4ecf22d4 | |||
| 111852a983 | |||
| 940d85241b | |||
| 4ed4bba305 | |||
| e0f2db4376 | |||
| 4d4afc1502 | |||
| f3a1bf53f9 | |||
| 2634e3c6eb | |||
| 3602df7f1f | |||
| fa4294cc6f | |||
| e3a615a616 | |||
| d66b897a6d | |||
| ddff03cff5 | |||
| 10e8acc451 | |||
| 77532ebde3 | |||
| cd6f4f7eed | |||
| 8b0f334e0c | |||
| c307ae2402 | |||
| 6d9661939f | |||
| ffeb4ef83e | |||
| b14d344dfc | |||
| aa35e51fcd | |||
| e107870bc8 | |||
| f43a1da808 | |||
| d264b7375c | |||
| b8219ec838 | |||
| 0dc6967ff1 | |||
| fcd0145eb5 | |||
| 2b863c9aa3 | |||
| ff45c39578 | |||
| c07fd2898b | |||
| a881efbf26 | |||
| 53829d4cbd | |||
| 7a504a9365 | |||
| a2eb44db82 | |||
| 754109fd54 | |||
| 7003090187 | |||
| 8a85a562ed | |||
| 4f5bbe56ba | |||
| 58b0ae84b5 | |||
| c5e257017f | |||
| 059dd724d6 | |||
| 91bca9eb0b | |||
| ab961e0701 | |||
| 050a4a401b | |||
| 70499b8cbd | |||
| 8568f44ffa | |||
| 669005b75e | |||
| 40a72e9cd5 | |||
| 41c2f5200c | |||
| b5784e9af2 | |||
| 57162e1df3 | |||
| 1adf640d37 | |||
| 34635a42c0 |
@@ -9,6 +9,7 @@ stages:
|
||||
displayName: 'build'
|
||||
jobs:
|
||||
- job: build
|
||||
timeoutInMinutes: 120
|
||||
displayName: 'windows-msvc'
|
||||
pool:
|
||||
vmImage: windows-2019
|
||||
|
||||
Vendored
+4749
File diff suppressed because it is too large
Load Diff
Vendored
+4757
File diff suppressed because it is too large
Load Diff
Vendored
+4732
File diff suppressed because it is too large
Load Diff
Vendored
+4724
File diff suppressed because it is too large
Load Diff
Vendored
+4752
File diff suppressed because it is too large
Load Diff
Vendored
+4719
File diff suppressed because it is too large
Load Diff
Vendored
+4713
File diff suppressed because it is too large
Load Diff
Vendored
+4757
File diff suppressed because it is too large
Load Diff
Vendored
+4725
File diff suppressed because it is too large
Load Diff
Vendored
+4720
File diff suppressed because it is too large
Load Diff
Vendored
+4747
File diff suppressed because it is too large
Load Diff
@@ -44,6 +44,16 @@ add_library(audio_core STATIC
|
||||
|
||||
create_target_directory_groups(audio_core)
|
||||
|
||||
if (NOT MSVC)
|
||||
target_compile_options(audio_core PRIVATE
|
||||
-Werror=ignored-qualifiers
|
||||
-Werror=implicit-fallthrough
|
||||
-Werror=reorder
|
||||
-Werror=sign-compare
|
||||
-Werror=unused-variable
|
||||
)
|
||||
endif()
|
||||
|
||||
target_link_libraries(audio_core PUBLIC common core)
|
||||
target_link_libraries(audio_core PRIVATE SoundTouch)
|
||||
|
||||
|
||||
@@ -3,16 +3,13 @@
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include <vector>
|
||||
#include "audio_core/algorithm/interpolate.h"
|
||||
|
||||
#include "audio_core/audio_out.h"
|
||||
#include "audio_core/audio_renderer.h"
|
||||
#include "audio_core/codec.h"
|
||||
#include "audio_core/common.h"
|
||||
#include "audio_core/info_updater.h"
|
||||
#include "audio_core/voice_context.h"
|
||||
#include "common/assert.h"
|
||||
#include "common/logging/log.h"
|
||||
#include "core/core.h"
|
||||
#include "core/hle/kernel/writable_event.h"
|
||||
#include "core/memory.h"
|
||||
#include "core/settings.h"
|
||||
|
||||
@@ -21,7 +21,6 @@
|
||||
#include "common/common_funcs.h"
|
||||
#include "common/common_types.h"
|
||||
#include "common/swap.h"
|
||||
#include "core/hle/kernel/object.h"
|
||||
#include "core/hle/result.h"
|
||||
|
||||
namespace Core::Timing {
|
||||
|
||||
@@ -57,15 +57,15 @@ bool BehaviorInfo::IsLongSizePreDelaySupported() const {
|
||||
return AudioCommon::IsRevisionSupported(3, user_revision);
|
||||
}
|
||||
|
||||
bool BehaviorInfo::IsAudioRenererProcessingTimeLimit80PercentSupported() const {
|
||||
bool BehaviorInfo::IsAudioRendererProcessingTimeLimit80PercentSupported() const {
|
||||
return AudioCommon::IsRevisionSupported(5, user_revision);
|
||||
}
|
||||
|
||||
bool BehaviorInfo::IsAudioRenererProcessingTimeLimit75PercentSupported() const {
|
||||
bool BehaviorInfo::IsAudioRendererProcessingTimeLimit75PercentSupported() const {
|
||||
return AudioCommon::IsRevisionSupported(4, user_revision);
|
||||
}
|
||||
|
||||
bool BehaviorInfo::IsAudioRenererProcessingTimeLimit70PercentSupported() const {
|
||||
bool BehaviorInfo::IsAudioRendererProcessingTimeLimit70PercentSupported() const {
|
||||
return AudioCommon::IsRevisionSupported(1, user_revision);
|
||||
}
|
||||
|
||||
|
||||
@@ -49,9 +49,9 @@ public:
|
||||
bool IsAdpcmLoopContextBugFixed() const;
|
||||
bool IsSplitterSupported() const;
|
||||
bool IsLongSizePreDelaySupported() const;
|
||||
bool IsAudioRenererProcessingTimeLimit80PercentSupported() const;
|
||||
bool IsAudioRenererProcessingTimeLimit75PercentSupported() const;
|
||||
bool IsAudioRenererProcessingTimeLimit70PercentSupported() const;
|
||||
bool IsAudioRendererProcessingTimeLimit80PercentSupported() const;
|
||||
bool IsAudioRendererProcessingTimeLimit75PercentSupported() const;
|
||||
bool IsAudioRendererProcessingTimeLimit70PercentSupported() const;
|
||||
bool IsElapsedFrameCountSupported() const;
|
||||
bool IsMemoryPoolForceMappingEnabled() const;
|
||||
bool IsFlushVoiceWaveBuffersSupported() const;
|
||||
|
||||
@@ -16,8 +16,9 @@ std::vector<s16> DecodeADPCM(const u8* const data, std::size_t size, const ADPCM
|
||||
|
||||
constexpr std::size_t FRAME_LEN = 8;
|
||||
constexpr std::size_t SAMPLES_PER_FRAME = 14;
|
||||
constexpr std::array<int, 16> SIGNED_NIBBLES = {
|
||||
{0, 1, 2, 3, 4, 5, 6, 7, -8, -7, -6, -5, -4, -3, -2, -1}};
|
||||
static constexpr std::array<int, 16> SIGNED_NIBBLES{
|
||||
0, 1, 2, 3, 4, 5, 6, 7, -8, -7, -6, -5, -4, -3, -2, -1,
|
||||
};
|
||||
|
||||
const std::size_t sample_count = (size / FRAME_LEN) * SAMPLES_PER_FRAME;
|
||||
const std::size_t ret_size =
|
||||
|
||||
@@ -38,7 +38,7 @@ using ADPCM_Coeff = std::array<s16, 16>;
|
||||
* @param state ADPCM state, this is updated with new state
|
||||
* @return Decoded stereo signed PCM16 data, sample_count in length
|
||||
*/
|
||||
std::vector<s16> DecodeADPCM(const u8* const data, std::size_t size, const ADPCM_Coeff& coeff,
|
||||
std::vector<s16> DecodeADPCM(const u8* data, std::size_t size, const ADPCM_Coeff& coeff,
|
||||
ADPCMState& state);
|
||||
|
||||
}; // namespace AudioCore::Codec
|
||||
|
||||
@@ -152,7 +152,7 @@ void CommandGenerator::GenerateVoiceCommand(ServerVoiceInfo& voice_info) {
|
||||
if (!destination_data->IsConfigured()) {
|
||||
continue;
|
||||
}
|
||||
if (destination_data->GetMixId() >= mix_context.GetCount()) {
|
||||
if (destination_data->GetMixId() >= static_cast<int>(mix_context.GetCount())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -435,7 +435,7 @@ void CommandGenerator::GenerateAuxCommand(s32 mix_buffer_offset, EffectBase* inf
|
||||
GetMixBuffer(output_index), worker_params.sample_count, offset, write_count);
|
||||
memory.WriteBlock(aux->GetRecvInfo(), &recv_info, sizeof(AuxInfoDSP));
|
||||
|
||||
if (samples_read != worker_params.sample_count &&
|
||||
if (samples_read != static_cast<int>(worker_params.sample_count) &&
|
||||
samples_read <= params.sample_count) {
|
||||
std::memset(GetMixBuffer(output_index), 0, params.sample_count - samples_read);
|
||||
}
|
||||
@@ -611,7 +611,8 @@ void CommandGenerator::GenerateMixCommands(ServerMixInfo& mix_info) {
|
||||
const auto& dest_mix = mix_context.GetInfo(destination_data->GetMixId());
|
||||
const auto& dest_in_params = dest_mix.GetInParams();
|
||||
const auto mix_index = (base - 1) % in_params.buffer_count + in_params.buffer_offset;
|
||||
for (std::size_t i = 0; i < dest_in_params.buffer_count; i++) {
|
||||
for (std::size_t i = 0; i < static_cast<std::size_t>(dest_in_params.buffer_count);
|
||||
i++) {
|
||||
const auto mixed_volume = in_params.volume * destination_data->GetMixVolume(i);
|
||||
if (mixed_volume != 0.0f) {
|
||||
GenerateMixCommand(dest_in_params.buffer_offset + i, mix_index, mixed_volume,
|
||||
@@ -704,7 +705,7 @@ s32 CommandGenerator::DecodePcm16(ServerVoiceInfo& voice_info, VoiceState& dsp_s
|
||||
std::vector<s16> buffer(samples_processed * channel_count);
|
||||
memory.ReadBlock(buffer_pos, buffer.data(), buffer.size() * sizeof(s16));
|
||||
|
||||
for (std::size_t i = 0; i < samples_processed; i++) {
|
||||
for (std::size_t i = 0; i < static_cast<std::size_t>(samples_processed); i++) {
|
||||
sample_buffer[mix_offset + i] = buffer[i * channel_count + channel];
|
||||
}
|
||||
}
|
||||
@@ -726,8 +727,9 @@ s32 CommandGenerator::DecodeAdpcm(ServerVoiceInfo& voice_info, VoiceState& dsp_s
|
||||
return 0;
|
||||
}
|
||||
|
||||
constexpr std::array<int, 16> SIGNED_NIBBLES = {
|
||||
{0, 1, 2, 3, 4, 5, 6, 7, -8, -7, -6, -5, -4, -3, -2, -1}};
|
||||
static constexpr std::array<int, 16> SIGNED_NIBBLES{
|
||||
0, 1, 2, 3, 4, 5, 6, 7, -8, -7, -6, -5, -4, -3, -2, -1,
|
||||
};
|
||||
|
||||
constexpr std::size_t FRAME_LEN = 8;
|
||||
constexpr std::size_t NIBBLES_PER_SAMPLE = 16;
|
||||
@@ -789,7 +791,7 @@ s32 CommandGenerator::DecodeAdpcm(ServerVoiceInfo& voice_info, VoiceState& dsp_s
|
||||
position_in_frame += 2;
|
||||
|
||||
// Decode entire frame
|
||||
if (remaining_samples >= SAMPLES_PER_FRAME) {
|
||||
if (remaining_samples >= static_cast<int>(SAMPLES_PER_FRAME)) {
|
||||
for (std::size_t i = 0; i < SAMPLES_PER_FRAME / 2; i++) {
|
||||
|
||||
// Sample 1
|
||||
@@ -866,7 +868,6 @@ void CommandGenerator::DecodeFromWaveBuffers(ServerVoiceInfo& voice_info, s32* o
|
||||
const auto resample_rate = static_cast<s32>(
|
||||
static_cast<float>(in_params.sample_rate) / static_cast<float>(target_sample_rate) *
|
||||
static_cast<float>(static_cast<s32>(in_params.pitch * 32768.0f)));
|
||||
auto* output_base = output;
|
||||
if (dsp_state.fraction + sample_count * resample_rate >
|
||||
static_cast<s32>(SCALED_MIX_BUFFER_SIZE - 4ULL)) {
|
||||
return;
|
||||
|
||||
@@ -7,7 +7,6 @@
|
||||
#include <array>
|
||||
#include "audio_core/common.h"
|
||||
#include "audio_core/voice_context.h"
|
||||
#include "common/common_funcs.h"
|
||||
#include "common/common_types.h"
|
||||
|
||||
namespace Core::Memory {
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "common/common_funcs.h"
|
||||
#include "common/common_types.h"
|
||||
#include "common/swap.h"
|
||||
|
||||
@@ -192,8 +192,8 @@ SinkStream& CubebSink::AcquireSinkStream(u32 sample_rate, u32 num_channels,
|
||||
|
||||
long CubebSinkStream::DataCallback(cubeb_stream* stream, void* user_data, const void* input_buffer,
|
||||
void* output_buffer, long num_frames) {
|
||||
CubebSinkStream* impl = static_cast<CubebSinkStream*>(user_data);
|
||||
u8* buffer = reinterpret_cast<u8*>(output_buffer);
|
||||
auto* impl = static_cast<CubebSinkStream*>(user_data);
|
||||
auto* buffer = static_cast<u8*>(output_buffer);
|
||||
|
||||
if (!impl) {
|
||||
return {};
|
||||
|
||||
@@ -184,19 +184,19 @@ void EffectAuxInfo::UpdateForCommandGeneration() {
|
||||
}
|
||||
}
|
||||
|
||||
const VAddr EffectAuxInfo::GetSendInfo() const {
|
||||
VAddr EffectAuxInfo::GetSendInfo() const {
|
||||
return send_info;
|
||||
}
|
||||
|
||||
const VAddr EffectAuxInfo::GetSendBuffer() const {
|
||||
VAddr EffectAuxInfo::GetSendBuffer() const {
|
||||
return send_buffer;
|
||||
}
|
||||
|
||||
const VAddr EffectAuxInfo::GetRecvInfo() const {
|
||||
VAddr EffectAuxInfo::GetRecvInfo() const {
|
||||
return recv_info;
|
||||
}
|
||||
|
||||
const VAddr EffectAuxInfo::GetRecvBuffer() const {
|
||||
VAddr EffectAuxInfo::GetRecvBuffer() const {
|
||||
return recv_buffer;
|
||||
}
|
||||
|
||||
|
||||
@@ -166,13 +166,13 @@ public:
|
||||
std::array<u8, 0xa0> raw;
|
||||
};
|
||||
};
|
||||
static_assert(sizeof(EffectInfo::InParams) == 0xc0, "InParams is an invalid size");
|
||||
static_assert(sizeof(InParams) == 0xc0, "InParams is an invalid size");
|
||||
|
||||
struct OutParams {
|
||||
UsageStatus status{};
|
||||
INSERT_PADDING_BYTES(15);
|
||||
};
|
||||
static_assert(sizeof(EffectInfo::OutParams) == 0x10, "OutParams is an invalid size");
|
||||
static_assert(sizeof(OutParams) == 0x10, "OutParams is an invalid size");
|
||||
};
|
||||
|
||||
struct AuxAddress {
|
||||
@@ -184,8 +184,8 @@ struct AuxAddress {
|
||||
|
||||
class EffectBase {
|
||||
public:
|
||||
EffectBase(EffectType effect_type);
|
||||
~EffectBase();
|
||||
explicit EffectBase(EffectType effect_type);
|
||||
virtual ~EffectBase();
|
||||
|
||||
virtual void Update(EffectInfo::InParams& in_params) = 0;
|
||||
virtual void UpdateForCommandGeneration() = 0;
|
||||
@@ -206,8 +206,7 @@ protected:
|
||||
template <typename T>
|
||||
class EffectGeneric : public EffectBase {
|
||||
public:
|
||||
EffectGeneric(EffectType effect_type) : EffectBase::EffectBase(effect_type) {}
|
||||
~EffectGeneric() = default;
|
||||
explicit EffectGeneric(EffectType effect_type) : EffectBase(effect_type) {}
|
||||
|
||||
T& GetParams() {
|
||||
return internal_params;
|
||||
@@ -224,7 +223,7 @@ private:
|
||||
class EffectStubbed : public EffectBase {
|
||||
public:
|
||||
explicit EffectStubbed();
|
||||
~EffectStubbed();
|
||||
~EffectStubbed() override;
|
||||
|
||||
void Update(EffectInfo::InParams& in_params) override;
|
||||
void UpdateForCommandGeneration() override;
|
||||
@@ -233,7 +232,7 @@ public:
|
||||
class EffectI3dl2Reverb : public EffectGeneric<I3dl2ReverbParams> {
|
||||
public:
|
||||
explicit EffectI3dl2Reverb();
|
||||
~EffectI3dl2Reverb();
|
||||
~EffectI3dl2Reverb() override;
|
||||
|
||||
void Update(EffectInfo::InParams& in_params) override;
|
||||
void UpdateForCommandGeneration() override;
|
||||
@@ -245,7 +244,7 @@ private:
|
||||
class EffectBiquadFilter : public EffectGeneric<BiquadFilterParams> {
|
||||
public:
|
||||
explicit EffectBiquadFilter();
|
||||
~EffectBiquadFilter();
|
||||
~EffectBiquadFilter() override;
|
||||
|
||||
void Update(EffectInfo::InParams& in_params) override;
|
||||
void UpdateForCommandGeneration() override;
|
||||
@@ -254,14 +253,14 @@ public:
|
||||
class EffectAuxInfo : public EffectGeneric<AuxInfo> {
|
||||
public:
|
||||
explicit EffectAuxInfo();
|
||||
~EffectAuxInfo();
|
||||
~EffectAuxInfo() override;
|
||||
|
||||
void Update(EffectInfo::InParams& in_params) override;
|
||||
void UpdateForCommandGeneration() override;
|
||||
const VAddr GetSendInfo() const;
|
||||
const VAddr GetSendBuffer() const;
|
||||
const VAddr GetRecvInfo() const;
|
||||
const VAddr GetRecvBuffer() const;
|
||||
VAddr GetSendInfo() const;
|
||||
VAddr GetSendBuffer() const;
|
||||
VAddr GetRecvInfo() const;
|
||||
VAddr GetRecvBuffer() const;
|
||||
|
||||
private:
|
||||
VAddr send_info{};
|
||||
@@ -275,7 +274,7 @@ private:
|
||||
class EffectDelay : public EffectGeneric<DelayParams> {
|
||||
public:
|
||||
explicit EffectDelay();
|
||||
~EffectDelay();
|
||||
~EffectDelay() override;
|
||||
|
||||
void Update(EffectInfo::InParams& in_params) override;
|
||||
void UpdateForCommandGeneration() override;
|
||||
@@ -287,7 +286,7 @@ private:
|
||||
class EffectBufferMixer : public EffectGeneric<BufferMixerParams> {
|
||||
public:
|
||||
explicit EffectBufferMixer();
|
||||
~EffectBufferMixer();
|
||||
~EffectBufferMixer() override;
|
||||
|
||||
void Update(EffectInfo::InParams& in_params) override;
|
||||
void UpdateForCommandGeneration() override;
|
||||
@@ -296,7 +295,7 @@ public:
|
||||
class EffectReverb : public EffectGeneric<ReverbParams> {
|
||||
public:
|
||||
explicit EffectReverb();
|
||||
~EffectReverb();
|
||||
~EffectReverb() override;
|
||||
|
||||
void Update(EffectInfo::InParams& in_params) override;
|
||||
void UpdateForCommandGeneration() override;
|
||||
|
||||
@@ -64,7 +64,6 @@ bool InfoUpdater::UpdateBehaviorInfo(BehaviorInfo& in_behavior_info) {
|
||||
}
|
||||
|
||||
bool InfoUpdater::UpdateMemoryPools(std::vector<ServerMemoryPoolInfo>& memory_pool_info) {
|
||||
const auto force_mapping = behavior_info.IsMemoryPoolForceMappingEnabled();
|
||||
const auto memory_pool_count = memory_pool_info.size();
|
||||
const auto total_memory_pool_in = sizeof(ServerMemoryPoolInfo::InParams) * memory_pool_count;
|
||||
const auto total_memory_pool_out = sizeof(ServerMemoryPoolInfo::OutParams) * memory_pool_count;
|
||||
@@ -174,7 +173,7 @@ bool InfoUpdater::UpdateVoices(VoiceContext& voice_context,
|
||||
}
|
||||
// Voice states for each channel
|
||||
std::array<VoiceState*, AudioCommon::MAX_CHANNEL_COUNT> voice_states{};
|
||||
ASSERT(in_params.id < voice_count);
|
||||
ASSERT(static_cast<std::size_t>(in_params.id) < voice_count);
|
||||
|
||||
// Grab our current voice info
|
||||
auto& voice_info = voice_context.GetInfo(static_cast<std::size_t>(in_params.id));
|
||||
@@ -352,8 +351,8 @@ ResultCode InfoUpdater::UpdateMixes(MixContext& mix_context, std::size_t mix_buf
|
||||
for (std::size_t i = 0; i < mix_count; i++) {
|
||||
const auto& in = mix_in_params[i];
|
||||
total_buffer_count += in.buffer_count;
|
||||
if (in.dest_mix_id > mix_count && in.dest_mix_id != AudioCommon::NO_MIX &&
|
||||
in.mix_id != AudioCommon::FINAL_MIX) {
|
||||
if (static_cast<std::size_t>(in.dest_mix_id) > mix_count &&
|
||||
in.dest_mix_id != AudioCommon::NO_MIX && in.mix_id != AudioCommon::FINAL_MIX) {
|
||||
LOG_ERROR(
|
||||
Audio,
|
||||
"Invalid mix destination, mix_id={:X}, dest_mix_id={:X}, mix_buffer_count={:X}",
|
||||
|
||||
@@ -53,7 +53,7 @@ void MixContext::UpdateDistancesFromFinalMix() {
|
||||
auto mix_id = in_params.mix_id;
|
||||
// Needs to be referenced out of scope
|
||||
s32 distance_to_final_mix{AudioCommon::FINAL_MIX};
|
||||
for (; distance_to_final_mix < info_count; distance_to_final_mix++) {
|
||||
for (; distance_to_final_mix < static_cast<s32>(info_count); distance_to_final_mix++) {
|
||||
if (mix_id == AudioCommon::FINAL_MIX) {
|
||||
// If we're at the final mix, we're done
|
||||
break;
|
||||
@@ -77,7 +77,7 @@ void MixContext::UpdateDistancesFromFinalMix() {
|
||||
}
|
||||
|
||||
// If we're out of range for our distance, mark it as no final mix
|
||||
if (distance_to_final_mix >= info_count) {
|
||||
if (distance_to_final_mix >= static_cast<s32>(info_count)) {
|
||||
distance_to_final_mix = AudioCommon::NO_FINAL_MIX;
|
||||
}
|
||||
|
||||
|
||||
@@ -306,7 +306,7 @@ bool SplitterContext::UpdateInfo(const std::vector<u8>& input, std::size_t& inpu
|
||||
break;
|
||||
}
|
||||
|
||||
if (header.send_id < 0 || header.send_id > info_count) {
|
||||
if (header.send_id < 0 || static_cast<std::size_t>(header.send_id) > info_count) {
|
||||
LOG_ERROR(Audio, "Bad splitter data id");
|
||||
break;
|
||||
}
|
||||
@@ -348,7 +348,7 @@ bool SplitterContext::UpdateData(const std::vector<u8>& input, std::size_t& inpu
|
||||
break;
|
||||
}
|
||||
|
||||
if (header.splitter_id < 0 || header.splitter_id > data_count) {
|
||||
if (header.splitter_id < 0 || static_cast<std::size_t>(header.splitter_id) > data_count) {
|
||||
LOG_ERROR(Audio, "Bad splitter data id");
|
||||
break;
|
||||
}
|
||||
@@ -434,7 +434,7 @@ const std::vector<s32>& NodeStates::GetIndexList() const {
|
||||
}
|
||||
|
||||
void NodeStates::PushTsortResult(s32 index) {
|
||||
ASSERT(index < node_count);
|
||||
ASSERT(index < static_cast<s32>(node_count));
|
||||
index_list[index_pos++] = index;
|
||||
}
|
||||
|
||||
|
||||
@@ -12,7 +12,6 @@
|
||||
#include "common/assert.h"
|
||||
#include "common/logging/log.h"
|
||||
#include "core/core_timing.h"
|
||||
#include "core/core_timing_util.h"
|
||||
#include "core/settings.h"
|
||||
|
||||
namespace AudioCore {
|
||||
|
||||
@@ -488,11 +488,11 @@ s32 VoiceContext::DecodePcm16(s32* output_buffer, ServerWaveBuffer* wave_buffer,
|
||||
|
||||
// Fast path
|
||||
if (channel_count == 1) {
|
||||
for (std::size_t i = 0; i < samples_processed; i++) {
|
||||
for (std::ptrdiff_t i = 0; i < samples_processed; i++) {
|
||||
output_buffer[i] = buffer_data[i];
|
||||
}
|
||||
} else {
|
||||
for (std::size_t i = 0; i < samples_processed; i++) {
|
||||
for (std::ptrdiff_t i = 0; i < samples_processed; i++) {
|
||||
output_buffer[i] = buffer_data[i * channel_count + channel];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -192,4 +192,9 @@ create_target_directory_groups(common)
|
||||
find_package(Boost 1.71 COMPONENTS context headers REQUIRED)
|
||||
|
||||
target_link_libraries(common PUBLIC ${Boost_LIBRARIES} fmt::fmt microprofile)
|
||||
target_link_libraries(common PRIVATE lz4::lz4 zstd::zstd xbyak)
|
||||
target_link_libraries(common PRIVATE lz4::lz4 xbyak)
|
||||
if (MSVC)
|
||||
target_link_libraries(common PRIVATE zstd::zstd)
|
||||
else()
|
||||
target_link_libraries(common PRIVATE zstd)
|
||||
endif()
|
||||
|
||||
@@ -15,7 +15,7 @@ namespace Common {
|
||||
using base_timer = std::chrono::steady_clock;
|
||||
using base_time_point = std::chrono::time_point<base_timer>;
|
||||
|
||||
class StandardWallClock : public WallClock {
|
||||
class StandardWallClock final : public WallClock {
|
||||
public:
|
||||
StandardWallClock(u64 emulated_cpu_frequency, u64 emulated_clock_frequency)
|
||||
: WallClock(emulated_cpu_frequency, emulated_clock_frequency, false) {
|
||||
|
||||
@@ -13,6 +13,8 @@ namespace Common {
|
||||
|
||||
class WallClock {
|
||||
public:
|
||||
virtual ~WallClock() = default;
|
||||
|
||||
/// Returns current wall time in nanoseconds
|
||||
[[nodiscard]] virtual std::chrono::nanoseconds GetTimeNS() = 0;
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
namespace Common {
|
||||
|
||||
namespace X64 {
|
||||
class NativeClock : public WallClock {
|
||||
class NativeClock final : public WallClock {
|
||||
public:
|
||||
NativeClock(u64 emulated_cpu_frequency, u64 emulated_clock_frequency, u64 rtsc_frequency);
|
||||
|
||||
|
||||
@@ -34,7 +34,7 @@ std::optional<Callback> DynarmicCP15::CompileInternalOperation(bool two, unsigne
|
||||
CoprocReg CRm, unsigned opc2) {
|
||||
LOG_CRITICAL(Core_ARM, "CP15: cdp{} p15, {}, {}, {}, {}, {}", two ? "2" : "", opc1, CRd, CRn,
|
||||
CRm, opc2);
|
||||
return {};
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
CallbackOrAccessOneWord DynarmicCP15::CompileSendOneWord(bool two, unsigned opc1, CoprocReg CRn,
|
||||
@@ -115,7 +115,7 @@ std::optional<Callback> DynarmicCP15::CompileLoadWords(bool two, bool long_trans
|
||||
LOG_CRITICAL(Core_ARM, "CP15: mrrc{}{} p15, {}, [...]", two ? "2" : "",
|
||||
long_transfer ? "l" : "", CRd);
|
||||
}
|
||||
return {};
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
std::optional<Callback> DynarmicCP15::CompileStoreWords(bool two, bool long_transfer, CoprocReg CRd,
|
||||
@@ -127,7 +127,7 @@ std::optional<Callback> DynarmicCP15::CompileStoreWords(bool two, bool long_tran
|
||||
LOG_CRITICAL(Core_ARM, "CP15: mrrc{}{} p15, {}, [...]", two ? "2" : "",
|
||||
long_transfer ? "l" : "", CRd);
|
||||
}
|
||||
return {};
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
} // namespace Core
|
||||
|
||||
+14
-1
@@ -40,6 +40,7 @@
|
||||
#include "core/hle/service/lm/manager.h"
|
||||
#include "core/hle/service/service.h"
|
||||
#include "core/hle/service/sm/sm.h"
|
||||
#include "core/hle/service/time/time_manager.h"
|
||||
#include "core/loader/loader.h"
|
||||
#include "core/memory.h"
|
||||
#include "core/memory/cheat_engine.h"
|
||||
@@ -121,7 +122,7 @@ FileSys::VirtualFile GetGameFileFromPath(const FileSys::VirtualFilesystem& vfs,
|
||||
struct System::Impl {
|
||||
explicit Impl(System& system)
|
||||
: kernel{system}, fs_controller{system}, memory{system},
|
||||
cpu_manager{system}, reporter{system}, applet_manager{system} {}
|
||||
cpu_manager{system}, reporter{system}, applet_manager{system}, time_manager{system} {}
|
||||
|
||||
ResultStatus Run() {
|
||||
status = ResultStatus::Success;
|
||||
@@ -189,6 +190,9 @@ struct System::Impl {
|
||||
return ResultStatus::ErrorVideoCore;
|
||||
}
|
||||
|
||||
// Initialize time manager, which must happen after kernel is created
|
||||
time_manager.Initialize();
|
||||
|
||||
is_powered_on = true;
|
||||
exit_lock = false;
|
||||
|
||||
@@ -387,6 +391,7 @@ struct System::Impl {
|
||||
/// Service State
|
||||
Service::Glue::ARPManager arp_manager;
|
||||
Service::LM::Manager lm_manager{reporter};
|
||||
Service::Time::TimeManager time_manager;
|
||||
|
||||
/// Service manager
|
||||
std::shared_ptr<Service::SM::ServiceManager> service_manager;
|
||||
@@ -717,6 +722,14 @@ const Service::LM::Manager& System::GetLogManager() const {
|
||||
return impl->lm_manager;
|
||||
}
|
||||
|
||||
Service::Time::TimeManager& System::GetTimeManager() {
|
||||
return impl->time_manager;
|
||||
}
|
||||
|
||||
const Service::Time::TimeManager& System::GetTimeManager() const {
|
||||
return impl->time_manager;
|
||||
}
|
||||
|
||||
void System::SetExitLock(bool locked) {
|
||||
impl->exit_lock = locked;
|
||||
}
|
||||
|
||||
+9
-1
@@ -69,6 +69,10 @@ namespace SM {
|
||||
class ServiceManager;
|
||||
} // namespace SM
|
||||
|
||||
namespace Time {
|
||||
class TimeManager;
|
||||
} // namespace Time
|
||||
|
||||
} // namespace Service
|
||||
|
||||
namespace Tegra {
|
||||
@@ -120,7 +124,7 @@ public:
|
||||
* Gets the instance of the System singleton class.
|
||||
* @returns Reference to the instance of the System singleton class.
|
||||
*/
|
||||
static System& GetInstance() {
|
||||
[[deprecated("Use of the global system instance is deprecated")]] static System& GetInstance() {
|
||||
return s_instance;
|
||||
}
|
||||
|
||||
@@ -361,6 +365,10 @@ public:
|
||||
|
||||
const Service::LM::Manager& GetLogManager() const;
|
||||
|
||||
Service::Time::TimeManager& GetTimeManager();
|
||||
|
||||
const Service::Time::TimeManager& GetTimeManager() const;
|
||||
|
||||
void SetExitLock(bool locked);
|
||||
|
||||
bool GetExitLock() const;
|
||||
|
||||
@@ -323,7 +323,7 @@ bool NCA::ReadRomFSSection(const NCASectionHeader& section, const NCASectionTabl
|
||||
subsection_buckets.back().entries.push_back({section.bktr.relocation.offset, {0}, ctr_low});
|
||||
subsection_buckets.back().entries.push_back({size, {0}, 0});
|
||||
|
||||
std::optional<Core::Crypto::Key128> key = {};
|
||||
std::optional<Core::Crypto::Key128> key;
|
||||
if (encrypted) {
|
||||
if (has_rights_id) {
|
||||
status = Loader::ResultStatus::Success;
|
||||
@@ -442,18 +442,18 @@ std::optional<Core::Crypto::Key128> NCA::GetTitlekey() {
|
||||
memcpy(rights_id.data(), header.rights_id.data(), 16);
|
||||
if (rights_id == u128{}) {
|
||||
status = Loader::ResultStatus::ErrorInvalidRightsID;
|
||||
return {};
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
auto titlekey = keys.GetKey(Core::Crypto::S128KeyType::Titlekey, rights_id[1], rights_id[0]);
|
||||
if (titlekey == Core::Crypto::Key128{}) {
|
||||
status = Loader::ResultStatus::ErrorMissingTitlekey;
|
||||
return {};
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
if (!keys.HasKey(Core::Crypto::S128KeyType::Titlekek, master_key_id)) {
|
||||
status = Loader::ResultStatus::ErrorMissingTitlekek;
|
||||
return {};
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
Core::Crypto::AESCipher<Core::Crypto::Key128> cipher(
|
||||
@@ -477,7 +477,7 @@ VirtualFile NCA::Decrypt(const NCASectionHeader& s_header, VirtualFile in, u64 s
|
||||
case NCASectionCryptoType::BKTR:
|
||||
LOG_TRACE(Crypto, "called with mode=CTR, starting_offset={:016X}", starting_offset);
|
||||
{
|
||||
std::optional<Core::Crypto::Key128> key = {};
|
||||
std::optional<Core::Crypto::Key128> key;
|
||||
if (has_rights_id) {
|
||||
status = Loader::ResultStatus::Success;
|
||||
key = GetTitlekey();
|
||||
|
||||
@@ -245,9 +245,11 @@ void IPSwitchCompiler::Parse() {
|
||||
|
||||
// Read rest of patch
|
||||
while (true) {
|
||||
if (i + 1 >= lines.size())
|
||||
if (i + 1 >= lines.size()) {
|
||||
break;
|
||||
const auto patch_line = lines[++i];
|
||||
}
|
||||
|
||||
const auto& patch_line = lines[++i];
|
||||
|
||||
// Start of new patch
|
||||
if (StartsWith(patch_line, "@enabled") || StartsWith(patch_line, "@disabled")) {
|
||||
|
||||
@@ -267,9 +267,9 @@ void NSP::ReadNCAs(const std::vector<VirtualFile>& files) {
|
||||
}
|
||||
|
||||
const CNMT cnmt(inner_file);
|
||||
auto& ncas_title = ncas[cnmt.GetTitleID()];
|
||||
|
||||
ncas_title[{cnmt.GetType(), ContentRecordType::Meta}] = nca;
|
||||
ncas[cnmt.GetTitleID()][{cnmt.GetType(), ContentRecordType::Meta}] = nca;
|
||||
|
||||
for (const auto& rec : cnmt.GetContentRecords()) {
|
||||
const auto id_string = Common::HexToString(rec.nca_id, false);
|
||||
auto next_file = pfs->GetFile(fmt::format("{}.nca", id_string));
|
||||
@@ -286,13 +286,32 @@ void NSP::ReadNCAs(const std::vector<VirtualFile>& files) {
|
||||
}
|
||||
|
||||
auto next_nca = std::make_shared<NCA>(std::move(next_file), nullptr, 0);
|
||||
|
||||
if (next_nca->GetType() == NCAContentType::Program) {
|
||||
program_status[cnmt.GetTitleID()] = next_nca->GetStatus();
|
||||
program_status[next_nca->GetTitleId()] = next_nca->GetStatus();
|
||||
}
|
||||
if (next_nca->GetStatus() == Loader::ResultStatus::Success ||
|
||||
(next_nca->GetStatus() == Loader::ResultStatus::ErrorMissingBKTRBaseRomFS &&
|
||||
(cnmt.GetTitleID() & 0x800) != 0)) {
|
||||
ncas_title[{cnmt.GetType(), rec.type}] = std::move(next_nca);
|
||||
|
||||
if (next_nca->GetStatus() != Loader::ResultStatus::Success &&
|
||||
next_nca->GetStatus() != Loader::ResultStatus::ErrorMissingBKTRBaseRomFS) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// If the last 3 hexadecimal digits of the CNMT TitleID is 0x800 or is missing the
|
||||
// BKTRBaseRomFS, this is an update NCA. Otherwise, this is a base NCA.
|
||||
if ((cnmt.GetTitleID() & 0x800) != 0 ||
|
||||
next_nca->GetStatus() == Loader::ResultStatus::ErrorMissingBKTRBaseRomFS) {
|
||||
// If the last 3 hexadecimal digits of the NCA's TitleID is between 0x1 and
|
||||
// 0x7FF, this is a multi-program update NCA. Otherwise, this is a regular
|
||||
// update NCA.
|
||||
if ((next_nca->GetTitleId() & 0x7FF) != 0 &&
|
||||
(next_nca->GetTitleId() & 0x800) == 0) {
|
||||
ncas[next_nca->GetTitleId()][{cnmt.GetType(), rec.type}] =
|
||||
std::move(next_nca);
|
||||
} else {
|
||||
ncas[cnmt.GetTitleID()][{cnmt.GetType(), rec.type}] = std::move(next_nca);
|
||||
}
|
||||
} else {
|
||||
ncas[next_nca->GetTitleId()][{cnmt.GetType(), rec.type}] = std::move(next_nca);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -169,11 +169,12 @@ VfsDirectory::~VfsDirectory() = default;
|
||||
|
||||
std::optional<u8> VfsFile::ReadByte(std::size_t offset) const {
|
||||
u8 out{};
|
||||
std::size_t size = Read(&out, 1, offset);
|
||||
if (size == 1)
|
||||
const std::size_t size = Read(&out, sizeof(u8), offset);
|
||||
if (size == 1) {
|
||||
return out;
|
||||
}
|
||||
|
||||
return {};
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
std::vector<u8> VfsFile::ReadBytes(std::size_t size, std::size_t offset) const {
|
||||
|
||||
@@ -58,10 +58,11 @@ std::size_t OffsetVfsFile::Write(const u8* data, std::size_t length, std::size_t
|
||||
}
|
||||
|
||||
std::optional<u8> OffsetVfsFile::ReadByte(std::size_t r_offset) const {
|
||||
if (r_offset < size)
|
||||
return file->ReadByte(offset + r_offset);
|
||||
if (r_offset >= size) {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
return {};
|
||||
return file->ReadByte(offset + r_offset);
|
||||
}
|
||||
|
||||
std::vector<u8> OffsetVfsFile::ReadBytes(std::size_t r_size, std::size_t r_offset) const {
|
||||
|
||||
@@ -54,9 +54,11 @@ public:
|
||||
}
|
||||
|
||||
std::optional<u8> ReadByte(std::size_t offset) const override {
|
||||
if (offset < size)
|
||||
return value;
|
||||
return {};
|
||||
if (offset >= size) {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
std::vector<u8> ReadBytes(std::size_t length, std::size_t offset) const override {
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
|
||||
#include "common/assert.h"
|
||||
#include "common/logging/log.h"
|
||||
#include "core/core.h"
|
||||
#include "core/frontend/applets/controller.h"
|
||||
#include "core/hle/service/hid/controllers/npad.h"
|
||||
#include "core/hle/service/hid/hid.h"
|
||||
@@ -14,6 +13,9 @@ namespace Core::Frontend {
|
||||
|
||||
ControllerApplet::~ControllerApplet() = default;
|
||||
|
||||
DefaultControllerApplet::DefaultControllerApplet(Service::SM::ServiceManager& service_manager_)
|
||||
: service_manager{service_manager_} {}
|
||||
|
||||
DefaultControllerApplet::~DefaultControllerApplet() = default;
|
||||
|
||||
void DefaultControllerApplet::ReconfigureControllers(std::function<void()> callback,
|
||||
@@ -21,9 +23,7 @@ void DefaultControllerApplet::ReconfigureControllers(std::function<void()> callb
|
||||
LOG_INFO(Service_HID, "called, deducing the best configuration based on the given parameters!");
|
||||
|
||||
auto& npad =
|
||||
Core::System::GetInstance()
|
||||
.ServiceManager()
|
||||
.GetService<Service::HID::Hid>("hid")
|
||||
service_manager.GetService<Service::HID::Hid>("hid")
|
||||
->GetAppletResource()
|
||||
->GetController<Service::HID::Controller_NPad>(Service::HID::HidController::NPad);
|
||||
|
||||
|
||||
@@ -8,6 +8,10 @@
|
||||
|
||||
#include "common/common_types.h"
|
||||
|
||||
namespace Service::SM {
|
||||
class ServiceManager;
|
||||
}
|
||||
|
||||
namespace Core::Frontend {
|
||||
|
||||
using BorderColor = std::array<u8, 4>;
|
||||
@@ -39,10 +43,14 @@ public:
|
||||
|
||||
class DefaultControllerApplet final : public ControllerApplet {
|
||||
public:
|
||||
explicit DefaultControllerApplet(Service::SM::ServiceManager& service_manager_);
|
||||
~DefaultControllerApplet() override;
|
||||
|
||||
void ReconfigureControllers(std::function<void()> callback,
|
||||
ControllerParameters parameters) const override;
|
||||
|
||||
private:
|
||||
Service::SM::ServiceManager& service_manager;
|
||||
};
|
||||
|
||||
} // namespace Core::Frontend
|
||||
|
||||
@@ -33,6 +33,9 @@ public:
|
||||
virtual bool GetAnalogDirectionStatus(AnalogDirection direction) const {
|
||||
return {};
|
||||
}
|
||||
virtual bool SetRumblePlay(f32 amp_high, f32 amp_low, f32 freq_high, f32 freq_low) const {
|
||||
return {};
|
||||
}
|
||||
};
|
||||
|
||||
/// An abstract class template for a factory that can create input devices.
|
||||
|
||||
@@ -774,6 +774,17 @@ void Module::Interface::ListQualifiedUsers(Kernel::HLERequestContext& ctx) {
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
}
|
||||
|
||||
void Module::Interface::LoadOpenContext(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_ACC, "(STUBBED) called");
|
||||
|
||||
// This is similar to GetBaasAccountManagerForApplication
|
||||
// This command is used concurrently with ListOpenContextStoredUsers
|
||||
// TODO: Find the differences between this and GetBaasAccountManagerForApplication
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushIpcInterface<IManagerForApplication>(profile_manager->GetLastOpenedUser());
|
||||
}
|
||||
|
||||
void Module::Interface::ListOpenContextStoredUsers(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_ACC, "(STUBBED) called");
|
||||
|
||||
|
||||
@@ -34,6 +34,7 @@ public:
|
||||
void IsUserAccountSwitchLocked(Kernel::HLERequestContext& ctx);
|
||||
void GetProfileEditor(Kernel::HLERequestContext& ctx);
|
||||
void ListQualifiedUsers(Kernel::HLERequestContext& ctx);
|
||||
void LoadOpenContext(Kernel::HLERequestContext& ctx);
|
||||
void ListOpenContextStoredUsers(Kernel::HLERequestContext& ctx);
|
||||
|
||||
private:
|
||||
|
||||
@@ -29,7 +29,7 @@ ACC_U0::ACC_U0(std::shared_ptr<Module> module, std::shared_ptr<ProfileManager> p
|
||||
{110, nullptr, "StoreSaveDataThumbnail"},
|
||||
{111, nullptr, "ClearSaveDataThumbnail"},
|
||||
{120, nullptr, "CreateGuestLoginRequest"},
|
||||
{130, nullptr, "LoadOpenContext"}, // 5.0.0+
|
||||
{130, &ACC_U0::LoadOpenContext, "LoadOpenContext"}, // 5.0.0+
|
||||
{131, &ACC_U0::ListOpenContextStoredUsers, "ListOpenContextStoredUsers"}, // 6.0.0+
|
||||
{140, &ACC_U0::InitializeApplicationInfoRestricted, "InitializeApplicationInfoRestricted"}, // 6.0.0+
|
||||
{141, &ACC_U0::ListQualifiedUsers, "ListQualifiedUsers"}, // 6.0.0+
|
||||
|
||||
@@ -1192,7 +1192,7 @@ IApplicationFunctions::IApplicationFunctions(Core::System& system_)
|
||||
{120, nullptr, "ExecuteProgram"},
|
||||
{121, nullptr, "ClearUserChannel"},
|
||||
{122, nullptr, "UnpopToUserChannel"},
|
||||
{123, nullptr, "GetPreviousProgramIndex"},
|
||||
{123, &IApplicationFunctions::GetPreviousProgramIndex, "GetPreviousProgramIndex"},
|
||||
{124, nullptr, "EnableApplicationAllThreadDumpOnCrash"},
|
||||
{130, &IApplicationFunctions::GetGpuErrorDetectedSystemEvent, "GetGpuErrorDetectedSystemEvent"},
|
||||
{140, &IApplicationFunctions::GetFriendInvitationStorageChannelEvent, "GetFriendInvitationStorageChannelEvent"},
|
||||
@@ -1554,6 +1554,14 @@ void IApplicationFunctions::QueryApplicationPlayStatisticsByUid(Kernel::HLEReque
|
||||
rb.Push<u32>(0);
|
||||
}
|
||||
|
||||
void IApplicationFunctions::GetPreviousProgramIndex(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.Push<s32>(previous_program_index);
|
||||
}
|
||||
|
||||
void IApplicationFunctions::GetGpuErrorDetectedSystemEvent(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
|
||||
|
||||
@@ -288,11 +288,13 @@ private:
|
||||
void SetApplicationCopyrightVisibility(Kernel::HLERequestContext& ctx);
|
||||
void QueryApplicationPlayStatistics(Kernel::HLERequestContext& ctx);
|
||||
void QueryApplicationPlayStatisticsByUid(Kernel::HLERequestContext& ctx);
|
||||
void GetPreviousProgramIndex(Kernel::HLERequestContext& ctx);
|
||||
void GetGpuErrorDetectedSystemEvent(Kernel::HLERequestContext& ctx);
|
||||
void GetFriendInvitationStorageChannelEvent(Kernel::HLERequestContext& ctx);
|
||||
|
||||
bool launch_popped_application_specific = false;
|
||||
bool launch_popped_account_preselect = false;
|
||||
s32 previous_program_index{-1};
|
||||
Kernel::EventPair gpu_error_detected_event;
|
||||
Kernel::EventPair friend_invitation_storage_channel_event;
|
||||
Core::System& system;
|
||||
|
||||
@@ -206,7 +206,8 @@ void AppletManager::SetDefaultAppletFrontendSet() {
|
||||
|
||||
void AppletManager::SetDefaultAppletsIfMissing() {
|
||||
if (frontend.controller == nullptr) {
|
||||
frontend.controller = std::make_unique<Core::Frontend::DefaultControllerApplet>();
|
||||
frontend.controller =
|
||||
std::make_unique<Core::Frontend::DefaultControllerApplet>(system.ServiceManager());
|
||||
}
|
||||
|
||||
if (frontend.e_commerce == nullptr) {
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "common/logging/log.h"
|
||||
#include "core/hle/ipc_helpers.h"
|
||||
#include "core/hle/service/caps/caps_c.h"
|
||||
|
||||
namespace Service::Capture {
|
||||
@@ -47,7 +49,7 @@ CAPS_C::CAPS_C() : ServiceFramework("caps:c") {
|
||||
static const FunctionInfo functions[] = {
|
||||
{1, nullptr, "CaptureRawImage"},
|
||||
{2, nullptr, "CaptureRawImageWithTimeout"},
|
||||
{33, nullptr, "Unknown33"},
|
||||
{33, &CAPS_C::SetShimLibraryVersion, "SetShimLibraryVersion"},
|
||||
{1001, nullptr, "RequestTakingScreenShot"},
|
||||
{1002, nullptr, "RequestTakingScreenShotWithTimeout"},
|
||||
{1011, nullptr, "NotifyTakingScreenShotRefused"},
|
||||
@@ -72,4 +74,16 @@ CAPS_C::CAPS_C() : ServiceFramework("caps:c") {
|
||||
|
||||
CAPS_C::~CAPS_C() = default;
|
||||
|
||||
void CAPS_C::SetShimLibraryVersion(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
const auto library_version{rp.Pop<u64>()};
|
||||
const auto applet_resource_user_id{rp.Pop<u64>()};
|
||||
|
||||
LOG_WARNING(Service_Capture, "(STUBBED) called. library_version={}, applet_resource_user_id={}",
|
||||
library_version, applet_resource_user_id);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
}
|
||||
|
||||
} // namespace Service::Capture
|
||||
|
||||
@@ -16,6 +16,9 @@ class CAPS_C final : public ServiceFramework<CAPS_C> {
|
||||
public:
|
||||
explicit CAPS_C();
|
||||
~CAPS_C() override;
|
||||
|
||||
private:
|
||||
void SetShimLibraryVersion(Kernel::HLERequestContext& ctx);
|
||||
};
|
||||
|
||||
} // namespace Service::Capture
|
||||
|
||||
@@ -25,7 +25,12 @@ CAPS_SU::CAPS_SU() : ServiceFramework("caps:su") {
|
||||
CAPS_SU::~CAPS_SU() = default;
|
||||
|
||||
void CAPS_SU::SetShimLibraryVersion(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_Capture, "(STUBBED) called");
|
||||
IPC::RequestParser rp{ctx};
|
||||
const auto library_version{rp.Pop<u64>()};
|
||||
const auto applet_resource_user_id{rp.Pop<u64>()};
|
||||
|
||||
LOG_WARNING(Service_Capture, "(STUBBED) called. library_version={}, applet_resource_user_id={}",
|
||||
library_version, applet_resource_user_id);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
|
||||
@@ -31,8 +31,7 @@ public:
|
||||
CAPS_U::CAPS_U() : ServiceFramework("caps:u") {
|
||||
// clang-format off
|
||||
static const FunctionInfo functions[] = {
|
||||
{31, nullptr, "GetShimLibraryVersion"},
|
||||
{32, nullptr, "SetShimLibraryVersion"},
|
||||
{32, &CAPS_U::SetShimLibraryVersion, "SetShimLibraryVersion"},
|
||||
{102, &CAPS_U::GetAlbumContentsFileListForApplication, "GetAlbumContentsFileListForApplication"},
|
||||
{103, nullptr, "DeleteAlbumContentsFileForApplication"},
|
||||
{104, nullptr, "GetAlbumContentsFileSizeForApplication"},
|
||||
@@ -53,6 +52,18 @@ CAPS_U::CAPS_U() : ServiceFramework("caps:u") {
|
||||
|
||||
CAPS_U::~CAPS_U() = default;
|
||||
|
||||
void CAPS_U::SetShimLibraryVersion(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
const auto library_version{rp.Pop<u64>()};
|
||||
const auto applet_resource_user_id{rp.Pop<u64>()};
|
||||
|
||||
LOG_WARNING(Service_Capture, "(STUBBED) called. library_version={}, applet_resource_user_id={}",
|
||||
library_version, applet_resource_user_id);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
}
|
||||
|
||||
void CAPS_U::GetAlbumContentsFileListForApplication(Kernel::HLERequestContext& ctx) {
|
||||
// Takes a type-0x6 output buffer containing an array of ApplicationAlbumFileEntry, a PID, an
|
||||
// u8 ContentType, two s64s, and an u64 AppletResourceUserId. Returns an output u64 for total
|
||||
|
||||
@@ -18,6 +18,7 @@ public:
|
||||
~CAPS_U() override;
|
||||
|
||||
private:
|
||||
void SetShimLibraryVersion(Kernel::HLERequestContext& ctx);
|
||||
void GetAlbumContentsFileListForApplication(Kernel::HLERequestContext& ctx);
|
||||
};
|
||||
|
||||
|
||||
@@ -31,6 +31,10 @@ public:
|
||||
virtual void OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data,
|
||||
std::size_t size) = 0;
|
||||
|
||||
// When the controller is requesting a motion update for the shared memory
|
||||
virtual void OnMotionUpdate(const Core::Timing::CoreTiming& core_timing, u8* data,
|
||||
std::size_t size) {}
|
||||
|
||||
// Called when input devices should be loaded
|
||||
virtual void OnLoadInputDevices() = 0;
|
||||
|
||||
|
||||
@@ -260,7 +260,7 @@ void Controller_NPad::OnRelease() {}
|
||||
|
||||
void Controller_NPad::RequestPadStateUpdate(u32 npad_id) {
|
||||
const auto controller_idx = NPadIdToIndex(npad_id);
|
||||
[[maybe_unused]] const auto controller_type = connected_controllers[controller_idx].type;
|
||||
const auto controller_type = connected_controllers[controller_idx].type;
|
||||
if (!connected_controllers[controller_idx].is_connected) {
|
||||
return;
|
||||
}
|
||||
@@ -276,54 +276,63 @@ void Controller_NPad::RequestPadStateUpdate(u32 npad_id) {
|
||||
analog_state[static_cast<std::size_t>(JoystickId::Joystick_Right)]->GetStatus();
|
||||
|
||||
using namespace Settings::NativeButton;
|
||||
pad_state.a.Assign(button_state[A - BUTTON_HID_BEGIN]->GetStatus());
|
||||
pad_state.b.Assign(button_state[B - BUTTON_HID_BEGIN]->GetStatus());
|
||||
pad_state.x.Assign(button_state[X - BUTTON_HID_BEGIN]->GetStatus());
|
||||
pad_state.y.Assign(button_state[Y - BUTTON_HID_BEGIN]->GetStatus());
|
||||
pad_state.l_stick.Assign(button_state[LStick - BUTTON_HID_BEGIN]->GetStatus());
|
||||
pad_state.r_stick.Assign(button_state[RStick - BUTTON_HID_BEGIN]->GetStatus());
|
||||
pad_state.l.Assign(button_state[L - BUTTON_HID_BEGIN]->GetStatus());
|
||||
pad_state.r.Assign(button_state[R - BUTTON_HID_BEGIN]->GetStatus());
|
||||
pad_state.zl.Assign(button_state[ZL - BUTTON_HID_BEGIN]->GetStatus());
|
||||
pad_state.zr.Assign(button_state[ZR - BUTTON_HID_BEGIN]->GetStatus());
|
||||
pad_state.plus.Assign(button_state[Plus - BUTTON_HID_BEGIN]->GetStatus());
|
||||
pad_state.minus.Assign(button_state[Minus - BUTTON_HID_BEGIN]->GetStatus());
|
||||
if (controller_type != NPadControllerType::JoyLeft) {
|
||||
pad_state.a.Assign(button_state[A - BUTTON_HID_BEGIN]->GetStatus());
|
||||
pad_state.b.Assign(button_state[B - BUTTON_HID_BEGIN]->GetStatus());
|
||||
pad_state.x.Assign(button_state[X - BUTTON_HID_BEGIN]->GetStatus());
|
||||
pad_state.y.Assign(button_state[Y - BUTTON_HID_BEGIN]->GetStatus());
|
||||
pad_state.r_stick.Assign(button_state[RStick - BUTTON_HID_BEGIN]->GetStatus());
|
||||
pad_state.r.Assign(button_state[R - BUTTON_HID_BEGIN]->GetStatus());
|
||||
pad_state.zr.Assign(button_state[ZR - BUTTON_HID_BEGIN]->GetStatus());
|
||||
pad_state.plus.Assign(button_state[Plus - BUTTON_HID_BEGIN]->GetStatus());
|
||||
|
||||
pad_state.d_left.Assign(button_state[DLeft - BUTTON_HID_BEGIN]->GetStatus());
|
||||
pad_state.d_up.Assign(button_state[DUp - BUTTON_HID_BEGIN]->GetStatus());
|
||||
pad_state.d_right.Assign(button_state[DRight - BUTTON_HID_BEGIN]->GetStatus());
|
||||
pad_state.d_down.Assign(button_state[DDown - BUTTON_HID_BEGIN]->GetStatus());
|
||||
pad_state.r_stick_right.Assign(
|
||||
analog_state[static_cast<std::size_t>(JoystickId::Joystick_Right)]
|
||||
->GetAnalogDirectionStatus(Input::AnalogDirection::RIGHT));
|
||||
pad_state.r_stick_left.Assign(
|
||||
analog_state[static_cast<std::size_t>(JoystickId::Joystick_Right)]
|
||||
->GetAnalogDirectionStatus(Input::AnalogDirection::LEFT));
|
||||
pad_state.r_stick_up.Assign(
|
||||
analog_state[static_cast<std::size_t>(JoystickId::Joystick_Right)]
|
||||
->GetAnalogDirectionStatus(Input::AnalogDirection::UP));
|
||||
pad_state.r_stick_down.Assign(
|
||||
analog_state[static_cast<std::size_t>(JoystickId::Joystick_Right)]
|
||||
->GetAnalogDirectionStatus(Input::AnalogDirection::DOWN));
|
||||
rstick_entry.x = static_cast<s32>(stick_r_x_f * HID_JOYSTICK_MAX);
|
||||
rstick_entry.y = static_cast<s32>(stick_r_y_f * HID_JOYSTICK_MAX);
|
||||
}
|
||||
|
||||
pad_state.l_stick_right.Assign(
|
||||
analog_state[static_cast<std::size_t>(JoystickId::Joystick_Left)]->GetAnalogDirectionStatus(
|
||||
Input::AnalogDirection::RIGHT));
|
||||
pad_state.l_stick_left.Assign(
|
||||
analog_state[static_cast<std::size_t>(JoystickId::Joystick_Left)]->GetAnalogDirectionStatus(
|
||||
Input::AnalogDirection::LEFT));
|
||||
pad_state.l_stick_up.Assign(
|
||||
analog_state[static_cast<std::size_t>(JoystickId::Joystick_Left)]->GetAnalogDirectionStatus(
|
||||
Input::AnalogDirection::UP));
|
||||
pad_state.l_stick_down.Assign(
|
||||
analog_state[static_cast<std::size_t>(JoystickId::Joystick_Left)]->GetAnalogDirectionStatus(
|
||||
Input::AnalogDirection::DOWN));
|
||||
if (controller_type != NPadControllerType::JoyRight) {
|
||||
pad_state.d_left.Assign(button_state[DLeft - BUTTON_HID_BEGIN]->GetStatus());
|
||||
pad_state.d_up.Assign(button_state[DUp - BUTTON_HID_BEGIN]->GetStatus());
|
||||
pad_state.d_right.Assign(button_state[DRight - BUTTON_HID_BEGIN]->GetStatus());
|
||||
pad_state.d_down.Assign(button_state[DDown - BUTTON_HID_BEGIN]->GetStatus());
|
||||
pad_state.l_stick.Assign(button_state[LStick - BUTTON_HID_BEGIN]->GetStatus());
|
||||
pad_state.l.Assign(button_state[L - BUTTON_HID_BEGIN]->GetStatus());
|
||||
pad_state.zl.Assign(button_state[ZL - BUTTON_HID_BEGIN]->GetStatus());
|
||||
pad_state.minus.Assign(button_state[Minus - BUTTON_HID_BEGIN]->GetStatus());
|
||||
|
||||
pad_state.r_stick_right.Assign(
|
||||
analog_state[static_cast<std::size_t>(JoystickId::Joystick_Right)]
|
||||
->GetAnalogDirectionStatus(Input::AnalogDirection::RIGHT));
|
||||
pad_state.r_stick_left.Assign(analog_state[static_cast<std::size_t>(JoystickId::Joystick_Right)]
|
||||
->GetAnalogDirectionStatus(Input::AnalogDirection::LEFT));
|
||||
pad_state.r_stick_up.Assign(analog_state[static_cast<std::size_t>(JoystickId::Joystick_Right)]
|
||||
->GetAnalogDirectionStatus(Input::AnalogDirection::UP));
|
||||
pad_state.r_stick_down.Assign(analog_state[static_cast<std::size_t>(JoystickId::Joystick_Right)]
|
||||
->GetAnalogDirectionStatus(Input::AnalogDirection::DOWN));
|
||||
pad_state.l_stick_right.Assign(
|
||||
analog_state[static_cast<std::size_t>(JoystickId::Joystick_Left)]
|
||||
->GetAnalogDirectionStatus(Input::AnalogDirection::RIGHT));
|
||||
pad_state.l_stick_left.Assign(
|
||||
analog_state[static_cast<std::size_t>(JoystickId::Joystick_Left)]
|
||||
->GetAnalogDirectionStatus(Input::AnalogDirection::LEFT));
|
||||
pad_state.l_stick_up.Assign(
|
||||
analog_state[static_cast<std::size_t>(JoystickId::Joystick_Left)]
|
||||
->GetAnalogDirectionStatus(Input::AnalogDirection::UP));
|
||||
pad_state.l_stick_down.Assign(
|
||||
analog_state[static_cast<std::size_t>(JoystickId::Joystick_Left)]
|
||||
->GetAnalogDirectionStatus(Input::AnalogDirection::DOWN));
|
||||
lstick_entry.x = static_cast<s32>(stick_l_x_f * HID_JOYSTICK_MAX);
|
||||
lstick_entry.y = static_cast<s32>(stick_l_y_f * HID_JOYSTICK_MAX);
|
||||
}
|
||||
|
||||
pad_state.left_sl.Assign(button_state[SL - BUTTON_HID_BEGIN]->GetStatus());
|
||||
pad_state.left_sr.Assign(button_state[SR - BUTTON_HID_BEGIN]->GetStatus());
|
||||
|
||||
lstick_entry.x = static_cast<s32>(stick_l_x_f * HID_JOYSTICK_MAX);
|
||||
lstick_entry.y = static_cast<s32>(stick_l_y_f * HID_JOYSTICK_MAX);
|
||||
rstick_entry.x = static_cast<s32>(stick_r_x_f * HID_JOYSTICK_MAX);
|
||||
rstick_entry.y = static_cast<s32>(stick_r_y_f * HID_JOYSTICK_MAX);
|
||||
if (controller_type == NPadControllerType::JoyLeft ||
|
||||
controller_type == NPadControllerType::JoyRight) {
|
||||
pad_state.left_sl.Assign(button_state[SL - BUTTON_HID_BEGIN]->GetStatus());
|
||||
pad_state.left_sr.Assign(button_state[SR - BUTTON_HID_BEGIN]->GetStatus());
|
||||
}
|
||||
}
|
||||
|
||||
void Controller_NPad::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data,
|
||||
@@ -365,44 +374,6 @@ void Controller_NPad::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8*
|
||||
}
|
||||
const u32 npad_index = static_cast<u32>(i);
|
||||
|
||||
const std::array<SixAxisGeneric*, 6> controller_sixaxes{
|
||||
&npad.sixaxis_full, &npad.sixaxis_handheld, &npad.sixaxis_dual_left,
|
||||
&npad.sixaxis_dual_right, &npad.sixaxis_left, &npad.sixaxis_right,
|
||||
};
|
||||
|
||||
for (auto* sixaxis_sensor : controller_sixaxes) {
|
||||
sixaxis_sensor->common.entry_count = 16;
|
||||
sixaxis_sensor->common.total_entry_count = 17;
|
||||
|
||||
const auto& last_entry =
|
||||
sixaxis_sensor->sixaxis[sixaxis_sensor->common.last_entry_index];
|
||||
|
||||
sixaxis_sensor->common.timestamp = core_timing.GetCPUTicks();
|
||||
sixaxis_sensor->common.last_entry_index =
|
||||
(sixaxis_sensor->common.last_entry_index + 1) % 17;
|
||||
|
||||
auto& cur_entry = sixaxis_sensor->sixaxis[sixaxis_sensor->common.last_entry_index];
|
||||
|
||||
cur_entry.timestamp = last_entry.timestamp + 1;
|
||||
cur_entry.timestamp2 = cur_entry.timestamp;
|
||||
}
|
||||
|
||||
// Try to read sixaxis sensor states
|
||||
std::array<MotionDevice, 2> motion_devices;
|
||||
|
||||
if (sixaxis_sensors_enabled && Settings::values.motion_enabled) {
|
||||
sixaxis_at_rest = true;
|
||||
for (std::size_t e = 0; e < motion_devices.size(); ++e) {
|
||||
const auto& device = motions[i][e];
|
||||
if (device) {
|
||||
std::tie(motion_devices[e].accel, motion_devices[e].gyro,
|
||||
motion_devices[e].rotation, motion_devices[e].orientation) =
|
||||
device->GetStatus();
|
||||
sixaxis_at_rest = sixaxis_at_rest && motion_devices[e].gyro.Length2() < 0.0001f;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
RequestPadStateUpdate(npad_index);
|
||||
auto& pad_state = npad_pad_states[npad_index];
|
||||
|
||||
@@ -446,13 +417,6 @@ void Controller_NPad::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8*
|
||||
main_controller.pad.r_stick = pad_state.r_stick;
|
||||
|
||||
libnx_entry.connection_status.IsWired.Assign(1);
|
||||
|
||||
if (sixaxis_sensors_enabled && motions[i][0]) {
|
||||
full_sixaxis_entry.accel = motion_devices[0].accel;
|
||||
full_sixaxis_entry.gyro = motion_devices[0].gyro;
|
||||
full_sixaxis_entry.rotation = motion_devices[0].rotation;
|
||||
full_sixaxis_entry.orientation = motion_devices[0].orientation;
|
||||
}
|
||||
break;
|
||||
case NPadControllerType::Handheld:
|
||||
handheld_entry.connection_status.raw = 0;
|
||||
@@ -471,13 +435,6 @@ void Controller_NPad::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8*
|
||||
libnx_entry.connection_status.IsRightJoyConnected.Assign(1);
|
||||
libnx_entry.connection_status.IsLeftJoyWired.Assign(1);
|
||||
libnx_entry.connection_status.IsRightJoyWired.Assign(1);
|
||||
|
||||
if (sixaxis_sensors_enabled && motions[i][0]) {
|
||||
handheld_sixaxis_entry.accel = motion_devices[0].accel;
|
||||
handheld_sixaxis_entry.gyro = motion_devices[0].gyro;
|
||||
handheld_sixaxis_entry.rotation = motion_devices[0].rotation;
|
||||
handheld_sixaxis_entry.orientation = motion_devices[0].orientation;
|
||||
}
|
||||
break;
|
||||
case NPadControllerType::JoyDual:
|
||||
dual_entry.connection_status.raw = 0;
|
||||
@@ -490,21 +447,6 @@ void Controller_NPad::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8*
|
||||
|
||||
libnx_entry.connection_status.IsLeftJoyConnected.Assign(1);
|
||||
libnx_entry.connection_status.IsRightJoyConnected.Assign(1);
|
||||
|
||||
if (sixaxis_sensors_enabled && motions[i][0]) {
|
||||
// Set motion for the left joycon
|
||||
dual_left_sixaxis_entry.accel = motion_devices[0].accel;
|
||||
dual_left_sixaxis_entry.gyro = motion_devices[0].gyro;
|
||||
dual_left_sixaxis_entry.rotation = motion_devices[0].rotation;
|
||||
dual_left_sixaxis_entry.orientation = motion_devices[0].orientation;
|
||||
}
|
||||
if (sixaxis_sensors_enabled && motions[i][1]) {
|
||||
// Set motion for the right joycon
|
||||
dual_right_sixaxis_entry.accel = motion_devices[1].accel;
|
||||
dual_right_sixaxis_entry.gyro = motion_devices[1].gyro;
|
||||
dual_right_sixaxis_entry.rotation = motion_devices[1].rotation;
|
||||
dual_right_sixaxis_entry.orientation = motion_devices[1].orientation;
|
||||
}
|
||||
break;
|
||||
case NPadControllerType::JoyLeft:
|
||||
left_entry.connection_status.raw = 0;
|
||||
@@ -515,13 +457,6 @@ void Controller_NPad::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8*
|
||||
left_entry.pad.r_stick = pad_state.r_stick;
|
||||
|
||||
libnx_entry.connection_status.IsLeftJoyConnected.Assign(1);
|
||||
|
||||
if (sixaxis_sensors_enabled && motions[i][0]) {
|
||||
left_sixaxis_entry.accel = motion_devices[0].accel;
|
||||
left_sixaxis_entry.gyro = motion_devices[0].gyro;
|
||||
left_sixaxis_entry.rotation = motion_devices[0].rotation;
|
||||
left_sixaxis_entry.orientation = motion_devices[0].orientation;
|
||||
}
|
||||
break;
|
||||
case NPadControllerType::JoyRight:
|
||||
right_entry.connection_status.raw = 0;
|
||||
@@ -532,13 +467,6 @@ void Controller_NPad::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8*
|
||||
right_entry.pad.r_stick = pad_state.r_stick;
|
||||
|
||||
libnx_entry.connection_status.IsRightJoyConnected.Assign(1);
|
||||
|
||||
if (sixaxis_sensors_enabled && motions[i][1]) {
|
||||
right_sixaxis_entry.accel = motion_devices[1].accel;
|
||||
right_sixaxis_entry.gyro = motion_devices[1].gyro;
|
||||
right_sixaxis_entry.rotation = motion_devices[1].rotation;
|
||||
right_sixaxis_entry.orientation = motion_devices[1].orientation;
|
||||
}
|
||||
break;
|
||||
case NPadControllerType::Pokeball:
|
||||
pokeball_entry.connection_status.raw = 0;
|
||||
@@ -561,6 +489,143 @@ void Controller_NPad::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8*
|
||||
shared_memory_entries.size() * sizeof(NPadEntry));
|
||||
}
|
||||
|
||||
void Controller_NPad::OnMotionUpdate(const Core::Timing::CoreTiming& core_timing, u8* data,
|
||||
std::size_t data_len) {
|
||||
if (!IsControllerActivated()) {
|
||||
return;
|
||||
}
|
||||
for (std::size_t i = 0; i < shared_memory_entries.size(); i++) {
|
||||
auto& npad = shared_memory_entries[i];
|
||||
|
||||
const auto& controller_type = connected_controllers[i].type;
|
||||
|
||||
if (controller_type == NPadControllerType::None || !connected_controllers[i].is_connected) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const std::array<SixAxisGeneric*, 6> controller_sixaxes{
|
||||
&npad.sixaxis_full, &npad.sixaxis_handheld, &npad.sixaxis_dual_left,
|
||||
&npad.sixaxis_dual_right, &npad.sixaxis_left, &npad.sixaxis_right,
|
||||
};
|
||||
|
||||
for (auto* sixaxis_sensor : controller_sixaxes) {
|
||||
sixaxis_sensor->common.entry_count = 16;
|
||||
sixaxis_sensor->common.total_entry_count = 17;
|
||||
|
||||
const auto& last_entry =
|
||||
sixaxis_sensor->sixaxis[sixaxis_sensor->common.last_entry_index];
|
||||
|
||||
sixaxis_sensor->common.timestamp = core_timing.GetCPUTicks();
|
||||
sixaxis_sensor->common.last_entry_index =
|
||||
(sixaxis_sensor->common.last_entry_index + 1) % 17;
|
||||
|
||||
auto& cur_entry = sixaxis_sensor->sixaxis[sixaxis_sensor->common.last_entry_index];
|
||||
|
||||
cur_entry.timestamp = last_entry.timestamp + 1;
|
||||
cur_entry.timestamp2 = cur_entry.timestamp;
|
||||
}
|
||||
|
||||
// Try to read sixaxis sensor states
|
||||
std::array<MotionDevice, 2> motion_devices;
|
||||
|
||||
if (sixaxis_sensors_enabled && Settings::values.motion_enabled) {
|
||||
sixaxis_at_rest = true;
|
||||
for (std::size_t e = 0; e < motion_devices.size(); ++e) {
|
||||
const auto& device = motions[i][e];
|
||||
if (device) {
|
||||
std::tie(motion_devices[e].accel, motion_devices[e].gyro,
|
||||
motion_devices[e].rotation, motion_devices[e].orientation) =
|
||||
device->GetStatus();
|
||||
sixaxis_at_rest = sixaxis_at_rest && motion_devices[e].gyro.Length2() < 0.0001f;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto& main_controller =
|
||||
npad.main_controller_states.npad[npad.main_controller_states.common.last_entry_index];
|
||||
auto& handheld_entry =
|
||||
npad.handheld_states.npad[npad.handheld_states.common.last_entry_index];
|
||||
auto& dual_entry = npad.dual_states.npad[npad.dual_states.common.last_entry_index];
|
||||
auto& left_entry = npad.left_joy_states.npad[npad.left_joy_states.common.last_entry_index];
|
||||
auto& right_entry =
|
||||
npad.right_joy_states.npad[npad.right_joy_states.common.last_entry_index];
|
||||
auto& pokeball_entry =
|
||||
npad.pokeball_states.npad[npad.pokeball_states.common.last_entry_index];
|
||||
auto& libnx_entry = npad.libnx.npad[npad.libnx.common.last_entry_index];
|
||||
|
||||
auto& full_sixaxis_entry =
|
||||
npad.sixaxis_full.sixaxis[npad.sixaxis_full.common.last_entry_index];
|
||||
auto& handheld_sixaxis_entry =
|
||||
npad.sixaxis_handheld.sixaxis[npad.sixaxis_handheld.common.last_entry_index];
|
||||
auto& dual_left_sixaxis_entry =
|
||||
npad.sixaxis_dual_left.sixaxis[npad.sixaxis_dual_left.common.last_entry_index];
|
||||
auto& dual_right_sixaxis_entry =
|
||||
npad.sixaxis_dual_right.sixaxis[npad.sixaxis_dual_right.common.last_entry_index];
|
||||
auto& left_sixaxis_entry =
|
||||
npad.sixaxis_left.sixaxis[npad.sixaxis_left.common.last_entry_index];
|
||||
auto& right_sixaxis_entry =
|
||||
npad.sixaxis_right.sixaxis[npad.sixaxis_right.common.last_entry_index];
|
||||
|
||||
switch (controller_type) {
|
||||
case NPadControllerType::None:
|
||||
UNREACHABLE();
|
||||
break;
|
||||
case NPadControllerType::ProController:
|
||||
if (sixaxis_sensors_enabled && motions[i][0]) {
|
||||
full_sixaxis_entry.accel = motion_devices[0].accel;
|
||||
full_sixaxis_entry.gyro = motion_devices[0].gyro;
|
||||
full_sixaxis_entry.rotation = motion_devices[0].rotation;
|
||||
full_sixaxis_entry.orientation = motion_devices[0].orientation;
|
||||
}
|
||||
break;
|
||||
case NPadControllerType::Handheld:
|
||||
if (sixaxis_sensors_enabled && motions[i][0]) {
|
||||
handheld_sixaxis_entry.accel = motion_devices[0].accel;
|
||||
handheld_sixaxis_entry.gyro = motion_devices[0].gyro;
|
||||
handheld_sixaxis_entry.rotation = motion_devices[0].rotation;
|
||||
handheld_sixaxis_entry.orientation = motion_devices[0].orientation;
|
||||
}
|
||||
break;
|
||||
case NPadControllerType::JoyDual:
|
||||
if (sixaxis_sensors_enabled && motions[i][0]) {
|
||||
// Set motion for the left joycon
|
||||
dual_left_sixaxis_entry.accel = motion_devices[0].accel;
|
||||
dual_left_sixaxis_entry.gyro = motion_devices[0].gyro;
|
||||
dual_left_sixaxis_entry.rotation = motion_devices[0].rotation;
|
||||
dual_left_sixaxis_entry.orientation = motion_devices[0].orientation;
|
||||
}
|
||||
if (sixaxis_sensors_enabled && motions[i][1]) {
|
||||
// Set motion for the right joycon
|
||||
dual_right_sixaxis_entry.accel = motion_devices[1].accel;
|
||||
dual_right_sixaxis_entry.gyro = motion_devices[1].gyro;
|
||||
dual_right_sixaxis_entry.rotation = motion_devices[1].rotation;
|
||||
dual_right_sixaxis_entry.orientation = motion_devices[1].orientation;
|
||||
}
|
||||
break;
|
||||
case NPadControllerType::JoyLeft:
|
||||
if (sixaxis_sensors_enabled && motions[i][0]) {
|
||||
left_sixaxis_entry.accel = motion_devices[0].accel;
|
||||
left_sixaxis_entry.gyro = motion_devices[0].gyro;
|
||||
left_sixaxis_entry.rotation = motion_devices[0].rotation;
|
||||
left_sixaxis_entry.orientation = motion_devices[0].orientation;
|
||||
}
|
||||
break;
|
||||
case NPadControllerType::JoyRight:
|
||||
if (sixaxis_sensors_enabled && motions[i][1]) {
|
||||
right_sixaxis_entry.accel = motion_devices[1].accel;
|
||||
right_sixaxis_entry.gyro = motion_devices[1].gyro;
|
||||
right_sixaxis_entry.rotation = motion_devices[1].rotation;
|
||||
right_sixaxis_entry.orientation = motion_devices[1].orientation;
|
||||
}
|
||||
break;
|
||||
case NPadControllerType::Pokeball:
|
||||
break;
|
||||
}
|
||||
}
|
||||
std::memcpy(data + NPAD_OFFSET, shared_memory_entries.data(),
|
||||
shared_memory_entries.size() * sizeof(NPadEntry));
|
||||
}
|
||||
|
||||
void Controller_NPad::SetSupportedStyleSet(NPadType style_set) {
|
||||
style.raw = style_set.raw;
|
||||
}
|
||||
@@ -593,6 +658,14 @@ Controller_NPad::NpadHoldType Controller_NPad::GetHoldType() const {
|
||||
return hold_type;
|
||||
}
|
||||
|
||||
void Controller_NPad::SetNpadHandheldActivationMode(NpadHandheldActivationMode activation_mode) {
|
||||
handheld_activation_mode = activation_mode;
|
||||
}
|
||||
|
||||
Controller_NPad::NpadHandheldActivationMode Controller_NPad::GetNpadHandheldActivationMode() const {
|
||||
return handheld_activation_mode;
|
||||
}
|
||||
|
||||
void Controller_NPad::SetNpadMode(u32 npad_id, NPadAssignments assignment_mode) {
|
||||
const std::size_t npad_index = NPadIdToIndex(npad_id);
|
||||
ASSERT(npad_index < shared_memory_entries.size());
|
||||
@@ -601,20 +674,31 @@ void Controller_NPad::SetNpadMode(u32 npad_id, NPadAssignments assignment_mode)
|
||||
}
|
||||
}
|
||||
|
||||
void Controller_NPad::VibrateController(const std::vector<u32>& controller_ids,
|
||||
void Controller_NPad::VibrateController(const std::vector<u32>& controllers,
|
||||
const std::vector<Vibration>& vibrations) {
|
||||
LOG_DEBUG(Service_HID, "(STUBBED) called");
|
||||
LOG_TRACE(Service_HID, "called");
|
||||
|
||||
if (!Settings::values.vibration_enabled || !can_controllers_vibrate) {
|
||||
return;
|
||||
}
|
||||
for (std::size_t i = 0; i < controller_ids.size(); i++) {
|
||||
std::size_t controller_pos = NPadIdToIndex(static_cast<u32>(i));
|
||||
if (connected_controllers[controller_pos].is_connected) {
|
||||
// TODO(ogniK): Vibrate the physical controller
|
||||
bool success = true;
|
||||
for (std::size_t i = 0; i < controllers.size(); ++i) {
|
||||
if (!connected_controllers[i].is_connected) {
|
||||
continue;
|
||||
}
|
||||
using namespace Settings::NativeButton;
|
||||
const auto& button_state = buttons[i];
|
||||
if (button_state[A - BUTTON_HID_BEGIN]) {
|
||||
if (button_state[A - BUTTON_HID_BEGIN]->SetRumblePlay(
|
||||
vibrations[0].amp_high, vibrations[0].amp_low, vibrations[0].freq_high,
|
||||
vibrations[0].freq_low)) {
|
||||
success = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
last_processed_vibration = vibrations.back();
|
||||
if (success) {
|
||||
last_processed_vibration = vibrations.back();
|
||||
}
|
||||
}
|
||||
|
||||
Controller_NPad::Vibration Controller_NPad::GetLastVibration() const {
|
||||
@@ -762,6 +846,15 @@ Controller_NPad::LedPattern Controller_NPad::GetLedPattern(u32 npad_id) {
|
||||
}
|
||||
}
|
||||
|
||||
bool Controller_NPad::IsUnintendedHomeButtonInputProtectionEnabled(u32 npad_id) const {
|
||||
return unintended_home_button_input_protection[NPadIdToIndex(npad_id)];
|
||||
}
|
||||
|
||||
void Controller_NPad::SetUnintendedHomeButtonInputProtectionEnabled(bool is_protection_enabled,
|
||||
u32 npad_id) {
|
||||
unintended_home_button_input_protection[NPadIdToIndex(npad_id)] = is_protection_enabled;
|
||||
}
|
||||
|
||||
void Controller_NPad::SetVibrationEnabled(bool can_vibrate) {
|
||||
can_controllers_vibrate = can_vibrate;
|
||||
}
|
||||
|
||||
@@ -32,6 +32,10 @@ public:
|
||||
// When the controller is requesting an update for the shared memory
|
||||
void OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, std::size_t size) override;
|
||||
|
||||
// When the controller is requesting a motion update for the shared memory
|
||||
void OnMotionUpdate(const Core::Timing::CoreTiming& core_timing, u8* data,
|
||||
std::size_t size) override;
|
||||
|
||||
// Called when input devices should be loaded
|
||||
void OnLoadInputDevices() override;
|
||||
|
||||
@@ -74,6 +78,12 @@ public:
|
||||
Single = 1,
|
||||
};
|
||||
|
||||
enum class NpadHandheldActivationMode : u64 {
|
||||
Dual = 0,
|
||||
Single = 1,
|
||||
None = 2,
|
||||
};
|
||||
|
||||
enum class NPadControllerType {
|
||||
None,
|
||||
ProController,
|
||||
@@ -110,9 +120,12 @@ public:
|
||||
void SetHoldType(NpadHoldType joy_hold_type);
|
||||
NpadHoldType GetHoldType() const;
|
||||
|
||||
void SetNpadHandheldActivationMode(NpadHandheldActivationMode activation_mode);
|
||||
NpadHandheldActivationMode GetNpadHandheldActivationMode() const;
|
||||
|
||||
void SetNpadMode(u32 npad_id, NPadAssignments assignment_mode);
|
||||
|
||||
void VibrateController(const std::vector<u32>& controller_ids,
|
||||
void VibrateController(const std::vector<u32>& controllers,
|
||||
const std::vector<Vibration>& vibrations);
|
||||
|
||||
Vibration GetLastVibration() const;
|
||||
@@ -133,6 +146,8 @@ public:
|
||||
bool IsSixAxisSensorAtRest() const;
|
||||
void SetSixAxisEnabled(bool six_axis_status);
|
||||
LedPattern GetLedPattern(u32 npad_id);
|
||||
bool IsUnintendedHomeButtonInputProtectionEnabled(u32 npad_id) const;
|
||||
void SetUnintendedHomeButtonInputProtectionEnabled(bool is_protection_enabled, u32 npad_id);
|
||||
void SetVibrationEnabled(bool can_vibrate);
|
||||
bool IsVibrationEnabled() const;
|
||||
void ClearAllConnectedControllers();
|
||||
@@ -369,10 +384,12 @@ private:
|
||||
MotionArray motions;
|
||||
std::vector<u32> supported_npad_id_types{};
|
||||
NpadHoldType hold_type{NpadHoldType::Vertical};
|
||||
NpadHandheldActivationMode handheld_activation_mode{NpadHandheldActivationMode::Dual};
|
||||
// Each controller should have their own styleset changed event
|
||||
std::array<Kernel::EventPair, 10> styleset_changed_events;
|
||||
Vibration last_processed_vibration{};
|
||||
std::array<ControllerHolder, 10> connected_controllers{};
|
||||
std::array<bool, 10> unintended_home_button_input_protection{};
|
||||
GyroscopeZeroDriftMode gyroscope_zero_drift_mode{GyroscopeZeroDriftMode::Standard};
|
||||
bool can_controllers_vibrate{true};
|
||||
bool sixaxis_sensors_enabled{true};
|
||||
|
||||
@@ -40,7 +40,8 @@ namespace Service::HID {
|
||||
// Updating period for each HID device.
|
||||
// HID is polled every 15ms, this value was derived from
|
||||
// https://github.com/dekuNukem/Nintendo_Switch_Reverse_Engineering#joy-con-status-data-packet
|
||||
constexpr auto pad_update_ns = std::chrono::nanoseconds{15 * 1000 * 1000}; // (15ms, 66.6Hz)
|
||||
constexpr auto pad_update_ns = std::chrono::nanoseconds{1000 * 1000}; // (1ms, 1000Hz)
|
||||
constexpr auto motion_update_ns = std::chrono::nanoseconds{15 * 1000 * 1000}; // (15ms, 66.666Hz)
|
||||
constexpr std::size_t SHARED_MEMORY_SIZE = 0x40000;
|
||||
|
||||
IAppletResource::IAppletResource(Core::System& system)
|
||||
@@ -79,10 +80,14 @@ IAppletResource::IAppletResource(Core::System& system)
|
||||
[this](std::uintptr_t user_data, std::chrono::nanoseconds ns_late) {
|
||||
UpdateControllers(user_data, ns_late);
|
||||
});
|
||||
|
||||
// TODO(shinyquagsire23): Other update callbacks? (accel, gyro?)
|
||||
motion_update_event = Core::Timing::CreateEvent(
|
||||
"HID::MotionPadCallback",
|
||||
[this](std::uintptr_t user_data, std::chrono::nanoseconds ns_late) {
|
||||
UpdateMotion(user_data, ns_late);
|
||||
});
|
||||
|
||||
system.CoreTiming().ScheduleEvent(pad_update_ns, pad_update_event);
|
||||
system.CoreTiming().ScheduleEvent(motion_update_ns, motion_update_event);
|
||||
|
||||
ReloadInputDevices();
|
||||
}
|
||||
@@ -122,6 +127,16 @@ void IAppletResource::UpdateControllers(std::uintptr_t user_data,
|
||||
core_timing.ScheduleEvent(pad_update_ns - ns_late, pad_update_event);
|
||||
}
|
||||
|
||||
void IAppletResource::UpdateMotion(std::uintptr_t user_data, std::chrono::nanoseconds ns_late) {
|
||||
auto& core_timing = system.CoreTiming();
|
||||
|
||||
for (const auto& controller : controllers) {
|
||||
controller->OnMotionUpdate(core_timing, shared_mem->GetPointer(), SHARED_MEMORY_SIZE);
|
||||
}
|
||||
|
||||
core_timing.ScheduleEvent(motion_update_ns - ns_late, motion_update_event);
|
||||
}
|
||||
|
||||
class IActiveVibrationDeviceList final : public ServiceFramework<IActiveVibrationDeviceList> {
|
||||
public:
|
||||
IActiveVibrationDeviceList() : ServiceFramework("IActiveVibrationDeviceList") {
|
||||
@@ -173,7 +188,7 @@ Hid::Hid(Core::System& system) : ServiceFramework("hid"), system(system) {
|
||||
{66, &Hid::StartSixAxisSensor, "StartSixAxisSensor"},
|
||||
{67, &Hid::StopSixAxisSensor, "StopSixAxisSensor"},
|
||||
{68, nullptr, "IsSixAxisSensorFusionEnabled"},
|
||||
{69, nullptr, "EnableSixAxisSensorFusion"},
|
||||
{69, &Hid::EnableSixAxisSensorFusion, "EnableSixAxisSensorFusion"},
|
||||
{70, nullptr, "SetSixAxisSensorFusionParameters"},
|
||||
{71, nullptr, "GetSixAxisSensorFusionParameters"},
|
||||
{72, nullptr, "ResetSixAxisSensorFusionParameters"},
|
||||
@@ -209,8 +224,8 @@ Hid::Hid(Core::System& system) : ServiceFramework("hid"), system(system) {
|
||||
{128, &Hid::SetNpadHandheldActivationMode, "SetNpadHandheldActivationMode"},
|
||||
{129, &Hid::GetNpadHandheldActivationMode, "GetNpadHandheldActivationMode"},
|
||||
{130, &Hid::SwapNpadAssignment, "SwapNpadAssignment"},
|
||||
{131, nullptr, "IsUnintendedHomeButtonInputProtectionEnabled"},
|
||||
{132, nullptr, "EnableUnintendedHomeButtonInputProtection"},
|
||||
{131, &Hid::IsUnintendedHomeButtonInputProtectionEnabled, "IsUnintendedHomeButtonInputProtectionEnabled"},
|
||||
{132, &Hid::EnableUnintendedHomeButtonInputProtection, "EnableUnintendedHomeButtonInputProtection"},
|
||||
{133, nullptr, "SetNpadJoyAssignmentModeSingleWithDestination"},
|
||||
{134, nullptr, "SetNpadAnalogStickUseCenterClamp"},
|
||||
{135, nullptr, "SetNpadCaptureButtonAssignment"},
|
||||
@@ -458,6 +473,19 @@ void Hid::StopSixAxisSensor(Kernel::HLERequestContext& ctx) {
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
}
|
||||
|
||||
void Hid::EnableSixAxisSensorFusion(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
const auto enable{rp.Pop<bool>()};
|
||||
const auto handle{rp.Pop<u32>()};
|
||||
const auto applet_resource_user_id{rp.Pop<u64>()};
|
||||
|
||||
LOG_WARNING(Service_HID, "(STUBBED) called, handle={}, applet_resource_user_id={}", handle,
|
||||
applet_resource_user_id);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
}
|
||||
|
||||
void Hid::SetGyroscopeZeroDriftMode(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
const auto handle{rp.Pop<u32>()};
|
||||
@@ -739,8 +767,11 @@ void Hid::SetNpadHandheldActivationMode(Kernel::HLERequestContext& ctx) {
|
||||
const auto applet_resource_user_id{rp.Pop<u64>()};
|
||||
const auto mode{rp.Pop<u64>()};
|
||||
|
||||
LOG_WARNING(Service_HID, "(STUBBED) called, applet_resource_user_id={}, mode={}",
|
||||
applet_resource_user_id, mode);
|
||||
LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}, mode={}", applet_resource_user_id,
|
||||
mode);
|
||||
|
||||
applet_resource->GetController<Controller_NPad>(HidController::NPad)
|
||||
.SetNpadHandheldActivationMode(Controller_NPad::NpadHandheldActivationMode{mode});
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
@@ -750,11 +781,13 @@ void Hid::GetNpadHandheldActivationMode(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
const auto applet_resource_user_id{rp.Pop<u64>()};
|
||||
|
||||
LOG_WARNING(Service_HID, "(STUBBED) called, applet_resource_user_id={}",
|
||||
applet_resource_user_id);
|
||||
LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
IPC::ResponseBuilder rb{ctx, 4};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.Push<u64>(
|
||||
static_cast<u64>(applet_resource->GetController<Controller_NPad>(HidController::NPad)
|
||||
.GetNpadHandheldActivationMode()));
|
||||
}
|
||||
|
||||
void Hid::SwapNpadAssignment(Kernel::HLERequestContext& ctx) {
|
||||
@@ -776,6 +809,40 @@ void Hid::SwapNpadAssignment(Kernel::HLERequestContext& ctx) {
|
||||
}
|
||||
}
|
||||
|
||||
void Hid::IsUnintendedHomeButtonInputProtectionEnabled(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
const auto npad_id{rp.Pop<u32>()};
|
||||
const auto applet_resource_user_id{rp.Pop<u64>()};
|
||||
|
||||
LOG_WARNING(Service_HID, "(STUBBED) called, npad_id={}, applet_resource_user_id={}", npad_id,
|
||||
applet_resource_user_id);
|
||||
|
||||
auto& controller = applet_resource->GetController<Controller_NPad>(HidController::NPad);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.Push<bool>(controller.IsUnintendedHomeButtonInputProtectionEnabled(npad_id));
|
||||
}
|
||||
|
||||
void Hid::EnableUnintendedHomeButtonInputProtection(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
const auto unintended_home_button_input_protection{rp.Pop<bool>()};
|
||||
const auto npad_id{rp.Pop<u32>()};
|
||||
const auto applet_resource_user_id{rp.Pop<u64>()};
|
||||
|
||||
LOG_WARNING(Service_HID,
|
||||
"(STUBBED) called, unintended_home_button_input_protection={}, npad_id={},"
|
||||
"applet_resource_user_id={}",
|
||||
npad_id, unintended_home_button_input_protection, applet_resource_user_id);
|
||||
|
||||
auto& controller = applet_resource->GetController<Controller_NPad>(HidController::NPad);
|
||||
controller.SetUnintendedHomeButtonInputProtectionEnabled(
|
||||
unintended_home_button_input_protection, npad_id);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
}
|
||||
|
||||
void Hid::BeginPermitVibrationSession(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
const auto applet_resource_user_id{rp.Pop<u64>()};
|
||||
@@ -797,18 +864,18 @@ void Hid::EndPermitVibrationSession(Kernel::HLERequestContext& ctx) {
|
||||
|
||||
void Hid::SendVibrationValue(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
const auto controller_id{rp.Pop<u32>()};
|
||||
const auto controller{rp.Pop<u32>()};
|
||||
const auto vibration_values{rp.PopRaw<Controller_NPad::Vibration>()};
|
||||
const auto applet_resource_user_id{rp.Pop<u64>()};
|
||||
|
||||
LOG_DEBUG(Service_HID, "called, controller_id={}, applet_resource_user_id={}", controller_id,
|
||||
LOG_DEBUG(Service_HID, "called, controller={}, applet_resource_user_id={}", controller,
|
||||
applet_resource_user_id);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
|
||||
applet_resource->GetController<Controller_NPad>(HidController::NPad)
|
||||
.VibrateController({controller_id}, {vibration_values});
|
||||
.VibrateController({controller}, {vibration_values});
|
||||
}
|
||||
|
||||
void Hid::SendVibrationValues(Kernel::HLERequestContext& ctx) {
|
||||
@@ -826,8 +893,6 @@ void Hid::SendVibrationValues(Kernel::HLERequestContext& ctx) {
|
||||
|
||||
std::memcpy(controller_list.data(), controllers.data(), controllers.size());
|
||||
std::memcpy(vibration_list.data(), vibrations.data(), vibrations.size());
|
||||
std::transform(controller_list.begin(), controller_list.end(), controller_list.begin(),
|
||||
[](u32 controller_id) { return controller_id - 3; });
|
||||
|
||||
applet_resource->GetController<Controller_NPad>(HidController::NPad)
|
||||
.VibrateController(controller_list, vibration_list);
|
||||
|
||||
@@ -65,10 +65,12 @@ private:
|
||||
|
||||
void GetSharedMemoryHandle(Kernel::HLERequestContext& ctx);
|
||||
void UpdateControllers(std::uintptr_t user_data, std::chrono::nanoseconds ns_late);
|
||||
void UpdateMotion(std::uintptr_t user_data, std::chrono::nanoseconds ns_late);
|
||||
|
||||
std::shared_ptr<Kernel::SharedMemory> shared_mem;
|
||||
|
||||
std::shared_ptr<Core::Timing::EventType> pad_update_event;
|
||||
std::shared_ptr<Core::Timing::EventType> motion_update_event;
|
||||
Core::System& system;
|
||||
|
||||
std::array<std::unique_ptr<ControllerBase>, static_cast<size_t>(HidController::MaxControllers)>
|
||||
@@ -97,6 +99,7 @@ private:
|
||||
void ActivateNpadWithRevision(Kernel::HLERequestContext& ctx);
|
||||
void StartSixAxisSensor(Kernel::HLERequestContext& ctx);
|
||||
void StopSixAxisSensor(Kernel::HLERequestContext& ctx);
|
||||
void EnableSixAxisSensorFusion(Kernel::HLERequestContext& ctx);
|
||||
void SetGyroscopeZeroDriftMode(Kernel::HLERequestContext& ctx);
|
||||
void GetGyroscopeZeroDriftMode(Kernel::HLERequestContext& ctx);
|
||||
void ResetGyroscopeZeroDriftMode(Kernel::HLERequestContext& ctx);
|
||||
@@ -120,6 +123,8 @@ private:
|
||||
void SetNpadHandheldActivationMode(Kernel::HLERequestContext& ctx);
|
||||
void GetNpadHandheldActivationMode(Kernel::HLERequestContext& ctx);
|
||||
void SwapNpadAssignment(Kernel::HLERequestContext& ctx);
|
||||
void IsUnintendedHomeButtonInputProtectionEnabled(Kernel::HLERequestContext& ctx);
|
||||
void EnableUnintendedHomeButtonInputProtection(Kernel::HLERequestContext& ctx);
|
||||
void BeginPermitVibrationSession(Kernel::HLERequestContext& ctx);
|
||||
void EndPermitVibrationSession(Kernel::HLERequestContext& ctx);
|
||||
void SendVibrationValue(Kernel::HLERequestContext& ctx);
|
||||
|
||||
@@ -265,7 +265,7 @@ std::optional<nvhost_as_gpu::BufferMap> nvhost_as_gpu::FindBufferMap(GPUVAddr gp
|
||||
}
|
||||
}
|
||||
|
||||
return {};
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
void nvhost_as_gpu::AddBufferMap(GPUVAddr gpu_addr, std::size_t size, VAddr cpu_addr,
|
||||
@@ -286,7 +286,7 @@ std::optional<std::size_t> nvhost_as_gpu::RemoveBufferMap(GPUVAddr gpu_addr) {
|
||||
return size;
|
||||
}
|
||||
|
||||
return {};
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
} // namespace Service::Nvidia::Devices
|
||||
|
||||
@@ -22,6 +22,18 @@ u32 nvhost_nvdec::ioctl(Ioctl command, const std::vector<u8>& input, const std::
|
||||
switch (static_cast<IoctlCommand>(command.raw)) {
|
||||
case IoctlCommand::IocSetNVMAPfdCommand:
|
||||
return SetNVMAPfd(input, output);
|
||||
case IoctlCommand::IocSubmit:
|
||||
return Submit(input, output);
|
||||
case IoctlCommand::IocGetSyncpoint:
|
||||
return GetSyncpoint(input, output);
|
||||
case IoctlCommand::IocGetWaitbase:
|
||||
return GetWaitbase(input, output);
|
||||
case IoctlCommand::IocMapBuffer:
|
||||
return MapBuffer(input, output);
|
||||
case IoctlCommand::IocMapBufferEx:
|
||||
return MapBufferEx(input, output);
|
||||
case IoctlCommand::IocUnmapBufferEx:
|
||||
return UnmapBufferEx(input, output);
|
||||
}
|
||||
|
||||
UNIMPLEMENTED_MSG("Unimplemented ioctl");
|
||||
@@ -30,11 +42,67 @@ u32 nvhost_nvdec::ioctl(Ioctl command, const std::vector<u8>& input, const std::
|
||||
|
||||
u32 nvhost_nvdec::SetNVMAPfd(const std::vector<u8>& input, std::vector<u8>& output) {
|
||||
IoctlSetNvmapFD params{};
|
||||
std::memcpy(¶ms, input.data(), input.size());
|
||||
std::memcpy(¶ms, input.data(), sizeof(IoctlSetNvmapFD));
|
||||
LOG_DEBUG(Service_NVDRV, "called, fd={}", params.nvmap_fd);
|
||||
|
||||
nvmap_fd = params.nvmap_fd;
|
||||
return 0;
|
||||
}
|
||||
|
||||
u32 nvhost_nvdec::Submit(const std::vector<u8>& input, std::vector<u8>& output) {
|
||||
IoctlSubmit params{};
|
||||
std::memcpy(¶ms, input.data(), sizeof(IoctlSubmit));
|
||||
LOG_WARNING(Service_NVDRV, "(STUBBED) called");
|
||||
std::memcpy(output.data(), ¶ms, sizeof(IoctlSubmit));
|
||||
return 0;
|
||||
}
|
||||
|
||||
u32 nvhost_nvdec::GetSyncpoint(const std::vector<u8>& input, std::vector<u8>& output) {
|
||||
IoctlGetSyncpoint params{};
|
||||
std::memcpy(¶ms, input.data(), sizeof(IoctlGetSyncpoint));
|
||||
LOG_INFO(Service_NVDRV, "called, unknown=0x{:X}", params.unknown);
|
||||
params.value = 0; // Seems to be hard coded at 0
|
||||
std::memcpy(output.data(), ¶ms, sizeof(IoctlGetSyncpoint));
|
||||
return 0;
|
||||
}
|
||||
|
||||
u32 nvhost_nvdec::GetWaitbase(const std::vector<u8>& input, std::vector<u8>& output) {
|
||||
IoctlGetWaitbase params{};
|
||||
std::memcpy(¶ms, input.data(), sizeof(IoctlGetWaitbase));
|
||||
LOG_INFO(Service_NVDRV, "called, unknown=0x{:X}", params.unknown);
|
||||
params.value = 0; // Seems to be hard coded at 0
|
||||
std::memcpy(output.data(), ¶ms, sizeof(IoctlGetWaitbase));
|
||||
return 0;
|
||||
}
|
||||
|
||||
u32 nvhost_nvdec::MapBuffer(const std::vector<u8>& input, std::vector<u8>& output) {
|
||||
IoctlMapBuffer params{};
|
||||
std::memcpy(¶ms, input.data(), sizeof(IoctlMapBuffer));
|
||||
LOG_WARNING(Service_NVDRV, "(STUBBED) called with address={:08X}{:08X}", params.address_2,
|
||||
params.address_1);
|
||||
params.address_1 = 0;
|
||||
params.address_2 = 0;
|
||||
std::memcpy(output.data(), ¶ms, sizeof(IoctlMapBuffer));
|
||||
return 0;
|
||||
}
|
||||
|
||||
u32 nvhost_nvdec::MapBufferEx(const std::vector<u8>& input, std::vector<u8>& output) {
|
||||
IoctlMapBufferEx params{};
|
||||
std::memcpy(¶ms, input.data(), sizeof(IoctlMapBufferEx));
|
||||
LOG_WARNING(Service_NVDRV, "(STUBBED) called with address={:08X}{:08X}", params.address_2,
|
||||
params.address_1);
|
||||
params.address_1 = 0;
|
||||
params.address_2 = 0;
|
||||
std::memcpy(output.data(), ¶ms, sizeof(IoctlMapBufferEx));
|
||||
return 0;
|
||||
}
|
||||
|
||||
u32 nvhost_nvdec::UnmapBufferEx(const std::vector<u8>& input, std::vector<u8>& output) {
|
||||
IoctlUnmapBufferEx params{};
|
||||
std::memcpy(¶ms, input.data(), sizeof(IoctlUnmapBufferEx));
|
||||
LOG_WARNING(Service_NVDRV, "(STUBBED) called");
|
||||
std::memcpy(output.data(), ¶ms, sizeof(IoctlUnmapBufferEx));
|
||||
return 0;
|
||||
}
|
||||
|
||||
} // namespace Service::Nvidia::Devices
|
||||
|
||||
@@ -23,16 +23,66 @@ public:
|
||||
private:
|
||||
enum class IoctlCommand : u32_le {
|
||||
IocSetNVMAPfdCommand = 0x40044801,
|
||||
IocSubmit = 0xC0400001,
|
||||
IocGetSyncpoint = 0xC0080002,
|
||||
IocGetWaitbase = 0xC0080003,
|
||||
IocMapBuffer = 0xC01C0009,
|
||||
IocMapBufferEx = 0xC0A40009,
|
||||
IocUnmapBufferEx = 0xC0A4000A,
|
||||
};
|
||||
|
||||
struct IoctlSetNvmapFD {
|
||||
u32_le nvmap_fd;
|
||||
};
|
||||
static_assert(sizeof(IoctlSetNvmapFD) == 4, "IoctlSetNvmapFD is incorrect size");
|
||||
static_assert(sizeof(IoctlSetNvmapFD) == 0x4, "IoctlSetNvmapFD is incorrect size");
|
||||
|
||||
struct IoctlSubmit {
|
||||
INSERT_PADDING_BYTES(0x40); // TODO(DarkLordZach): RE this structure
|
||||
};
|
||||
static_assert(sizeof(IoctlSubmit) == 0x40, "IoctlSubmit has incorrect size");
|
||||
|
||||
struct IoctlGetSyncpoint {
|
||||
u32 unknown; // seems to be ignored? Nintendo added this
|
||||
u32 value;
|
||||
};
|
||||
static_assert(sizeof(IoctlGetSyncpoint) == 0x08, "IoctlGetSyncpoint has incorrect size");
|
||||
|
||||
struct IoctlGetWaitbase {
|
||||
u32 unknown; // seems to be ignored? Nintendo added this
|
||||
u32 value;
|
||||
};
|
||||
static_assert(sizeof(IoctlGetWaitbase) == 0x08, "IoctlGetWaitbase has incorrect size");
|
||||
|
||||
struct IoctlMapBuffer {
|
||||
u32 unknown;
|
||||
u32 address_1;
|
||||
u32 address_2;
|
||||
INSERT_PADDING_BYTES(0x10); // TODO(DarkLordZach): RE this structure
|
||||
};
|
||||
static_assert(sizeof(IoctlMapBuffer) == 0x1C, "IoctlMapBuffer is incorrect size");
|
||||
|
||||
struct IoctlMapBufferEx {
|
||||
u32 unknown;
|
||||
u32 address_1;
|
||||
u32 address_2;
|
||||
INSERT_PADDING_BYTES(0x98); // TODO(DarkLordZach): RE this structure
|
||||
};
|
||||
static_assert(sizeof(IoctlMapBufferEx) == 0xA4, "IoctlMapBufferEx has incorrect size");
|
||||
|
||||
struct IoctlUnmapBufferEx {
|
||||
INSERT_PADDING_BYTES(0xA4); // TODO(DarkLordZach): RE this structure
|
||||
};
|
||||
static_assert(sizeof(IoctlUnmapBufferEx) == 0xA4, "IoctlUnmapBufferEx has incorrect size");
|
||||
|
||||
u32_le nvmap_fd{};
|
||||
|
||||
u32 SetNVMAPfd(const std::vector<u8>& input, std::vector<u8>& output);
|
||||
u32 Submit(const std::vector<u8>& input, std::vector<u8>& output);
|
||||
u32 GetSyncpoint(const std::vector<u8>& input, std::vector<u8>& output);
|
||||
u32 GetWaitbase(const std::vector<u8>& input, std::vector<u8>& output);
|
||||
u32 MapBuffer(const std::vector<u8>& input, std::vector<u8>& output);
|
||||
u32 MapBufferEx(const std::vector<u8>& input, std::vector<u8>& output);
|
||||
u32 UnmapBufferEx(const std::vector<u8>& input, std::vector<u8>& output);
|
||||
};
|
||||
|
||||
} // namespace Service::Nvidia::Devices
|
||||
|
||||
@@ -22,6 +22,18 @@ u32 nvhost_vic::ioctl(Ioctl command, const std::vector<u8>& input, const std::ve
|
||||
switch (static_cast<IoctlCommand>(command.raw)) {
|
||||
case IoctlCommand::IocSetNVMAPfdCommand:
|
||||
return SetNVMAPfd(input, output);
|
||||
case IoctlCommand::IocSubmit:
|
||||
return Submit(input, output);
|
||||
case IoctlCommand::IocGetSyncpoint:
|
||||
return GetSyncpoint(input, output);
|
||||
case IoctlCommand::IocGetWaitbase:
|
||||
return GetWaitbase(input, output);
|
||||
case IoctlCommand::IocMapBuffer:
|
||||
return MapBuffer(input, output);
|
||||
case IoctlCommand::IocMapBufferEx:
|
||||
return MapBuffer(input, output);
|
||||
case IoctlCommand::IocUnmapBufferEx:
|
||||
return UnmapBufferEx(input, output);
|
||||
}
|
||||
|
||||
UNIMPLEMENTED_MSG("Unimplemented ioctl");
|
||||
@@ -30,11 +42,71 @@ u32 nvhost_vic::ioctl(Ioctl command, const std::vector<u8>& input, const std::ve
|
||||
|
||||
u32 nvhost_vic::SetNVMAPfd(const std::vector<u8>& input, std::vector<u8>& output) {
|
||||
IoctlSetNvmapFD params{};
|
||||
std::memcpy(¶ms, input.data(), input.size());
|
||||
std::memcpy(¶ms, input.data(), sizeof(IoctlSetNvmapFD));
|
||||
LOG_DEBUG(Service_NVDRV, "called, fd={}", params.nvmap_fd);
|
||||
|
||||
nvmap_fd = params.nvmap_fd;
|
||||
return 0;
|
||||
}
|
||||
|
||||
u32 nvhost_vic::Submit(const std::vector<u8>& input, std::vector<u8>& output) {
|
||||
IoctlSubmit params{};
|
||||
std::memcpy(¶ms, input.data(), sizeof(IoctlSubmit));
|
||||
LOG_WARNING(Service_NVDRV, "(STUBBED) called");
|
||||
|
||||
// Workaround for Luigi's Mansion 3, as nvhost_vic is not implemented for asynch GPU
|
||||
params.command_buffer = {};
|
||||
|
||||
std::memcpy(output.data(), ¶ms, sizeof(IoctlSubmit));
|
||||
return 0;
|
||||
}
|
||||
|
||||
u32 nvhost_vic::GetSyncpoint(const std::vector<u8>& input, std::vector<u8>& output) {
|
||||
IoctlGetSyncpoint params{};
|
||||
std::memcpy(¶ms, input.data(), sizeof(IoctlGetSyncpoint));
|
||||
LOG_INFO(Service_NVDRV, "called, unknown=0x{:X}", params.unknown);
|
||||
params.value = 0; // Seems to be hard coded at 0
|
||||
std::memcpy(output.data(), ¶ms, sizeof(IoctlGetSyncpoint));
|
||||
return 0;
|
||||
}
|
||||
|
||||
u32 nvhost_vic::GetWaitbase(const std::vector<u8>& input, std::vector<u8>& output) {
|
||||
IoctlGetWaitbase params{};
|
||||
std::memcpy(¶ms, input.data(), sizeof(IoctlGetWaitbase));
|
||||
LOG_INFO(Service_NVDRV, "called, unknown=0x{:X}", params.unknown);
|
||||
params.value = 0; // Seems to be hard coded at 0
|
||||
std::memcpy(output.data(), ¶ms, sizeof(IoctlGetWaitbase));
|
||||
return 0;
|
||||
}
|
||||
|
||||
u32 nvhost_vic::MapBuffer(const std::vector<u8>& input, std::vector<u8>& output) {
|
||||
IoctlMapBuffer params{};
|
||||
std::memcpy(¶ms, input.data(), sizeof(IoctlMapBuffer));
|
||||
LOG_WARNING(Service_NVDRV, "(STUBBED) called with address={:08X}{:08X}", params.address_2,
|
||||
params.address_1);
|
||||
params.address_1 = 0;
|
||||
params.address_2 = 0;
|
||||
std::memcpy(output.data(), ¶ms, sizeof(IoctlMapBuffer));
|
||||
return 0;
|
||||
}
|
||||
|
||||
u32 nvhost_vic::MapBufferEx(const std::vector<u8>& input, std::vector<u8>& output) {
|
||||
IoctlMapBufferEx params{};
|
||||
std::memcpy(¶ms, input.data(), sizeof(IoctlMapBufferEx));
|
||||
LOG_WARNING(Service_NVDRV, "(STUBBED) called with address={:08X}{:08X}", params.address_2,
|
||||
params.address_1);
|
||||
params.address_1 = 0;
|
||||
params.address_2 = 0;
|
||||
std::memcpy(output.data(), ¶ms, sizeof(IoctlMapBufferEx));
|
||||
return 0;
|
||||
}
|
||||
|
||||
u32 nvhost_vic::UnmapBufferEx(const std::vector<u8>& input, std::vector<u8>& output) {
|
||||
IoctlUnmapBufferEx params{};
|
||||
std::memcpy(¶ms, input.data(), sizeof(IoctlUnmapBufferEx));
|
||||
LOG_WARNING(Service_NVDRV, "(STUBBED) called");
|
||||
std::memcpy(output.data(), ¶ms, sizeof(IoctlUnmapBufferEx));
|
||||
return 0;
|
||||
}
|
||||
|
||||
} // namespace Service::Nvidia::Devices
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
#include <vector>
|
||||
#include "common/common_types.h"
|
||||
#include "common/swap.h"
|
||||
@@ -23,6 +24,12 @@ public:
|
||||
private:
|
||||
enum class IoctlCommand : u32_le {
|
||||
IocSetNVMAPfdCommand = 0x40044801,
|
||||
IocSubmit = 0xC0400001,
|
||||
IocGetSyncpoint = 0xC0080002,
|
||||
IocGetWaitbase = 0xC0080003,
|
||||
IocMapBuffer = 0xC01C0009,
|
||||
IocMapBufferEx = 0xC03C0009,
|
||||
IocUnmapBufferEx = 0xC03C000A,
|
||||
};
|
||||
|
||||
struct IoctlSetNvmapFD {
|
||||
@@ -30,9 +37,65 @@ private:
|
||||
};
|
||||
static_assert(sizeof(IoctlSetNvmapFD) == 4, "IoctlSetNvmapFD is incorrect size");
|
||||
|
||||
struct IoctlSubmitCommandBuffer {
|
||||
u32 id;
|
||||
u32 offset;
|
||||
u32 count;
|
||||
};
|
||||
static_assert(sizeof(IoctlSubmitCommandBuffer) == 0xC,
|
||||
"IoctlSubmitCommandBuffer is incorrect size");
|
||||
|
||||
struct IoctlSubmit {
|
||||
u32 command_buffer_count;
|
||||
u32 relocations_count;
|
||||
u32 syncpt_count;
|
||||
u32 wait_count;
|
||||
std::array<IoctlSubmitCommandBuffer, 4> command_buffer;
|
||||
};
|
||||
static_assert(sizeof(IoctlSubmit) == 0x40, "IoctlSubmit is incorrect size");
|
||||
|
||||
struct IoctlGetSyncpoint {
|
||||
u32 unknown; // seems to be ignored? Nintendo added this
|
||||
u32 value;
|
||||
};
|
||||
static_assert(sizeof(IoctlGetSyncpoint) == 0x8, "IoctlGetSyncpoint is incorrect size");
|
||||
|
||||
struct IoctlGetWaitbase {
|
||||
u32 unknown; // seems to be ignored? Nintendo added this
|
||||
u32 value;
|
||||
};
|
||||
static_assert(sizeof(IoctlGetWaitbase) == 0x8, "IoctlGetWaitbase is incorrect size");
|
||||
|
||||
struct IoctlMapBuffer {
|
||||
u32 unknown;
|
||||
u32 address_1;
|
||||
u32 address_2;
|
||||
INSERT_PADDING_BYTES(0x10); // TODO(DarkLordZach): RE this structure
|
||||
};
|
||||
static_assert(sizeof(IoctlMapBuffer) == 0x1C, "IoctlMapBuffer is incorrect size");
|
||||
|
||||
struct IoctlMapBufferEx {
|
||||
u32 unknown;
|
||||
u32 address_1;
|
||||
u32 address_2;
|
||||
INSERT_PADDING_BYTES(0x30); // TODO(DarkLordZach): RE this structure
|
||||
};
|
||||
static_assert(sizeof(IoctlMapBufferEx) == 0x3C, "IoctlMapBufferEx is incorrect size");
|
||||
|
||||
struct IoctlUnmapBufferEx {
|
||||
INSERT_PADDING_BYTES(0x3C); // TODO(DarkLordZach): RE this structure
|
||||
};
|
||||
static_assert(sizeof(IoctlUnmapBufferEx) == 0x3C, "IoctlUnmapBufferEx is incorrect size");
|
||||
|
||||
u32_le nvmap_fd{};
|
||||
|
||||
u32 SetNVMAPfd(const std::vector<u8>& input, std::vector<u8>& output);
|
||||
u32 Submit(const std::vector<u8>& input, std::vector<u8>& output);
|
||||
u32 GetSyncpoint(const std::vector<u8>& input, std::vector<u8>& output);
|
||||
u32 GetWaitbase(const std::vector<u8>& input, std::vector<u8>& output);
|
||||
u32 MapBuffer(const std::vector<u8>& input, std::vector<u8>& output);
|
||||
u32 MapBufferEx(const std::vector<u8>& input, std::vector<u8>& output);
|
||||
u32 UnmapBufferEx(const std::vector<u8>& input, std::vector<u8>& output);
|
||||
};
|
||||
|
||||
} // namespace Service::Nvidia::Devices
|
||||
|
||||
@@ -54,7 +54,7 @@ struct EventInterface {
|
||||
}
|
||||
mask = mask >> 1;
|
||||
}
|
||||
return {};
|
||||
return std::nullopt;
|
||||
}
|
||||
void SetEventStatus(const u32 event_id, EventState new_status) {
|
||||
EventState old_status = status[event_id];
|
||||
|
||||
@@ -114,7 +114,7 @@ std::optional<u64> NVFlinger::OpenDisplay(std::string_view name) {
|
||||
[&](const VI::Display& display) { return display.GetName() == name; });
|
||||
|
||||
if (itr == displays.end()) {
|
||||
return {};
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
return itr->GetID();
|
||||
@@ -124,7 +124,7 @@ std::optional<u64> NVFlinger::CreateLayer(u64 display_id) {
|
||||
auto* const display = FindDisplay(display_id);
|
||||
|
||||
if (display == nullptr) {
|
||||
return {};
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
const u64 layer_id = next_layer_id++;
|
||||
@@ -144,7 +144,7 @@ std::optional<u32> NVFlinger::FindBufferQueueId(u64 display_id, u64 layer_id) co
|
||||
const auto* const layer = FindLayer(display_id, layer_id);
|
||||
|
||||
if (layer == nullptr) {
|
||||
return {};
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
return layer->GetBufferQueue().GetId();
|
||||
|
||||
@@ -72,6 +72,23 @@
|
||||
|
||||
namespace Service {
|
||||
|
||||
/**
|
||||
* Creates a function string for logging, complete with the name (or header code, depending
|
||||
* on what's passed in) the port name, and all the cmd_buff arguments.
|
||||
*/
|
||||
[[maybe_unused]] static std::string MakeFunctionString(std::string_view name,
|
||||
std::string_view port_name,
|
||||
const u32* cmd_buff) {
|
||||
// Number of params == bits 0-5 + bits 6-11
|
||||
int num_params = (cmd_buff[0] & 0x3F) + ((cmd_buff[0] >> 6) & 0x3F);
|
||||
|
||||
std::string function_string = fmt::format("function '{}': port={}", name, port_name);
|
||||
for (int i = 1; i <= num_params; ++i) {
|
||||
function_string += fmt::format(", cmd_buff[{}]=0x{:X}", i, cmd_buff[i]);
|
||||
}
|
||||
return function_string;
|
||||
}
|
||||
|
||||
ServiceFrameworkBase::ServiceFrameworkBase(const char* service_name, u32 max_sessions,
|
||||
InvokerFn* handler_invoker)
|
||||
: service_name(service_name), max_sessions(max_sessions), handler_invoker(handler_invoker) {}
|
||||
|
||||
@@ -497,7 +497,7 @@ std::pair<s32, Errno> BSD::PollImpl(std::vector<u8>& write_buffer, std::vector<u
|
||||
return {0, Errno::SUCCESS};
|
||||
}
|
||||
|
||||
std::optional<FileDescriptor>& descriptor = file_descriptors[pollfd.fd];
|
||||
const std::optional<FileDescriptor>& descriptor = file_descriptors[pollfd.fd];
|
||||
if (!descriptor) {
|
||||
LOG_ERROR(Service, "File descriptor handle={} is not allocated", pollfd.fd);
|
||||
pollfd.revents = POLL_NVAL;
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#include "core/hle/ipc_helpers.h"
|
||||
#include "core/hle/kernel/client_port.h"
|
||||
#include "core/hle/kernel/client_session.h"
|
||||
#include "core/hle/kernel/kernel.h"
|
||||
#include "core/hle/kernel/scheduler.h"
|
||||
#include "core/hle/service/time/interface.h"
|
||||
#include "core/hle/service/time/time.h"
|
||||
@@ -125,7 +126,7 @@ ResultCode Module::Interface::GetClockSnapshotFromSystemClockContextInternal(
|
||||
Kernel::Thread* thread, Clock::SystemClockContext user_context,
|
||||
Clock::SystemClockContext network_context, u8 type, Clock::ClockSnapshot& clock_snapshot) {
|
||||
|
||||
auto& time_manager{module->GetTimeManager()};
|
||||
auto& time_manager{system.GetTimeManager()};
|
||||
|
||||
clock_snapshot.is_automatic_correction_enabled =
|
||||
time_manager.GetStandardUserSystemClockCore().IsAutomaticCorrectionEnabled();
|
||||
@@ -182,7 +183,7 @@ void Module::Interface::GetStandardUserSystemClock(Kernel::HLERequestContext& ct
|
||||
LOG_DEBUG(Service_Time, "called");
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushIpcInterface<ISystemClock>(module->GetTimeManager().GetStandardUserSystemClockCore(),
|
||||
rb.PushIpcInterface<ISystemClock>(system.GetTimeManager().GetStandardUserSystemClockCore(),
|
||||
system);
|
||||
}
|
||||
|
||||
@@ -190,7 +191,7 @@ void Module::Interface::GetStandardNetworkSystemClock(Kernel::HLERequestContext&
|
||||
LOG_DEBUG(Service_Time, "called");
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushIpcInterface<ISystemClock>(module->GetTimeManager().GetStandardNetworkSystemClockCore(),
|
||||
rb.PushIpcInterface<ISystemClock>(system.GetTimeManager().GetStandardNetworkSystemClockCore(),
|
||||
system);
|
||||
}
|
||||
|
||||
@@ -198,29 +199,28 @@ void Module::Interface::GetStandardSteadyClock(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_Time, "called");
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushIpcInterface<ISteadyClock>(module->GetTimeManager().GetStandardSteadyClockCore(),
|
||||
system);
|
||||
rb.PushIpcInterface<ISteadyClock>(system.GetTimeManager().GetStandardSteadyClockCore(), system);
|
||||
}
|
||||
|
||||
void Module::Interface::GetTimeZoneService(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_Time, "called");
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushIpcInterface<ITimeZoneService>(module->GetTimeManager().GetTimeZoneContentManager());
|
||||
rb.PushIpcInterface<ITimeZoneService>(system.GetTimeManager().GetTimeZoneContentManager());
|
||||
}
|
||||
|
||||
void Module::Interface::GetStandardLocalSystemClock(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_Time, "called");
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushIpcInterface<ISystemClock>(module->GetTimeManager().GetStandardLocalSystemClockCore(),
|
||||
rb.PushIpcInterface<ISystemClock>(system.GetTimeManager().GetStandardLocalSystemClockCore(),
|
||||
system);
|
||||
}
|
||||
|
||||
void Module::Interface::IsStandardNetworkSystemClockAccuracySufficient(
|
||||
Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_Time, "called");
|
||||
auto& clock_core{module->GetTimeManager().GetStandardNetworkSystemClockCore()};
|
||||
auto& clock_core{system.GetTimeManager().GetStandardNetworkSystemClockCore()};
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.Push<u32>(clock_core.IsStandardNetworkSystemClockAccuracySufficient(system));
|
||||
@@ -229,7 +229,7 @@ void Module::Interface::IsStandardNetworkSystemClockAccuracySufficient(
|
||||
void Module::Interface::CalculateMonotonicSystemClockBaseTimePoint(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_Time, "called");
|
||||
|
||||
auto& steady_clock_core{module->GetTimeManager().GetStandardSteadyClockCore()};
|
||||
auto& steady_clock_core{system.GetTimeManager().GetStandardSteadyClockCore()};
|
||||
if (!steady_clock_core.IsInitialized()) {
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ERROR_UNINITIALIZED_CLOCK);
|
||||
@@ -262,8 +262,8 @@ void Module::Interface::GetClockSnapshot(Kernel::HLERequestContext& ctx) {
|
||||
|
||||
Clock::SystemClockContext user_context{};
|
||||
if (const ResultCode result{
|
||||
module->GetTimeManager().GetStandardUserSystemClockCore().GetClockContext(
|
||||
system, user_context)};
|
||||
system.GetTimeManager().GetStandardUserSystemClockCore().GetClockContext(system,
|
||||
user_context)};
|
||||
result.IsError()) {
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(result);
|
||||
@@ -271,7 +271,7 @@ void Module::Interface::GetClockSnapshot(Kernel::HLERequestContext& ctx) {
|
||||
}
|
||||
Clock::SystemClockContext network_context{};
|
||||
if (const ResultCode result{
|
||||
module->GetTimeManager().GetStandardNetworkSystemClockCore().GetClockContext(
|
||||
system.GetTimeManager().GetStandardNetworkSystemClockCore().GetClockContext(
|
||||
system, network_context)};
|
||||
result.IsError()) {
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
@@ -372,7 +372,7 @@ void Module::Interface::GetSharedMemoryNativeHandle(Kernel::HLERequestContext& c
|
||||
LOG_DEBUG(Service_Time, "called");
|
||||
IPC::ResponseBuilder rb{ctx, 2, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushCopyObjects(module->GetTimeManager().GetSharedMemory().GetSharedMemoryHolder());
|
||||
rb.PushCopyObjects(SharedFrom(&system.Kernel().GetTimeSharedMem()));
|
||||
}
|
||||
|
||||
Module::Interface::Interface(std::shared_ptr<Module> module, Core::System& system, const char* name)
|
||||
@@ -381,7 +381,7 @@ Module::Interface::Interface(std::shared_ptr<Module> module, Core::System& syste
|
||||
Module::Interface::~Interface() = default;
|
||||
|
||||
void InstallInterfaces(Core::System& system) {
|
||||
auto module{std::make_shared<Module>(system)};
|
||||
auto module{std::make_shared<Module>()};
|
||||
std::make_shared<Time>(module, system, "time:a")->InstallAsService(system.ServiceManager());
|
||||
std::make_shared<Time>(module, system, "time:s")->InstallAsService(system.ServiceManager());
|
||||
std::make_shared<Time>(module, system, "time:u")->InstallAsService(system.ServiceManager());
|
||||
|
||||
@@ -16,7 +16,7 @@ namespace Service::Time {
|
||||
|
||||
class Module final {
|
||||
public:
|
||||
Module(Core::System& system) : time_manager{system} {}
|
||||
Module() = default;
|
||||
|
||||
class Interface : public ServiceFramework<Interface> {
|
||||
public:
|
||||
@@ -46,13 +46,6 @@ public:
|
||||
std::shared_ptr<Module> module;
|
||||
Core::System& system;
|
||||
};
|
||||
|
||||
TimeManager& GetTimeManager() {
|
||||
return time_manager;
|
||||
}
|
||||
|
||||
private:
|
||||
TimeManager time_manager;
|
||||
};
|
||||
|
||||
/// Registers all Time services with the specified service manager.
|
||||
|
||||
@@ -22,7 +22,277 @@ static std::chrono::seconds GetSecondsSinceEpoch() {
|
||||
Settings::values.custom_rtc_differential;
|
||||
}
|
||||
|
||||
static s64 GetExternalTimeZoneOffset() {
|
||||
static s64 GetExternalRtcValue() {
|
||||
return GetSecondsSinceEpoch().count() + TimeManager::GetExternalTimeZoneOffset();
|
||||
}
|
||||
|
||||
struct TimeManager::Impl final {
|
||||
explicit Impl(Core::System& system)
|
||||
: shared_memory{system}, standard_local_system_clock_core{standard_steady_clock_core},
|
||||
standard_network_system_clock_core{standard_steady_clock_core},
|
||||
standard_user_system_clock_core{standard_local_system_clock_core,
|
||||
standard_network_system_clock_core, system},
|
||||
ephemeral_network_system_clock_core{tick_based_steady_clock_core},
|
||||
local_system_clock_context_writer{
|
||||
std::make_shared<Clock::LocalSystemClockContextWriter>(shared_memory)},
|
||||
network_system_clock_context_writer{
|
||||
std::make_shared<Clock::NetworkSystemClockContextWriter>(shared_memory)},
|
||||
ephemeral_network_system_clock_context_writer{
|
||||
std::make_shared<Clock::EphemeralNetworkSystemClockContextWriter>()},
|
||||
time_zone_content_manager{system} {
|
||||
|
||||
const auto system_time{Clock::TimeSpanType::FromSeconds(GetExternalRtcValue())};
|
||||
SetupStandardSteadyClock(system, Common::UUID::Generate(), system_time, {}, {});
|
||||
SetupStandardLocalSystemClock(system, {}, system_time.ToSeconds());
|
||||
SetupStandardNetworkSystemClock({}, standard_network_clock_accuracy);
|
||||
SetupStandardUserSystemClock(system, {}, Clock::SteadyClockTimePoint::GetRandom());
|
||||
SetupEphemeralNetworkSystemClock();
|
||||
}
|
||||
|
||||
~Impl() = default;
|
||||
|
||||
Clock::StandardSteadyClockCore& GetStandardSteadyClockCore() {
|
||||
return standard_steady_clock_core;
|
||||
}
|
||||
|
||||
const Clock::StandardSteadyClockCore& GetStandardSteadyClockCore() const {
|
||||
return standard_steady_clock_core;
|
||||
}
|
||||
|
||||
Clock::StandardLocalSystemClockCore& GetStandardLocalSystemClockCore() {
|
||||
return standard_local_system_clock_core;
|
||||
}
|
||||
|
||||
const Clock::StandardLocalSystemClockCore& GetStandardLocalSystemClockCore() const {
|
||||
return standard_local_system_clock_core;
|
||||
}
|
||||
|
||||
Clock::StandardNetworkSystemClockCore& GetStandardNetworkSystemClockCore() {
|
||||
return standard_network_system_clock_core;
|
||||
}
|
||||
|
||||
const Clock::StandardNetworkSystemClockCore& GetStandardNetworkSystemClockCore() const {
|
||||
return standard_network_system_clock_core;
|
||||
}
|
||||
|
||||
Clock::StandardUserSystemClockCore& GetStandardUserSystemClockCore() {
|
||||
return standard_user_system_clock_core;
|
||||
}
|
||||
|
||||
const Clock::StandardUserSystemClockCore& GetStandardUserSystemClockCore() const {
|
||||
return standard_user_system_clock_core;
|
||||
}
|
||||
|
||||
TimeZone::TimeZoneContentManager& GetTimeZoneContentManager() {
|
||||
return time_zone_content_manager;
|
||||
}
|
||||
|
||||
const TimeZone::TimeZoneContentManager& GetTimeZoneContentManager() const {
|
||||
return time_zone_content_manager;
|
||||
}
|
||||
|
||||
SharedMemory& GetSharedMemory() {
|
||||
return shared_memory;
|
||||
}
|
||||
|
||||
const SharedMemory& GetSharedMemory() const {
|
||||
return shared_memory;
|
||||
}
|
||||
|
||||
void SetupTimeZoneManager(std::string location_name,
|
||||
Clock::SteadyClockTimePoint time_zone_updated_time_point,
|
||||
std::size_t total_location_name_count, u128 time_zone_rule_version,
|
||||
FileSys::VirtualFile& vfs_file) {
|
||||
if (time_zone_content_manager.GetTimeZoneManager().SetDeviceLocationNameWithTimeZoneRule(
|
||||
location_name, vfs_file) != RESULT_SUCCESS) {
|
||||
UNREACHABLE();
|
||||
return;
|
||||
}
|
||||
|
||||
time_zone_content_manager.GetTimeZoneManager().SetUpdatedTime(time_zone_updated_time_point);
|
||||
time_zone_content_manager.GetTimeZoneManager().SetTotalLocationNameCount(
|
||||
total_location_name_count);
|
||||
time_zone_content_manager.GetTimeZoneManager().SetTimeZoneRuleVersion(
|
||||
time_zone_rule_version);
|
||||
time_zone_content_manager.GetTimeZoneManager().MarkAsInitialized();
|
||||
}
|
||||
|
||||
static s64 GetExternalTimeZoneOffset() {
|
||||
// With "auto" timezone setting, we use the external system's timezone offset
|
||||
if (Settings::GetTimeZoneString() == "auto") {
|
||||
return Common::TimeZone::GetCurrentOffsetSeconds().count();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void SetupStandardSteadyClock(Core::System& system, Common::UUID clock_source_id,
|
||||
Clock::TimeSpanType setup_value,
|
||||
Clock::TimeSpanType internal_offset, bool is_rtc_reset_detected) {
|
||||
standard_steady_clock_core.SetClockSourceId(clock_source_id);
|
||||
standard_steady_clock_core.SetSetupValue(setup_value);
|
||||
standard_steady_clock_core.SetInternalOffset(internal_offset);
|
||||
standard_steady_clock_core.MarkAsInitialized();
|
||||
|
||||
const auto current_time_point{standard_steady_clock_core.GetCurrentRawTimePoint(system)};
|
||||
shared_memory.SetupStandardSteadyClock(system, clock_source_id, current_time_point);
|
||||
}
|
||||
|
||||
void SetupStandardLocalSystemClock(Core::System& system,
|
||||
Clock::SystemClockContext clock_context, s64 posix_time) {
|
||||
standard_local_system_clock_core.SetUpdateCallbackInstance(
|
||||
local_system_clock_context_writer);
|
||||
|
||||
const auto current_time_point{
|
||||
standard_local_system_clock_core.GetSteadyClockCore().GetCurrentTimePoint(system)};
|
||||
if (current_time_point.clock_source_id == clock_context.steady_time_point.clock_source_id) {
|
||||
standard_local_system_clock_core.SetSystemClockContext(clock_context);
|
||||
} else {
|
||||
if (standard_local_system_clock_core.SetCurrentTime(system, posix_time) !=
|
||||
RESULT_SUCCESS) {
|
||||
UNREACHABLE();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
standard_local_system_clock_core.MarkAsInitialized();
|
||||
}
|
||||
|
||||
void SetupStandardNetworkSystemClock(Clock::SystemClockContext clock_context,
|
||||
Clock::TimeSpanType sufficient_accuracy) {
|
||||
standard_network_system_clock_core.SetUpdateCallbackInstance(
|
||||
network_system_clock_context_writer);
|
||||
|
||||
if (standard_network_system_clock_core.SetSystemClockContext(clock_context) !=
|
||||
RESULT_SUCCESS) {
|
||||
UNREACHABLE();
|
||||
return;
|
||||
}
|
||||
|
||||
standard_network_system_clock_core.SetStandardNetworkClockSufficientAccuracy(
|
||||
sufficient_accuracy);
|
||||
standard_network_system_clock_core.MarkAsInitialized();
|
||||
}
|
||||
|
||||
void SetupStandardUserSystemClock(Core::System& system, bool is_automatic_correction_enabled,
|
||||
Clock::SteadyClockTimePoint steady_clock_time_point) {
|
||||
if (standard_user_system_clock_core.SetAutomaticCorrectionEnabled(
|
||||
system, is_automatic_correction_enabled) != RESULT_SUCCESS) {
|
||||
UNREACHABLE();
|
||||
return;
|
||||
}
|
||||
|
||||
standard_user_system_clock_core.SetAutomaticCorrectionUpdatedTime(steady_clock_time_point);
|
||||
standard_user_system_clock_core.MarkAsInitialized();
|
||||
shared_memory.SetAutomaticCorrectionEnabled(is_automatic_correction_enabled);
|
||||
}
|
||||
|
||||
void SetupEphemeralNetworkSystemClock() {
|
||||
ephemeral_network_system_clock_core.SetUpdateCallbackInstance(
|
||||
ephemeral_network_system_clock_context_writer);
|
||||
ephemeral_network_system_clock_core.MarkAsInitialized();
|
||||
}
|
||||
|
||||
void UpdateLocalSystemClockTime(Core::System& system, s64 posix_time) {
|
||||
const auto timespan{Service::Time::Clock::TimeSpanType::FromSeconds(posix_time)};
|
||||
if (GetStandardLocalSystemClockCore()
|
||||
.SetCurrentTime(system, timespan.ToSeconds())
|
||||
.IsError()) {
|
||||
UNREACHABLE();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
SharedMemory shared_memory;
|
||||
|
||||
Clock::StandardSteadyClockCore standard_steady_clock_core;
|
||||
Clock::TickBasedSteadyClockCore tick_based_steady_clock_core;
|
||||
Clock::StandardLocalSystemClockCore standard_local_system_clock_core;
|
||||
Clock::StandardNetworkSystemClockCore standard_network_system_clock_core;
|
||||
Clock::StandardUserSystemClockCore standard_user_system_clock_core;
|
||||
Clock::EphemeralNetworkSystemClockCore ephemeral_network_system_clock_core;
|
||||
|
||||
std::shared_ptr<Clock::LocalSystemClockContextWriter> local_system_clock_context_writer;
|
||||
std::shared_ptr<Clock::NetworkSystemClockContextWriter> network_system_clock_context_writer;
|
||||
std::shared_ptr<Clock::EphemeralNetworkSystemClockContextWriter>
|
||||
ephemeral_network_system_clock_context_writer;
|
||||
|
||||
TimeZone::TimeZoneContentManager time_zone_content_manager;
|
||||
};
|
||||
|
||||
TimeManager::TimeManager(Core::System& system) : system{system} {}
|
||||
|
||||
TimeManager::~TimeManager() = default;
|
||||
|
||||
void TimeManager::Initialize() {
|
||||
impl = std::make_unique<Impl>(system);
|
||||
|
||||
// Time zones can only be initialized after impl is valid
|
||||
impl->time_zone_content_manager.Initialize(*this);
|
||||
}
|
||||
|
||||
Clock::StandardSteadyClockCore& TimeManager::GetStandardSteadyClockCore() {
|
||||
return impl->standard_steady_clock_core;
|
||||
}
|
||||
|
||||
const Clock::StandardSteadyClockCore& TimeManager::GetStandardSteadyClockCore() const {
|
||||
return impl->standard_steady_clock_core;
|
||||
}
|
||||
|
||||
Clock::StandardLocalSystemClockCore& TimeManager::GetStandardLocalSystemClockCore() {
|
||||
return impl->standard_local_system_clock_core;
|
||||
}
|
||||
|
||||
const Clock::StandardLocalSystemClockCore& TimeManager::GetStandardLocalSystemClockCore() const {
|
||||
return impl->standard_local_system_clock_core;
|
||||
}
|
||||
|
||||
Clock::StandardNetworkSystemClockCore& TimeManager::GetStandardNetworkSystemClockCore() {
|
||||
return impl->standard_network_system_clock_core;
|
||||
}
|
||||
|
||||
const Clock::StandardNetworkSystemClockCore& TimeManager::GetStandardNetworkSystemClockCore()
|
||||
const {
|
||||
return impl->standard_network_system_clock_core;
|
||||
}
|
||||
|
||||
Clock::StandardUserSystemClockCore& TimeManager::GetStandardUserSystemClockCore() {
|
||||
return impl->standard_user_system_clock_core;
|
||||
}
|
||||
|
||||
const Clock::StandardUserSystemClockCore& TimeManager::GetStandardUserSystemClockCore() const {
|
||||
return impl->standard_user_system_clock_core;
|
||||
}
|
||||
|
||||
TimeZone::TimeZoneContentManager& TimeManager::GetTimeZoneContentManager() {
|
||||
return impl->time_zone_content_manager;
|
||||
}
|
||||
|
||||
const TimeZone::TimeZoneContentManager& TimeManager::GetTimeZoneContentManager() const {
|
||||
return impl->time_zone_content_manager;
|
||||
}
|
||||
|
||||
SharedMemory& TimeManager::GetSharedMemory() {
|
||||
return impl->shared_memory;
|
||||
}
|
||||
|
||||
const SharedMemory& TimeManager::GetSharedMemory() const {
|
||||
return impl->shared_memory;
|
||||
}
|
||||
|
||||
void TimeManager::UpdateLocalSystemClockTime(s64 posix_time) {
|
||||
impl->UpdateLocalSystemClockTime(system, posix_time);
|
||||
}
|
||||
|
||||
void TimeManager::SetupTimeZoneManager(std::string location_name,
|
||||
Clock::SteadyClockTimePoint time_zone_updated_time_point,
|
||||
std::size_t total_location_name_count,
|
||||
u128 time_zone_rule_version,
|
||||
FileSys::VirtualFile& vfs_file) {
|
||||
impl->SetupTimeZoneManager(location_name, time_zone_updated_time_point,
|
||||
total_location_name_count, time_zone_rule_version, vfs_file);
|
||||
}
|
||||
|
||||
/*static*/ s64 TimeManager::GetExternalTimeZoneOffset() {
|
||||
// With "auto" timezone setting, we use the external system's timezone offset
|
||||
if (Settings::GetTimeZoneString() == "auto") {
|
||||
return Common::TimeZone::GetCurrentOffsetSeconds().count();
|
||||
@@ -30,117 +300,4 @@ static s64 GetExternalTimeZoneOffset() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static s64 GetExternalRtcValue() {
|
||||
return GetSecondsSinceEpoch().count() + GetExternalTimeZoneOffset();
|
||||
}
|
||||
|
||||
TimeManager::TimeManager(Core::System& system)
|
||||
: shared_memory{system}, standard_local_system_clock_core{standard_steady_clock_core},
|
||||
standard_network_system_clock_core{standard_steady_clock_core},
|
||||
standard_user_system_clock_core{standard_local_system_clock_core,
|
||||
standard_network_system_clock_core, system},
|
||||
ephemeral_network_system_clock_core{tick_based_steady_clock_core},
|
||||
local_system_clock_context_writer{
|
||||
std::make_shared<Clock::LocalSystemClockContextWriter>(shared_memory)},
|
||||
network_system_clock_context_writer{
|
||||
std::make_shared<Clock::NetworkSystemClockContextWriter>(shared_memory)},
|
||||
ephemeral_network_system_clock_context_writer{
|
||||
std::make_shared<Clock::EphemeralNetworkSystemClockContextWriter>()},
|
||||
time_zone_content_manager{*this, system} {
|
||||
|
||||
const auto system_time{Clock::TimeSpanType::FromSeconds(GetExternalRtcValue())};
|
||||
SetupStandardSteadyClock(system, Common::UUID::Generate(), system_time, {}, {});
|
||||
SetupStandardLocalSystemClock(system, {}, system_time.ToSeconds());
|
||||
SetupStandardNetworkSystemClock({}, standard_network_clock_accuracy);
|
||||
SetupStandardUserSystemClock(system, {}, Clock::SteadyClockTimePoint::GetRandom());
|
||||
SetupEphemeralNetworkSystemClock();
|
||||
}
|
||||
|
||||
TimeManager::~TimeManager() = default;
|
||||
|
||||
void TimeManager::SetupTimeZoneManager(std::string location_name,
|
||||
Clock::SteadyClockTimePoint time_zone_updated_time_point,
|
||||
std::size_t total_location_name_count,
|
||||
u128 time_zone_rule_version,
|
||||
FileSys::VirtualFile& vfs_file) {
|
||||
if (time_zone_content_manager.GetTimeZoneManager().SetDeviceLocationNameWithTimeZoneRule(
|
||||
location_name, vfs_file) != RESULT_SUCCESS) {
|
||||
UNREACHABLE();
|
||||
return;
|
||||
}
|
||||
|
||||
time_zone_content_manager.GetTimeZoneManager().SetUpdatedTime(time_zone_updated_time_point);
|
||||
time_zone_content_manager.GetTimeZoneManager().SetTotalLocationNameCount(
|
||||
total_location_name_count);
|
||||
time_zone_content_manager.GetTimeZoneManager().SetTimeZoneRuleVersion(time_zone_rule_version);
|
||||
time_zone_content_manager.GetTimeZoneManager().MarkAsInitialized();
|
||||
}
|
||||
|
||||
void TimeManager::SetupStandardSteadyClock(Core::System& system, Common::UUID clock_source_id,
|
||||
Clock::TimeSpanType setup_value,
|
||||
Clock::TimeSpanType internal_offset,
|
||||
bool is_rtc_reset_detected) {
|
||||
standard_steady_clock_core.SetClockSourceId(clock_source_id);
|
||||
standard_steady_clock_core.SetSetupValue(setup_value);
|
||||
standard_steady_clock_core.SetInternalOffset(internal_offset);
|
||||
standard_steady_clock_core.MarkAsInitialized();
|
||||
|
||||
const auto current_time_point{standard_steady_clock_core.GetCurrentRawTimePoint(system)};
|
||||
shared_memory.SetupStandardSteadyClock(system, clock_source_id, current_time_point);
|
||||
}
|
||||
|
||||
void TimeManager::SetupStandardLocalSystemClock(Core::System& system,
|
||||
Clock::SystemClockContext clock_context,
|
||||
s64 posix_time) {
|
||||
standard_local_system_clock_core.SetUpdateCallbackInstance(local_system_clock_context_writer);
|
||||
|
||||
const auto current_time_point{
|
||||
standard_local_system_clock_core.GetSteadyClockCore().GetCurrentTimePoint(system)};
|
||||
if (current_time_point.clock_source_id == clock_context.steady_time_point.clock_source_id) {
|
||||
standard_local_system_clock_core.SetSystemClockContext(clock_context);
|
||||
} else {
|
||||
if (standard_local_system_clock_core.SetCurrentTime(system, posix_time) != RESULT_SUCCESS) {
|
||||
UNREACHABLE();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
standard_local_system_clock_core.MarkAsInitialized();
|
||||
}
|
||||
|
||||
void TimeManager::SetupStandardNetworkSystemClock(Clock::SystemClockContext clock_context,
|
||||
Clock::TimeSpanType sufficient_accuracy) {
|
||||
standard_network_system_clock_core.SetUpdateCallbackInstance(
|
||||
network_system_clock_context_writer);
|
||||
|
||||
if (standard_network_system_clock_core.SetSystemClockContext(clock_context) != RESULT_SUCCESS) {
|
||||
UNREACHABLE();
|
||||
return;
|
||||
}
|
||||
|
||||
standard_network_system_clock_core.SetStandardNetworkClockSufficientAccuracy(
|
||||
sufficient_accuracy);
|
||||
standard_network_system_clock_core.MarkAsInitialized();
|
||||
}
|
||||
|
||||
void TimeManager::SetupStandardUserSystemClock(
|
||||
Core::System& system, bool is_automatic_correction_enabled,
|
||||
Clock::SteadyClockTimePoint steady_clock_time_point) {
|
||||
if (standard_user_system_clock_core.SetAutomaticCorrectionEnabled(
|
||||
system, is_automatic_correction_enabled) != RESULT_SUCCESS) {
|
||||
UNREACHABLE();
|
||||
return;
|
||||
}
|
||||
|
||||
standard_user_system_clock_core.SetAutomaticCorrectionUpdatedTime(steady_clock_time_point);
|
||||
standard_user_system_clock_core.MarkAsInitialized();
|
||||
shared_memory.SetAutomaticCorrectionEnabled(is_automatic_correction_enabled);
|
||||
}
|
||||
|
||||
void TimeManager::SetupEphemeralNetworkSystemClock() {
|
||||
ephemeral_network_system_clock_core.SetUpdateCallbackInstance(
|
||||
ephemeral_network_system_clock_context_writer);
|
||||
ephemeral_network_system_clock_core.MarkAsInitialized();
|
||||
}
|
||||
|
||||
} // namespace Service::Time
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "common/common_types.h"
|
||||
#include "common/time_zone.h"
|
||||
#include "core/file_sys/vfs_types.h"
|
||||
#include "core/hle/service/time/clock_types.h"
|
||||
#include "core/hle/service/time/ephemeral_network_system_clock_core.h"
|
||||
@@ -32,86 +33,46 @@ public:
|
||||
explicit TimeManager(Core::System& system);
|
||||
~TimeManager();
|
||||
|
||||
Clock::StandardSteadyClockCore& GetStandardSteadyClockCore() {
|
||||
return standard_steady_clock_core;
|
||||
}
|
||||
void Initialize();
|
||||
|
||||
const Clock::StandardSteadyClockCore& GetStandardSteadyClockCore() const {
|
||||
return standard_steady_clock_core;
|
||||
}
|
||||
Clock::StandardSteadyClockCore& GetStandardSteadyClockCore();
|
||||
|
||||
Clock::StandardLocalSystemClockCore& GetStandardLocalSystemClockCore() {
|
||||
return standard_local_system_clock_core;
|
||||
}
|
||||
const Clock::StandardSteadyClockCore& GetStandardSteadyClockCore() const;
|
||||
|
||||
const Clock::StandardLocalSystemClockCore& GetStandardLocalSystemClockCore() const {
|
||||
return standard_local_system_clock_core;
|
||||
}
|
||||
Clock::StandardLocalSystemClockCore& GetStandardLocalSystemClockCore();
|
||||
|
||||
Clock::StandardNetworkSystemClockCore& GetStandardNetworkSystemClockCore() {
|
||||
return standard_network_system_clock_core;
|
||||
}
|
||||
const Clock::StandardLocalSystemClockCore& GetStandardLocalSystemClockCore() const;
|
||||
|
||||
const Clock::StandardNetworkSystemClockCore& GetStandardNetworkSystemClockCore() const {
|
||||
return standard_network_system_clock_core;
|
||||
}
|
||||
Clock::StandardNetworkSystemClockCore& GetStandardNetworkSystemClockCore();
|
||||
|
||||
Clock::StandardUserSystemClockCore& GetStandardUserSystemClockCore() {
|
||||
return standard_user_system_clock_core;
|
||||
}
|
||||
const Clock::StandardNetworkSystemClockCore& GetStandardNetworkSystemClockCore() const;
|
||||
|
||||
const Clock::StandardUserSystemClockCore& GetStandardUserSystemClockCore() const {
|
||||
return standard_user_system_clock_core;
|
||||
}
|
||||
Clock::StandardUserSystemClockCore& GetStandardUserSystemClockCore();
|
||||
|
||||
TimeZone::TimeZoneContentManager& GetTimeZoneContentManager() {
|
||||
return time_zone_content_manager;
|
||||
}
|
||||
const Clock::StandardUserSystemClockCore& GetStandardUserSystemClockCore() const;
|
||||
|
||||
const TimeZone::TimeZoneContentManager& GetTimeZoneContentManager() const {
|
||||
return time_zone_content_manager;
|
||||
}
|
||||
TimeZone::TimeZoneContentManager& GetTimeZoneContentManager();
|
||||
|
||||
SharedMemory& GetSharedMemory() {
|
||||
return shared_memory;
|
||||
}
|
||||
const TimeZone::TimeZoneContentManager& GetTimeZoneContentManager() const;
|
||||
|
||||
const SharedMemory& GetSharedMemory() const {
|
||||
return shared_memory;
|
||||
}
|
||||
void UpdateLocalSystemClockTime(s64 posix_time);
|
||||
|
||||
SharedMemory& GetSharedMemory();
|
||||
|
||||
const SharedMemory& GetSharedMemory() const;
|
||||
|
||||
void SetupTimeZoneManager(std::string location_name,
|
||||
Clock::SteadyClockTimePoint time_zone_updated_time_point,
|
||||
std::size_t total_location_name_count, u128 time_zone_rule_version,
|
||||
FileSys::VirtualFile& vfs_file);
|
||||
|
||||
static s64 GetExternalTimeZoneOffset();
|
||||
|
||||
private:
|
||||
void SetupStandardSteadyClock(Core::System& system, Common::UUID clock_source_id,
|
||||
Clock::TimeSpanType setup_value,
|
||||
Clock::TimeSpanType internal_offset, bool is_rtc_reset_detected);
|
||||
void SetupStandardLocalSystemClock(Core::System& system,
|
||||
Clock::SystemClockContext clock_context, s64 posix_time);
|
||||
void SetupStandardNetworkSystemClock(Clock::SystemClockContext clock_context,
|
||||
Clock::TimeSpanType sufficient_accuracy);
|
||||
void SetupStandardUserSystemClock(Core::System& system, bool is_automatic_correction_enabled,
|
||||
Clock::SteadyClockTimePoint steady_clock_time_point);
|
||||
void SetupEphemeralNetworkSystemClock();
|
||||
Core::System& system;
|
||||
|
||||
SharedMemory shared_memory;
|
||||
|
||||
Clock::StandardSteadyClockCore standard_steady_clock_core;
|
||||
Clock::TickBasedSteadyClockCore tick_based_steady_clock_core;
|
||||
Clock::StandardLocalSystemClockCore standard_local_system_clock_core;
|
||||
Clock::StandardNetworkSystemClockCore standard_network_system_clock_core;
|
||||
Clock::StandardUserSystemClockCore standard_user_system_clock_core;
|
||||
Clock::EphemeralNetworkSystemClockCore ephemeral_network_system_clock_core;
|
||||
|
||||
std::shared_ptr<Clock::LocalSystemClockContextWriter> local_system_clock_context_writer;
|
||||
std::shared_ptr<Clock::NetworkSystemClockContextWriter> network_system_clock_context_writer;
|
||||
std::shared_ptr<Clock::EphemeralNetworkSystemClockContextWriter>
|
||||
ephemeral_network_system_clock_context_writer;
|
||||
|
||||
TimeZone::TimeZoneContentManager time_zone_content_manager;
|
||||
struct Impl;
|
||||
std::unique_ptr<Impl> impl;
|
||||
};
|
||||
|
||||
} // namespace Service::Time
|
||||
|
||||
@@ -68,9 +68,10 @@ static std::vector<std::string> BuildLocationNameCache(Core::System& system) {
|
||||
return location_name_cache;
|
||||
}
|
||||
|
||||
TimeZoneContentManager::TimeZoneContentManager(TimeManager& time_manager, Core::System& system)
|
||||
: system{system}, location_name_cache{BuildLocationNameCache(system)} {
|
||||
TimeZoneContentManager::TimeZoneContentManager(Core::System& system)
|
||||
: system{system}, location_name_cache{BuildLocationNameCache(system)} {}
|
||||
|
||||
void TimeZoneContentManager::Initialize(TimeManager& time_manager) {
|
||||
std::string location_name;
|
||||
const auto timezone_setting = Settings::GetTimeZoneString();
|
||||
if (timezone_setting == "auto" || timezone_setting == "default") {
|
||||
|
||||
@@ -21,7 +21,9 @@ namespace Service::Time::TimeZone {
|
||||
|
||||
class TimeZoneContentManager final {
|
||||
public:
|
||||
TimeZoneContentManager(TimeManager& time_manager, Core::System& system);
|
||||
TimeZoneContentManager(Core::System& system);
|
||||
|
||||
void Initialize(TimeManager& time_manager);
|
||||
|
||||
TimeZoneManager& GetTimeZoneManager() {
|
||||
return time_zone_manager;
|
||||
|
||||
@@ -76,16 +76,16 @@ std::optional<VAddr> AppLoader_NSO::LoadModule(Kernel::Process& process, Core::S
|
||||
bool should_pass_arguments, bool load_into_process,
|
||||
std::optional<FileSys::PatchManager> pm) {
|
||||
if (file.GetSize() < sizeof(NSOHeader)) {
|
||||
return {};
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
NSOHeader nso_header{};
|
||||
if (sizeof(NSOHeader) != file.ReadObject(&nso_header)) {
|
||||
return {};
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
if (nso_header.magic != Common::MakeMagic('N', 'S', 'O', '0')) {
|
||||
return {};
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
// Build program image
|
||||
|
||||
+1
-1
@@ -567,7 +567,7 @@ struct Memory::Impl {
|
||||
* @param page_table The page table to use to perform the mapping.
|
||||
* @param base The base address to begin mapping at.
|
||||
* @param size The total size of the range in bytes.
|
||||
* @param memory The memory to map.
|
||||
* @param target The target address to begin mapping from.
|
||||
* @param type The page type to map the memory as.
|
||||
*/
|
||||
void MapPages(Common::PageTable& page_table, VAddr base, u64 size, PAddr target,
|
||||
|
||||
@@ -7,6 +7,8 @@ add_library(input_common STATIC
|
||||
main.h
|
||||
motion_emu.cpp
|
||||
motion_emu.h
|
||||
motion_from_button.cpp
|
||||
motion_from_button.h
|
||||
motion_input.cpp
|
||||
motion_input.h
|
||||
settings.cpp
|
||||
|
||||
@@ -15,7 +15,9 @@
|
||||
#endif
|
||||
|
||||
#include "common/logging/log.h"
|
||||
#include "common/param_package.h"
|
||||
#include "input_common/gcadapter/gc_adapter.h"
|
||||
#include "input_common/settings.h"
|
||||
|
||||
namespace GCAdapter {
|
||||
|
||||
@@ -292,6 +294,92 @@ void Adapter::Reset() {
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<Common::ParamPackage> Adapter::GetInputDevices() const {
|
||||
std::vector<Common::ParamPackage> devices;
|
||||
for (std::size_t port = 0; port < state.size(); ++port) {
|
||||
if (!DeviceConnected(port)) {
|
||||
continue;
|
||||
}
|
||||
std::string name = fmt::format("Gamecube Controller {}", port);
|
||||
devices.emplace_back(Common::ParamPackage{
|
||||
{"class", "gcpad"},
|
||||
{"display", std::move(name)},
|
||||
{"port", std::to_string(port)},
|
||||
});
|
||||
}
|
||||
return devices;
|
||||
}
|
||||
|
||||
InputCommon::ButtonMapping Adapter::GetButtonMappingForDevice(
|
||||
const Common::ParamPackage& params) const {
|
||||
// This list is missing ZL/ZR since those are not considered buttons.
|
||||
// We will add those afterwards
|
||||
// This list also excludes any button that can't be really mapped
|
||||
static constexpr std::array<std::pair<Settings::NativeButton::Values, PadButton>, 12>
|
||||
switch_to_gcadapter_button = {
|
||||
std::pair{Settings::NativeButton::A, PadButton::PAD_BUTTON_A},
|
||||
{Settings::NativeButton::B, PadButton::PAD_BUTTON_B},
|
||||
{Settings::NativeButton::X, PadButton::PAD_BUTTON_X},
|
||||
{Settings::NativeButton::Y, PadButton::PAD_BUTTON_Y},
|
||||
{Settings::NativeButton::Plus, PadButton::PAD_BUTTON_START},
|
||||
{Settings::NativeButton::DLeft, PadButton::PAD_BUTTON_LEFT},
|
||||
{Settings::NativeButton::DUp, PadButton::PAD_BUTTON_UP},
|
||||
{Settings::NativeButton::DRight, PadButton::PAD_BUTTON_RIGHT},
|
||||
{Settings::NativeButton::DDown, PadButton::PAD_BUTTON_DOWN},
|
||||
{Settings::NativeButton::SL, PadButton::PAD_TRIGGER_L},
|
||||
{Settings::NativeButton::SR, PadButton::PAD_TRIGGER_R},
|
||||
{Settings::NativeButton::R, PadButton::PAD_TRIGGER_Z},
|
||||
};
|
||||
if (!params.Has("port")) {
|
||||
return {};
|
||||
}
|
||||
|
||||
InputCommon::ButtonMapping mapping{};
|
||||
for (const auto& [switch_button, gcadapter_button] : switch_to_gcadapter_button) {
|
||||
Common::ParamPackage button_params({{"engine", "gcpad"}});
|
||||
button_params.Set("port", params.Get("port", 0));
|
||||
button_params.Set("button", static_cast<int>(gcadapter_button));
|
||||
mapping.insert_or_assign(switch_button, std::move(button_params));
|
||||
}
|
||||
|
||||
// Add the missing bindings for ZL/ZR
|
||||
static constexpr std::array<std::pair<Settings::NativeButton::Values, PadAxes>, 2>
|
||||
switch_to_gcadapter_axis = {
|
||||
std::pair{Settings::NativeButton::ZL, PadAxes::TriggerLeft},
|
||||
{Settings::NativeButton::ZR, PadAxes::TriggerRight},
|
||||
};
|
||||
for (const auto& [switch_button, gcadapter_axis] : switch_to_gcadapter_axis) {
|
||||
Common::ParamPackage button_params({{"engine", "gcpad"}});
|
||||
button_params.Set("port", params.Get("port", 0));
|
||||
button_params.Set("button", static_cast<int>(PadButton::PAD_STICK));
|
||||
button_params.Set("axis", static_cast<int>(gcadapter_axis));
|
||||
mapping.insert_or_assign(switch_button, std::move(button_params));
|
||||
}
|
||||
return mapping;
|
||||
}
|
||||
|
||||
InputCommon::AnalogMapping Adapter::GetAnalogMappingForDevice(
|
||||
const Common::ParamPackage& params) const {
|
||||
if (!params.Has("port")) {
|
||||
return {};
|
||||
}
|
||||
|
||||
InputCommon::AnalogMapping mapping = {};
|
||||
Common::ParamPackage left_analog_params;
|
||||
left_analog_params.Set("engine", "gcpad");
|
||||
left_analog_params.Set("port", params.Get("port", 0));
|
||||
left_analog_params.Set("axis_x", static_cast<int>(PadAxes::StickX));
|
||||
left_analog_params.Set("axis_y", static_cast<int>(PadAxes::StickY));
|
||||
mapping.insert_or_assign(Settings::NativeAnalog::LStick, std::move(left_analog_params));
|
||||
Common::ParamPackage right_analog_params;
|
||||
right_analog_params.Set("engine", "gcpad");
|
||||
right_analog_params.Set("port", params.Get("port", 0));
|
||||
right_analog_params.Set("axis_x", static_cast<int>(PadAxes::SubstickX));
|
||||
right_analog_params.Set("axis_y", static_cast<int>(PadAxes::SubstickY));
|
||||
mapping.insert_or_assign(Settings::NativeAnalog::RStick, std::move(right_analog_params));
|
||||
return mapping;
|
||||
}
|
||||
|
||||
bool Adapter::DeviceConnected(std::size_t port) const {
|
||||
return adapter_controllers_status[port] != ControllerTypes::None;
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#include <unordered_map>
|
||||
#include "common/common_types.h"
|
||||
#include "common/threadsafe_queue.h"
|
||||
#include "input_common/main.h"
|
||||
|
||||
struct libusb_context;
|
||||
struct libusb_device;
|
||||
@@ -75,6 +76,10 @@ public:
|
||||
void BeginConfiguration();
|
||||
void EndConfiguration();
|
||||
|
||||
std::vector<Common::ParamPackage> GetInputDevices() const;
|
||||
InputCommon::ButtonMapping GetButtonMappingForDevice(const Common::ParamPackage& params) const;
|
||||
InputCommon::AnalogMapping GetAnalogMappingForDevice(const Common::ParamPackage& params) const;
|
||||
|
||||
/// Returns true if there is a device connected to port
|
||||
bool DeviceConnected(std::size_t port) const;
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#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/touch_from_button.h"
|
||||
#include "input_common/udp/client.h"
|
||||
#include "input_common/udp/udp.h"
|
||||
@@ -22,7 +23,7 @@ namespace InputCommon {
|
||||
|
||||
struct InputSubsystem::Impl {
|
||||
void Initialize() {
|
||||
auto gcadapter = std::make_shared<GCAdapter::Adapter>();
|
||||
gcadapter = std::make_shared<GCAdapter::Adapter>();
|
||||
gcbuttons = std::make_shared<GCButtonFactory>(gcadapter);
|
||||
Input::RegisterFactory<Input::ButtonDevice>("gcpad", gcbuttons);
|
||||
gcanalog = std::make_shared<GCAnalogFactory>(gcadapter);
|
||||
@@ -32,6 +33,8 @@ struct InputSubsystem::Impl {
|
||||
Input::RegisterFactory<Input::ButtonDevice>("keyboard", keyboard);
|
||||
Input::RegisterFactory<Input::AnalogDevice>("analog_from_button",
|
||||
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",
|
||||
@@ -50,6 +53,7 @@ struct InputSubsystem::Impl {
|
||||
|
||||
void Shutdown() {
|
||||
Input::UnregisterFactory<Input::ButtonDevice>("keyboard");
|
||||
Input::UnregisterFactory<Input::MotionDevice>("keyboard");
|
||||
keyboard.reset();
|
||||
Input::UnregisterFactory<Input::AnalogDevice>("analog_from_button");
|
||||
Input::UnregisterFactory<Input::MotionDevice>("motion_emu");
|
||||
@@ -82,6 +86,8 @@ struct InputSubsystem::Impl {
|
||||
#endif
|
||||
auto udp_devices = udp->GetInputDevices();
|
||||
devices.insert(devices.end(), udp_devices.begin(), udp_devices.end());
|
||||
auto gcpad_devices = gcadapter->GetInputDevices();
|
||||
devices.insert(devices.end(), gcpad_devices.begin(), gcpad_devices.end());
|
||||
return devices;
|
||||
}
|
||||
|
||||
@@ -94,6 +100,9 @@ struct InputSubsystem::Impl {
|
||||
// TODO consider returning the SDL key codes for the default keybindings
|
||||
return {};
|
||||
}
|
||||
if (params.Get("class", "") == "gcpad") {
|
||||
return gcadapter->GetAnalogMappingForDevice(params);
|
||||
}
|
||||
#ifdef HAVE_SDL2
|
||||
if (params.Get("class", "") == "sdl") {
|
||||
return sdl->GetAnalogMappingForDevice(params);
|
||||
@@ -111,6 +120,9 @@ struct InputSubsystem::Impl {
|
||||
// TODO consider returning the SDL key codes for the default keybindings
|
||||
return {};
|
||||
}
|
||||
if (params.Get("class", "") == "gcpad") {
|
||||
return gcadapter->GetButtonMappingForDevice(params);
|
||||
}
|
||||
#ifdef HAVE_SDL2
|
||||
if (params.Get("class", "") == "sdl") {
|
||||
return sdl->GetButtonMappingForDevice(params);
|
||||
@@ -141,6 +153,7 @@ struct InputSubsystem::Impl {
|
||||
std::shared_ptr<UDPMotionFactory> udpmotion;
|
||||
std::shared_ptr<UDPTouchFactory> udptouch;
|
||||
std::shared_ptr<CemuhookUDP::Client> udp;
|
||||
std::shared_ptr<GCAdapter::Adapter> gcadapter;
|
||||
};
|
||||
|
||||
InputSubsystem::InputSubsystem() : impl{std::make_unique<Impl>()} {}
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
// Copyright 2020 yuzu Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "input_common/motion_from_button.h"
|
||||
#include "input_common/motion_input.h"
|
||||
|
||||
namespace InputCommon {
|
||||
|
||||
class MotionKey final : public Input::MotionDevice {
|
||||
public:
|
||||
using Button = std::unique_ptr<Input::ButtonDevice>;
|
||||
|
||||
MotionKey(Button key_) : key(std::move(key_)) {}
|
||||
|
||||
Input::MotionStatus GetStatus() const override {
|
||||
|
||||
if (key->GetStatus()) {
|
||||
return motion.GetRandomMotion(2, 6);
|
||||
}
|
||||
return motion.GetRandomMotion(0, 0);
|
||||
}
|
||||
|
||||
private:
|
||||
Button key;
|
||||
InputCommon::MotionInput motion{0.0f, 0.0f, 0.0f};
|
||||
};
|
||||
|
||||
std::unique_ptr<Input::MotionDevice> MotionFromButton::Create(const Common::ParamPackage& params) {
|
||||
auto key = Input::CreateDevice<Input::ButtonDevice>(params.Serialize());
|
||||
return std::make_unique<MotionKey>(std::move(key));
|
||||
}
|
||||
|
||||
} // namespace InputCommon
|
||||
@@ -0,0 +1,25 @@
|
||||
// Copyright 2020 yuzu 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 {
|
||||
|
||||
/**
|
||||
* An motion device factory that takes a keyboard button and uses it as a random
|
||||
* motion device.
|
||||
*/
|
||||
class MotionFromButton final : public Input::Factory<Input::MotionDevice> {
|
||||
public:
|
||||
/**
|
||||
* Creates an motion device from button devices
|
||||
* @param params contains parameters for creating the device:
|
||||
* - "key": a serialized ParamPackage for creating a button device
|
||||
*/
|
||||
std::unique_ptr<Input::MotionDevice> Create(const Common::ParamPackage& params) override;
|
||||
};
|
||||
|
||||
} // namespace InputCommon
|
||||
@@ -2,6 +2,7 @@
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included
|
||||
|
||||
#include <random>
|
||||
#include "common/math_util.h"
|
||||
#include "input_common/motion_input.h"
|
||||
|
||||
@@ -16,8 +17,16 @@ void MotionInput::SetAcceleration(const Common::Vec3f& acceleration) {
|
||||
|
||||
void MotionInput::SetGyroscope(const Common::Vec3f& gyroscope) {
|
||||
gyro = gyroscope - gyro_drift;
|
||||
|
||||
// Auto adjust drift to minimize drift
|
||||
if (!IsMoving(0.1f)) {
|
||||
gyro_drift = (gyro_drift * 0.9999f) + (gyroscope * 0.0001f);
|
||||
}
|
||||
|
||||
if (gyro.Length2() < gyro_threshold) {
|
||||
gyro = {};
|
||||
} else {
|
||||
only_accelerometer = false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -68,7 +77,7 @@ void MotionInput::UpdateOrientation(u64 elapsed_time) {
|
||||
f32 q4 = quat.xyz[2];
|
||||
const f32 sample_period = elapsed_time / 1000000.0f;
|
||||
|
||||
// ignore invalid elapsed time
|
||||
// Ignore invalid elapsed time
|
||||
if (sample_period > 0.1f) {
|
||||
return;
|
||||
}
|
||||
@@ -80,6 +89,13 @@ void MotionInput::UpdateOrientation(u64 elapsed_time) {
|
||||
rad_gyro.y = -swap;
|
||||
rad_gyro.z = -rad_gyro.z;
|
||||
|
||||
// Clear gyro values if there is no gyro present
|
||||
if (only_accelerometer) {
|
||||
rad_gyro.x = 0;
|
||||
rad_gyro.y = 0;
|
||||
rad_gyro.z = 0;
|
||||
}
|
||||
|
||||
// Ignore drift correction if acceleration is not reliable
|
||||
if (accel.Length() >= 0.75f && accel.Length() <= 1.25f) {
|
||||
const f32 ax = -normal_accel.x;
|
||||
@@ -92,8 +108,11 @@ void MotionInput::UpdateOrientation(u64 elapsed_time) {
|
||||
const f32 vz = q1 * q1 - q2 * q2 - q3 * q3 + q4 * q4;
|
||||
|
||||
// Error is cross product between estimated direction and measured direction of gravity
|
||||
const Common::Vec3f new_real_error = {az * vx - ax * vz, ay * vz - az * vy,
|
||||
ax * vy - ay * vx};
|
||||
const Common::Vec3f new_real_error = {
|
||||
az * vx - ax * vz,
|
||||
ay * vz - az * vy,
|
||||
ax * vy - ay * vx,
|
||||
};
|
||||
|
||||
derivative_error = new_real_error - real_error;
|
||||
real_error = new_real_error;
|
||||
@@ -106,9 +125,22 @@ void MotionInput::UpdateOrientation(u64 elapsed_time) {
|
||||
}
|
||||
|
||||
// Apply feedback terms
|
||||
rad_gyro += kp * real_error;
|
||||
rad_gyro += ki * integral_error;
|
||||
rad_gyro += kd * derivative_error;
|
||||
if (!only_accelerometer) {
|
||||
rad_gyro += kp * real_error;
|
||||
rad_gyro += ki * integral_error;
|
||||
rad_gyro += kd * derivative_error;
|
||||
} else {
|
||||
// Give more weight to acelerometer values to compensate for the lack of gyro
|
||||
rad_gyro += 35.0f * kp * real_error;
|
||||
rad_gyro += 10.0f * ki * integral_error;
|
||||
rad_gyro += 10.0f * kd * derivative_error;
|
||||
|
||||
// Emulate gyro values for games that need them
|
||||
gyro.x = -rad_gyro.y;
|
||||
gyro.y = rad_gyro.x;
|
||||
gyro.z = -rad_gyro.z;
|
||||
UpdateRotation(elapsed_time);
|
||||
}
|
||||
}
|
||||
|
||||
const f32 gx = rad_gyro.y;
|
||||
@@ -159,18 +191,49 @@ Common::Vec3f MotionInput::GetRotations() const {
|
||||
return rotations;
|
||||
}
|
||||
|
||||
Input::MotionStatus MotionInput::GetMotion() const {
|
||||
const Common::Vec3f gyroscope = GetGyroscope();
|
||||
const Common::Vec3f accelerometer = GetAcceleration();
|
||||
const Common::Vec3f rotation = GetRotations();
|
||||
const std::array<Common::Vec3f, 3> orientation = GetOrientation();
|
||||
return {accelerometer, gyroscope, rotation, orientation};
|
||||
}
|
||||
|
||||
Input::MotionStatus MotionInput::GetRandomMotion(int accel_magnitude, int gyro_magnitude) const {
|
||||
std::random_device device;
|
||||
std::mt19937 gen(device());
|
||||
std::uniform_int_distribution<s16> distribution(-1000, 1000);
|
||||
const Common::Vec3f gyroscope = {
|
||||
distribution(gen) * 0.001f,
|
||||
distribution(gen) * 0.001f,
|
||||
distribution(gen) * 0.001f,
|
||||
};
|
||||
const Common::Vec3f accelerometer = {
|
||||
distribution(gen) * 0.001f,
|
||||
distribution(gen) * 0.001f,
|
||||
distribution(gen) * 0.001f,
|
||||
};
|
||||
const Common::Vec3f rotation = {};
|
||||
const std::array<Common::Vec3f, 3> orientation = {
|
||||
Common::Vec3f{1.0f, 0, 0},
|
||||
Common::Vec3f{0, 1.0f, 0},
|
||||
Common::Vec3f{0, 0, 1.0f},
|
||||
};
|
||||
return {accelerometer * accel_magnitude, gyroscope * gyro_magnitude, rotation, orientation};
|
||||
}
|
||||
|
||||
void MotionInput::ResetOrientation() {
|
||||
if (!reset_enabled) {
|
||||
if (!reset_enabled || only_accelerometer) {
|
||||
return;
|
||||
}
|
||||
if (!IsMoving(0.5f) && accel.z <= -0.9f) {
|
||||
++reset_counter;
|
||||
if (reset_counter > 900) {
|
||||
// TODO: calculate quaternion from gravity vector
|
||||
quat.w = 0;
|
||||
quat.xyz[0] = 0;
|
||||
quat.xyz[1] = 0;
|
||||
quat.xyz[2] = -1;
|
||||
SetOrientationFromAccelerometer();
|
||||
integral_error = {};
|
||||
reset_counter = 0;
|
||||
}
|
||||
@@ -178,4 +241,65 @@ void MotionInput::ResetOrientation() {
|
||||
reset_counter = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void MotionInput::SetOrientationFromAccelerometer() {
|
||||
int iterations = 0;
|
||||
const f32 sample_period = 0.015f;
|
||||
|
||||
const auto normal_accel = accel.Normalized();
|
||||
const f32 ax = -normal_accel.x;
|
||||
const f32 ay = normal_accel.y;
|
||||
const f32 az = -normal_accel.z;
|
||||
|
||||
while (!IsCalibrated(0.01f) && ++iterations < 100) {
|
||||
// Short name local variable for readability
|
||||
f32 q1 = quat.w;
|
||||
f32 q2 = quat.xyz[0];
|
||||
f32 q3 = quat.xyz[1];
|
||||
f32 q4 = quat.xyz[2];
|
||||
|
||||
Common::Vec3f rad_gyro = {};
|
||||
const f32 ax = -normal_accel.x;
|
||||
const f32 ay = normal_accel.y;
|
||||
const f32 az = -normal_accel.z;
|
||||
|
||||
// Estimated direction of gravity
|
||||
const f32 vx = 2.0f * (q2 * q4 - q1 * q3);
|
||||
const f32 vy = 2.0f * (q1 * q2 + q3 * q4);
|
||||
const f32 vz = q1 * q1 - q2 * q2 - q3 * q3 + q4 * q4;
|
||||
|
||||
// Error is cross product between estimated direction and measured direction of gravity
|
||||
const Common::Vec3f new_real_error = {
|
||||
az * vx - ax * vz,
|
||||
ay * vz - az * vy,
|
||||
ax * vy - ay * vx,
|
||||
};
|
||||
|
||||
derivative_error = new_real_error - real_error;
|
||||
real_error = new_real_error;
|
||||
|
||||
rad_gyro += 10.0f * kp * real_error;
|
||||
rad_gyro += 5.0f * ki * integral_error;
|
||||
rad_gyro += 10.0f * kd * derivative_error;
|
||||
|
||||
const f32 gx = rad_gyro.y;
|
||||
const f32 gy = rad_gyro.x;
|
||||
const f32 gz = rad_gyro.z;
|
||||
|
||||
// Integrate rate of change of quaternion
|
||||
const f32 pa = q2;
|
||||
const f32 pb = q3;
|
||||
const f32 pc = q4;
|
||||
q1 = q1 + (-q2 * gx - q3 * gy - q4 * gz) * (0.5f * sample_period);
|
||||
q2 = pa + (q1 * gx + pb * gz - pc * gy) * (0.5f * sample_period);
|
||||
q3 = pb + (q1 * gy - pa * gz + pc * gx) * (0.5f * sample_period);
|
||||
q4 = pc + (q1 * gz + pa * gy - pb * gx) * (0.5f * sample_period);
|
||||
|
||||
quat.w = q1;
|
||||
quat.xyz[0] = q2;
|
||||
quat.xyz[1] = q3;
|
||||
quat.xyz[2] = q4;
|
||||
quat = quat.Normalized();
|
||||
}
|
||||
}
|
||||
} // namespace InputCommon
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#include "common/common_types.h"
|
||||
#include "common/quaternion.h"
|
||||
#include "common/vector_math.h"
|
||||
#include "core/frontend/input.h"
|
||||
|
||||
namespace InputCommon {
|
||||
|
||||
@@ -37,12 +38,15 @@ public:
|
||||
Common::Vec3f GetGyroscope() const;
|
||||
Common::Vec3f GetRotations() const;
|
||||
Common::Quaternion<f32> GetQuaternion() const;
|
||||
Input::MotionStatus GetMotion() const;
|
||||
Input::MotionStatus GetRandomMotion(int accel_magnitude, int gyro_magnitude) const;
|
||||
|
||||
bool IsMoving(f32 sensitivity) const;
|
||||
bool IsCalibrated(f32 sensitivity) const;
|
||||
|
||||
private:
|
||||
void ResetOrientation();
|
||||
void SetOrientationFromAccelerometer();
|
||||
|
||||
// PID constants
|
||||
const f32 kp;
|
||||
@@ -63,6 +67,7 @@ private:
|
||||
f32 gyro_threshold = 0.0f;
|
||||
u32 reset_counter = 0;
|
||||
bool reset_enabled = true;
|
||||
bool only_accelerometer = true;
|
||||
};
|
||||
|
||||
} // namespace InputCommon
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <atomic>
|
||||
#include <chrono>
|
||||
#include <cmath>
|
||||
#include <functional>
|
||||
#include <mutex>
|
||||
@@ -21,6 +22,7 @@
|
||||
#include "common/param_package.h"
|
||||
#include "common/threadsafe_queue.h"
|
||||
#include "core/frontend/input.h"
|
||||
#include "input_common/motion_input.h"
|
||||
#include "input_common/sdl/sdl_impl.h"
|
||||
#include "input_common/settings.h"
|
||||
|
||||
@@ -78,6 +80,33 @@ public:
|
||||
return state.axes.at(axis) / (32767.0f * range);
|
||||
}
|
||||
|
||||
bool RumblePlay(f32 amp_low, f32 amp_high, int time) {
|
||||
const u16 raw_amp_low = static_cast<u16>(amp_low * 0xFFFF);
|
||||
const u16 raw_amp_high = static_cast<u16>(amp_high * 0xFFFF);
|
||||
// Lower drastically the number of state changes
|
||||
if (raw_amp_low >> 11 == last_state_rumble_low >> 11 &&
|
||||
raw_amp_high >> 11 == last_state_rumble_high >> 11) {
|
||||
if (raw_amp_low + raw_amp_high != 0 ||
|
||||
last_state_rumble_low + last_state_rumble_high == 0) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// Don't change state if last vibration was < 20ms
|
||||
const auto now = std::chrono::system_clock::now();
|
||||
if (std::chrono::duration_cast<std::chrono::milliseconds>(now - last_vibration) <
|
||||
std::chrono::milliseconds(20)) {
|
||||
return raw_amp_low + raw_amp_high == 0;
|
||||
}
|
||||
|
||||
last_vibration = now;
|
||||
last_state_rumble_low = raw_amp_low;
|
||||
last_state_rumble_high = raw_amp_high;
|
||||
if (sdl_joystick) {
|
||||
SDL_JoystickRumble(sdl_joystick.get(), raw_amp_low, raw_amp_high, time);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
std::tuple<float, float> GetAnalog(int axis_x, int axis_y, float range) const {
|
||||
float x = GetAxis(axis_x, range);
|
||||
float y = GetAxis(axis_y, range);
|
||||
@@ -95,6 +124,10 @@ public:
|
||||
return std::make_tuple(x, y);
|
||||
}
|
||||
|
||||
const InputCommon::MotionInput& GetMotion() const {
|
||||
return motion;
|
||||
}
|
||||
|
||||
void SetHat(int hat, Uint8 direction) {
|
||||
std::lock_guard lock{mutex};
|
||||
state.hats.insert_or_assign(hat, direction);
|
||||
@@ -139,9 +172,15 @@ private:
|
||||
} state;
|
||||
std::string guid;
|
||||
int port;
|
||||
u16 last_state_rumble_high;
|
||||
u16 last_state_rumble_low;
|
||||
std::chrono::time_point<std::chrono::system_clock> last_vibration;
|
||||
std::unique_ptr<SDL_Joystick, decltype(&SDL_JoystickClose)> sdl_joystick;
|
||||
std::unique_ptr<SDL_GameController, decltype(&SDL_GameControllerClose)> sdl_controller;
|
||||
mutable std::mutex mutex;
|
||||
|
||||
// motion is initalized without PID values as motion input is not aviable for SDL2
|
||||
InputCommon::MotionInput motion{0.0f, 0.0f, 0.0f};
|
||||
};
|
||||
|
||||
std::shared_ptr<SDLJoystick> SDLState::GetSDLJoystickByGUID(const std::string& guid, int port) {
|
||||
@@ -207,7 +246,7 @@ void SDLState::InitJoystick(int joystick_index) {
|
||||
sdl_gamecontroller = SDL_GameControllerOpen(joystick_index);
|
||||
}
|
||||
if (!sdl_joystick) {
|
||||
LOG_ERROR(Input, "failed to open joystick {}", joystick_index);
|
||||
LOG_ERROR(Input, "Failed to open joystick {}", joystick_index);
|
||||
return;
|
||||
}
|
||||
const std::string guid = GetGUID(sdl_joystick);
|
||||
@@ -303,6 +342,12 @@ public:
|
||||
return joystick->GetButton(button);
|
||||
}
|
||||
|
||||
bool SetRumblePlay(f32 amp_high, f32 amp_low, f32 freq_high, f32 freq_low) const override {
|
||||
const f32 new_amp_low = pow(amp_low, 0.5f) * (3.0f - 2.0f * pow(amp_low, 0.15f));
|
||||
const f32 new_amp_high = pow(amp_high, 0.5f) * (3.0f - 2.0f * pow(amp_high, 0.15f));
|
||||
return joystick->RumblePlay(new_amp_low, new_amp_high, 250);
|
||||
}
|
||||
|
||||
private:
|
||||
std::shared_ptr<SDLJoystick> joystick;
|
||||
int button;
|
||||
@@ -386,6 +431,68 @@ private:
|
||||
const float range;
|
||||
};
|
||||
|
||||
class SDLDirectionMotion final : public Input::MotionDevice {
|
||||
public:
|
||||
explicit SDLDirectionMotion(std::shared_ptr<SDLJoystick> joystick_, int hat_, Uint8 direction_)
|
||||
: joystick(std::move(joystick_)), hat(hat_), direction(direction_) {}
|
||||
|
||||
Input::MotionStatus GetStatus() const override {
|
||||
if (joystick->GetHatDirection(hat, direction)) {
|
||||
return joystick->GetMotion().GetRandomMotion(2, 6);
|
||||
}
|
||||
return joystick->GetMotion().GetRandomMotion(0, 0);
|
||||
}
|
||||
|
||||
private:
|
||||
std::shared_ptr<SDLJoystick> joystick;
|
||||
int hat;
|
||||
Uint8 direction;
|
||||
};
|
||||
|
||||
class SDLAxisMotion final : public Input::MotionDevice {
|
||||
public:
|
||||
explicit SDLAxisMotion(std::shared_ptr<SDLJoystick> joystick_, int axis_, float threshold_,
|
||||
bool trigger_if_greater_)
|
||||
: joystick(std::move(joystick_)), axis(axis_), threshold(threshold_),
|
||||
trigger_if_greater(trigger_if_greater_) {}
|
||||
|
||||
Input::MotionStatus GetStatus() const override {
|
||||
const float axis_value = joystick->GetAxis(axis, 1.0f);
|
||||
bool trigger = axis_value < threshold;
|
||||
if (trigger_if_greater) {
|
||||
trigger = axis_value > threshold;
|
||||
}
|
||||
|
||||
if (trigger) {
|
||||
return joystick->GetMotion().GetRandomMotion(2, 6);
|
||||
}
|
||||
return joystick->GetMotion().GetRandomMotion(0, 0);
|
||||
}
|
||||
|
||||
private:
|
||||
std::shared_ptr<SDLJoystick> joystick;
|
||||
int axis;
|
||||
float threshold;
|
||||
bool trigger_if_greater;
|
||||
};
|
||||
|
||||
class SDLButtonMotion final : public Input::MotionDevice {
|
||||
public:
|
||||
explicit SDLButtonMotion(std::shared_ptr<SDLJoystick> joystick_, int button_)
|
||||
: joystick(std::move(joystick_)), button(button_) {}
|
||||
|
||||
Input::MotionStatus GetStatus() const override {
|
||||
if (joystick->GetButton(button)) {
|
||||
return joystick->GetMotion().GetRandomMotion(2, 6);
|
||||
}
|
||||
return joystick->GetMotion().GetRandomMotion(0, 0);
|
||||
}
|
||||
|
||||
private:
|
||||
std::shared_ptr<SDLJoystick> joystick;
|
||||
int button;
|
||||
};
|
||||
|
||||
/// A button device factory that creates button devices from SDL joystick
|
||||
class SDLButtonFactory final : public Input::Factory<Input::ButtonDevice> {
|
||||
public:
|
||||
@@ -492,12 +599,78 @@ private:
|
||||
SDLState& state;
|
||||
};
|
||||
|
||||
/// A motion device factory that creates motion devices from SDL joystick
|
||||
class SDLMotionFactory final : public Input::Factory<Input::MotionDevice> {
|
||||
public:
|
||||
explicit SDLMotionFactory(SDLState& state_) : state(state_) {}
|
||||
/**
|
||||
* Creates motion device from joystick axes
|
||||
* @param params contains parameters for creating the device:
|
||||
* - "guid": the guid of the joystick to bind
|
||||
* - "port": the nth joystick of the same type
|
||||
*/
|
||||
std::unique_ptr<Input::MotionDevice> Create(const Common::ParamPackage& params) override {
|
||||
const std::string guid = params.Get("guid", "0");
|
||||
const int port = params.Get("port", 0);
|
||||
|
||||
auto joystick = state.GetSDLJoystickByGUID(guid, port);
|
||||
|
||||
if (params.Has("hat")) {
|
||||
const int hat = params.Get("hat", 0);
|
||||
const std::string direction_name = params.Get("direction", "");
|
||||
Uint8 direction;
|
||||
if (direction_name == "up") {
|
||||
direction = SDL_HAT_UP;
|
||||
} else if (direction_name == "down") {
|
||||
direction = SDL_HAT_DOWN;
|
||||
} else if (direction_name == "left") {
|
||||
direction = SDL_HAT_LEFT;
|
||||
} else if (direction_name == "right") {
|
||||
direction = SDL_HAT_RIGHT;
|
||||
} else {
|
||||
direction = 0;
|
||||
}
|
||||
// This is necessary so accessing GetHat with hat won't crash
|
||||
joystick->SetHat(hat, SDL_HAT_CENTERED);
|
||||
return std::make_unique<SDLDirectionMotion>(joystick, hat, direction);
|
||||
}
|
||||
|
||||
if (params.Has("axis")) {
|
||||
const int axis = params.Get("axis", 0);
|
||||
const float threshold = params.Get("threshold", 0.5f);
|
||||
const std::string direction_name = params.Get("direction", "");
|
||||
bool trigger_if_greater;
|
||||
if (direction_name == "+") {
|
||||
trigger_if_greater = true;
|
||||
} else if (direction_name == "-") {
|
||||
trigger_if_greater = false;
|
||||
} else {
|
||||
trigger_if_greater = true;
|
||||
LOG_ERROR(Input, "Unknown direction {}", direction_name);
|
||||
}
|
||||
// This is necessary so accessing GetAxis with axis won't crash
|
||||
joystick->SetAxis(axis, 0);
|
||||
return std::make_unique<SDLAxisMotion>(joystick, axis, threshold, trigger_if_greater);
|
||||
}
|
||||
|
||||
const int button = params.Get("button", 0);
|
||||
// This is necessary so accessing GetButton with button won't crash
|
||||
joystick->SetButton(button, false);
|
||||
return std::make_unique<SDLButtonMotion>(joystick, button);
|
||||
}
|
||||
|
||||
private:
|
||||
SDLState& state;
|
||||
};
|
||||
|
||||
SDLState::SDLState() {
|
||||
using namespace Input;
|
||||
analog_factory = std::make_shared<SDLAnalogFactory>(*this);
|
||||
button_factory = std::make_shared<SDLButtonFactory>(*this);
|
||||
motion_factory = std::make_shared<SDLMotionFactory>(*this);
|
||||
RegisterFactory<AnalogDevice>("sdl", analog_factory);
|
||||
RegisterFactory<ButtonDevice>("sdl", button_factory);
|
||||
RegisterFactory<MotionDevice>("sdl", motion_factory);
|
||||
|
||||
// If the frontend is going to manage the event loop, then we dont start one here
|
||||
start_thread = !SDL_WasInit(SDL_INIT_JOYSTICK);
|
||||
@@ -533,6 +706,7 @@ SDLState::~SDLState() {
|
||||
using namespace Input;
|
||||
UnregisterFactory<ButtonDevice>("sdl");
|
||||
UnregisterFactory<AnalogDevice>("sdl");
|
||||
UnregisterFactory<MotionDevice>("sdl");
|
||||
|
||||
CloseJoysticks();
|
||||
SDL_DelEventWatch(&SDLEventWatcher, this);
|
||||
@@ -644,6 +818,27 @@ Common::ParamPackage SDLEventToButtonParamPackage(SDLState& state, const SDL_Eve
|
||||
return {};
|
||||
}
|
||||
|
||||
Common::ParamPackage SDLEventToMotionParamPackage(SDLState& state, const SDL_Event& event) {
|
||||
switch (event.type) {
|
||||
case SDL_JOYAXISMOTION: {
|
||||
const auto joystick = state.GetSDLJoystickBySDLID(event.jaxis.which);
|
||||
return BuildAnalogParamPackageForButton(joystick->GetPort(), joystick->GetGUID(),
|
||||
event.jaxis.axis, event.jaxis.value);
|
||||
}
|
||||
case SDL_JOYBUTTONUP: {
|
||||
const auto joystick = state.GetSDLJoystickBySDLID(event.jbutton.which);
|
||||
return BuildButtonParamPackageForButton(joystick->GetPort(), joystick->GetGUID(),
|
||||
event.jbutton.button);
|
||||
}
|
||||
case SDL_JOYHATMOTION: {
|
||||
const auto joystick = state.GetSDLJoystickBySDLID(event.jhat.which);
|
||||
return BuildHatParamPackageForButton(joystick->GetPort(), joystick->GetGUID(),
|
||||
event.jhat.hat, event.jhat.value);
|
||||
}
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
Common::ParamPackage BuildParamPackageForBinding(int port, const std::string& guid,
|
||||
const SDL_GameControllerButtonBind& binding) {
|
||||
switch (binding.bindType) {
|
||||
@@ -809,6 +1004,35 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
class SDLMotionPoller final : public SDLPoller {
|
||||
public:
|
||||
explicit SDLMotionPoller(SDLState& state_) : SDLPoller(state_) {}
|
||||
|
||||
Common::ParamPackage GetNextInput() override {
|
||||
SDL_Event event;
|
||||
while (state.event_queue.Pop(event)) {
|
||||
const auto package = FromEvent(event);
|
||||
if (package) {
|
||||
return *package;
|
||||
}
|
||||
}
|
||||
return {};
|
||||
}
|
||||
[[nodiscard]] std::optional<Common::ParamPackage> FromEvent(const SDL_Event& event) const {
|
||||
switch (event.type) {
|
||||
case SDL_JOYAXISMOTION:
|
||||
if (std::abs(event.jaxis.value / 32767.0) < 0.5) {
|
||||
break;
|
||||
}
|
||||
[[fallthrough]];
|
||||
case SDL_JOYBUTTONUP:
|
||||
case SDL_JOYHATMOTION:
|
||||
return {SDLEventToMotionParamPackage(state, event)};
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Attempts to match the press to a controller joy axis (left/right stick) and if a match
|
||||
* isn't found, checks if the event matches anything from SDLButtonPoller and uses that
|
||||
@@ -900,6 +1124,9 @@ SDLState::Pollers SDLState::GetPollers(InputCommon::Polling::DeviceType type) {
|
||||
case InputCommon::Polling::DeviceType::Button:
|
||||
pollers.emplace_back(std::make_unique<Polling::SDLButtonPoller>(*this));
|
||||
break;
|
||||
case InputCommon::Polling::DeviceType::Motion:
|
||||
pollers.emplace_back(std::make_unique<Polling::SDLMotionPoller>(*this));
|
||||
break;
|
||||
}
|
||||
|
||||
return pollers;
|
||||
|
||||
@@ -21,6 +21,7 @@ namespace InputCommon::SDL {
|
||||
|
||||
class SDLAnalogFactory;
|
||||
class SDLButtonFactory;
|
||||
class SDLMotionFactory;
|
||||
class SDLJoystick;
|
||||
|
||||
class SDLState : public State {
|
||||
@@ -71,6 +72,7 @@ private:
|
||||
|
||||
std::shared_ptr<SDLButtonFactory> button_factory;
|
||||
std::shared_ptr<SDLAnalogFactory> analog_factory;
|
||||
std::shared_ptr<SDLMotionFactory> motion_factory;
|
||||
|
||||
bool start_thread = false;
|
||||
std::atomic<bool> initialized = false;
|
||||
|
||||
@@ -219,14 +219,10 @@ void Client::OnPadData(Response::PadData data) {
|
||||
clients[client].motion.SetGyroscope(raw_gyroscope / 312.0f);
|
||||
clients[client].motion.UpdateRotation(time_difference);
|
||||
clients[client].motion.UpdateOrientation(time_difference);
|
||||
Common::Vec3f gyroscope = clients[client].motion.GetGyroscope();
|
||||
Common::Vec3f accelerometer = clients[client].motion.GetAcceleration();
|
||||
Common::Vec3f rotation = clients[client].motion.GetRotations();
|
||||
std::array<Common::Vec3f, 3> orientation = clients[client].motion.GetOrientation();
|
||||
|
||||
{
|
||||
std::lock_guard guard(clients[client].status.update_mutex);
|
||||
clients[client].status.motion_status = {accelerometer, gyroscope, rotation, orientation};
|
||||
clients[client].status.motion_status = clients[client].motion.GetMotion();
|
||||
|
||||
// TODO: add a setting for "click" touch. Click touch refers to a device that differentiates
|
||||
// between a simple "tap" and a hard press that causes the touch screen to click.
|
||||
@@ -250,6 +246,8 @@ void Client::OnPadData(Response::PadData data) {
|
||||
clients[client].status.touch_status = {x, y, is_active};
|
||||
|
||||
if (configuring) {
|
||||
const Common::Vec3f gyroscope = clients[client].motion.GetGyroscope();
|
||||
const Common::Vec3f accelerometer = clients[client].motion.GetAcceleration();
|
||||
UpdateYuzuSettings(client, accelerometer, gyroscope, is_active);
|
||||
}
|
||||
}
|
||||
@@ -274,18 +272,22 @@ void Client::Reset() {
|
||||
|
||||
void Client::UpdateYuzuSettings(std::size_t client, const Common::Vec3<float>& acc,
|
||||
const Common::Vec3<float>& gyro, bool touch) {
|
||||
if (gyro.Length() > 0.2f) {
|
||||
LOG_DEBUG(Input, "UDP Controller {}: gyro=({}, {}, {}), accel=({}, {}, {}), touch={}",
|
||||
client, gyro[0], gyro[1], gyro[2], acc[0], acc[1], acc[2], touch);
|
||||
}
|
||||
UDPPadStatus pad;
|
||||
if (touch) {
|
||||
pad.touch = PadTouch::Click;
|
||||
pad_queue[client].Push(pad);
|
||||
}
|
||||
for (size_t i = 0; i < 3; ++i) {
|
||||
if (gyro[i] > 6.0f || gyro[i] < -6.0f) {
|
||||
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);
|
||||
}
|
||||
if (acc[i] > 2.0f || acc[i] < -2.0f) {
|
||||
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);
|
||||
|
||||
@@ -190,6 +190,8 @@ if (ENABLE_VULKAN)
|
||||
renderer_vulkan/vk_blit_screen.h
|
||||
renderer_vulkan/vk_buffer_cache.cpp
|
||||
renderer_vulkan/vk_buffer_cache.h
|
||||
renderer_vulkan/vk_command_pool.cpp
|
||||
renderer_vulkan/vk_command_pool.h
|
||||
renderer_vulkan/vk_compute_pass.cpp
|
||||
renderer_vulkan/vk_compute_pass.h
|
||||
renderer_vulkan/vk_compute_pipeline.cpp
|
||||
@@ -204,6 +206,8 @@ if (ENABLE_VULKAN)
|
||||
renderer_vulkan/vk_graphics_pipeline.h
|
||||
renderer_vulkan/vk_image.cpp
|
||||
renderer_vulkan/vk_image.h
|
||||
renderer_vulkan/vk_master_semaphore.cpp
|
||||
renderer_vulkan/vk_master_semaphore.h
|
||||
renderer_vulkan/vk_memory_manager.cpp
|
||||
renderer_vulkan/vk_memory_manager.h
|
||||
renderer_vulkan/vk_pipeline_cache.cpp
|
||||
@@ -214,8 +218,8 @@ if (ENABLE_VULKAN)
|
||||
renderer_vulkan/vk_rasterizer.h
|
||||
renderer_vulkan/vk_renderpass_cache.cpp
|
||||
renderer_vulkan/vk_renderpass_cache.h
|
||||
renderer_vulkan/vk_resource_manager.cpp
|
||||
renderer_vulkan/vk_resource_manager.h
|
||||
renderer_vulkan/vk_resource_pool.cpp
|
||||
renderer_vulkan/vk_resource_pool.h
|
||||
renderer_vulkan/vk_sampler_cache.cpp
|
||||
renderer_vulkan/vk_sampler_cache.h
|
||||
renderer_vulkan/vk_scheduler.cpp
|
||||
@@ -269,5 +273,12 @@ endif()
|
||||
if (MSVC)
|
||||
target_compile_options(video_core PRIVATE /we4267)
|
||||
else()
|
||||
target_compile_options(video_core PRIVATE -Werror=conversion -Wno-error=sign-conversion -Werror=switch)
|
||||
target_compile_options(video_core PRIVATE
|
||||
-Werror=conversion
|
||||
-Wno-error=sign-conversion
|
||||
-Werror=switch
|
||||
-Werror=unused-variable
|
||||
-Werror=unused-but-set-variable
|
||||
-Werror=class-memaccess
|
||||
)
|
||||
endif()
|
||||
|
||||
@@ -87,12 +87,12 @@ void Fermi2D::HandleSurfaceCopy() {
|
||||
const Common::Rectangle<u32> src_rect{src_blit_x1, src_blit_y1, src_blit_x2, src_blit_y2};
|
||||
const Common::Rectangle<u32> dst_rect{regs.blit_dst_x, regs.blit_dst_y, dst_blit_x2,
|
||||
dst_blit_y2};
|
||||
Config copy_config;
|
||||
copy_config.operation = regs.operation;
|
||||
copy_config.filter = regs.blit_control.filter;
|
||||
copy_config.src_rect = src_rect;
|
||||
copy_config.dst_rect = dst_rect;
|
||||
|
||||
const Config copy_config{
|
||||
.operation = regs.operation,
|
||||
.filter = regs.blit_control.filter,
|
||||
.src_rect = src_rect,
|
||||
.dst_rect = dst_rect,
|
||||
};
|
||||
if (!rasterizer->AccelerateSurfaceCopy(regs.src, regs.dst, copy_config)) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
@@ -145,8 +145,8 @@ public:
|
||||
} regs{};
|
||||
|
||||
struct Config {
|
||||
Operation operation;
|
||||
Filter filter;
|
||||
Operation operation{};
|
||||
Filter filter{};
|
||||
Common::Rectangle<u32> src_rect;
|
||||
Common::Rectangle<u32> dst_rect;
|
||||
};
|
||||
|
||||
@@ -597,7 +597,7 @@ std::optional<u64> Maxwell3D::GetQueryResult() {
|
||||
// Deferred.
|
||||
rasterizer->Query(regs.query.QueryAddress(), VideoCore::QueryType::SamplesPassed,
|
||||
system.GPU().GetTicks());
|
||||
return {};
|
||||
return std::nullopt;
|
||||
default:
|
||||
LOG_DEBUG(HW_GPU, "Unimplemented query select type {}",
|
||||
static_cast<u32>(regs.query.query_get.select.Value()));
|
||||
|
||||
@@ -114,8 +114,6 @@ void MaxwellDMA::CopyBlockLinearToPitch() {
|
||||
const u32 block_depth = src_params.block_size.depth;
|
||||
const size_t src_size =
|
||||
CalculateSize(true, bytes_per_pixel, width, height, depth, block_height, block_depth);
|
||||
const size_t src_layer_size =
|
||||
CalculateSize(true, bytes_per_pixel, width, height, 1, block_height, block_depth);
|
||||
|
||||
if (read_buffer.size() < src_size) {
|
||||
read_buffer.resize(src_size);
|
||||
|
||||
@@ -41,30 +41,30 @@ struct Header {
|
||||
BitField<26, 1, u32> does_load_or_store;
|
||||
BitField<27, 1, u32> does_fp64;
|
||||
BitField<28, 4, u32> stream_out_mask;
|
||||
} common0{};
|
||||
} common0;
|
||||
|
||||
union {
|
||||
BitField<0, 24, u32> shader_local_memory_low_size;
|
||||
BitField<24, 8, u32> per_patch_attribute_count;
|
||||
} common1{};
|
||||
} common1;
|
||||
|
||||
union {
|
||||
BitField<0, 24, u32> shader_local_memory_high_size;
|
||||
BitField<24, 8, u32> threads_per_input_primitive;
|
||||
} common2{};
|
||||
} common2;
|
||||
|
||||
union {
|
||||
BitField<0, 24, u32> shader_local_memory_crs_size;
|
||||
BitField<24, 4, OutputTopology> output_topology;
|
||||
BitField<28, 4, u32> reserved;
|
||||
} common3{};
|
||||
} common3;
|
||||
|
||||
union {
|
||||
BitField<0, 12, u32> max_output_vertices;
|
||||
BitField<12, 8, u32> store_req_start; // NOTE: not used by geometry shaders.
|
||||
BitField<20, 4, u32> reserved;
|
||||
BitField<24, 8, u32> store_req_end; // NOTE: not used by geometry shaders.
|
||||
} common4{};
|
||||
} common4;
|
||||
|
||||
union {
|
||||
struct {
|
||||
@@ -145,7 +145,7 @@ struct Header {
|
||||
}
|
||||
} ps;
|
||||
|
||||
std::array<u32, 0xF> raw{};
|
||||
std::array<u32, 0xF> raw;
|
||||
};
|
||||
|
||||
u64 GetLocalMemorySize() const {
|
||||
@@ -153,7 +153,6 @@ struct Header {
|
||||
(common2.shader_local_memory_high_size << 24));
|
||||
}
|
||||
};
|
||||
|
||||
static_assert(sizeof(Header) == 0x50, "Incorrect structure size");
|
||||
|
||||
} // namespace Tegra::Shader
|
||||
|
||||
@@ -36,7 +36,7 @@ void MacroEngine::Execute(Engines::Maxwell3D& maxwell3d, u32 method,
|
||||
}
|
||||
} else {
|
||||
// Macro not compiled, check if it's uploaded and if so, compile it
|
||||
std::optional<u32> mid_method = std::nullopt;
|
||||
std::optional<u32> mid_method;
|
||||
const auto macro_code = uploaded_macro_code.find(method);
|
||||
if (macro_code == uploaded_macro_code.end()) {
|
||||
for (const auto& [method_base, code] : uploaded_macro_code) {
|
||||
|
||||
@@ -58,7 +58,7 @@ void MemoryManager::Unmap(GPUVAddr gpu_addr, std::size_t size) {
|
||||
std::optional<GPUVAddr> MemoryManager::AllocateFixed(GPUVAddr gpu_addr, std::size_t size) {
|
||||
for (u64 offset{}; offset < size; offset += page_size) {
|
||||
if (!GetPageEntry(gpu_addr + offset).IsUnmapped()) {
|
||||
return {};
|
||||
return std::nullopt;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -135,13 +135,13 @@ std::optional<GPUVAddr> MemoryManager::FindFreeRange(std::size_t size, std::size
|
||||
}
|
||||
}
|
||||
|
||||
return {};
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
std::optional<VAddr> MemoryManager::GpuToCpuAddress(GPUVAddr gpu_addr) const {
|
||||
const auto page_entry{GetPageEntry(gpu_addr)};
|
||||
if (!page_entry.IsValid()) {
|
||||
return {};
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
return page_entry.ToAddress() + (gpu_addr & page_mask);
|
||||
|
||||
@@ -91,8 +91,7 @@ private:
|
||||
std::shared_ptr<HostCounter> last;
|
||||
};
|
||||
|
||||
template <class QueryCache, class CachedQuery, class CounterStream, class HostCounter,
|
||||
class QueryPool>
|
||||
template <class QueryCache, class CachedQuery, class CounterStream, class HostCounter>
|
||||
class QueryCacheBase {
|
||||
public:
|
||||
explicit QueryCacheBase(VideoCore::RasterizerInterface& rasterizer_,
|
||||
@@ -206,9 +205,6 @@ public:
|
||||
committed_flushes.pop_front();
|
||||
}
|
||||
|
||||
protected:
|
||||
std::array<QueryPool, VideoCore::NumQueryTypes> query_pools;
|
||||
|
||||
private:
|
||||
/// Flushes a memory range to guest memory and removes it from the cache.
|
||||
void FlushAndRemoveRegion(VAddr addr, std::size_t size) {
|
||||
|
||||
@@ -46,11 +46,6 @@ public:
|
||||
/// Finalize rendering the guest frame and draw into the presentation texture
|
||||
virtual void SwapBuffers(const Tegra::FramebufferConfig* framebuffer) = 0;
|
||||
|
||||
/// Draws the latest frame to the window waiting timeout_ms for a frame to arrive (Renderer
|
||||
/// specific implementation)
|
||||
/// Returns true if a frame was drawn
|
||||
virtual bool TryPresent(int timeout_ms) = 0;
|
||||
|
||||
// Getter/setter functions:
|
||||
// ------------------------
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user