Refactor audio/camera/mic threads

This commit is contained in:
Nekotekina 2018-10-01 20:58:34 +03:00
commit 1456678316
6 changed files with 88 additions and 126 deletions

View file

@ -8,8 +8,6 @@
#include "Emu/Audio/AudioThread.h" #include "Emu/Audio/AudioThread.h"
#include "cellAudio.h" #include "cellAudio.h"
#include <thread>
LOG_CHANNEL(cellAudio); LOG_CHANNEL(cellAudio);
template <> template <>
@ -40,22 +38,7 @@ void fmt_class_string<CellAudioError>::format(std::string& out, u64 arg)
}); });
} }
void audio_config::on_init(const std::shared_ptr<void>& _this) std::pair<u32, u32> audio_thread::operator()()
{
m_buffer.set(vm::alloc(AUDIO_PORT_OFFSET * AUDIO_PORT_COUNT, vm::main));
m_indexes.set(vm::alloc(sizeof(u64) * AUDIO_PORT_COUNT, vm::main));
for (u32 i = 0; i < AUDIO_PORT_COUNT; i++)
{
ports[i].number = i;
ports[i].addr = m_buffer + AUDIO_PORT_OFFSET * i;
ports[i].index = m_indexes + i;
}
old_thread::on_init(_this);
}
void audio_config::on_task()
{ {
thread_ctrl::set_native_priority(1); thread_ctrl::set_native_priority(1);
@ -76,11 +59,11 @@ void audio_config::on_task()
const auto audio = Emu.GetCallbacks().get_audio(); const auto audio = Emu.GetCallbacks().get_audio();
audio->Open(buf8ch, buf_sz); audio->Open(buf8ch, buf_sz);
while (fxm::check<audio_config>() && !Emu.IsStopped()) while (fxm::check<audio_config>() == this && !Emu.IsStopped())
{ {
if (Emu.IsPaused()) if (Emu.IsPaused())
{ {
std::this_thread::sleep_for(1ms); // hack thread_ctrl::wait_for(1000); // hack
continue; continue;
} }
@ -94,7 +77,7 @@ void audio_config::on_task()
const u64 expected_time = m_counter * AUDIO_SAMPLES * 1000000 / 48000; const u64 expected_time = m_counter * AUDIO_SAMPLES * 1000000 / 48000;
if (expected_time >= time_pos) if (expected_time >= time_pos)
{ {
std::this_thread::sleep_for(1ms); // hack thread_ctrl::wait_for(1000); // hack
continue; continue;
} }
@ -342,17 +325,24 @@ void audio_config::on_task()
cellAudio.trace("Audio perf: (access=%d, AddData=%d, events=%d, dump=%d)", cellAudio.trace("Audio perf: (access=%d, AddData=%d, events=%d, dump=%d)",
stamp1 - stamp0, stamp2 - stamp1, stamp3 - stamp2, get_system_time() - stamp3); stamp1 - stamp0, stamp2 - stamp1, stamp3 - stamp2, get_system_time() - stamp3);
} }
return {m_buffer.addr(), m_indexes.addr()};
} }
error_code cellAudioInit() error_code cellAudioInit()
{ {
cellAudio.warning("cellAudioInit()"); cellAudio.warning("cellAudioInit()");
const auto buf = vm::cast(vm::alloc(AUDIO_PORT_OFFSET * AUDIO_PORT_COUNT, vm::main));
const auto ind = vm::cast(vm::alloc(sizeof(u64) * AUDIO_PORT_COUNT, vm::main));
// Start audio thread // Start audio thread
const auto g_audio = fxm::make<audio_config>(); const auto g_audio = fxm::make<audio_config>("Audio Thread", buf, ind);
if (!g_audio) if (!g_audio)
{ {
vm::dealloc(buf);
vm::dealloc(ind);
return CELL_AUDIO_ERROR_ALREADY_INIT; return CELL_AUDIO_ERROR_ALREADY_INIT;
} }
@ -371,6 +361,10 @@ error_code cellAudioQuit()
return CELL_AUDIO_ERROR_NOT_INIT; return CELL_AUDIO_ERROR_NOT_INIT;
} }
// Join and dealloc
auto [buf, ind] = g_audio->operator()();
vm::dealloc(buf);
vm::dealloc(ind);
return CELL_OK; return CELL_OK;
} }

View file

