sys_rsxaudio: Initial implementation (#11907)

This commit is contained in:
Vestrel 2022-05-05 22:47:44 +09:00 committed by GitHub
parent 0ac90ac395
commit d1e468fefb
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
33 changed files with 4148 additions and 546 deletions

View file

@ -1,129 +1,202 @@
#include "Utilities/simple_ringbuf.h"
simple_ringbuf::simple_ringbuf(u32 size)
simple_ringbuf::simple_ringbuf(u64 size)
{
set_buf_size(size);
}
simple_ringbuf::~simple_ringbuf()
{
rw_ptr.load(); // Sync
}
simple_ringbuf::simple_ringbuf(const simple_ringbuf& other)
{
ctr_state old = other.rw_ptr.load();
for (;;)
{
buf = other.buf;
rw_ptr = old;
const ctr_state current = other.rw_ptr.load();
if (old == current)
{
break;
}
old = current;
}
}
simple_ringbuf& simple_ringbuf::operator=(const simple_ringbuf& other)
{
if (this == &other) return *this;
ctr_state old = other.rw_ptr.load();
for (;;)
{
buf = other.buf;
rw_ptr = old;
const ctr_state current = other.rw_ptr.load();
if (old == current)
{
break;
}
old = current;
}
return *this;
}
simple_ringbuf::simple_ringbuf(simple_ringbuf&& other)
{
rw_ptr = other.rw_ptr.load();
buf_size = other.buf_size;
const ctr_state other_rw_ptr = other.rw_ptr.load();
buf = std::move(other.buf);
initialized = other.initialized.observe();
rw_ptr = other_rw_ptr;
other.buf_size = 0;
other.rw_ptr = 0;
other.initialized = false;
other.rw_ptr.store({});
}
simple_ringbuf& simple_ringbuf::operator=(simple_ringbuf&& other)
{
if (this == &other) return *this;
rw_ptr = other.rw_ptr.load();
buf_size = other.buf_size;
const ctr_state other_rw_ptr = other.rw_ptr.load();
buf = std::move(other.buf);
initialized = other.initialized.observe();
rw_ptr = other_rw_ptr;
other.buf_size = 0;
other.rw_ptr = 0;
other.initialized = false;
other.rw_ptr.store({});
return *this;
}
u32 simple_ringbuf::get_free_size() const
u64 simple_ringbuf::get_free_size() const
{
const u64 _rw_ptr = rw_ptr;
const u32 rd = static_cast<u32>(_rw_ptr);
const u32 wr = static_cast<u32>(_rw_ptr >> 32);
return wr >= rd ? buf_size - 1 - (wr - rd) : rd - wr - 1U;
return get_free_size(rw_ptr);
}
u32 simple_ringbuf::get_used_size() const
u64 simple_ringbuf::get_used_size() const
{
return buf_size - 1 - get_free_size();
return get_used_size(rw_ptr);
}
u32 simple_ringbuf::get_total_size() const
u64 simple_ringbuf::get_total_size() const
{
return buf_size;
rw_ptr.load(); // Sync
return buf.size() - 1;
}
void simple_ringbuf::set_buf_size(u32 size)
u64 simple_ringbuf::get_free_size(ctr_state val) const
{
ensure(size);
const u64 buf_size = buf.size();
const u64 rd = val.read_ptr % buf_size;
const u64 wr = val.write_ptr % buf_size;
this->buf_size = size + 1;
buf = std::make_unique<u8[]>(this->buf_size);
flush();
initialized = true;
return (wr >= rd ? buf_size + rd - wr : rd - wr) - 1;
}
void simple_ringbuf::flush()
u64 simple_ringbuf::get_used_size(ctr_state val) const
{
rw_ptr.atomic_op([&](u64 &val)
const u64 buf_size = buf.size();
const u64 rd = val.read_ptr % buf_size;
const u64 wr = val.write_ptr % buf_size;
return wr >= rd ? wr - rd : buf_size + wr - rd;
}
void simple_ringbuf::set_buf_size(u64 size)
{
ensure(size != umax);
buf.resize(size + 1);
rw_ptr.store({});
}
void simple_ringbuf::writer_flush(u64 cnt)
{
rw_ptr.atomic_op([&](ctr_state& val)
{
val = static_cast<u32>(val >> 32) | (val & 0xFFFFFFFF'00000000);
const u64 used = get_used_size(val);
if (used == 0) return;
val.write_ptr += buf.size() - std::min<u64>(used, cnt);
});
}
u32 simple_ringbuf::push(const void *data, u32 size)
void simple_ringbuf::reader_flush(u64 cnt)
{
ensure(data != nullptr && initialized.observe());
const u32 old = static_cast<u32>(rw_ptr.load() >> 32);
const u32 to_push = std::min(size, get_free_size());
auto b_data = static_cast<const u8*>(data);
if (!to_push) return 0;
if (old + to_push > buf_size)
rw_ptr.atomic_op([&](ctr_state& val)
{
const auto first_write_sz = buf_size - old;
memcpy(&buf[old], b_data, first_write_sz);
memcpy(&buf[0], b_data + first_write_sz, to_push - first_write_sz);
}
else
{
memcpy(&buf[old], b_data, to_push);
}
rw_ptr.atomic_op([&](u64 &val)
{
val = static_cast<u64>((old + to_push) % buf_size) << 32 | static_cast<u32>(val);
val.read_ptr += std::min(get_used_size(val), cnt);
});
return to_push;
}
u32 simple_ringbuf::pop(void *data, u32 size)
u64 simple_ringbuf::push(const void* data, u64 size, bool force)
{
ensure(data != nullptr && initialized.observe());
ensure(data != nullptr);
const u32 old = static_cast<u32>(rw_ptr.load());
const u32 to_pop = std::min(size, get_used_size());
u8 *b_data = static_cast<u8*>(data);
if (!to_pop) return 0;
if (old + to_pop > buf_size)
return rw_ptr.atomic_op([&](ctr_state& val) -> u64
{
const auto first_read_sz = buf_size - old;
memcpy(b_data, &buf[old], first_read_sz);
memcpy(b_data + first_read_sz, &buf[0], to_pop - first_read_sz);
}
else
{
memcpy(b_data, &buf[old], to_pop);
}
const u64 buf_size = buf.size();
const u64 old = val.write_ptr % buf_size;
const u64 free_size = get_free_size(val);
const u64 to_push = std::min(size, free_size);
const auto b_data = static_cast<const u8*>(data);
rw_ptr.atomic_op([&](u64 &val)
{
val = (old + to_pop) % buf_size | (val & 0xFFFFFFFF'00000000);
if (!to_push || (!force && free_size < size))
{
return 0;
}
if (old + to_push > buf_size)
{
const auto first_write_sz = buf_size - old;
memcpy(&buf[old], b_data, first_write_sz);
memcpy(&buf[0], b_data + first_write_sz, to_push - first_write_sz);
}
else
{
memcpy(&buf[old], b_data, to_push);
}
val.write_ptr += to_push;
return to_push;
});
}
u64 simple_ringbuf::pop(void* data, u64 size, bool force)
{
ensure(data != nullptr);
return rw_ptr.atomic_op([&](ctr_state& val) -> u64
{
const u64 buf_size = buf.size();
const u64 old = val.read_ptr % buf_size;
const u64 used_size = get_used_size(val);
const u64 to_pop = std::min(size, used_size);
const auto b_data = static_cast<u8*>(data);
if (!to_pop || (!force && used_size < size))
{
return 0;
}
if (old + to_pop > buf_size)
{
const auto first_read_sz = buf_size - old;
memcpy(b_data, &buf[old], first_read_sz);
memcpy(b_data + first_read_sz, &buf[0], to_pop - first_read_sz);
}
else
{
memcpy(b_data, &buf[old], to_pop);
}
val.read_ptr += to_pop;
return to_pop;
});
return to_pop;
}