forked from ShuriZma/suyu
1
0
Fork 0

audio_renderer: Preliminary BehaviorInfo (#3736)

* audio_renderer: Preliminary BehaviorInfo

* clang format

* Fixed IsRevisionSupported

* fixed IsValidRevision

* Fixed logic error & spelling errors & crash

* Addressed issues
This commit is contained in:
David 2020-04-21 12:57:30 +10:00 committed by GitHub
parent d3e0cefa60
commit 11c63ca969
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 249 additions and 13 deletions

View File

@ -7,9 +7,12 @@ add_library(audio_core STATIC
audio_out.h audio_out.h
audio_renderer.cpp audio_renderer.cpp
audio_renderer.h audio_renderer.h
behavior_info.cpp
behavior_info.h
buffer.h buffer.h
codec.cpp codec.cpp
codec.h codec.h
common.h
null_sink.h null_sink.h
sink.h sink.h
sink_details.cpp sink_details.cpp

View File

@ -6,6 +6,7 @@
#include "audio_core/audio_out.h" #include "audio_core/audio_out.h"
#include "audio_core/audio_renderer.h" #include "audio_core/audio_renderer.h"
#include "audio_core/codec.h" #include "audio_core/codec.h"
#include "audio_core/common.h"
#include "common/assert.h" #include "common/assert.h"
#include "common/logging/log.h" #include "common/logging/log.h"
#include "core/core.h" #include "core/core.h"
@ -79,7 +80,7 @@ AudioRenderer::AudioRenderer(Core::Timing::CoreTiming& core_timing, Core::Memory
std::size_t instance_number) std::size_t instance_number)
: 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), memory{memory_} { effects(params.effect_count), memory{memory_} {
behavior_info.SetUserRevision(params.revision);
audio_out = std::make_unique<AudioCore::AudioOut>(); audio_out = std::make_unique<AudioCore::AudioOut>();
stream = audio_out->OpenStream(core_timing, STREAM_SAMPLE_RATE, STREAM_NUM_CHANNELS, stream = audio_out->OpenStream(core_timing, STREAM_SAMPLE_RATE, STREAM_NUM_CHANNELS,
fmt::format("AudioRenderer-Instance{}", instance_number), fmt::format("AudioRenderer-Instance{}", instance_number),
@ -109,17 +110,17 @@ Stream::State AudioRenderer::GetStreamState() const {
return stream->GetState(); return stream->GetState();
} }
static constexpr u32 VersionFromRevision(u32_le rev) { ResultVal<std::vector<u8>> AudioRenderer::UpdateAudioRenderer(const std::vector<u8>& input_params) {
// "REV7" -> 7
return ((rev >> 24) & 0xff) - 0x30;
}
std::vector<u8> AudioRenderer::UpdateAudioRenderer(const std::vector<u8>& input_params) {
// Copy UpdateDataHeader struct // Copy UpdateDataHeader struct
UpdateDataHeader config{}; UpdateDataHeader config{};
std::memcpy(&config, input_params.data(), sizeof(UpdateDataHeader)); std::memcpy(&config, input_params.data(), sizeof(UpdateDataHeader));
u32 memory_pool_count = worker_params.effect_count + (worker_params.voice_count * 4); u32 memory_pool_count = worker_params.effect_count + (worker_params.voice_count * 4);
if (!behavior_info.UpdateInput(input_params, sizeof(UpdateDataHeader))) {
LOG_ERROR(Audio, "Failed to update behavior info input parameters");
return Audren::ERR_INVALID_PARAMETERS;
}
// Copy MemoryPoolInfo structs // Copy MemoryPoolInfo structs
std::vector<MemoryPoolInfo> mem_pool_info(memory_pool_count); std::vector<MemoryPoolInfo> mem_pool_info(memory_pool_count);
std::memcpy(mem_pool_info.data(), std::memcpy(mem_pool_info.data(),
@ -173,8 +174,7 @@ std::vector<u8> AudioRenderer::UpdateAudioRenderer(const std::vector<u8>& input_
// Copy output header // Copy output header
UpdateDataHeader response_data{worker_params}; UpdateDataHeader response_data{worker_params};
std::vector<u8> output_params(response_data.total_size); std::vector<u8> output_params(response_data.total_size);
const auto audren_revision = VersionFromRevision(config.revision); if (behavior_info.IsElapsedFrameCountSupported()) {
if (audren_revision >= 5) {
response_data.frame_count = 0x10; response_data.frame_count = 0x10;
response_data.total_size += 0x10; response_data.total_size += 0x10;
} }
@ -200,7 +200,19 @@ std::vector<u8> AudioRenderer::UpdateAudioRenderer(const std::vector<u8>& input_
sizeof(EffectOutStatus)); sizeof(EffectOutStatus));
effect_out_status_offset += sizeof(EffectOutStatus); effect_out_status_offset += sizeof(EffectOutStatus);
} }
return output_params;
// Update behavior info output
const std::size_t behavior_out_status_offset{
sizeof(UpdateDataHeader) + response_data.memory_pools_size + response_data.voices_size +
response_data.effects_size + response_data.sinks_size +
response_data.performance_manager_size};
if (!behavior_info.UpdateOutput(output_params, behavior_out_status_offset)) {
LOG_ERROR(Audio, "Failed to update behavior info output parameters");
return Audren::ERR_INVALID_PARAMETERS;
}
return MakeResult(output_params);
} }
void AudioRenderer::VoiceState::SetWaveIndex(std::size_t index) { void AudioRenderer::VoiceState::SetWaveIndex(std::size_t index) {

View File

@ -8,11 +8,13 @@
#include <memory> #include <memory>
#include <vector> #include <vector>
#include "audio_core/behavior_info.h"
#include "audio_core/stream.h" #include "audio_core/stream.h"
#include "common/common_funcs.h" #include "common/common_funcs.h"
#include "common/common_types.h" #include "common/common_types.h"
#include "common/swap.h" #include "common/swap.h"
#include "core/hle/kernel/object.h" #include "core/hle/kernel/object.h"
#include "core/hle/result.h"
namespace Core::Timing { namespace Core::Timing {
class CoreTiming; class CoreTiming;
@ -226,7 +228,7 @@ public:
std::shared_ptr<Kernel::WritableEvent> buffer_event, std::size_t instance_number); std::shared_ptr<Kernel::WritableEvent> buffer_event, std::size_t instance_number);
~AudioRenderer(); ~AudioRenderer();
std::vector<u8> UpdateAudioRenderer(const std::vector<u8>& input_params); ResultVal<std::vector<u8>> UpdateAudioRenderer(const std::vector<u8>& input_params);
void QueueMixedBuffer(Buffer::Tag tag); void QueueMixedBuffer(Buffer::Tag tag);
void ReleaseAndQueueBuffers(); void ReleaseAndQueueBuffers();
u32 GetSampleRate() const; u32 GetSampleRate() const;
@ -237,6 +239,7 @@ public:
private: private:
class EffectState; class EffectState;
class VoiceState; class VoiceState;
BehaviorInfo behavior_info{};
AudioRendererParameter worker_params; AudioRendererParameter worker_params;
std::shared_ptr<Kernel::WritableEvent> buffer_event; std::shared_ptr<Kernel::WritableEvent> buffer_event;

View File

@ -0,0 +1,100 @@
// Copyright 2020 yuzu Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include <cstring>
#include "audio_core/behavior_info.h"
#include "audio_core/common.h"
#include "common/logging/log.h"
namespace AudioCore {
BehaviorInfo::BehaviorInfo() : process_revision(CURRENT_PROCESS_REVISION) {}
BehaviorInfo::~BehaviorInfo() = default;
bool BehaviorInfo::UpdateInput(const std::vector<u8>& buffer, std::size_t offset) {
if (!CanConsumeBuffer(buffer.size(), offset, sizeof(InParams))) {
LOG_ERROR(Audio, "Buffer is an invalid size!");
return false;
}
InParams params{};
std::memcpy(&params, buffer.data() + offset, sizeof(InParams));
if (!IsValidRevision(params.revision)) {
LOG_ERROR(Audio, "Invalid input revision, revision=0x{:08X}", params.revision);
return false;
}
if (user_revision != params.revision) {
LOG_ERROR(Audio,
"User revision differs from input revision, expecting 0x{:08X} but got 0x{:08X}",
user_revision, params.revision);
return false;
}
ClearError();
UpdateFlags(params.flags);
// TODO(ogniK): Check input params size when InfoUpdater is used
return true;
}
bool BehaviorInfo::UpdateOutput(std::vector<u8>& buffer, std::size_t offset) {
if (!CanConsumeBuffer(buffer.size(), offset, sizeof(OutParams))) {
LOG_ERROR(Audio, "Buffer is an invalid size!");
return false;
}
OutParams params{};
std::memcpy(params.errors.data(), errors.data(), sizeof(ErrorInfo) * errors.size());
params.error_count = static_cast<u32_le>(error_count);
std::memcpy(buffer.data() + offset, &params, sizeof(OutParams));
return true;
}
void BehaviorInfo::ClearError() {
error_count = 0;
}
void BehaviorInfo::UpdateFlags(u64_le dest_flags) {
flags = dest_flags;
}
void BehaviorInfo::SetUserRevision(u32_le revision) {
user_revision = revision;
}
bool BehaviorInfo::IsAdpcmLoopContextBugFixed() const {
return IsRevisionSupported(2, user_revision);
}
bool BehaviorInfo::IsSplitterSupported() const {
return IsRevisionSupported(2, user_revision);
}
bool BehaviorInfo::IsLongSizePreDelaySupported() const {
return IsRevisionSupported(3, user_revision);
}
bool BehaviorInfo::IsAudioRenererProcessingTimeLimit80PercentSupported() const {
return IsRevisionSupported(5, user_revision);
}
bool BehaviorInfo::IsAudioRenererProcessingTimeLimit75PercentSupported() const {
return IsRevisionSupported(4, user_revision);
}
bool BehaviorInfo::IsAudioRenererProcessingTimeLimit70PercentSupported() const {
return IsRevisionSupported(1, user_revision);
}
bool BehaviorInfo::IsElapsedFrameCountSupported() const {
return IsRevisionSupported(5, user_revision);
}
bool BehaviorInfo::IsMemoryPoolForceMappingEnabled() const {
return (flags & 1) != 0;
}
} // namespace AudioCore

View File

@ -0,0 +1,66 @@
// Copyright 2020 yuzu Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
#include <array>
#include <vector>
#include "common/common_funcs.h"
#include "common/common_types.h"
#include "common/swap.h"
namespace AudioCore {
class BehaviorInfo {
public:
explicit BehaviorInfo();
~BehaviorInfo();
bool UpdateInput(const std::vector<u8>& buffer, std::size_t offset);
bool UpdateOutput(std::vector<u8>& buffer, std::size_t offset);
void ClearError();
void UpdateFlags(u64_le dest_flags);
void SetUserRevision(u32_le revision);
bool IsAdpcmLoopContextBugFixed() const;
bool IsSplitterSupported() const;
bool IsLongSizePreDelaySupported() const;
bool IsAudioRenererProcessingTimeLimit80PercentSupported() const;
bool IsAudioRenererProcessingTimeLimit75PercentSupported() const;
bool IsAudioRenererProcessingTimeLimit70PercentSupported() const;
bool IsElapsedFrameCountSupported() const;
bool IsMemoryPoolForceMappingEnabled() const;
private:
u32_le process_revision{};
u32_le user_revision{};
u64_le flags{};
struct ErrorInfo {
u32_le result{};
INSERT_PADDING_WORDS(1);
u64_le result_info{};
};
static_assert(sizeof(ErrorInfo) == 0x10, "ErrorInfo is an invalid size");
std::array<ErrorInfo, 10> errors{};
std::size_t error_count{};
struct InParams {
u32_le revision{};
u32_le padding{};
u64_le flags{};
};
static_assert(sizeof(InParams) == 0x10, "InParams is an invalid size");
struct OutParams {
std::array<ErrorInfo, 10> errors{};
u32_le error_count{};
INSERT_PADDING_BYTES(12);
};
static_assert(sizeof(OutParams) == 0xb0, "OutParams is an invalid size");
};
} // namespace AudioCore

47
src/audio_core/common.h Normal file
View File

@ -0,0 +1,47 @@
// Copyright 2020 yuzu Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
#include "common/common_funcs.h"
#include "common/common_types.h"
#include "common/swap.h"
#include "core/hle/result.h"
namespace AudioCore {
namespace Audren {
constexpr ResultCode ERR_INVALID_PARAMETERS{ErrorModule::Audio, 41};
}
constexpr u32_le CURRENT_PROCESS_REVISION = Common::MakeMagic('R', 'E', 'V', '8');
static constexpr u32 VersionFromRevision(u32_le rev) {
// "REV7" -> 7
return ((rev >> 24) & 0xff) - 0x30;
}
static constexpr bool IsRevisionSupported(u32 required, u32_le user_revision) {
const auto base = VersionFromRevision(user_revision);
return required <= base;
}
static constexpr bool IsValidRevision(u32_le revision) {
const auto base = VersionFromRevision(revision);
constexpr auto max_rev = VersionFromRevision(CURRENT_PROCESS_REVISION);
return base <= max_rev;
}
static constexpr bool CanConsumeBuffer(std::size_t size, std::size_t offset, std::size_t required) {
if (offset > size) {
return false;
}
if (size < required) {
return false;
}
if ((size - offset) < required) {
return false;
}
return true;
}
} // namespace AudioCore

View File

@ -94,9 +94,14 @@ private:
void RequestUpdateImpl(Kernel::HLERequestContext& ctx) { void RequestUpdateImpl(Kernel::HLERequestContext& ctx) {
LOG_DEBUG(Service_Audio, "(STUBBED) called"); LOG_DEBUG(Service_Audio, "(STUBBED) called");
ctx.WriteBuffer(renderer->UpdateAudioRenderer(ctx.ReadBuffer())); auto result = renderer->UpdateAudioRenderer(ctx.ReadBuffer());
if (result.Succeeded()) {
ctx.WriteBuffer(result.Unwrap());
}
IPC::ResponseBuilder rb{ctx, 2}; IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS); rb.Push(result.Code());
} }
void Start(Kernel::HLERequestContext& ctx) { void Start(Kernel::HLERequestContext& ctx) {