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
	 David
						David