@ -2,8 +2,6 @@
#include "Utilities/Thread.h" #include "Utilities/Thread.h"
// Error codes // Error codes
enum CellAudioError : u32 enum CellAudioError : u32
{ {
@ -85,8 +83,6 @@ enum : u32
AUDIO_SAMPLES = CELL_AUDIO_BLOCK_SAMPLES, AUDIO_SAMPLES = CELL_AUDIO_BLOCK_SAMPLES,
}; };
extern u64 get_system_time();
enum class audio_port_state : u32 enum class audio_port_state : u32
{ {
closed, closed,
@ -96,7 +92,7 @@ enum class audio_port_state : u32
struct audio_port struct audio_port
{ {
atomic_t<audio_port_state> state{ audio_port_state::closed }; atomic_t<audio_port_state> state = audio_port_state::closed;
u32 number; u32 number;
vm::ptr<char> addr{}; vm::ptr<char> addr{};
@ -119,35 +115,35 @@ struct audio_port
atomic_t<level_set_t> level_set; atomic_t<level_set_t> level_set;
}; };
class audio_config final : public old_thread class audio_thread
{ {
void on_task() override; vm::ptr<char> m_buffer;
vm::ptr<u64> m_indexes;
std::string get_name() const override { return "Audio Thread"; }
vm::ptr<char> m_buffer = vm::null;
vm::ptr<u64> m_indexes = vm::null;
u64 m_counter{}; u64 m_counter{};
public: public:
void on_init(const std::shared_ptr<void>&) override;
const u64 start_time = get_system_time(); const u64 start_time = get_system_time();
std::array<audio_port, AUDIO_PORT_COUNT> ports; std::array<audio_port, AUDIO_PORT_COUNT> ports;
std::vector<u64> keys; std::vector<u64> keys;
semaphore<> mutex; shared_mutex mutex;
audio_config() = default; audio_thread(vm::ptr<char> buf, vm::ptr<u64> ind)
: m_buffer(buf)
~audio_config() , m_indexes(ind)
{ {
vm::dealloc_verbose_nothrow(m_buffer.addr()); for (u32 i = 0; i < AUDIO_PORT_COUNT; i++)
vm::dealloc_verbose_nothrow(m_indexes.addr()); {
ports[i].number = i;
ports[i].addr = m_buffer + AUDIO_PORT_OFFSET * i;
ports[i].index = m_indexes + i;
} }
}
std::pair<u32, u32> operator()();
audio_port* open_port() audio_port* open_port()
{ {
@ -162,3 +158,5 @@ public:
return nullptr; return nullptr;
} }
}; };
using audio_config = named_thread<audio_thread>;

View file

@ -7,8 +7,6 @@
#include "Emu/Io/PadHandler.h" #include "Emu/Io/PadHandler.h"
#include "Emu/System.h" #include "Emu/System.h"
#include <thread>
LOG_CHANNEL(cellCamera); LOG_CHANNEL(cellCamera);
// ************** // **************
@ -284,7 +282,7 @@ s32 cellCameraInit()
} }
// Start camera thread // Start camera thread
const auto g_camera = fxm::make<camera_thread>(); const auto g_camera = fxm::make<camera_thread>("Camera Thread");
if (!g_camera) if (!g_camera)
{ {
@ -356,6 +354,13 @@ s32 cellCameraEnd()
return CELL_OK; return CELL_OK;
} }
const auto g_camera = fxm::withdraw<camera_thread>();
if (!g_camera)
{
return CELL_CAMERA_ERROR_NOT_INIT;
}
// TODO: My tests hinted to this behavior, but I'm not sure, so I'll leave this commented // TODO: My tests hinted to this behavior, but I'm not sure, so I'll leave this commented
//s32 res = cellCameraClose(0); //s32 res = cellCameraClose(0);
//if (res != CELL_OK) //if (res != CELL_OK)
@ -363,11 +368,8 @@ s32 cellCameraEnd()
// return res; // return res;
//} //}
if (!fxm::remove<camera_thread>()) // Join thread
{ g_camera->operator()();
return CELL_CAMERA_ERROR_NOT_INIT;
}
return CELL_OK; return CELL_OK;
} }
@ -1154,19 +1156,19 @@ DECLARE(ppu_module_manager::cellCamera)("cellCamera", []()
// camera_thread members // camera_thread members
void camera_thread::on_task() void camera_context::operator()()
{ {
while (fxm::check<camera_thread>() && !Emu.IsStopped()) while (fxm::check<camera_thread>() == this && !Emu.IsStopped())
{ {
std::chrono::steady_clock::time_point frame_start = std::chrono::steady_clock::now(); const u64 frame_start = get_system_time();
if (Emu.IsPaused()) if (Emu.IsPaused())
{ {
std::this_thread::sleep_for(1ms); // hack thread_ctrl::wait_for(1000); // hack
continue; continue;
} }
std::lock_guard lock(mutex_notify_data_map); std::unique_lock lock(mutex_notify_data_map);
for (auto const& notify_data_entry : notify_data_map) for (auto const& notify_data_entry : notify_data_map)
{ {
@ -1180,8 +1182,8 @@ void camera_thread::on_task()
{ {
if (auto queue = lv2_event_queue::find(key)) if (auto queue = lv2_event_queue::find(key))
{ {
u64 data2{ 0 }; u64 data2 = 0;
u64 data3{ 0 }; u64 data3 = 0;
if (read_mode.load() == CELL_CAMERA_READ_DIRECT) if (read_mode.load() == CELL_CAMERA_READ_DIRECT)
{ {
@ -1205,29 +1207,22 @@ void camera_thread::on_task()
} }
} }
} }
} }
const std::chrono::microseconds frame_target_time{ static_cast<u32>(1000000.0 / info.framerate) }; lock.unlock();
std::chrono::steady_clock::time_point now = std::chrono::steady_clock::now(); for (const u64 frame_target_time = 1000000u / info.framerate;;)
std::chrono::microseconds frame_processing_time = std::chrono::duration_cast<std::chrono::microseconds>(now - frame_start);
if (frame_processing_time < frame_target_time)
{ {
std::chrono::microseconds frame_idle_time = frame_target_time - frame_processing_time; const u64 time_passed = get_system_time() - frame_start;
std::this_thread::sleep_for(frame_idle_time); if (time_passed >= frame_target_time)
break;
thread_ctrl::wait_for(frame_target_time - time_passed);
} }
} }
} }
void camera_thread::on_init(const std::shared_ptr<void>& _this) void camera_context::send_attach_state(bool attached)
{
old_thread::on_init(_this);
}
void camera_thread::send_attach_state(bool attached)
{ {
std::lock_guard lock(mutex_notify_data_map); std::lock_guard lock(mutex_notify_data_map);
@ -1255,7 +1250,7 @@ void camera_thread::send_attach_state(bool attached)
} }
} }
void camera_thread::set_attr(s32 attrib, u32 arg1, u32 arg2) void camera_context::set_attr(s32 attrib, u32 arg1, u32 arg2)
{ {
if (attrib == CELL_CAMERA_READMODE) if (attrib == CELL_CAMERA_READMODE)
{ {
@ -1271,7 +1266,7 @@ void camera_thread::set_attr(s32 attrib, u32 arg1, u32 arg2)
attr[attrib] = {arg1, arg2}; attr[attrib] = {arg1, arg2};
} }
void camera_thread::add_queue(u64 key, u64 source, u64 flag) void camera_context::add_queue(u64 key, u64 source, u64 flag)
{ {
std::lock_guard lock(mutex); std::lock_guard lock(mutex);
{ {
@ -1284,7 +1279,7 @@ void camera_thread::add_queue(u64 key, u64 source, u64 flag)
send_attach_state(true); send_attach_state(true);
} }
void camera_thread::remove_queue(u64 key) void camera_context::remove_queue(u64 key)
{ {
std::lock_guard lock(mutex); std::lock_guard lock(mutex);
{ {

View file

@ -351,21 +351,16 @@ struct CellCameraReadEx
vm::bptr<u8> pbuf; vm::bptr<u8> pbuf;
}; };
class camera_thread final : public old_thread class camera_context
{ {
private:
struct notify_event_data struct notify_event_data
{ {
u64 source; u64 source;
u64 flag; u64 flag;
}; };
void on_task() override;
std::string get_name() const override { return "Camera Thread"; }
public: public:
void on_init(const std::shared_ptr<void>&) override; void operator()();
void send_attach_state(bool attached); void send_attach_state(bool attached);
void set_attr(s32 attrib, u32 arg1, u32 arg2); void set_attr(s32 attrib, u32 arg1, u32 arg2);
@ -385,11 +380,11 @@ public:
std::map<u64, notify_event_data> notify_data_map; std::map<u64, notify_event_data> notify_data_map;
semaphore<> mutex; shared_mutex mutex;
semaphore<> mutex_notify_data_map; shared_mutex mutex_notify_data_map;
Timer timer; Timer timer;
atomic_t<u8> read_mode{0}; atomic_t<u8> read_mode{CELL_CAMERA_READ_FUNCCALL};
atomic_t<bool> is_streaming{false}; atomic_t<bool> is_streaming{false};
atomic_t<bool> is_attached{false}; atomic_t<bool> is_attached{false};
atomic_t<bool> is_open{false}; atomic_t<bool> is_open{false};
@ -404,11 +399,10 @@ public:
lv2_memory_container container; lv2_memory_container container;
atomic_t<u32> frame_num; atomic_t<u32> frame_num;
camera_thread() : read_mode(CELL_CAMERA_READ_FUNCCALL) {}
~camera_thread() = default;
}; };
using camera_thread = named_thread<camera_context>;
/// Shared data between cellGem and cellCamera /// Shared data between cellGem and cellCamera
struct gem_camera_shared struct gem_camera_shared
{ {

View file

@ -5,38 +5,24 @@
#include "cellMic.h" #include "cellMic.h"
#include <Emu/IdManager.h> #include <Emu/IdManager.h>
#include <Emu/Cell/lv2/sys_event.h> #include <Emu/Cell/lv2/sys_event.h>
#include <thread>
LOG_CHANNEL(cellMic); LOG_CHANNEL(cellMic);
void mic_thread::on_init(const std::shared_ptr<void>& _this) void mic_context::operator()()
{ {
old_thread::on_init(_this); while (fxm::check<mic_thread>() == this && !Emu.IsStopped())
} {
thread_ctrl::wait_for(1000);
void mic_thread::on_task()
{
while (micInited && !Emu.IsStopped())
{
if (Emu.IsPaused()) if (Emu.IsPaused())
{
std::this_thread::sleep_for(1ms); // hack from cellAudio
continue; continue;
}
if (!micOpened || !micStarted) if (!micOpened || !micStarted)
continue; continue;
// If event queue is not set, then we can't send any events
if (eventQueueKey == 0)
continue;
std::this_thread::sleep_for(1s);
// Make sure the mic thread wasn't stopped while we were sleeping
if (!micInited)
break;
auto micQueue = lv2_event_queue::find(eventQueueKey); auto micQueue = lv2_event_queue::find(eventQueueKey);
if (!micQueue)
continue;
micQueue->send(0, CELL_MIC_DATA, 0, 0); micQueue->send(0, CELL_MIC_DATA, 0, 0);
} }
@ -47,8 +33,8 @@ void mic_thread::on_task()
s32 cellMicInit() s32 cellMicInit()
{ {
cellMic.notice("cellMicInit()"); cellMic.notice("cellMicInit()");
const auto micThread = fxm::make<mic_thread>();
micInited = true; const auto micThread = fxm::make<mic_thread>("Mic Thread");
if (!micThread) if (!micThread)
return CELL_MIC_ERROR_ALREADY_INIT; return CELL_MIC_ERROR_ALREADY_INIT;
@ -58,11 +44,13 @@ s32 cellMicInit()
s32 cellMicEnd() s32 cellMicEnd()
{ {
cellMic.notice("cellMicEnd()"); cellMic.notice("cellMicEnd()");
micInited = false;
const auto micThread = fxm::withdraw<mic_thread>(); const auto micThread = fxm::withdraw<mic_thread>();
if (!micThread) if (!micThread)
return CELL_MIC_ERROR_NOT_INIT; return CELL_MIC_ERROR_NOT_INIT;
// Join
micThread->operator()();
return CELL_OK; return CELL_OK;
} }
@ -479,8 +467,8 @@ s32 cellMicGetDeviceIdentifier()
return CELL_OK; return CELL_OK;
} }
DECLARE(ppu_module_manager::cellMic) DECLARE(ppu_module_manager::cellMic)("cellMic", []()
("cellMic", []() { {
REG_FUNC(cellMic, cellMicInit); REG_FUNC(cellMic, cellMicInit);
REG_FUNC(cellMic, cellMicEnd); REG_FUNC(cellMic, cellMicEnd);
REG_FUNC(cellMic, cellMicOpen); REG_FUNC(cellMic, cellMicOpen);

View file

@ -52,15 +52,11 @@ enum CellMicCommand
// TODO: generate this from input from an actual microphone // TODO: generate this from input from an actual microphone
const u32 bufferSize = 1; const u32 bufferSize = 1;
bool micInited = false; class mic_context
class mic_thread final : public old_thread
{ {
private:
void on_task() override;
std::string get_name() const override { return "Mic Thread"; }
public: public:
void on_init(const std::shared_ptr<void>&) override; void operator()();
// Default value of 48000 for no particular reason // Default value of 48000 for no particular reason
u32 DspFrequency = 48000; // DSP is the default type u32 DspFrequency = 48000; // DSP is the default type
u32 rawFrequency = 48000; u32 rawFrequency = 48000;
@ -76,9 +72,6 @@ public:
f32 signalStateGainControl; f32 signalStateGainControl;
f32 signalStateMicSignalLevel; // value is in decibels f32 signalStateMicSignalLevel; // value is in decibels
f32 signalStateSpeakerSignalLevel; // value is in decibels f32 signalStateSpeakerSignalLevel; // value is in decibels
mic_thread() = default;
~mic_thread()
{
micInited = false;
}
}; };
using mic_thread = named_thread<mic_context>;