mirror of
				https://git.suyu.dev/suyu/suyu
				synced 2025-10-30 23:49:01 -05:00 
			
		
		
		
	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
This commit is contained in:
		| @@ -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; | ||||
|   | ||||
| @@ -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, | ||||
|     }; | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 David
					David