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:
parent
ea1880f47c
commit
81f24f5685
|
@ -17,7 +17,8 @@ constexpr u64 audio_ticks{static_cast<u64>(CoreTiming::BASE_CLOCK_RATE / 200)};
|
||||||
|
|
||||||
class IAudioRenderer final : public ServiceFramework<IAudioRenderer> {
|
class IAudioRenderer final : public ServiceFramework<IAudioRenderer> {
|
||||||
public:
|
public:
|
||||||
IAudioRenderer() : ServiceFramework("IAudioRenderer") {
|
IAudioRenderer(AudioRendererParameters audren_params)
|
||||||
|
: ServiceFramework("IAudioRenderer"), worker_params(audren_params) {
|
||||||
static const FunctionInfo functions[] = {
|
static const FunctionInfo functions[] = {
|
||||||
{0, nullptr, "GetAudioRendererSampleRate"},
|
{0, nullptr, "GetAudioRendererSampleRate"},
|
||||||
{1, nullptr, "GetAudioRendererSampleCount"},
|
{1, nullptr, "GetAudioRendererSampleCount"},
|
||||||
|
@ -60,16 +61,27 @@ private:
|
||||||
AudioRendererConfig config;
|
AudioRendererConfig config;
|
||||||
auto buf = ctx.ReadBuffer();
|
auto buf = ctx.ReadBuffer();
|
||||||
std::memcpy(&config, buf.data(), sizeof(AudioRendererConfig));
|
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);
|
ASSERT(ctx.GetWriteBufferSize() == response_data.total_size);
|
||||||
|
|
||||||
std::vector<u8> output(response_data.total_size);
|
std::vector<u8> output(response_data.total_size);
|
||||||
std::memcpy(output.data(), &response_data, sizeof(AudioRendererResponse));
|
std::memcpy(output.data(), &response_data, sizeof(AudioRendererResponse));
|
||||||
std::vector<MemoryPoolEntry> memory_pool(config.memory_pools_size / 0x20);
|
std::vector<MemoryPoolEntry> memory_pool(memory_pool_count);
|
||||||
for (auto& entry : memory_pool) {
|
for (unsigned i = 0; i < memory_pool.size(); i++) {
|
||||||
entry.state = 5;
|
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(),
|
std::memcpy(output.data() + sizeof(AudioRendererResponse), memory_pool.data(),
|
||||||
response_data.memory_pools_size);
|
response_data.memory_pools_size);
|
||||||
|
@ -108,14 +120,32 @@ private:
|
||||||
NGLOG_WARNING(Service_Audio, "(STUBBED) called");
|
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 {
|
struct MemoryPoolEntry {
|
||||||
u32_le state;
|
MemoryPoolStates state;
|
||||||
u32_le unknown_4;
|
u32_le unknown_4;
|
||||||
u32_le unknown_8;
|
u32_le unknown_8;
|
||||||
u32_le unknown_c;
|
u32_le unknown_c;
|
||||||
};
|
};
|
||||||
static_assert(sizeof(MemoryPoolEntry) == 0x10, "MemoryPoolEntry has wrong size");
|
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 {
|
struct AudioRendererConfig {
|
||||||
u32 revision;
|
u32 revision;
|
||||||
u32 behavior_size;
|
u32 behavior_size;
|
||||||
|
@ -132,13 +162,13 @@ private:
|
||||||
static_assert(sizeof(AudioRendererConfig) == 0x40, "AudioRendererConfig has wrong size");
|
static_assert(sizeof(AudioRendererConfig) == 0x40, "AudioRendererConfig has wrong size");
|
||||||
|
|
||||||
struct AudioRendererResponse {
|
struct AudioRendererResponse {
|
||||||
AudioRendererResponse(const AudioRendererConfig& config) {
|
AudioRendererResponse(const AudioRendererParameters& config) {
|
||||||
revision = config.revision;
|
revision = config.revision;
|
||||||
error_info_size = 0xb0;
|
error_info_size = 0xb0;
|
||||||
memory_pools_size = (config.memory_pools_size / 0x20) * 0x10;
|
memory_pools_size = (config.effect_count + (config.voice_count * 4)) * 0x10;
|
||||||
voices_size = (config.voices_size / 0x170) * 0x10;
|
voices_size = config.voice_count * 0x10;
|
||||||
effects_size = (config.effects_size / 0xC0) * 0x10;
|
effects_size = config.effect_count * 0x10;
|
||||||
sinks_size = (config.sinks_size / 0x140) * 0x20;
|
sinks_size = config.sink_count * 0x20;
|
||||||
performance_manager_size = 0x10;
|
performance_manager_size = 0x10;
|
||||||
total_size = sizeof(AudioRendererResponse) + error_info_size + memory_pools_size +
|
total_size = sizeof(AudioRendererResponse) + error_info_size + memory_pools_size +
|
||||||
voices_size + effects_size + sinks_size + performance_manager_size;
|
voices_size + effects_size + sinks_size + performance_manager_size;
|
||||||
|
@ -162,6 +192,7 @@ private:
|
||||||
CoreTiming::EventType* audio_event;
|
CoreTiming::EventType* audio_event;
|
||||||
|
|
||||||
Kernel::SharedPtr<Kernel::Event> system_event;
|
Kernel::SharedPtr<Kernel::Event> system_event;
|
||||||
|
AudioRendererParameters worker_params;
|
||||||
};
|
};
|
||||||
|
|
||||||
class IAudioDevice final : public ServiceFramework<IAudioDevice> {
|
class IAudioDevice final : public ServiceFramework<IAudioDevice> {
|
||||||
|
@ -259,10 +290,12 @@ AudRenU::AudRenU() : ServiceFramework("audren:u") {
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudRenU::OpenAudioRenderer(Kernel::HLERequestContext& ctx) {
|
void AudRenU::OpenAudioRenderer(Kernel::HLERequestContext& ctx) {
|
||||||
|
IPC::RequestParser rp{ctx};
|
||||||
|
auto params = rp.PopRaw<AudioRendererParameters>();
|
||||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||||
|
|
||||||
rb.Push(RESULT_SUCCESS);
|
rb.Push(RESULT_SUCCESS);
|
||||||
rb.PushIpcInterface<Audio::IAudioRenderer>();
|
rb.PushIpcInterface<Audio::IAudioRenderer>(std::move(params));
|
||||||
|
|
||||||
NGLOG_DEBUG(Service_Audio, "called");
|
NGLOG_DEBUG(Service_Audio, "called");
|
||||||
}
|
}
|
||||||
|
@ -271,19 +304,19 @@ void AudRenU::GetAudioRendererWorkBufferSize(Kernel::HLERequestContext& ctx) {
|
||||||
IPC::RequestParser rp{ctx};
|
IPC::RequestParser rp{ctx};
|
||||||
auto params = rp.PopRaw<AudioRendererParameters>();
|
auto params = rp.PopRaw<AudioRendererParameters>();
|
||||||
|
|
||||||
u64 buffer_sz = Common::AlignUp(4 * params.unknown8, 0x40);
|
u64 buffer_sz = Common::AlignUp(4 * params.unknown_8, 0x40);
|
||||||
buffer_sz += params.unknownC * 1024;
|
buffer_sz += params.unknown_c * 1024;
|
||||||
buffer_sz += 0x940 * (params.unknownC + 1);
|
buffer_sz += 0x940 * (params.unknown_c + 1);
|
||||||
buffer_sz += 0x3F0 * params.voice_count;
|
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(8 * params.voice_count, 0x10);
|
||||||
buffer_sz +=
|
buffer_sz +=
|
||||||
Common::AlignUp((0x3C0 * (params.sink_count + params.unknownC) + 4 * params.sample_count) *
|
Common::AlignUp((0x3C0 * (params.sink_count + params.unknown_c) + 4 * params.sample_count) *
|
||||||
(params.unknown8 + 6),
|
(params.unknown_8 + 6),
|
||||||
0x40);
|
0x40);
|
||||||
|
|
||||||
if (IsFeatureSupported(AudioFeatures::Splitter, params.magic)) {
|
if (IsFeatureSupported(AudioFeatures::Splitter, params.revision)) {
|
||||||
u32 count = params.unknownC + 1;
|
u32 count = params.unknown_c + 1;
|
||||||
u64 node_count = Common::AlignUp(count, 0x40);
|
u64 node_count = Common::AlignUp(count, 0x40);
|
||||||
u64 node_state_buffer_sz =
|
u64 node_state_buffer_sz =
|
||||||
4 * (node_count * node_count) + 0xC * node_count + 2 * (node_count / 8);
|
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;
|
buffer_sz += 0x20 * (params.effect_count + 4 * params.voice_count) + 0x50;
|
||||||
if (IsFeatureSupported(AudioFeatures::Splitter, params.magic)) {
|
if (IsFeatureSupported(AudioFeatures::Splitter, params.revision)) {
|
||||||
buffer_sz += 0xE0 * params.unknown2c;
|
buffer_sz += 0xE0 * params.unknown_2c;
|
||||||
buffer_sz += 0x20 * params.splitter_count;
|
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;
|
buffer_sz = Common::AlignUp(buffer_sz, 0x40) + 0x170 * params.sink_count;
|
||||||
u64 output_sz = buffer_sz + 0x280 * params.sink_count + 0x4B0 * params.effect_count +
|
u64 output_sz = buffer_sz + 0x280 * params.sink_count + 0x4B0 * params.effect_count +
|
||||||
((params.voice_count * 256) | 0x40);
|
((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 +
|
output_sz = Common::AlignUp(((16 * params.sink_count + 16 * params.effect_count +
|
||||||
16 * params.voice_count + 16) +
|
16 * params.voice_count + 16) +
|
||||||
0x658) *
|
0x658) *
|
||||||
(params.unknown1c + 1) +
|
(params.unknown_1c + 1) +
|
||||||
0xc0,
|
0xc0,
|
||||||
0x40) +
|
0x40) +
|
||||||
output_sz;
|
output_sz;
|
||||||
|
|
|
@ -12,6 +12,24 @@ class HLERequestContext;
|
||||||
|
|
||||||
namespace Service::Audio {
|
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> {
|
class AudRenU final : public ServiceFramework<AudRenU> {
|
||||||
public:
|
public:
|
||||||
explicit AudRenU();
|
explicit AudRenU();
|
||||||
|
@ -22,25 +40,6 @@ private:
|
||||||
void GetAudioRendererWorkBufferSize(Kernel::HLERequestContext& ctx);
|
void GetAudioRendererWorkBufferSize(Kernel::HLERequestContext& ctx);
|
||||||
void GetAudioDevice(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 {
|
enum class AudioFeatures : u32 {
|
||||||
Splitter,
|
Splitter,
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in New Issue