Merge pull request #1455 from ogniK5377/smo-softlockfix

Fixed smo softlock due to incorrect effect state updating
This commit is contained in:
bunnei 2018-10-09 16:56:11 -04:00 committed by GitHub
commit 6aab309e41
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 123 additions and 15 deletions

View File

@ -30,7 +30,7 @@ public:
return info; return info;
} }
VoiceInfo& Info() { VoiceInfo& GetInfo() {
return info; return info;
} }
@ -51,9 +51,30 @@ private:
VoiceInfo info{}; VoiceInfo info{};
}; };
class AudioRenderer::EffectState {
public:
const EffectOutStatus& GetOutStatus() const {
return out_status;
}
const EffectInStatus& GetInfo() const {
return info;
}
EffectInStatus& GetInfo() {
return info;
}
void UpdateState();
private:
EffectOutStatus out_status{};
EffectInStatus info{};
};
AudioRenderer::AudioRenderer(AudioRendererParameter params, AudioRenderer::AudioRenderer(AudioRendererParameter params,
Kernel::SharedPtr<Kernel::Event> buffer_event) Kernel::SharedPtr<Kernel::Event> buffer_event)
: worker_params{params}, buffer_event{buffer_event}, voices(params.voice_count) { : worker_params{params}, buffer_event{buffer_event}, voices(params.voice_count),
effects(params.effect_count) {
audio_out = std::make_unique<AudioCore::AudioOut>(); audio_out = std::make_unique<AudioCore::AudioOut>();
stream = audio_out->OpenStream(STREAM_SAMPLE_RATE, STREAM_NUM_CHANNELS, "AudioRenderer", stream = audio_out->OpenStream(STREAM_SAMPLE_RATE, STREAM_NUM_CHANNELS, "AudioRenderer",
@ -96,11 +117,29 @@ std::vector<u8> AudioRenderer::UpdateAudioRenderer(const std::vector<u8>& input_
memory_pool_count * sizeof(MemoryPoolInfo)); memory_pool_count * sizeof(MemoryPoolInfo));
// Copy VoiceInfo structs // Copy VoiceInfo structs
std::size_t offset{sizeof(UpdateDataHeader) + config.behavior_size + config.memory_pools_size + std::size_t voice_offset{sizeof(UpdateDataHeader) + config.behavior_size +
config.voice_resource_size}; config.memory_pools_size + config.voice_resource_size};
for (auto& voice : voices) { for (auto& voice : voices) {
std::memcpy(&voice.Info(), input_params.data() + offset, sizeof(VoiceInfo)); std::memcpy(&voice.GetInfo(), input_params.data() + voice_offset, sizeof(VoiceInfo));
offset += sizeof(VoiceInfo); voice_offset += sizeof(VoiceInfo);
}
std::size_t effect_offset{sizeof(UpdateDataHeader) + config.behavior_size +
config.memory_pools_size + config.voice_resource_size +
config.voices_size};
for (auto& effect : effects) {
std::memcpy(&effect.GetInfo(), input_params.data() + effect_offset, sizeof(EffectInStatus));
effect_offset += sizeof(EffectInStatus);
}
// Update memory pool state
std::vector<MemoryPoolEntry> memory_pool(memory_pool_count);
for (std::size_t index = 0; index < memory_pool.size(); ++index) {
if (mem_pool_info[index].pool_state == MemoryPoolStates::RequestAttach) {
memory_pool[index].state = MemoryPoolStates::Attached;
} else if (mem_pool_info[index].pool_state == MemoryPoolStates::RequestDetach) {
memory_pool[index].state = MemoryPoolStates::Detached;
}
} }
// Update voices // Update voices
@ -114,14 +153,8 @@ std::vector<u8> AudioRenderer::UpdateAudioRenderer(const std::vector<u8>& input_
} }
} }
// Update memory pool state for (auto& effect : effects) {
std::vector<MemoryPoolEntry> memory_pool(memory_pool_count); effect.UpdateState();
for (std::size_t index = 0; index < memory_pool.size(); ++index) {
if (mem_pool_info[index].pool_state == MemoryPoolStates::RequestAttach) {
memory_pool[index].state = MemoryPoolStates::Attached;
} else if (mem_pool_info[index].pool_state == MemoryPoolStates::RequestDetach) {
memory_pool[index].state = MemoryPoolStates::Detached;
}
} }
// Release previous buffers and queue next ones for playback // Release previous buffers and queue next ones for playback
@ -144,6 +177,14 @@ std::vector<u8> AudioRenderer::UpdateAudioRenderer(const std::vector<u8>& input_
voice_out_status_offset += sizeof(VoiceOutStatus); voice_out_status_offset += sizeof(VoiceOutStatus);
} }
std::size_t effect_out_status_offset{
sizeof(UpdateDataHeader) + response_data.memory_pools_size + response_data.voices_size +
response_data.voice_resource_size};
for (const auto& effect : effects) {
std::memcpy(output_params.data() + effect_out_status_offset, &effect.GetOutStatus(),
sizeof(EffectOutStatus));
effect_out_status_offset += sizeof(EffectOutStatus);
}
return output_params; return output_params;
} }
@ -244,11 +285,29 @@ void AudioRenderer::VoiceState::RefreshBuffer() {
break; break;
} }
samples = Interpolate(interp_state, std::move(samples), Info().sample_rate, STREAM_SAMPLE_RATE); samples =
Interpolate(interp_state, std::move(samples), GetInfo().sample_rate, STREAM_SAMPLE_RATE);
is_refresh_pending = false; is_refresh_pending = false;
} }
void AudioRenderer::EffectState::UpdateState() {
if (info.is_new) {
out_status.state = EffectStatus::New;
} else {
if (info.type == Effect::Aux) {
ASSERT_MSG(Memory::Read32(info.aux_info.return_buffer_info) == 0,
"Aux buffers tried to update");
ASSERT_MSG(Memory::Read32(info.aux_info.send_buffer_info) == 0,
"Aux buffers tried to update");
ASSERT_MSG(Memory::Read32(info.aux_info.return_buffer_base) == 0,
"Aux buffers tried to update");
ASSERT_MSG(Memory::Read32(info.aux_info.send_buffer_base) == 0,
"Aux buffers tried to update");
}
}
}
static constexpr s16 ClampToS16(s32 value) { static constexpr s16 ClampToS16(s32 value) {
return static_cast<s16>(std::clamp(value, -32768, 32767)); return static_cast<s16>(std::clamp(value, -32768, 32767));
} }

