early-access version 3384
This commit is contained in:
parent
45615dab82
commit
0f6c8ffea1
@ -1,7 +1,7 @@
|
|||||||
yuzu emulator early access
|
yuzu emulator early access
|
||||||
=============
|
=============
|
||||||
|
|
||||||
This is the source code for early-access 3383.
|
This is the source code for early-access 3384.
|
||||||
|
|
||||||
## Legal Notice
|
## Legal Notice
|
||||||
|
|
||||||
|
@ -48,7 +48,7 @@ public:
|
|||||||
*
|
*
|
||||||
* @param out_buffers - The buffers which were registered.
|
* @param out_buffers - The buffers which were registered.
|
||||||
*/
|
*/
|
||||||
void RegisterBuffers(std::span<AudioBuffer> out_buffers, u32& out_size) {
|
void RegisterBuffers(std::vector<AudioBuffer>& out_buffers) {
|
||||||
std::scoped_lock l{lock};
|
std::scoped_lock l{lock};
|
||||||
const s32 to_register{std::min(std::min(appended_count, BufferAppendLimit),
|
const s32 to_register{std::min(std::min(appended_count, BufferAppendLimit),
|
||||||
BufferAppendLimit - registered_count)};
|
BufferAppendLimit - registered_count)};
|
||||||
@ -59,7 +59,7 @@ public:
|
|||||||
index += N;
|
index += N;
|
||||||
}
|
}
|
||||||
|
|
||||||
out_buffers[out_size++] = buffers[index];
|
out_buffers.push_back(buffers[index]);
|
||||||
registered_count++;
|
registered_count++;
|
||||||
registered_index = (registered_index + 1) % append_limit;
|
registered_index = (registered_index + 1) % append_limit;
|
||||||
|
|
||||||
@ -162,7 +162,7 @@ public:
|
|||||||
* @param max_buffers - Maximum number of buffers to released.
|
* @param max_buffers - Maximum number of buffers to released.
|
||||||
* @return The number of buffers released.
|
* @return The number of buffers released.
|
||||||
*/
|
*/
|
||||||
u32 GetRegisteredAppendedBuffers(std::span<AudioBuffer> out_buffers, u32 max_buffers) {
|
u32 GetRegisteredAppendedBuffers(std::vector<AudioBuffer>& buffers_flushed, u32 max_buffers) {
|
||||||
std::scoped_lock l{lock};
|
std::scoped_lock l{lock};
|
||||||
if (registered_count + appended_count == 0) {
|
if (registered_count + appended_count == 0) {
|
||||||
return 0;
|
return 0;
|
||||||
@ -174,20 +174,19 @@ public:
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 buffers_flushed{0};
|
|
||||||
while (registered_count > 0) {
|
while (registered_count > 0) {
|
||||||
auto index{registered_index - registered_count};
|
auto index{registered_index - registered_count};
|
||||||
if (index < 0) {
|
if (index < 0) {
|
||||||
index += N;
|
index += N;
|
||||||
}
|
}
|
||||||
|
|
||||||
out_buffers[buffers_flushed++] = buffers[index];
|
buffers_flushed.push_back(buffers[index]);
|
||||||
|
|
||||||
registered_count--;
|
registered_count--;
|
||||||
released_count++;
|
released_count++;
|
||||||
released_index = (released_index + 1) % append_limit;
|
released_index = (released_index + 1) % append_limit;
|
||||||
|
|
||||||
if (buffers_flushed >= buffers_to_flush) {
|
if (buffers_flushed.size() >= buffers_to_flush) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -198,18 +197,18 @@ public:
|
|||||||
index += N;
|
index += N;
|
||||||
}
|
}
|
||||||
|
|
||||||
out_buffers[buffers_flushed++] = buffers[index];
|
buffers_flushed.push_back(buffers[index]);
|
||||||
|
|
||||||
appended_count--;
|
appended_count--;
|
||||||
released_count++;
|
released_count++;
|
||||||
released_index = (released_index + 1) % append_limit;
|
released_index = (released_index + 1) % append_limit;
|
||||||
|
|
||||||
if (buffers_flushed >= buffers_to_flush) {
|
if (buffers_flushed.size() >= buffers_to_flush) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return buffers_flushed;
|
return static_cast<u32>(buffers_flushed.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -271,9 +270,8 @@ public:
|
|||||||
*/
|
*/
|
||||||
bool FlushBuffers(u32& buffers_released) {
|
bool FlushBuffers(u32& buffers_released) {
|
||||||
std::scoped_lock l{lock};
|
std::scoped_lock l{lock};
|
||||||
|
std::vector<AudioBuffer> buffers_flushed{};
|
||||||
|
|
||||||
static Common::ScratchBuffer<AudioBuffer> buffers_flushed{};
|
|
||||||
buffers_flushed.resize_destructive(append_limit);
|
|
||||||
buffers_released = GetRegisteredAppendedBuffers(buffers_flushed, append_limit);
|
buffers_released = GetRegisteredAppendedBuffers(buffers_flushed, append_limit);
|
||||||
|
|
||||||
if (registered_count > 0) {
|
if (registered_count > 0) {
|
||||||
|
@ -6,7 +6,6 @@
|
|||||||
#include "audio_core/device/audio_buffer.h"
|
#include "audio_core/device/audio_buffer.h"
|
||||||
#include "audio_core/device/device_session.h"
|
#include "audio_core/device/device_session.h"
|
||||||
#include "audio_core/sink/sink_stream.h"
|
#include "audio_core/sink/sink_stream.h"
|
||||||
#include "common/scratch_buffer.h"
|
|
||||||
#include "core/core.h"
|
#include "core/core.h"
|
||||||
#include "core/core_timing.h"
|
#include "core/core_timing.h"
|
||||||
#include "core/memory.h"
|
#include "core/memory.h"
|
||||||
@ -80,22 +79,21 @@ void DeviceSession::ClearBuffers() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void DeviceSession::AppendBuffers(std::span<const AudioBuffer> buffers, u32 out_size) const {
|
void DeviceSession::AppendBuffers(std::span<const AudioBuffer> buffers) const {
|
||||||
static Common::ScratchBuffer<s16> samples{};
|
for (const auto& buffer : buffers) {
|
||||||
|
|
||||||
for (u32 i = 0; i < out_size; i++) {
|
|
||||||
Sink::SinkBuffer new_buffer{
|
Sink::SinkBuffer new_buffer{
|
||||||
.frames = buffers[i].size / (channel_count * sizeof(s16)),
|
.frames = buffer.size / (channel_count * sizeof(s16)),
|
||||||
.frames_played = 0,
|
.frames_played = 0,
|
||||||
.tag = buffers[i].tag,
|
.tag = buffer.tag,
|
||||||
.consumed = false,
|
.consumed = false,
|
||||||
};
|
};
|
||||||
|
|
||||||
if (type == Sink::StreamType::In) {
|
if (type == Sink::StreamType::In) {
|
||||||
|
std::vector<s16> samples{};
|
||||||
stream->AppendBuffer(new_buffer, samples);
|
stream->AppendBuffer(new_buffer, samples);
|
||||||
} else {
|
} else {
|
||||||
samples.resize_destructive(buffers[i].size / sizeof(s16));
|
std::vector<s16> samples(buffer.size / sizeof(s16));
|
||||||
system.Memory().ReadBlockUnsafe(buffers[i].samples, samples.data(), buffers[i].size);
|
system.Memory().ReadBlockUnsafe(buffer.samples, samples.data(), buffer.size);
|
||||||
stream->AppendBuffer(new_buffer, samples);
|
stream->AppendBuffer(new_buffer, samples);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -62,7 +62,7 @@ public:
|
|||||||
*
|
*
|
||||||
* @param buffers - The buffers to play.
|
* @param buffers - The buffers to play.
|
||||||
*/
|
*/
|
||||||
void AppendBuffers(std::span<const AudioBuffer> buffers, u32 out_size) const;
|
void AppendBuffers(std::span<const AudioBuffer> buffers) const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* (Audio In only) Pop samples from the backend, and write them back to this buffer's address.
|
* (Audio In only) Pop samples from the backend, and write them back to this buffer's address.
|
||||||
|
@ -89,10 +89,9 @@ Result System::Start() {
|
|||||||
session->Start();
|
session->Start();
|
||||||
state = State::Started;
|
state = State::Started;
|
||||||
|
|
||||||
std::array<AudioBuffer, BufferAppendLimit> buffers_to_flush{};
|
std::vector<AudioBuffer> buffers_to_flush{};
|
||||||
u32 out_size{0};
|
buffers.RegisterBuffers(buffers_to_flush);
|
||||||
buffers.RegisterBuffers(buffers_to_flush, out_size);
|
session->AppendBuffers(buffers_to_flush);
|
||||||
session->AppendBuffers(buffers_to_flush, out_size);
|
|
||||||
session->SetRingSize(static_cast<u32>(buffers_to_flush.size()));
|
session->SetRingSize(static_cast<u32>(buffers_to_flush.size()));
|
||||||
|
|
||||||
return ResultSuccess;
|
return ResultSuccess;
|
||||||
@ -135,10 +134,9 @@ bool System::AppendBuffer(const AudioInBuffer& buffer, const u64 tag) {
|
|||||||
|
|
||||||
void System::RegisterBuffers() {
|
void System::RegisterBuffers() {
|
||||||
if (state == State::Started) {
|
if (state == State::Started) {
|
||||||
std::array<AudioBuffer, BufferAppendLimit> registered_buffers{};
|
std::vector<AudioBuffer> registered_buffers{};
|
||||||
u32 out_size{0};
|
buffers.RegisterBuffers(registered_buffers);
|
||||||
buffers.RegisterBuffers(registered_buffers, out_size);
|
session->AppendBuffers(registered_buffers);
|
||||||
session->AppendBuffers(registered_buffers, out_size);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -89,10 +89,9 @@ Result System::Start() {
|
|||||||
session->Start();
|
session->Start();
|
||||||
state = State::Started;
|
state = State::Started;
|
||||||
|
|
||||||
std::array<AudioBuffer, BufferAppendLimit> buffers_to_flush{};
|
std::vector<AudioBuffer> buffers_to_flush{};
|
||||||
u32 out_size{0};
|
buffers.RegisterBuffers(buffers_to_flush);
|
||||||
buffers.RegisterBuffers(buffers_to_flush, out_size);
|
session->AppendBuffers(buffers_to_flush);
|
||||||
session->AppendBuffers(buffers_to_flush, out_size);
|
|
||||||
session->SetRingSize(static_cast<u32>(buffers_to_flush.size()));
|
session->SetRingSize(static_cast<u32>(buffers_to_flush.size()));
|
||||||
|
|
||||||
return ResultSuccess;
|
return ResultSuccess;
|
||||||
@ -135,10 +134,9 @@ bool System::AppendBuffer(const AudioOutBuffer& buffer, u64 tag) {
|
|||||||
|
|
||||||
void System::RegisterBuffers() {
|
void System::RegisterBuffers() {
|
||||||
if (state == State::Started) {
|
if (state == State::Started) {
|
||||||
std::array<AudioBuffer, BufferAppendLimit> registered_buffers{};
|
std::vector<AudioBuffer> registered_buffers{};
|
||||||
u32 out_size{0};
|
buffers.RegisterBuffers(registered_buffers);
|
||||||
buffers.RegisterBuffers(registered_buffers, out_size);
|
session->AppendBuffers(registered_buffers);
|
||||||
session->AppendBuffers(registered_buffers, out_size);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -46,7 +46,7 @@ void CommandGenerator::GenerateDataSourceCommand(VoiceInfo& voice_info,
|
|||||||
while (destination != nullptr) {
|
while (destination != nullptr) {
|
||||||
if (destination->IsConfigured()) {
|
if (destination->IsConfigured()) {
|
||||||
auto mix_id{destination->GetMixId()};
|
auto mix_id{destination->GetMixId()};
|
||||||
if (mix_id < mix_context.GetCount() && mix_id != -1) {
|
if (mix_id < mix_context.GetCount() && mix_id != UnusedSplitterId) {
|
||||||
auto mix_info{mix_context.GetInfo(mix_id)};
|
auto mix_info{mix_context.GetInfo(mix_id)};
|
||||||
command_buffer.GenerateDepopPrepareCommand(
|
command_buffer.GenerateDepopPrepareCommand(
|
||||||
voice_info.node_id, voice_state, render_context.depop_buffer,
|
voice_info.node_id, voice_state, render_context.depop_buffer,
|
||||||
|
@ -8,7 +8,6 @@
|
|||||||
#include "audio_core/renderer/command/resample/resample.h"
|
#include "audio_core/renderer/command/resample/resample.h"
|
||||||
#include "common/fixed_point.h"
|
#include "common/fixed_point.h"
|
||||||
#include "common/logging/log.h"
|
#include "common/logging/log.h"
|
||||||
#include "common/scratch_buffer.h"
|
|
||||||
#include "core/memory.h"
|
#include "core/memory.h"
|
||||||
|
|
||||||
namespace AudioCore::AudioRenderer {
|
namespace AudioCore::AudioRenderer {
|
||||||
@ -30,7 +29,6 @@ static u32 DecodePcm(Core::Memory::Memory& memory, std::span<s16> out_buffer,
|
|||||||
const DecodeArg& req) {
|
const DecodeArg& req) {
|
||||||
constexpr s32 min{std::numeric_limits<s16>::min()};
|
constexpr s32 min{std::numeric_limits<s16>::min()};
|
||||||
constexpr s32 max{std::numeric_limits<s16>::max()};
|
constexpr s32 max{std::numeric_limits<s16>::max()};
|
||||||
static Common::ScratchBuffer<T> samples;
|
|
||||||
|
|
||||||
if (req.buffer == 0 || req.buffer_size == 0) {
|
if (req.buffer == 0 || req.buffer_size == 0) {
|
||||||
return 0;
|
return 0;
|
||||||
@ -51,7 +49,7 @@ static u32 DecodePcm(Core::Memory::Memory& memory, std::span<s16> out_buffer,
|
|||||||
const u64 size{channel_count * samples_to_decode};
|
const u64 size{channel_count * samples_to_decode};
|
||||||
const u64 size_bytes{size * sizeof(T)};
|
const u64 size_bytes{size * sizeof(T)};
|
||||||
|
|
||||||
samples.resize_destructive(size);
|
std::vector<T> samples(size);
|
||||||
memory.ReadBlockUnsafe(source, samples.data(), size_bytes);
|
memory.ReadBlockUnsafe(source, samples.data(), size_bytes);
|
||||||
|
|
||||||
if constexpr (std::is_floating_point_v<T>) {
|
if constexpr (std::is_floating_point_v<T>) {
|
||||||
@ -75,7 +73,7 @@ static u32 DecodePcm(Core::Memory::Memory& memory, std::span<s16> out_buffer,
|
|||||||
}
|
}
|
||||||
|
|
||||||
const VAddr source{req.buffer + ((req.start_offset + req.offset) * sizeof(T))};
|
const VAddr source{req.buffer + ((req.start_offset + req.offset) * sizeof(T))};
|
||||||
samples.resize_destructive(samples_to_decode);
|
std::vector<T> samples(samples_to_decode);
|
||||||
memory.ReadBlockUnsafe(source, samples.data(), samples_to_decode * sizeof(T));
|
memory.ReadBlockUnsafe(source, samples.data(), samples_to_decode * sizeof(T));
|
||||||
|
|
||||||
if constexpr (std::is_floating_point_v<T>) {
|
if constexpr (std::is_floating_point_v<T>) {
|
||||||
@ -105,7 +103,6 @@ static u32 DecodeAdpcm(Core::Memory::Memory& memory, std::span<s16> out_buffer,
|
|||||||
const DecodeArg& req) {
|
const DecodeArg& req) {
|
||||||
constexpr u32 SamplesPerFrame{14};
|
constexpr u32 SamplesPerFrame{14};
|
||||||
constexpr u32 NibblesPerFrame{16};
|
constexpr u32 NibblesPerFrame{16};
|
||||||
static Common::ScratchBuffer<u8> wavebuffer;
|
|
||||||
|
|
||||||
if (req.buffer == 0 || req.buffer_size == 0) {
|
if (req.buffer == 0 || req.buffer_size == 0) {
|
||||||
return 0;
|
return 0;
|
||||||
@ -141,7 +138,7 @@ static u32 DecodeAdpcm(Core::Memory::Memory& memory, std::span<s16> out_buffer,
|
|||||||
}
|
}
|
||||||
|
|
||||||
const auto size{std::max((samples_to_process / 8U) * SamplesPerFrame, 8U)};
|
const auto size{std::max((samples_to_process / 8U) * SamplesPerFrame, 8U)};
|
||||||
wavebuffer.resize_destructive(size);
|
std::vector<u8> wavebuffer(size);
|
||||||
memory.ReadBlockUnsafe(req.buffer + position_in_frame / 2, wavebuffer.data(),
|
memory.ReadBlockUnsafe(req.buffer + position_in_frame / 2, wavebuffer.data(),
|
||||||
wavebuffer.size());
|
wavebuffer.size());
|
||||||
|
|
||||||
@ -230,8 +227,6 @@ static u32 DecodeAdpcm(Core::Memory::Memory& memory, std::span<s16> out_buffer,
|
|||||||
* @param args - The wavebuffer data, and information for how to decode it.
|
* @param args - The wavebuffer data, and information for how to decode it.
|
||||||
*/
|
*/
|
||||||
void DecodeFromWaveBuffers(Core::Memory::Memory& memory, const DecodeFromWaveBuffersArgs& args) {
|
void DecodeFromWaveBuffers(Core::Memory::Memory& memory, const DecodeFromWaveBuffersArgs& args) {
|
||||||
Common::ScratchBuffer<s16> temp_buffer(TempBufferSize);
|
|
||||||
|
|
||||||
auto& voice_state{*args.voice_state};
|
auto& voice_state{*args.voice_state};
|
||||||
auto remaining_sample_count{args.sample_count};
|
auto remaining_sample_count{args.sample_count};
|
||||||
auto fraction{voice_state.fraction};
|
auto fraction{voice_state.fraction};
|
||||||
@ -261,8 +256,9 @@ void DecodeFromWaveBuffers(Core::Memory::Memory& memory, const DecodeFromWaveBuf
|
|||||||
|
|
||||||
bool is_buffer_starved{false};
|
bool is_buffer_starved{false};
|
||||||
u32 offset{voice_state.offset};
|
u32 offset{voice_state.offset};
|
||||||
std::memset(temp_buffer.data(), 0, temp_buffer.size() * sizeof(s16));
|
|
||||||
auto output_buffer{args.output};
|
auto output_buffer{args.output};
|
||||||
|
std::vector<s16> temp_buffer(TempBufferSize, 0);
|
||||||
|
|
||||||
while (remaining_sample_count > 0) {
|
while (remaining_sample_count > 0) {
|
||||||
const auto samples_to_write{std::min(remaining_sample_count, max_remaining_sample_count)};
|
const auto samples_to_write{std::min(remaining_sample_count, max_remaining_sample_count)};
|
||||||
|
@ -41,11 +41,10 @@ static void ResetAuxBufferDsp(Core::Memory::Memory& memory, const CpuAddr aux_in
|
|||||||
* @param update_count - If non-zero, send_info_ will be updated.
|
* @param update_count - If non-zero, send_info_ will be updated.
|
||||||
* @return Number of samples written.
|
* @return Number of samples written.
|
||||||
*/
|
*/
|
||||||
static u32 WriteAuxBufferDsp(Core::Memory::Memory& memory, const CpuAddr send_info_,
|
static u32 WriteAuxBufferDsp(Core::Memory::Memory& memory, CpuAddr send_info_,
|
||||||
[[maybe_unused]] u32 sample_count, const CpuAddr send_buffer,
|
[[maybe_unused]] u32 sample_count, CpuAddr send_buffer, u32 count_max,
|
||||||
const u32 count_max, std::span<const s32> input,
|
std::span<const s32> input, u32 write_count_, u32 write_offset,
|
||||||
const u32 write_count_, const u32 write_offset,
|
u32 update_count) {
|
||||||
const u32 update_count) {
|
|
||||||
if (write_count_ > count_max) {
|
if (write_count_ > count_max) {
|
||||||
LOG_ERROR(Service_Audio,
|
LOG_ERROR(Service_Audio,
|
||||||
"write_count must be smaller than count_max! write_count {}, count_max {}",
|
"write_count must be smaller than count_max! write_count {}, count_max {}",
|
||||||
@ -53,6 +52,11 @@ static u32 WriteAuxBufferDsp(Core::Memory::Memory& memory, const CpuAddr send_in
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (send_info_ == 0) {
|
||||||
|
LOG_ERROR(Service_Audio, "send_info_ is 0!");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (input.empty()) {
|
if (input.empty()) {
|
||||||
LOG_ERROR(Service_Audio, "input buffer is empty!");
|
LOG_ERROR(Service_Audio, "input buffer is empty!");
|
||||||
return 0;
|
return 0;
|
||||||
@ -67,35 +71,30 @@ static u32 WriteAuxBufferDsp(Core::Memory::Memory& memory, const CpuAddr send_in
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
AuxInfo::AuxInfoDsp send_info{};
|
auto send_info{reinterpret_cast<AuxInfo::AuxInfoDsp*>(memory.GetPointer(send_info_))};
|
||||||
memory.ReadBlockUnsafe(send_info_, &send_info, sizeof(AuxInfo::AuxInfoDsp));
|
|
||||||
|
|
||||||
u32 target_write_offset{send_info.write_offset + write_offset};
|
u32 target_write_offset{send_info->write_offset + write_offset};
|
||||||
if (target_write_offset > count_max || write_count_ == 0) {
|
if (target_write_offset > count_max) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 write_count{write_count_};
|
u32 write_count{write_count_};
|
||||||
u32 write_pos{0};
|
u32 read_pos{0};
|
||||||
while (write_count > 0) {
|
while (write_count > 0) {
|
||||||
u32 to_write{std::min(count_max - target_write_offset, write_count)};
|
u32 to_write{std::min(count_max - target_write_offset, write_count)};
|
||||||
|
if (to_write) {
|
||||||
if (to_write > 0) {
|
|
||||||
memory.WriteBlockUnsafe(send_buffer + target_write_offset * sizeof(s32),
|
memory.WriteBlockUnsafe(send_buffer + target_write_offset * sizeof(s32),
|
||||||
&input[write_pos], to_write * sizeof(s32));
|
&input[read_pos], to_write * sizeof(s32));
|
||||||
}
|
}
|
||||||
|
|
||||||
target_write_offset = (target_write_offset + to_write) % count_max;
|
target_write_offset = (target_write_offset + to_write) % count_max;
|
||||||
write_count -= to_write;
|
write_count -= to_write;
|
||||||
write_pos += to_write;
|
read_pos += to_write;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (update_count) {
|
if (update_count) {
|
||||||
send_info.write_offset = (send_info.write_offset + update_count) % count_max;
|
send_info->write_offset = (send_info->write_offset + update_count) % count_max;
|
||||||
}
|
}
|
||||||
|
|
||||||
memory.WriteBlockUnsafe(send_info_, &send_info, sizeof(AuxInfo::AuxInfoDsp));
|
|
||||||
|
|
||||||
return write_count_;
|
return write_count_;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -103,7 +102,7 @@ static u32 WriteAuxBufferDsp(Core::Memory::Memory& memory, const CpuAddr send_in
|
|||||||
* Read the given memory at return_buffer into the output mix buffer, and update return_info_ if
|
* Read the given memory at return_buffer into the output mix buffer, and update return_info_ if
|
||||||
* update_count is set, to notify the game that an update happened.
|
* update_count is set, to notify the game that an update happened.
|
||||||
*
|
*
|
||||||
* @param memory - Core memory for writing.
|
* @param memory - Core memory for reading.
|
||||||
* @param return_info_ - Meta information for where to read the mix buffer.
|
* @param return_info_ - Meta information for where to read the mix buffer.
|
||||||
* @param return_buffer - Memory address to read the samples from.
|
* @param return_buffer - Memory address to read the samples from.
|
||||||
* @param count_max - Maximum number of samples in the receiving buffer.
|
* @param count_max - Maximum number of samples in the receiving buffer.
|
||||||
@ -113,16 +112,21 @@ static u32 WriteAuxBufferDsp(Core::Memory::Memory& memory, const CpuAddr send_in
|
|||||||
* @param update_count - If non-zero, send_info_ will be updated.
|
* @param update_count - If non-zero, send_info_ will be updated.
|
||||||
* @return Number of samples read.
|
* @return Number of samples read.
|
||||||
*/
|
*/
|
||||||
static u32 ReadAuxBufferDsp(Core::Memory::Memory& memory, const CpuAddr return_info_,
|
static u32 ReadAuxBufferDsp(Core::Memory::Memory& memory, CpuAddr return_info_,
|
||||||
const CpuAddr return_buffer, const u32 count_max, std::span<s32> output,
|
CpuAddr return_buffer, u32 count_max, std::span<s32> output,
|
||||||
const u32 count_, const u32 read_offset, const u32 update_count) {
|
u32 read_count_, u32 read_offset, u32 update_count) {
|
||||||
if (count_max == 0) {
|
if (count_max == 0) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (count_ > count_max) {
|
if (read_count_ > count_max) {
|
||||||
LOG_ERROR(Service_Audio, "count must be smaller than count_max! count {}, count_max {}",
|
LOG_ERROR(Service_Audio, "count must be smaller than count_max! count {}, count_max {}",
|
||||||
count_, count_max);
|
read_count_, count_max);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (return_info_ == 0) {
|
||||||
|
LOG_ERROR(Service_Audio, "return_info_ is 0!");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -136,36 +140,31 @@ static u32 ReadAuxBufferDsp(Core::Memory::Memory& memory, const CpuAddr return_i
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
AuxInfo::AuxInfoDsp return_info{};
|
auto return_info{reinterpret_cast<AuxInfo::AuxInfoDsp*>(memory.GetPointer(return_info_))};
|
||||||
memory.ReadBlockUnsafe(return_info_, &return_info, sizeof(AuxInfo::AuxInfoDsp));
|
|
||||||
|
|
||||||
u32 target_read_offset{return_info.read_offset + read_offset};
|
u32 target_read_offset{return_info->read_offset + read_offset};
|
||||||
if (target_read_offset > count_max) {
|
if (target_read_offset > count_max) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 read_count{count_};
|
u32 read_count{read_count_};
|
||||||
u32 read_pos{0};
|
u32 write_pos{0};
|
||||||
while (read_count > 0) {
|
while (read_count > 0) {
|
||||||
u32 to_read{std::min(count_max - target_read_offset, read_count)};
|
u32 to_read{std::min(count_max - target_read_offset, read_count)};
|
||||||
|
if (to_read) {
|
||||||
if (to_read > 0) {
|
|
||||||
memory.ReadBlockUnsafe(return_buffer + target_read_offset * sizeof(s32),
|
memory.ReadBlockUnsafe(return_buffer + target_read_offset * sizeof(s32),
|
||||||
&output[read_pos], to_read * sizeof(s32));
|
&output[write_pos], to_read * sizeof(s32));
|
||||||
}
|
}
|
||||||
|
|
||||||
target_read_offset = (target_read_offset + to_read) % count_max;
|
target_read_offset = (target_read_offset + to_read) % count_max;
|
||||||
read_count -= to_read;
|
read_count -= to_read;
|
||||||
read_pos += to_read;
|
write_pos += to_read;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (update_count) {
|
if (update_count) {
|
||||||
return_info.read_offset = (return_info.read_offset + update_count) % count_max;
|
return_info->read_offset = (return_info->read_offset + update_count) % count_max;
|
||||||
}
|
}
|
||||||
|
|
||||||
memory.WriteBlockUnsafe(return_info_, &return_info, sizeof(AuxInfo::AuxInfoDsp));
|
return read_count_;
|
||||||
|
|
||||||
return count_;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void AuxCommand::Dump([[maybe_unused]] const ADSP::CommandListProcessor& processor,
|
void AuxCommand::Dump([[maybe_unused]] const ADSP::CommandListProcessor& processor,
|
||||||
@ -175,19 +174,6 @@ void AuxCommand::Dump([[maybe_unused]] const ADSP::CommandListProcessor& process
|
|||||||
}
|
}
|
||||||
|
|
||||||
void AuxCommand::Process(const ADSP::CommandListProcessor& processor) {
|
void AuxCommand::Process(const ADSP::CommandListProcessor& processor) {
|
||||||
// HACK!
|
|
||||||
// Ignore aux for Super Mario Odyssey and Metroid Prime Remastered.
|
|
||||||
// For some reason these games receive output samples, and then send them back in as input
|
|
||||||
// again. Problem is the data being sent back in is slightly offset from the current output by
|
|
||||||
// 240 or 480 samples, leading to a very fast echoing effect, which should not be there.
|
|
||||||
// Timing issue or some bug in the code?
|
|
||||||
// We can't disable this unconditionally as some games rely on it for synchronisation and will
|
|
||||||
// softlock without it (Age of Calamity).
|
|
||||||
const auto program_id = processor.system->GetCurrentProcessProgramID();
|
|
||||||
if (program_id == 0x0100000000010000ull || program_id == 0x010012101468C000ull) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto input_buffer{
|
auto input_buffer{
|
||||||
processor.mix_buffers.subspan(input * processor.sample_count, processor.sample_count)};
|
processor.mix_buffers.subspan(input * processor.sample_count, processor.sample_count)};
|
||||||
auto output_buffer{
|
auto output_buffer{
|
||||||
@ -203,7 +189,7 @@ void AuxCommand::Process(const ADSP::CommandListProcessor& processor) {
|
|||||||
update_count)};
|
update_count)};
|
||||||
|
|
||||||
if (read != processor.sample_count) {
|
if (read != processor.sample_count) {
|
||||||
std::memset(&output_buffer[read], 0, processor.sample_count - read);
|
std::memset(&output_buffer[read], 0, (processor.sample_count - read) * sizeof(s32));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
ResetAuxBufferDsp(*processor.memory, send_buffer_info);
|
ResetAuxBufferDsp(*processor.memory, send_buffer_info);
|
||||||
|
@ -8,7 +8,6 @@
|
|||||||
#include "audio_core/renderer/adsp/command_list_processor.h"
|
#include "audio_core/renderer/adsp/command_list_processor.h"
|
||||||
#include "audio_core/renderer/command/effect/compressor.h"
|
#include "audio_core/renderer/command/effect/compressor.h"
|
||||||
#include "audio_core/renderer/effect/compressor.h"
|
#include "audio_core/renderer/effect/compressor.h"
|
||||||
#include "common/scratch_buffer.h"
|
|
||||||
|
|
||||||
namespace AudioCore::AudioRenderer {
|
namespace AudioCore::AudioRenderer {
|
||||||
|
|
||||||
@ -45,8 +44,8 @@ static void InitializeCompressorEffect(const CompressorInfo::ParameterVersion2&
|
|||||||
|
|
||||||
static void ApplyCompressorEffect(const CompressorInfo::ParameterVersion2& params,
|
static void ApplyCompressorEffect(const CompressorInfo::ParameterVersion2& params,
|
||||||
CompressorInfo::State& state, bool enabled,
|
CompressorInfo::State& state, bool enabled,
|
||||||
std::span<std::span<const s32>> input_buffers,
|
std::vector<std::span<const s32>> input_buffers,
|
||||||
std::span<std::span<s32>> output_buffers, u32 sample_count) {
|
std::vector<std::span<s32>> output_buffers, u32 sample_count) {
|
||||||
if (enabled) {
|
if (enabled) {
|
||||||
auto state_00{state.unk_00};
|
auto state_00{state.unk_00};
|
||||||
auto state_04{state.unk_04};
|
auto state_04{state.unk_04};
|
||||||
@ -125,10 +124,8 @@ void CompressorCommand::Dump([[maybe_unused]] const ADSP::CommandListProcessor&
|
|||||||
}
|
}
|
||||||
|
|
||||||
void CompressorCommand::Process(const ADSP::CommandListProcessor& processor) {
|
void CompressorCommand::Process(const ADSP::CommandListProcessor& processor) {
|
||||||
static Common::ScratchBuffer<std::span<const s32>> input_buffers{};
|
std::vector<std::span<const s32>> input_buffers(parameter.channel_count);
|
||||||
static Common::ScratchBuffer<std::span<s32>> output_buffers{};
|
std::vector<std::span<s32>> output_buffers(parameter.channel_count);
|
||||||
input_buffers.resize_destructive(parameter.channel_count);
|
|
||||||
output_buffers.resize_destructive(parameter.channel_count);
|
|
||||||
|
|
||||||
for (s16 i = 0; i < parameter.channel_count; i++) {
|
for (s16 i = 0; i < parameter.channel_count; i++) {
|
||||||
input_buffers[i] = processor.mix_buffers.subspan(inputs[i] * processor.sample_count,
|
input_buffers[i] = processor.mix_buffers.subspan(inputs[i] * processor.sample_count,
|
||||||
|
@ -3,7 +3,6 @@
|
|||||||
|
|
||||||
#include "audio_core/renderer/adsp/command_list_processor.h"
|
#include "audio_core/renderer/adsp/command_list_processor.h"
|
||||||
#include "audio_core/renderer/command/effect/delay.h"
|
#include "audio_core/renderer/command/effect/delay.h"
|
||||||
#include "common/scratch_buffer.h"
|
|
||||||
|
|
||||||
namespace AudioCore::AudioRenderer {
|
namespace AudioCore::AudioRenderer {
|
||||||
/**
|
/**
|
||||||
@ -75,8 +74,8 @@ static void InitializeDelayEffect(const DelayInfo::ParameterVersion1& params,
|
|||||||
*/
|
*/
|
||||||
template <size_t NumChannels>
|
template <size_t NumChannels>
|
||||||
static void ApplyDelay(const DelayInfo::ParameterVersion1& params, DelayInfo::State& state,
|
static void ApplyDelay(const DelayInfo::ParameterVersion1& params, DelayInfo::State& state,
|
||||||
std::span<std::span<const s32>> inputs, std::span<std::span<s32>> outputs,
|
std::vector<std::span<const s32>>& inputs,
|
||||||
const u32 sample_count) {
|
std::vector<std::span<s32>>& outputs, const u32 sample_count) {
|
||||||
for (u32 sample_index = 0; sample_index < sample_count; sample_index++) {
|
for (u32 sample_index = 0; sample_index < sample_count; sample_index++) {
|
||||||
std::array<Common::FixedPoint<50, 14>, NumChannels> input_samples{};
|
std::array<Common::FixedPoint<50, 14>, NumChannels> input_samples{};
|
||||||
for (u32 channel = 0; channel < NumChannels; channel++) {
|
for (u32 channel = 0; channel < NumChannels; channel++) {
|
||||||
@ -154,8 +153,8 @@ static void ApplyDelay(const DelayInfo::ParameterVersion1& params, DelayInfo::St
|
|||||||
* @param sample_count - Number of samples to process.
|
* @param sample_count - Number of samples to process.
|
||||||
*/
|
*/
|
||||||
static void ApplyDelayEffect(const DelayInfo::ParameterVersion1& params, DelayInfo::State& state,
|
static void ApplyDelayEffect(const DelayInfo::ParameterVersion1& params, DelayInfo::State& state,
|
||||||
const bool enabled, std::span<std::span<const s32>> inputs,
|
const bool enabled, std::vector<std::span<const s32>>& inputs,
|
||||||
std::span<std::span<s32>> outputs, const u32 sample_count) {
|
std::vector<std::span<s32>>& outputs, const u32 sample_count) {
|
||||||
|
|
||||||
if (!IsChannelCountValid(params.channel_count)) {
|
if (!IsChannelCountValid(params.channel_count)) {
|
||||||
LOG_ERROR(Service_Audio, "Invalid delay channels {}", params.channel_count);
|
LOG_ERROR(Service_Audio, "Invalid delay channels {}", params.channel_count);
|
||||||
@ -209,10 +208,8 @@ void DelayCommand::Dump([[maybe_unused]] const ADSP::CommandListProcessor& proce
|
|||||||
}
|
}
|
||||||
|
|
||||||
void DelayCommand::Process(const ADSP::CommandListProcessor& processor) {
|
void DelayCommand::Process(const ADSP::CommandListProcessor& processor) {
|
||||||
static Common::ScratchBuffer<std::span<const s32>> input_buffers{};
|
std::vector<std::span<const s32>> input_buffers(parameter.channel_count);
|
||||||
static Common::ScratchBuffer<std::span<s32>> output_buffers{};
|
std::vector<std::span<s32>> output_buffers(parameter.channel_count);
|
||||||
input_buffers.resize_destructive(parameter.channel_count);
|
|
||||||
output_buffers.resize_destructive(parameter.channel_count);
|
|
||||||
|
|
||||||
for (s16 i = 0; i < parameter.channel_count; i++) {
|
for (s16 i = 0; i < parameter.channel_count; i++) {
|
||||||
input_buffers[i] = processor.mix_buffers.subspan(inputs[i] * processor.sample_count,
|
input_buffers[i] = processor.mix_buffers.subspan(inputs[i] * processor.sample_count,
|
||||||
|
@ -6,7 +6,6 @@
|
|||||||
#include "audio_core/renderer/adsp/command_list_processor.h"
|
#include "audio_core/renderer/adsp/command_list_processor.h"
|
||||||
#include "audio_core/renderer/command/effect/i3dl2_reverb.h"
|
#include "audio_core/renderer/command/effect/i3dl2_reverb.h"
|
||||||
#include "common/polyfill_ranges.h"
|
#include "common/polyfill_ranges.h"
|
||||||
#include "common/scratch_buffer.h"
|
|
||||||
|
|
||||||
namespace AudioCore::AudioRenderer {
|
namespace AudioCore::AudioRenderer {
|
||||||
|
|
||||||
@ -409,10 +408,8 @@ void I3dl2ReverbCommand::Dump([[maybe_unused]] const ADSP::CommandListProcessor&
|
|||||||
}
|
}
|
||||||
|
|
||||||
void I3dl2ReverbCommand::Process(const ADSP::CommandListProcessor& processor) {
|
void I3dl2ReverbCommand::Process(const ADSP::CommandListProcessor& processor) {
|
||||||
static Common::ScratchBuffer<std::span<const s32>> input_buffers{};
|
std::vector<std::span<const s32>> input_buffers(parameter.channel_count);
|
||||||
static Common::ScratchBuffer<std::span<s32>> output_buffers{};
|
std::vector<std::span<s32>> output_buffers(parameter.channel_count);
|
||||||
input_buffers.resize_destructive(parameter.channel_count);
|
|
||||||
output_buffers.resize_destructive(parameter.channel_count);
|
|
||||||
|
|
||||||
for (u32 i = 0; i < parameter.channel_count; i++) {
|
for (u32 i = 0; i < parameter.channel_count; i++) {
|
||||||
input_buffers[i] = processor.mix_buffers.subspan(inputs[i] * processor.sample_count,
|
input_buffers[i] = processor.mix_buffers.subspan(inputs[i] * processor.sample_count,
|
||||||
|
@ -3,7 +3,6 @@
|
|||||||
|
|
||||||
#include "audio_core/renderer/adsp/command_list_processor.h"
|
#include "audio_core/renderer/adsp/command_list_processor.h"
|
||||||
#include "audio_core/renderer/command/effect/light_limiter.h"
|
#include "audio_core/renderer/command/effect/light_limiter.h"
|
||||||
#include "common/scratch_buffer.h"
|
|
||||||
|
|
||||||
namespace AudioCore::AudioRenderer {
|
namespace AudioCore::AudioRenderer {
|
||||||
/**
|
/**
|
||||||
@ -48,8 +47,8 @@ static void InitializeLightLimiterEffect(const LightLimiterInfo::ParameterVersio
|
|||||||
*/
|
*/
|
||||||
static void ApplyLightLimiterEffect(const LightLimiterInfo::ParameterVersion2& params,
|
static void ApplyLightLimiterEffect(const LightLimiterInfo::ParameterVersion2& params,
|
||||||
LightLimiterInfo::State& state, const bool enabled,
|
LightLimiterInfo::State& state, const bool enabled,
|
||||||
std::span<std::span<const s32>> inputs,
|
std::vector<std::span<const s32>>& inputs,
|
||||||
std::span<std::span<s32>> outputs, const u32 sample_count,
|
std::vector<std::span<s32>>& outputs, const u32 sample_count,
|
||||||
LightLimiterInfo::StatisticsInternal* statistics) {
|
LightLimiterInfo::StatisticsInternal* statistics) {
|
||||||
constexpr s64 min{std::numeric_limits<s32>::min()};
|
constexpr s64 min{std::numeric_limits<s32>::min()};
|
||||||
constexpr s64 max{std::numeric_limits<s32>::max()};
|
constexpr s64 max{std::numeric_limits<s32>::max()};
|
||||||
@ -148,10 +147,8 @@ void LightLimiterVersion1Command::Dump([[maybe_unused]] const ADSP::CommandListP
|
|||||||
}
|
}
|
||||||
|
|
||||||
void LightLimiterVersion1Command::Process(const ADSP::CommandListProcessor& processor) {
|
void LightLimiterVersion1Command::Process(const ADSP::CommandListProcessor& processor) {
|
||||||
static Common::ScratchBuffer<std::span<const s32>> input_buffers{};
|
std::vector<std::span<const s32>> input_buffers(parameter.channel_count);
|
||||||
static Common::ScratchBuffer<std::span<s32>> output_buffers{};
|
std::vector<std::span<s32>> output_buffers(parameter.channel_count);
|
||||||
input_buffers.resize_destructive(parameter.channel_count);
|
|
||||||
output_buffers.resize_destructive(parameter.channel_count);
|
|
||||||
|
|
||||||
for (u32 i = 0; i < parameter.channel_count; i++) {
|
for (u32 i = 0; i < parameter.channel_count; i++) {
|
||||||
input_buffers[i] = processor.mix_buffers.subspan(inputs[i] * processor.sample_count,
|
input_buffers[i] = processor.mix_buffers.subspan(inputs[i] * processor.sample_count,
|
||||||
@ -193,10 +190,8 @@ void LightLimiterVersion2Command::Dump([[maybe_unused]] const ADSP::CommandListP
|
|||||||
}
|
}
|
||||||
|
|
||||||
void LightLimiterVersion2Command::Process(const ADSP::CommandListProcessor& processor) {
|
void LightLimiterVersion2Command::Process(const ADSP::CommandListProcessor& processor) {
|
||||||
static Common::ScratchBuffer<std::span<const s32>> input_buffers{};
|
std::vector<std::span<const s32>> input_buffers(parameter.channel_count);
|
||||||
static Common::ScratchBuffer<std::span<s32>> output_buffers{};
|
std::vector<std::span<s32>> output_buffers(parameter.channel_count);
|
||||||
input_buffers.resize_destructive(parameter.channel_count);
|
|
||||||
output_buffers.resize_destructive(parameter.channel_count);
|
|
||||||
|
|
||||||
for (u32 i = 0; i < parameter.channel_count; i++) {
|
for (u32 i = 0; i < parameter.channel_count; i++) {
|
||||||
input_buffers[i] = processor.mix_buffers.subspan(inputs[i] * processor.sample_count,
|
input_buffers[i] = processor.mix_buffers.subspan(inputs[i] * processor.sample_count,
|
||||||
|
@ -7,7 +7,6 @@
|
|||||||
#include "audio_core/renderer/adsp/command_list_processor.h"
|
#include "audio_core/renderer/adsp/command_list_processor.h"
|
||||||
#include "audio_core/renderer/command/effect/reverb.h"
|
#include "audio_core/renderer/command/effect/reverb.h"
|
||||||
#include "common/polyfill_ranges.h"
|
#include "common/polyfill_ranges.h"
|
||||||
#include "common/scratch_buffer.h"
|
|
||||||
|
|
||||||
namespace AudioCore::AudioRenderer {
|
namespace AudioCore::AudioRenderer {
|
||||||
|
|
||||||
@ -251,8 +250,8 @@ static Common::FixedPoint<50, 14> Axfx2AllPassTick(ReverbInfo::ReverbDelayLine&
|
|||||||
*/
|
*/
|
||||||
template <size_t NumChannels>
|
template <size_t NumChannels>
|
||||||
static void ApplyReverbEffect(const ReverbInfo::ParameterVersion2& params, ReverbInfo::State& state,
|
static void ApplyReverbEffect(const ReverbInfo::ParameterVersion2& params, ReverbInfo::State& state,
|
||||||
std::span<std::span<const s32>> inputs,
|
std::vector<std::span<const s32>>& inputs,
|
||||||
std::span<std::span<s32>> outputs, const u32 sample_count) {
|
std::vector<std::span<s32>>& outputs, const u32 sample_count) {
|
||||||
constexpr std::array<u8, ReverbInfo::MaxDelayTaps> OutTapIndexes1Ch{
|
constexpr std::array<u8, ReverbInfo::MaxDelayTaps> OutTapIndexes1Ch{
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
};
|
};
|
||||||
@ -369,8 +368,8 @@ static void ApplyReverbEffect(const ReverbInfo::ParameterVersion2& params, Rever
|
|||||||
* @param sample_count - Number of samples to process.
|
* @param sample_count - Number of samples to process.
|
||||||
*/
|
*/
|
||||||
static void ApplyReverbEffect(const ReverbInfo::ParameterVersion2& params, ReverbInfo::State& state,
|
static void ApplyReverbEffect(const ReverbInfo::ParameterVersion2& params, ReverbInfo::State& state,
|
||||||
const bool enabled, std::span<std::span<const s32>> inputs,
|
const bool enabled, std::vector<std::span<const s32>>& inputs,
|
||||||
std::span<std::span<s32>> outputs, const u32 sample_count) {
|
std::vector<std::span<s32>>& outputs, const u32 sample_count) {
|
||||||
if (enabled) {
|
if (enabled) {
|
||||||
switch (params.channel_count) {
|
switch (params.channel_count) {
|
||||||
case 0:
|
case 0:
|
||||||
@ -412,10 +411,8 @@ void ReverbCommand::Dump([[maybe_unused]] const ADSP::CommandListProcessor& proc
|
|||||||
}
|
}
|
||||||
|
|
||||||
void ReverbCommand::Process(const ADSP::CommandListProcessor& processor) {
|
void ReverbCommand::Process(const ADSP::CommandListProcessor& processor) {
|
||||||
static Common::ScratchBuffer<std::span<const s32>> input_buffers{};
|
std::vector<std::span<const s32>> input_buffers(parameter.channel_count);
|
||||||
static Common::ScratchBuffer<std::span<s32>> output_buffers{};
|
std::vector<std::span<s32>> output_buffers(parameter.channel_count);
|
||||||
input_buffers.resize_destructive(parameter.channel_count);
|
|
||||||
output_buffers.resize_destructive(parameter.channel_count);
|
|
||||||
|
|
||||||
for (u32 i = 0; i < parameter.channel_count; i++) {
|
for (u32 i = 0; i < parameter.channel_count; i++) {
|
||||||
input_buffers[i] = processor.mix_buffers.subspan(inputs[i] * processor.sample_count,
|
input_buffers[i] = processor.mix_buffers.subspan(inputs[i] * processor.sample_count,
|
||||||
|
@ -5,7 +5,6 @@
|
|||||||
|
|
||||||
#include "audio_core/renderer/adsp/command_list_processor.h"
|
#include "audio_core/renderer/adsp/command_list_processor.h"
|
||||||
#include "audio_core/renderer/command/sink/circular_buffer.h"
|
#include "audio_core/renderer/command/sink/circular_buffer.h"
|
||||||
#include "common/scratch_buffer.h"
|
|
||||||
#include "core/memory.h"
|
#include "core/memory.h"
|
||||||
|
|
||||||
namespace AudioCore::AudioRenderer {
|
namespace AudioCore::AudioRenderer {
|
||||||
@ -25,9 +24,7 @@ void CircularBufferSinkCommand::Process(const ADSP::CommandListProcessor& proces
|
|||||||
constexpr s32 min{std::numeric_limits<s16>::min()};
|
constexpr s32 min{std::numeric_limits<s16>::min()};
|
||||||
constexpr s32 max{std::numeric_limits<s16>::max()};
|
constexpr s32 max{std::numeric_limits<s16>::max()};
|
||||||
|
|
||||||
static Common::ScratchBuffer<s16> output{};
|
std::vector<s16> output(processor.sample_count);
|
||||||
output.resize_destructive(processor.sample_count);
|
|
||||||
|
|
||||||
for (u32 channel = 0; channel < input_count; channel++) {
|
for (u32 channel = 0; channel < input_count; channel++) {
|
||||||
auto input{processor.mix_buffers.subspan(inputs[channel] * processor.sample_count,
|
auto input{processor.mix_buffers.subspan(inputs[channel] * processor.sample_count,
|
||||||
processor.sample_count)};
|
processor.sample_count)};
|
||||||
|
@ -33,8 +33,7 @@ void DeviceSinkCommand::Process(const ADSP::CommandListProcessor& processor) {
|
|||||||
.consumed{false},
|
.consumed{false},
|
||||||
};
|
};
|
||||||
|
|
||||||
static Common::ScratchBuffer<s16> samples{};
|
std::vector<s16> samples(out_buffer.frames * input_count);
|
||||||
samples.resize_destructive(out_buffer.frames * input_count);
|
|
||||||
|
|
||||||
for (u32 channel = 0; channel < input_count; channel++) {
|
for (u32 channel = 0; channel < input_count; channel++) {
|
||||||
const auto offset{inputs[channel] * out_buffer.frames};
|
const auto offset{inputs[channel] * out_buffer.frames};
|
||||||
|
@ -9,7 +9,6 @@
|
|||||||
|
|
||||||
#include "audio_core/sink/sink.h"
|
#include "audio_core/sink/sink.h"
|
||||||
#include "audio_core/sink/sink_stream.h"
|
#include "audio_core/sink/sink_stream.h"
|
||||||
#include "common/scratch_buffer.h"
|
|
||||||
|
|
||||||
namespace Core {
|
namespace Core {
|
||||||
class System;
|
class System;
|
||||||
@ -21,7 +20,7 @@ public:
|
|||||||
explicit NullSinkStreamImpl(Core::System& system_, StreamType type_)
|
explicit NullSinkStreamImpl(Core::System& system_, StreamType type_)
|
||||||
: SinkStream{system_, type_} {}
|
: SinkStream{system_, type_} {}
|
||||||
~NullSinkStreamImpl() override {}
|
~NullSinkStreamImpl() override {}
|
||||||
void AppendBuffer(SinkBuffer&, Common::ScratchBuffer<s16>&) override {}
|
void AppendBuffer(SinkBuffer&, std::vector<s16>&) override {}
|
||||||
std::vector<s16> ReleaseBuffer(u64) override {
|
std::vector<s16> ReleaseBuffer(u64) override {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
@ -17,7 +17,7 @@
|
|||||||
|
|
||||||
namespace AudioCore::Sink {
|
namespace AudioCore::Sink {
|
||||||
|
|
||||||
void SinkStream::AppendBuffer(SinkBuffer& buffer, Common::ScratchBuffer<s16>& samples) {
|
void SinkStream::AppendBuffer(SinkBuffer& buffer, std::vector<s16>& samples) {
|
||||||
if (type == StreamType::In) {
|
if (type == StreamType::In) {
|
||||||
queue.enqueue(buffer);
|
queue.enqueue(buffer);
|
||||||
queued_buffers++;
|
queued_buffers++;
|
||||||
@ -71,9 +71,7 @@ void SinkStream::AppendBuffer(SinkBuffer& buffer, Common::ScratchBuffer<s16>& sa
|
|||||||
// We need moar samples! Not all games will provide 6 channel audio.
|
// We need moar samples! Not all games will provide 6 channel audio.
|
||||||
// TODO: Implement some upmixing here. Currently just passthrough, with other
|
// TODO: Implement some upmixing here. Currently just passthrough, with other
|
||||||
// channels left as silence.
|
// channels left as silence.
|
||||||
static Common::ScratchBuffer<s16> new_samples{};
|
std::vector<s16> new_samples(samples.size() / system_channels * device_channels, 0);
|
||||||
new_samples.resize_destructive(samples.size() / system_channels * device_channels);
|
|
||||||
std::memset(new_samples.data(), 0, new_samples.size() * sizeof(s16));
|
|
||||||
|
|
||||||
for (u32 read_index = 0, write_index = 0; read_index < samples.size();
|
for (u32 read_index = 0, write_index = 0; read_index < samples.size();
|
||||||
read_index += system_channels, write_index += device_channels) {
|
read_index += system_channels, write_index += device_channels) {
|
||||||
@ -102,7 +100,7 @@ void SinkStream::AppendBuffer(SinkBuffer& buffer, Common::ScratchBuffer<s16>& sa
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
samples_buffer.Push(samples.data(), samples.size());
|
samples_buffer.Push(samples);
|
||||||
queue.enqueue(buffer);
|
queue.enqueue(buffer);
|
||||||
queued_buffers++;
|
queued_buffers++;
|
||||||
}
|
}
|
||||||
|
@ -14,7 +14,6 @@
|
|||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
#include "common/reader_writer_queue.h"
|
#include "common/reader_writer_queue.h"
|
||||||
#include "common/ring_buffer.h"
|
#include "common/ring_buffer.h"
|
||||||
#include "common/scratch_buffer.h"
|
|
||||||
|
|
||||||
namespace Core {
|
namespace Core {
|
||||||
class System;
|
class System;
|
||||||
@ -170,7 +169,7 @@ public:
|
|||||||
* @param buffer - Audio buffer information to be queued.
|
* @param buffer - Audio buffer information to be queued.
|
||||||
* @param samples - The s16 samples to be queue for playback.
|
* @param samples - The s16 samples to be queue for playback.
|
||||||
*/
|
*/
|
||||||
virtual void AppendBuffer(SinkBuffer& buffer, Common::ScratchBuffer<s16>& samples);
|
virtual void AppendBuffer(SinkBuffer& buffer, std::vector<s16>& samples);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Release a buffer. Audio In only, will fill a buffer with recorded samples.
|
* Release a buffer. Audio In only, will fill a buffer with recorded samples.
|
||||||
|
@ -24,24 +24,6 @@ public:
|
|||||||
|
|
||||||
~ScratchBuffer() = default;
|
~ScratchBuffer() = default;
|
||||||
|
|
||||||
ScratchBuffer(ScratchBuffer&& rhs) {
|
|
||||||
last_requested_size = rhs.last_requested_size;
|
|
||||||
buffer_capacity = rhs.buffer_capacity;
|
|
||||||
buffer = std::move(rhs.buffer);
|
|
||||||
|
|
||||||
rhs.last_requested_size = 0;
|
|
||||||
rhs.buffer_capacity = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void operator=(ScratchBuffer&& rhs) {
|
|
||||||
last_requested_size = rhs.last_requested_size;
|
|
||||||
buffer_capacity = rhs.buffer_capacity;
|
|
||||||
buffer = std::move(rhs.buffer);
|
|
||||||
|
|
||||||
rhs.last_requested_size = 0;
|
|
||||||
rhs.buffer_capacity = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// This will only grow the buffer's capacity if size is greater than the current capacity.
|
/// This will only grow the buffer's capacity if size is greater than the current capacity.
|
||||||
/// The previously held data will remain intact.
|
/// The previously held data will remain intact.
|
||||||
void resize(size_t size) {
|
void resize(size_t size) {
|
||||||
|
@ -289,6 +289,11 @@ public:
|
|||||||
return cpu_addr;
|
return cpu_addr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Update the base CPU address of the buffer
|
||||||
|
void UpdateCpuAddr(VAddr cpu_addr_) noexcept {
|
||||||
|
cpu_addr = cpu_addr_;
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns the offset relative to the given CPU address
|
/// Returns the offset relative to the given CPU address
|
||||||
/// @pre IsInBounds returns true
|
/// @pre IsInBounds returns true
|
||||||
[[nodiscard]] u32 Offset(VAddr other_cpu_addr) const noexcept {
|
[[nodiscard]] u32 Offset(VAddr other_cpu_addr) const noexcept {
|
||||||
|
@ -205,9 +205,9 @@ public:
|
|||||||
current_draw_indirect = current_draw_indirect_;
|
current_draw_indirect = current_draw_indirect_;
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] std::pair<Buffer*, u32> GetDrawIndirectCount();
|
[[nodiscard]] typename BufferCache<P>::Buffer* GetDrawIndirectCount();
|
||||||
|
|
||||||
[[nodiscard]] std::pair<Buffer*, u32> GetDrawIndirectBuffer();
|
[[nodiscard]] typename BufferCache<P>::Buffer* GetDrawIndirectBuffer();
|
||||||
|
|
||||||
std::recursive_mutex mutex;
|
std::recursive_mutex mutex;
|
||||||
Runtime& runtime;
|
Runtime& runtime;
|
||||||
@ -385,6 +385,9 @@ private:
|
|||||||
SlotVector<Buffer> slot_buffers;
|
SlotVector<Buffer> slot_buffers;
|
||||||
DelayedDestructionRing<Buffer, 8> delayed_destruction_ring;
|
DelayedDestructionRing<Buffer, 8> delayed_destruction_ring;
|
||||||
|
|
||||||
|
Buffer indirect_buffer;
|
||||||
|
Buffer indirect_count_buffer;
|
||||||
|
|
||||||
const Tegra::Engines::DrawManager::IndirectParams* current_draw_indirect{};
|
const Tegra::Engines::DrawManager::IndirectParams* current_draw_indirect{};
|
||||||
|
|
||||||
u32 last_index_count = 0;
|
u32 last_index_count = 0;
|
||||||
@ -458,7 +461,9 @@ private:
|
|||||||
template <class P>
|
template <class P>
|
||||||
BufferCache<P>::BufferCache(VideoCore::RasterizerInterface& rasterizer_,
|
BufferCache<P>::BufferCache(VideoCore::RasterizerInterface& rasterizer_,
|
||||||
Core::Memory::Memory& cpu_memory_, Runtime& runtime_)
|
Core::Memory::Memory& cpu_memory_, Runtime& runtime_)
|
||||||
: runtime{runtime_}, rasterizer{rasterizer_}, cpu_memory{cpu_memory_} {
|
: runtime{runtime_}, rasterizer{rasterizer_}, cpu_memory{cpu_memory_},
|
||||||
|
indirect_buffer(runtime, rasterizer, 0, 0x1000),
|
||||||
|
indirect_count_buffer(runtime, rasterizer, 0, 0x1000) {
|
||||||
// Ensure the first slot is used for the null buffer
|
// Ensure the first slot is used for the null buffer
|
||||||
void(slot_buffers.insert(runtime, NullBufferParams{}));
|
void(slot_buffers.insert(runtime, NullBufferParams{}));
|
||||||
common_ranges.clear();
|
common_ranges.clear();
|
||||||
@ -1064,15 +1069,13 @@ void BufferCache<P>::BindHostVertexBuffers() {
|
|||||||
|
|
||||||
template <class P>
|
template <class P>
|
||||||
void BufferCache<P>::BindHostDrawIndirectBuffers() {
|
void BufferCache<P>::BindHostDrawIndirectBuffers() {
|
||||||
const auto bind_buffer = [this](const Binding& binding) {
|
const auto bind_buffer = [this](const Binding& binding, Buffer& buffer) {
|
||||||
Buffer& buffer = slot_buffers[binding.buffer_id];
|
|
||||||
TouchBuffer(buffer, binding.buffer_id);
|
|
||||||
SynchronizeBuffer(buffer, binding.cpu_addr, binding.size);
|
SynchronizeBuffer(buffer, binding.cpu_addr, binding.size);
|
||||||
};
|
};
|
||||||
if (current_draw_indirect->include_count) {
|
if (current_draw_indirect->include_count) {
|
||||||
bind_buffer(count_buffer_binding);
|
bind_buffer(count_buffer_binding, indirect_count_buffer);
|
||||||
}
|
}
|
||||||
bind_buffer(indirect_buffer_binding);
|
bind_buffer(indirect_buffer_binding, indirect_buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class P>
|
template <class P>
|
||||||
@ -1409,14 +1412,16 @@ void BufferCache<P>::UpdateDrawIndirect() {
|
|||||||
binding = Binding{
|
binding = Binding{
|
||||||
.cpu_addr = *cpu_addr,
|
.cpu_addr = *cpu_addr,
|
||||||
.size = static_cast<u32>(size),
|
.size = static_cast<u32>(size),
|
||||||
.buffer_id = FindBuffer(*cpu_addr, static_cast<u32>(size)),
|
.buffer_id = NULL_BUFFER_ID,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
if (current_draw_indirect->include_count) {
|
if (current_draw_indirect->include_count) {
|
||||||
update(current_draw_indirect->count_start_address, sizeof(u32), count_buffer_binding);
|
update(current_draw_indirect->count_start_address, sizeof(u32), count_buffer_binding);
|
||||||
|
indirect_count_buffer.UpdateCpuAddr(count_buffer_binding.cpu_addr);
|
||||||
}
|
}
|
||||||
update(current_draw_indirect->indirect_start_address, current_draw_indirect->buffer_size,
|
update(current_draw_indirect->indirect_start_address, current_draw_indirect->buffer_size,
|
||||||
indirect_buffer_binding);
|
indirect_buffer_binding);
|
||||||
|
indirect_buffer.UpdateCpuAddr(indirect_buffer_binding.cpu_addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class P>
|
template <class P>
|
||||||
@ -2000,15 +2005,13 @@ bool BufferCache<P>::HasFastUniformBufferBound(size_t stage, u32 binding_index)
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <class P>
|
template <class P>
|
||||||
std::pair<typename BufferCache<P>::Buffer*, u32> BufferCache<P>::GetDrawIndirectCount() {
|
typename BufferCache<P>::Buffer* BufferCache<P>::GetDrawIndirectCount() {
|
||||||
auto& buffer = slot_buffers[count_buffer_binding.buffer_id];
|
return &indirect_count_buffer;
|
||||||
return std::make_pair(&buffer, buffer.Offset(count_buffer_binding.cpu_addr));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class P>
|
template <class P>
|
||||||
std::pair<typename BufferCache<P>::Buffer*, u32> BufferCache<P>::GetDrawIndirectBuffer() {
|
typename BufferCache<P>::Buffer* BufferCache<P>::GetDrawIndirectBuffer() {
|
||||||
auto& buffer = slot_buffers[indirect_buffer_binding.buffer_id];
|
return &indirect_buffer;
|
||||||
return std::make_pair(&buffer, buffer.Offset(indirect_buffer_binding.cpu_addr));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace VideoCommon
|
} // namespace VideoCommon
|
||||||
|
@ -285,23 +285,19 @@ void RasterizerOpenGL::DrawIndirect() {
|
|||||||
const auto& params = maxwell3d->draw_manager->GetIndirectParams();
|
const auto& params = maxwell3d->draw_manager->GetIndirectParams();
|
||||||
buffer_cache.SetDrawIndirect(¶ms);
|
buffer_cache.SetDrawIndirect(¶ms);
|
||||||
PrepareDraw(params.is_indexed, [this, ¶ms](GLenum primitive_mode) {
|
PrepareDraw(params.is_indexed, [this, ¶ms](GLenum primitive_mode) {
|
||||||
const auto [buffer, offset] = buffer_cache.GetDrawIndirectBuffer();
|
const auto buffer = buffer_cache.GetDrawIndirectBuffer();
|
||||||
const GLvoid* const gl_offset =
|
|
||||||
reinterpret_cast<const GLvoid*>(static_cast<uintptr_t>(offset));
|
|
||||||
glBindBuffer(GL_DRAW_INDIRECT_BUFFER, buffer->Handle());
|
glBindBuffer(GL_DRAW_INDIRECT_BUFFER, buffer->Handle());
|
||||||
if (params.include_count) {
|
if (params.include_count) {
|
||||||
const auto [draw_buffer, offset_base] = buffer_cache.GetDrawIndirectCount();
|
const auto draw_buffer = buffer_cache.GetDrawIndirectCount();
|
||||||
glBindBuffer(GL_PARAMETER_BUFFER, draw_buffer->Handle());
|
glBindBuffer(GL_PARAMETER_BUFFER, draw_buffer->Handle());
|
||||||
|
|
||||||
if (params.is_indexed) {
|
if (params.is_indexed) {
|
||||||
const GLenum format = MaxwellToGL::IndexFormat(maxwell3d->regs.index_buffer.format);
|
const GLenum format = MaxwellToGL::IndexFormat(maxwell3d->regs.index_buffer.format);
|
||||||
glMultiDrawElementsIndirectCount(primitive_mode, format, gl_offset,
|
glMultiDrawElementsIndirectCount(primitive_mode, format, nullptr, 0,
|
||||||
static_cast<GLintptr>(offset_base),
|
|
||||||
static_cast<GLsizei>(params.max_draw_counts),
|
static_cast<GLsizei>(params.max_draw_counts),
|
||||||
static_cast<GLsizei>(params.stride));
|
static_cast<GLsizei>(params.stride));
|
||||||
} else {
|
} else {
|
||||||
glMultiDrawArraysIndirectCount(primitive_mode, gl_offset,
|
glMultiDrawArraysIndirectCount(primitive_mode, nullptr, 0,
|
||||||
static_cast<GLintptr>(offset_base),
|
|
||||||
static_cast<GLsizei>(params.max_draw_counts),
|
static_cast<GLsizei>(params.max_draw_counts),
|
||||||
static_cast<GLsizei>(params.stride));
|
static_cast<GLsizei>(params.stride));
|
||||||
}
|
}
|
||||||
@ -309,11 +305,11 @@ void RasterizerOpenGL::DrawIndirect() {
|
|||||||
}
|
}
|
||||||
if (params.is_indexed) {
|
if (params.is_indexed) {
|
||||||
const GLenum format = MaxwellToGL::IndexFormat(maxwell3d->regs.index_buffer.format);
|
const GLenum format = MaxwellToGL::IndexFormat(maxwell3d->regs.index_buffer.format);
|
||||||
glMultiDrawElementsIndirect(primitive_mode, format, gl_offset,
|
glMultiDrawElementsIndirect(primitive_mode, format, nullptr,
|
||||||
static_cast<GLsizei>(params.max_draw_counts),
|
static_cast<GLsizei>(params.max_draw_counts),
|
||||||
static_cast<GLsizei>(params.stride));
|
static_cast<GLsizei>(params.stride));
|
||||||
} else {
|
} else {
|
||||||
glMultiDrawArraysIndirect(primitive_mode, gl_offset,
|
glMultiDrawArraysIndirect(primitive_mode, nullptr,
|
||||||
static_cast<GLsizei>(params.max_draw_counts),
|
static_cast<GLsizei>(params.max_draw_counts),
|
||||||
static_cast<GLsizei>(params.stride));
|
static_cast<GLsizei>(params.stride));
|
||||||
}
|
}
|
||||||
|
@ -230,35 +230,29 @@ void RasterizerVulkan::DrawIndirect() {
|
|||||||
const auto& params = maxwell3d->draw_manager->GetIndirectParams();
|
const auto& params = maxwell3d->draw_manager->GetIndirectParams();
|
||||||
buffer_cache.SetDrawIndirect(¶ms);
|
buffer_cache.SetDrawIndirect(¶ms);
|
||||||
PrepareDraw(params.is_indexed, [this, ¶ms] {
|
PrepareDraw(params.is_indexed, [this, ¶ms] {
|
||||||
const auto indirect_buffer = buffer_cache.GetDrawIndirectBuffer();
|
const auto buffer = buffer_cache.GetDrawIndirectBuffer();
|
||||||
const auto& buffer = indirect_buffer.first;
|
|
||||||
const auto& offset = indirect_buffer.second;
|
|
||||||
if (params.include_count) {
|
if (params.include_count) {
|
||||||
const auto count = buffer_cache.GetDrawIndirectCount();
|
const auto draw_buffer = buffer_cache.GetDrawIndirectCount();
|
||||||
const auto& draw_buffer = count.first;
|
|
||||||
const auto& offset_base = count.second;
|
|
||||||
scheduler.Record([draw_buffer_obj = draw_buffer->Handle(),
|
scheduler.Record([draw_buffer_obj = draw_buffer->Handle(),
|
||||||
buffer_obj = buffer->Handle(), offset_base, offset,
|
buffer_obj = buffer->Handle(), params](vk::CommandBuffer cmdbuf) {
|
||||||
params](vk::CommandBuffer cmdbuf) {
|
|
||||||
if (params.is_indexed) {
|
if (params.is_indexed) {
|
||||||
cmdbuf.DrawIndexedIndirectCount(
|
cmdbuf.DrawIndexedIndirectCount(buffer_obj, 0, draw_buffer_obj, 0,
|
||||||
buffer_obj, offset, draw_buffer_obj, offset_base,
|
static_cast<u32>(params.max_draw_counts),
|
||||||
static_cast<u32>(params.max_draw_counts), static_cast<u32>(params.stride));
|
static_cast<u32>(params.stride));
|
||||||
} else {
|
} else {
|
||||||
cmdbuf.DrawIndirectCount(buffer_obj, offset, draw_buffer_obj, offset_base,
|
cmdbuf.DrawIndirectCount(buffer_obj, 0, draw_buffer_obj, 0,
|
||||||
static_cast<u32>(params.max_draw_counts),
|
static_cast<u32>(params.max_draw_counts),
|
||||||
static_cast<u32>(params.stride));
|
static_cast<u32>(params.stride));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
scheduler.Record([buffer_obj = buffer->Handle(), offset, params](vk::CommandBuffer cmdbuf) {
|
scheduler.Record([buffer_obj = buffer->Handle(), params](vk::CommandBuffer cmdbuf) {
|
||||||
if (params.is_indexed) {
|
if (params.is_indexed) {
|
||||||
cmdbuf.DrawIndexedIndirect(buffer_obj, offset,
|
cmdbuf.DrawIndexedIndirect(buffer_obj, 0, static_cast<u32>(params.max_draw_counts),
|
||||||
static_cast<u32>(params.max_draw_counts),
|
|
||||||
static_cast<u32>(params.stride));
|
static_cast<u32>(params.stride));
|
||||||
} else {
|
} else {
|
||||||
cmdbuf.DrawIndirect(buffer_obj, offset, static_cast<u32>(params.max_draw_counts),
|
cmdbuf.DrawIndirect(buffer_obj, 0, static_cast<u32>(params.max_draw_counts),
|
||||||
static_cast<u32>(params.stride));
|
static_cast<u32>(params.stride));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
Loading…
Reference in New Issue
Block a user