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:
		
							parent
							
								
									d3e0cefa60
								
							
						
					
					
						commit
						11c63ca969
					
				@ -7,9 +7,12 @@ add_library(audio_core STATIC
 | 
			
		||||
    audio_out.h
 | 
			
		||||
    audio_renderer.cpp
 | 
			
		||||
    audio_renderer.h
 | 
			
		||||
    behavior_info.cpp
 | 
			
		||||
    behavior_info.h
 | 
			
		||||
    buffer.h
 | 
			
		||||
    codec.cpp
 | 
			
		||||
    codec.h
 | 
			
		||||
    common.h
 | 
			
		||||
    null_sink.h
 | 
			
		||||
    sink.h
 | 
			
		||||
    sink_details.cpp
 | 
			
		||||
 | 
			
		||||
@ -6,6 +6,7 @@
 | 
			
		||||
#include "audio_core/audio_out.h"
 | 
			
		||||
#include "audio_core/audio_renderer.h"
 | 
			
		||||
#include "audio_core/codec.h"
 | 
			
		||||
#include "audio_core/common.h"
 | 
			
		||||
#include "common/assert.h"
 | 
			
		||||
#include "common/logging/log.h"
 | 
			
		||||
#include "core/core.h"
 | 
			
		||||
@ -79,7 +80,7 @@ AudioRenderer::AudioRenderer(Core::Timing::CoreTiming& core_timing, Core::Memory
 | 
			
		||||
                             std::size_t instance_number)
 | 
			
		||||
    : worker_params{params}, buffer_event{buffer_event}, voices(params.voice_count),
 | 
			
		||||
      effects(params.effect_count), memory{memory_} {
 | 
			
		||||
 | 
			
		||||
    behavior_info.SetUserRevision(params.revision);
 | 
			
		||||
    audio_out = std::make_unique<AudioCore::AudioOut>();
 | 
			
		||||
    stream = audio_out->OpenStream(core_timing, STREAM_SAMPLE_RATE, STREAM_NUM_CHANNELS,
 | 
			
		||||
                                   fmt::format("AudioRenderer-Instance{}", instance_number),
 | 
			
		||||
@ -109,17 +110,17 @@ Stream::State AudioRenderer::GetStreamState() const {
 | 
			
		||||
    return stream->GetState();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static constexpr u32 VersionFromRevision(u32_le rev) {
 | 
			
		||||
    // "REV7" -> 7
 | 
			
		||||
    return ((rev >> 24) & 0xff) - 0x30;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
std::vector<u8> AudioRenderer::UpdateAudioRenderer(const std::vector<u8>& input_params) {
 | 
			
		||||
ResultVal<std::vector<u8>> AudioRenderer::UpdateAudioRenderer(const std::vector<u8>& input_params) {
 | 
			
		||||
    // Copy UpdateDataHeader struct
 | 
			
		||||
    UpdateDataHeader config{};
 | 
			
		||||
    std::memcpy(&config, input_params.data(), sizeof(UpdateDataHeader));
 | 
			
		||||
    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
 | 
			
		||||
    std::vector<MemoryPoolInfo> mem_pool_info(memory_pool_count);
 | 
			
		||||
    std::memcpy(mem_pool_info.data(),
 | 
			
		||||
@ -173,8 +174,7 @@ std::vector<u8> AudioRenderer::UpdateAudioRenderer(const std::vector<u8>& input_
 | 
			
		||||
    // Copy output header
 | 
			
		||||
    UpdateDataHeader response_data{worker_params};
 | 
			
		||||
    std::vector<u8> output_params(response_data.total_size);
 | 
			
		||||
    const auto audren_revision = VersionFromRevision(config.revision);
 | 
			
		||||
    if (audren_revision >= 5) {
 | 
			
		||||
    if (behavior_info.IsElapsedFrameCountSupported()) {
 | 
			
		||||
        response_data.frame_count = 0x10;
 | 
			
		||||
        response_data.total_size += 0x10;
 | 
			
		||||
    }
 | 
			
		||||
@ -200,7 +200,19 @@ std::vector<u8> AudioRenderer::UpdateAudioRenderer(const std::vector<u8>& input_
 | 
			
		||||
                    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) {
 | 
			
		||||
 | 
			
		||||
@ -8,11 +8,13 @@
 | 
			
		||||
#include <memory>
 | 
			
		||||
#include <vector>
 | 
			
		||||
 | 
			
		||||
#include "audio_core/behavior_info.h"
 | 
			
		||||
#include "audio_core/stream.h"
 | 
			
		||||
#include "common/common_funcs.h"
 | 
			
		||||
#include "common/common_types.h"
 | 
			
		||||
#include "common/swap.h"
 | 
			
		||||
#include "core/hle/kernel/object.h"
 | 
			
		||||
#include "core/hle/result.h"
 | 
			
		||||
 | 
			
		||||
namespace Core::Timing {
 | 
			
		||||
class CoreTiming;
 | 
			
		||||
@ -226,7 +228,7 @@ public:
 | 
			
		||||
                  std::shared_ptr<Kernel::WritableEvent> buffer_event, std::size_t instance_number);
 | 
			
		||||
    ~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 ReleaseAndQueueBuffers();
 | 
			
		||||
    u32 GetSampleRate() const;
 | 
			
		||||
@ -237,6 +239,7 @@ public:
 | 
			
		||||
private:
 | 
			
		||||
    class EffectState;
 | 
			
		||||
    class VoiceState;
 | 
			
		||||
    BehaviorInfo behavior_info{};
 | 
			
		||||
 | 
			
		||||
    AudioRendererParameter worker_params;
 | 
			
		||||
    std::shared_ptr<Kernel::WritableEvent> buffer_event;
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										100
									
								
								src/audio_core/behavior_info.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										100
									
								
								src/audio_core/behavior_info.cpp
									
									
									
									
									
										Normal 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(¶ms, 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, ¶ms, 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
 | 
			
		||||
							
								
								
									
										66
									
								
								src/audio_core/behavior_info.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										66
									
								
								src/audio_core/behavior_info.h
									
									
									
									
									
										Normal 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
									
								
							
							
						
						
									
										47
									
								
								src/audio_core/common.h
									
									
									
									
									
										Normal 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
 | 
			
		||||
@ -94,9 +94,14 @@ private:
 | 
			
		||||
    void RequestUpdateImpl(Kernel::HLERequestContext& ctx) {
 | 
			
		||||
        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};
 | 
			
		||||
        rb.Push(RESULT_SUCCESS);
 | 
			
		||||
        rb.Push(result.Code());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void Start(Kernel::HLERequestContext& ctx) {
 | 
			
		||||
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user