From 81f24f568519ce7b035e3631b12a816e2a1c8579 Mon Sep 17 00:00:00 2001 From: David <25727384+ogniK5377@users.noreply.github.com> Date: Sat, 23 Jun 2018 12:22:33 +1000 Subject: [PATCH] Fixed RequestUpdateAudioRenderer deadlocks and calculated section sizes properly (#580) * Fixed RequestUpdateAudioRenderer deadlocks and calculated section sizes properly This fixes RequestUpdateAudioRenderer deadlocks in games like Puyo Puyo Tetris and games which require a proper section size in games such as Retro City Rampage. This fixes causes various games to start rendering or trying to render --- src/core/hle/service/audio/audren_u.cpp | 83 +++++++++++++++++-------- src/core/hle/service/audio/audren_u.h | 37 ++++++----- 2 files changed, 76 insertions(+), 44 deletions(-) diff --git a/src/core/hle/service/audio/audren_u.cpp b/src/core/hle/service/audio/audren_u.cpp index 44b7ef2166..653ded8e9e 100644 --- a/src/core/hle/service/audio/audren_u.cpp +++ b/src/core/hle/service/audio/audren_u.cpp @@ -17,7 +17,8 @@ constexpr u64 audio_ticks{static_cast(CoreTiming::BASE_CLOCK_RATE / 200)}; class IAudioRenderer final : public ServiceFramework { public: - IAudioRenderer() : ServiceFramework("IAudioRenderer") { + IAudioRenderer(AudioRendererParameters audren_params) + : ServiceFramework("IAudioRenderer"), worker_params(audren_params) { static const FunctionInfo functions[] = { {0, nullptr, "GetAudioRendererSampleRate"}, {1, nullptr, "GetAudioRendererSampleCount"}, @@ -60,16 +61,27 @@ private: AudioRendererConfig config; auto buf = ctx.ReadBuffer(); std::memcpy(&config, buf.data(), sizeof(AudioRendererConfig)); + u32 memory_pool_count = worker_params.effect_count + (worker_params.voice_count * 4); - AudioRendererResponse response_data{config}; + std::vector mem_pool_info(memory_pool_count); + std::memcpy(mem_pool_info.data(), + buf.data() + sizeof(AudioRendererConfig) + config.behavior_size, + memory_pool_count * sizeof(MemoryPoolInfo)); + + AudioRendererResponse response_data{worker_params}; ASSERT(ctx.GetWriteBufferSize() == response_data.total_size); std::vector output(response_data.total_size); std::memcpy(output.data(), &response_data, sizeof(AudioRendererResponse)); - std::vector memory_pool(config.memory_pools_size / 0x20); - for (auto& entry : memory_pool) { - entry.state = 5; + std::vector memory_pool(memory_pool_count); + for (unsigned i = 0; i < memory_pool.size(); i++) { + if (mem_pool_info[i].pool_state == MemoryPoolStates::RequestAttach) + memory_pool[i].state = MemoryPoolStates::Attached; + else if (mem_pool_info[i].pool_state == MemoryPoolStates::RequestDetach) + memory_pool[i].state = MemoryPoolStates::Detached; + else + memory_pool[i].state = mem_pool_info[i].pool_state; } std::memcpy(output.data() + sizeof(AudioRendererResponse), memory_pool.data(), response_data.memory_pools_size); @@ -108,14 +120,32 @@ private: NGLOG_WARNING(Service_Audio, "(STUBBED) called"); } + enum class MemoryPoolStates : u32 { // Should be LE + Invalid = 0x0, + Unknown = 0x1, + RequestDetach = 0x2, + Detached = 0x3, + RequestAttach = 0x4, + Attached = 0x5, + Released = 0x6, + }; + struct MemoryPoolEntry { - u32_le state; + MemoryPoolStates state; u32_le unknown_4; u32_le unknown_8; u32_le unknown_c; }; static_assert(sizeof(MemoryPoolEntry) == 0x10, "MemoryPoolEntry has wrong size"); + struct MemoryPoolInfo { + u64_le pool_address; + u64_le pool_size; + MemoryPoolStates pool_state; + INSERT_PADDING_WORDS(3); // Unknown + }; + static_assert(sizeof(MemoryPoolInfo) == 0x20, "MemoryPoolInfo has wrong size"); + struct AudioRendererConfig { u32 revision; u32 behavior_size; @@ -132,13 +162,13 @@ private: static_assert(sizeof(AudioRendererConfig) == 0x40, "AudioRendererConfig has wrong size"); struct AudioRendererResponse { - AudioRendererResponse(const AudioRendererConfig& config) { + AudioRendererResponse(const AudioRendererParameters& config) { revision = config.revision; error_info_size = 0xb0; - memory_pools_size = (config.memory_pools_size / 0x20) * 0x10; - voices_size = (config.voices_size / 0x170) * 0x10; - effects_size = (config.effects_size / 0xC0) * 0x10; - sinks_size = (config.sinks_size / 0x140) * 0x20; + memory_pools_size = (config.effect_count + (config.voice_count * 4)) * 0x10; + voices_size = config.voice_count * 0x10; + effects_size = config.effect_count * 0x10; + sinks_size = config.sink_count * 0x20; performance_manager_size = 0x10; total_size = sizeof(AudioRendererResponse) + error_info_size + memory_pools_size + voices_size + effects_size + sinks_size + performance_manager_size; @@ -162,6 +192,7 @@ private: CoreTiming::EventType* audio_event; Kernel::SharedPtr system_event; + AudioRendererParameters worker_params; }; class IAudioDevice final : public ServiceFramework { @@ -259,10 +290,12 @@ AudRenU::AudRenU() : ServiceFramework("audren:u") { } void AudRenU::OpenAudioRenderer(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + auto params = rp.PopRaw(); IPC::ResponseBuilder rb{ctx, 2, 0, 1}; rb.Push(RESULT_SUCCESS); - rb.PushIpcInterface(); + rb.PushIpcInterface(std::move(params)); NGLOG_DEBUG(Service_Audio, "called"); } @@ -271,19 +304,19 @@ void AudRenU::GetAudioRendererWorkBufferSize(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; auto params = rp.PopRaw(); - u64 buffer_sz = Common::AlignUp(4 * params.unknown8, 0x40); - buffer_sz += params.unknownC * 1024; - buffer_sz += 0x940 * (params.unknownC + 1); + u64 buffer_sz = Common::AlignUp(4 * params.unknown_8, 0x40); + buffer_sz += params.unknown_c * 1024; + buffer_sz += 0x940 * (params.unknown_c + 1); buffer_sz += 0x3F0 * params.voice_count; - buffer_sz += Common::AlignUp(8 * (params.unknownC + 1), 0x10); + buffer_sz += Common::AlignUp(8 * (params.unknown_c + 1), 0x10); buffer_sz += Common::AlignUp(8 * params.voice_count, 0x10); buffer_sz += - Common::AlignUp((0x3C0 * (params.sink_count + params.unknownC) + 4 * params.sample_count) * - (params.unknown8 + 6), + Common::AlignUp((0x3C0 * (params.sink_count + params.unknown_c) + 4 * params.sample_count) * + (params.unknown_8 + 6), 0x40); - if (IsFeatureSupported(AudioFeatures::Splitter, params.magic)) { - u32 count = params.unknownC + 1; + if (IsFeatureSupported(AudioFeatures::Splitter, params.revision)) { + u32 count = params.unknown_c + 1; u64 node_count = Common::AlignUp(count, 0x40); u64 node_state_buffer_sz = 4 * (node_count * node_count) + 0xC * node_count + 2 * (node_count / 8); @@ -298,20 +331,20 @@ void AudRenU::GetAudioRendererWorkBufferSize(Kernel::HLERequestContext& ctx) { } buffer_sz += 0x20 * (params.effect_count + 4 * params.voice_count) + 0x50; - if (IsFeatureSupported(AudioFeatures::Splitter, params.magic)) { - buffer_sz += 0xE0 * params.unknown2c; + if (IsFeatureSupported(AudioFeatures::Splitter, params.revision)) { + buffer_sz += 0xE0 * params.unknown_2c; buffer_sz += 0x20 * params.splitter_count; - buffer_sz += Common::AlignUp(4 * params.unknown2c, 0x10); + buffer_sz += Common::AlignUp(4 * params.unknown_2c, 0x10); } buffer_sz = Common::AlignUp(buffer_sz, 0x40) + 0x170 * params.sink_count; u64 output_sz = buffer_sz + 0x280 * params.sink_count + 0x4B0 * params.effect_count + ((params.voice_count * 256) | 0x40); - if (params.unknown1c >= 1) { + if (params.unknown_1c >= 1) { output_sz = Common::AlignUp(((16 * params.sink_count + 16 * params.effect_count + 16 * params.voice_count + 16) + 0x658) * - (params.unknown1c + 1) + + (params.unknown_1c + 1) + 0xc0, 0x40) + output_sz; diff --git a/src/core/hle/service/audio/audren_u.h b/src/core/hle/service/audio/audren_u.h index 7dbd9b74d3..e8baf99eea 100644 --- a/src/core/hle/service/audio/audren_u.h +++ b/src/core/hle/service/audio/audren_u.h @@ -12,6 +12,24 @@ class HLERequestContext; namespace Service::Audio { +struct AudioRendererParameters { + u32_le sample_rate; + u32_le sample_count; + u32_le unknown_8; + u32_le unknown_c; + u32_le voice_count; + u32_le sink_count; + u32_le effect_count; + u32_le unknown_1c; + u8 unknown_20; + INSERT_PADDING_BYTES(3); + u32_le splitter_count; + u32_le unknown_2c; + INSERT_PADDING_WORDS(1); + u32_le revision; +}; +static_assert(sizeof(AudioRendererParameters) == 52, "AudioRendererParameters is an invalid size"); + class AudRenU final : public ServiceFramework { public: explicit AudRenU(); @@ -22,25 +40,6 @@ private: void GetAudioRendererWorkBufferSize(Kernel::HLERequestContext& ctx); void GetAudioDevice(Kernel::HLERequestContext& ctx); - struct AudioRendererParameters { - u32_le sample_rate; - u32_le sample_count; - u32_le unknown8; - u32_le unknownC; - u32_le voice_count; - u32_le sink_count; - u32_le effect_count; - u32_le unknown1c; - u8 unknown20; - u8 padding1[3]; - u32_le splitter_count; - u32_le unknown2c; - u8 padding2[4]; - u32_le magic; - }; - static_assert(sizeof(AudioRendererParameters) == 52, - "AudioRendererParameters is an invalid size"); - enum class AudioFeatures : u32 { Splitter, };