View File

@ -28,6 +28,16 @@ enum class PlayState : u8 {
Paused = 2, Paused = 2,
}; };
enum class Effect : u8 {
None = 0,
Aux = 2,
};
enum class EffectStatus : u8 {
None = 0,
New = 1,
};
struct AudioRendererParameter { struct AudioRendererParameter {
u32_le sample_rate; u32_le sample_rate;
u32_le sample_count; u32_le sample_count;
@ -128,6 +138,43 @@ struct VoiceOutStatus {
}; };
static_assert(sizeof(VoiceOutStatus) == 0x10, "VoiceOutStatus has wrong size"); static_assert(sizeof(VoiceOutStatus) == 0x10, "VoiceOutStatus has wrong size");
struct AuxInfo {
std::array<u8, 24> input_mix_buffers;
std::array<u8, 24> output_mix_buffers;
u32_le mix_buffer_count;
u32_le sample_rate; // Stored in the aux buffer currently
u32_le sampe_count;
u64_le send_buffer_info;
u64_le send_buffer_base;
u64_le return_buffer_info;
u64_le return_buffer_base;
};
static_assert(sizeof(AuxInfo) == 0x60, "AuxInfo is an invalid size");
struct EffectInStatus {
Effect type;
u8 is_new;
u8 is_enabled;
INSERT_PADDING_BYTES(1);
u32_le mix_id;
u64_le buffer_base;
u64_le buffer_sz;
s32_le priority;
INSERT_PADDING_BYTES(4);
union {
std::array<u8, 0xa0> raw;
AuxInfo aux_info;
};
};
static_assert(sizeof(EffectInStatus) == 0xc0, "EffectInStatus is an invalid size");
struct EffectOutStatus {
EffectStatus state;
INSERT_PADDING_BYTES(0xf);
};
static_assert(sizeof(EffectOutStatus) == 0x10, "EffectOutStatus is an invalid size");
struct UpdateDataHeader { struct UpdateDataHeader {
UpdateDataHeader() {} UpdateDataHeader() {}
@ -173,11 +220,13 @@ public:
Stream::State GetStreamState() const; Stream::State GetStreamState() const;
private: private:
class EffectState;
class VoiceState; class VoiceState;
AudioRendererParameter worker_params; AudioRendererParameter worker_params;
Kernel::SharedPtr<Kernel::Event> buffer_event; Kernel::SharedPtr<Kernel::Event> buffer_event;
std::vector<VoiceState> voices; std::vector<VoiceState> voices;
std::vector<EffectState> effects;
std::unique_ptr<AudioOut> audio_out; std::unique_ptr<AudioOut> audio_out;
AudioCore::StreamPtr stream; AudioCore::StreamPtr stream;
}; };