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<u64>(CoreTiming::BASE_CLOCK_RATE / 200)};
 
 class IAudioRenderer final : public ServiceFramework<IAudioRenderer> {
 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<MemoryPoolInfo> 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<u8> output(response_data.total_size);
         std::memcpy(output.data(), &response_data, sizeof(AudioRendererResponse));
-        std::vector<MemoryPoolEntry> memory_pool(config.memory_pools_size / 0x20);
-        for (auto& entry : memory_pool) {
-            entry.state = 5;
+        std::vector<MemoryPoolEntry> 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<Kernel::Event> system_event;
+    AudioRendererParameters worker_params;
 };
 
 class IAudioDevice final : public ServiceFramework<IAudioDevice> {
@@ -259,10 +290,12 @@ AudRenU::AudRenU() : ServiceFramework("audren:u") {
 }
 
 void AudRenU::OpenAudioRenderer(Kernel::HLERequestContext& ctx) {
+    IPC::RequestParser rp{ctx};
+    auto params = rp.PopRaw<AudioRendererParameters>();
     IPC::ResponseBuilder rb{ctx, 2, 0, 1};
 
     rb.Push(RESULT_SUCCESS);
-    rb.PushIpcInterface<Audio::IAudioRenderer>();
+    rb.PushIpcInterface<Audio::IAudioRenderer>(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<AudioRendererParameters>();
 
-    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<AudRenU> {
 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,
     };
-- 
GitLab