Merge pull request #965 from Nekotekina/master

cellAudio update, thread_t
This commit is contained in:
B1ackDaemon 2015-01-18 02:40:03 +02:00
commit 26f1e2c9e3
33 changed files with 1156 additions and 852 deletions

View File

@ -1,5 +1,6 @@
#include "stdafx.h"
#include "Log.h"
#include "rpcs3/Ini.h"
#include "Emu/System.h"
#include "Emu/CPU/CPUThread.h"
#include "Emu/SysCalls/SysCalls.h"
@ -285,7 +286,7 @@ void signal_handler(int sig, siginfo_t* info, void* uct)
ucontext_t* const ctx = (ucontext_t*)uct;
const u64 addr64 = (u64)info->si_addr - (u64)Memory.GetBaseAddr();
//const bool is_writing = false; // TODO: get it correctly
if (addr64 < 0x100000000ull)
if (addr64 < 0x100000000ull && GetCurrentNamedThread())
{
const u32 addr = (u32)addr64;
if (addr - RAW_SPU_BASE_ADDR < (6 * RAW_SPU_OFFSET) && (addr % RAW_SPU_OFFSET) >= RAW_SPU_PROB_OFFSET) // RawSPU MMIO registers
@ -384,7 +385,7 @@ NamedThreadBase* GetCurrentNamedThread()
void SetCurrentNamedThread(NamedThreadBase* value)
{
auto old_value = g_tls_this_thread;
const auto old_value = g_tls_this_thread;
if (old_value == value)
{
@ -536,23 +537,63 @@ bool ThreadBase::TestDestroy() const
return m_destroy;
}
thread::thread(const std::string& name, std::function<void()> func) : m_name(name)
thread_t::thread_t(const std::string& name, bool autojoin, std::function<void()> func)
: m_name(name)
, m_state(TS_NON_EXISTENT)
, m_autojoin(autojoin)
{
start(func);
}
thread::thread(const std::string& name) : m_name(name)
thread_t::thread_t(const std::string& name, std::function<void()> func)
: m_name(name)
, m_state(TS_NON_EXISTENT)
, m_autojoin(false)
{
start(func);
}
thread_t::thread_t(const std::string& name)
: m_name(name)
, m_state(TS_NON_EXISTENT)
, m_autojoin(false)
{
}
thread::thread()
thread_t::thread_t()
: m_state(TS_NON_EXISTENT)
, m_autojoin(false)
{
}
void thread::start(std::function<void()> func)
void thread_t::set_name(const std::string& name)
{
m_name = name;
}
thread_t::~thread_t()
{
if (m_state == TS_JOINABLE)
{
if (m_autojoin)
{
m_thr.join();
}
else
{
m_thr.detach();
}
}
}
void thread_t::start(std::function<void()> func)
{
if (m_state.exchange(TS_NON_EXISTENT) == TS_JOINABLE)
{
m_thr.join(); // forcefully join previously created thread
}
std::string name = m_name;
m_thr = std::thread([func, name]()
{
SetCurrentThreadDebugName(name.c_str());
@ -567,6 +608,11 @@ void thread::start(std::function<void()> func)
SetCurrentNamedThread(&info);
g_thread_count++;
if (Ini.HLELogging.GetValue())
{
LOG_NOTICE(HLE, name + " started");
}
try
{
func();
@ -580,6 +626,15 @@ void thread::start(std::function<void()> func)
LOG_ERROR(GENERAL, "%s: %s", name.c_str(), e.c_str());
}
if (Emu.IsStopped())
{
LOG_NOTICE(HLE, name + " aborted");
}
else if (Ini.HLELogging.GetValue())
{
LOG_NOTICE(HLE, name + " ended");
}
SetCurrentNamedThread(nullptr);
g_thread_count--;
@ -587,21 +642,41 @@ void thread::start(std::function<void()> func)
_set_se_translator(old_se_translator);
#endif
});
if (m_state.exchange(TS_JOINABLE) == TS_JOINABLE)
{
assert(!"thread_t::start() failed"); // probably started from another thread
}
}
void thread::detach()
void thread_t::detach()
{
m_thr.detach();
if (m_state.exchange(TS_NON_EXISTENT) == TS_JOINABLE)
{
m_thr.detach();
}
else
{
assert(!"thread_t::detach() failed"); // probably joined or detached
}
}
void thread::join()
void thread_t::join()
{
m_thr.join();
if (m_state.exchange(TS_NON_EXISTENT) == TS_JOINABLE)
{
m_thr.join();
}
else
{
assert(!"thread_t::join() failed"); // probably joined or detached
}
}
bool thread::joinable() const
bool thread_t::joinable() const
{
return m_thr.joinable();
//return m_thr.joinable();
return m_state == TS_JOINABLE;
}
bool waiter_map_t::is_stopped(u64 signal_id)
@ -665,7 +740,10 @@ void waiter_map_t::notify(u64 signal_id)
}
}
bool squeue_test_exit(const volatile bool* do_exit)
const std::function<bool()> SQUEUE_ALWAYS_EXIT = [](){ return true; };
const std::function<bool()> SQUEUE_NEVER_EXIT = [](){ return false; };
bool squeue_test_exit()
{
return Emu.IsStopped() || (do_exit && *do_exit);
return Emu.IsStopped();
}

View File

@ -54,18 +54,34 @@ public:
virtual void Task() = 0;
};
class thread
class thread_t
{
enum thread_state_t
{
TS_NON_EXISTENT,
TS_JOINABLE,
};
std::atomic<thread_state_t> m_state;
std::string m_name;
std::thread m_thr;
bool m_autojoin;
public:
thread(const std::string& name, std::function<void()> func);
thread(const std::string& name);
thread();
thread_t(const std::string& name, bool autojoin, std::function<void()> func);
thread_t(const std::string& name, std::function<void()> func);
thread_t(const std::string& name);
thread_t();
~thread_t();
thread_t(const thread_t& right) = delete;
thread_t(thread_t&& right) = delete;
thread_t& operator =(const thread_t& right) = delete;
thread_t& operator =(thread_t&& right) = delete;
public:
void set_name(const std::string& name);
void start(std::function<void()> func);
void detach();
void join();
@ -148,7 +164,10 @@ public:
void notify(u64 signal_id);
};
bool squeue_test_exit(const volatile bool* do_exit);
extern const std::function<bool()> SQUEUE_ALWAYS_EXIT;
extern const std::function<bool()> SQUEUE_NEVER_EXIT;
bool squeue_test_exit();
template<typename T, u32 sq_size = 256>
class squeue_t
@ -199,7 +218,7 @@ public:
return m_sync.read_relaxed().count == sq_size;
}
bool push(const T& data, const volatile bool* do_exit = nullptr)
bool push(const T& data, const std::function<bool()>& test_exit)
{
u32 pos = 0;
@ -222,7 +241,7 @@ public:
return SQSVR_OK;
}))
{
if (res == SQSVR_FAILED && squeue_test_exit(do_exit))
if (res == SQSVR_FAILED && (test_exit() || squeue_test_exit()))
{
return false;
}
@ -247,14 +266,22 @@ public:
return true;
}
bool try_push(const T& data)
bool push(const T& data, const volatile bool* do_exit)
{
static const volatile bool no_wait = true;
return push(data, &no_wait);
return push(data, [do_exit](){ return do_exit && *do_exit; });
}
bool pop(T& data, const volatile bool* do_exit = nullptr)
__forceinline bool push(const T& data)
{
return push(data, SQUEUE_NEVER_EXIT);
}
__forceinline bool try_push(const T& data)
{
return push(data, SQUEUE_ALWAYS_EXIT);
}
bool pop(T& data, const std::function<bool()>& test_exit)
{
u32 pos = 0;
@ -277,7 +304,7 @@ public:
return SQSVR_OK;
}))
{
if (res == SQSVR_FAILED && squeue_test_exit(do_exit))
if (res == SQSVR_FAILED && (test_exit() || squeue_test_exit()))
{
return false;
}
@ -307,14 +334,22 @@ public:
return true;
}
bool try_pop(T& data)
bool pop(T& data, const volatile bool* do_exit)
{
static const volatile bool no_wait = true;
return pop(data, &no_wait);
return pop(data, [do_exit](){ return do_exit && *do_exit; });
}
bool peek(T& data, u32 start_pos = 0, const volatile bool* do_exit = nullptr)
__forceinline bool pop(T& data)
{
return pop(data, SQUEUE_NEVER_EXIT);
}
__forceinline bool try_pop(T& data)
{
return pop(data, SQUEUE_ALWAYS_EXIT);
}
bool peek(T& data, u32 start_pos, const std::function<bool()>& test_exit)
{
assert(start_pos < sq_size);
u32 pos = 0;
@ -332,13 +367,13 @@ public:
{
return SQSVR_LOCKED;
}
sync.pop_lock = 1;
pos = sync.position + start_pos;
return SQSVR_OK;
}))
{
if (res == SQSVR_FAILED && squeue_test_exit(do_exit))
if (res == SQSVR_FAILED && (test_exit() || squeue_test_exit()))
{
return false;
}
@ -361,11 +396,19 @@ public:
return true;
}
bool try_peek(T& data, u32 start_pos = 0)
bool peek(T& data, u32 start_pos, const volatile bool* do_exit)
{
static const volatile bool no_wait = true;
return peek(data, start_pos, [do_exit](){ return do_exit && *do_exit; });
}
return peek(data, start_pos, &no_wait);
__forceinline bool peek(T& data, u32 start_pos = 0)
{
return peek(data, start_pos, SQUEUE_NEVER_EXIT);
}
__forceinline bool try_peek(T& data, u32 start_pos = 0)
{
return peek(data, start_pos, SQUEUE_ALWAYS_EXIT);
}
class squeue_data_t

View File

@ -26,7 +26,7 @@ namespace sce_libc_func
});
}
void printf(vm::psv::ptr<const char> fmt)
void printf(vm::psv::ptr<const char> fmt) // va_args...
{
sceLibc.Error("printf(fmt=0x%x)", fmt);

View File

@ -1,4 +1,5 @@
#include "stdafx.h"
#include <unordered_map>
#include "Utilities/Log.h"
#include "Emu/System.h"
#include "PSVFuncList.h"
@ -7,29 +8,19 @@ std::vector<psv_func> g_psv_func_list;
void add_psv_func(psv_func& data)
{
// setup special functions (without NIDs)
if (!g_psv_func_list.size())
{
psv_func unimplemented;
unimplemented.nid = 0x00000000; // must not be a valid id
unimplemented.name = "INVALID FUNCTION (0x0)";
unimplemented.func.reset(new psv_func_detail::func_binder<u32>([]() -> u32
{
LOG_ERROR(HLE, "Unimplemented function executed");
Emu.Pause();
return 0xffffffffu;
}));
unimplemented.nid = 0;
unimplemented.name = "Special function (unimplemented stub)";
unimplemented.func.reset(new psv_func_detail::func_binder<void, ARMv7Thread&>([](ARMv7Thread& CPU){ CPU.m_last_syscall = vm::psv::read32(CPU.PC + 4); throw "Unimplemented function executed"; }));
g_psv_func_list.push_back(unimplemented);
psv_func hle_return;
hle_return.nid = 0x00000001; // must not be a valid id
hle_return.name = "INVALID FUNCTION (0x1)";
hle_return.func.reset(new psv_func_detail::func_binder<void, ARMv7Thread&>([](ARMv7Thread& CPU)
{
CPU.FastStop();
return;
}));
hle_return.nid = 1;
hle_return.name = "Special function (return from HLE)";
hle_return.func.reset(new psv_func_detail::func_binder<void, ARMv7Thread&>([](ARMv7Thread& CPU){ CPU.FastStop(); }));
g_psv_func_list.push_back(hle_return);
}
@ -40,7 +31,7 @@ psv_func* get_psv_func_by_nid(u32 nid)
{
for (auto& f : g_psv_func_list)
{
if (f.nid == nid)
if (f.nid == nid && &f - g_psv_func_list.data() >= 2 /* special functions count */)
{
return &f;
}
@ -61,8 +52,13 @@ u32 get_psv_func_index(psv_func* func)
void execute_psv_func_by_index(ARMv7Thread& CPU, u32 index)
{
assert(index < g_psv_func_list.size());
auto old_last_syscall = CPU.m_last_syscall;
CPU.m_last_syscall = g_psv_func_list[index].nid;
(*g_psv_func_list[index].func)(CPU);
CPU.m_last_syscall = old_last_syscall;
}
extern psv_log_base sceLibc;

View File

@ -11,8 +11,6 @@ ALCenum g_last_alc_error = ALC_NO_ERROR;
#define checkForAlError(sit) if((g_last_al_error = alGetError()) != AL_NO_ERROR) printAlError(g_last_al_error, sit)
#define checkForAlcError(sit) if((g_last_alc_error = alcGetError(m_device)) != ALC_NO_ERROR) printAlcError(g_last_alc_error, sit)
static const ALenum g_audio_format = Ini.AudioConvertToU16.GetValue() ? AL_FORMAT_STEREO16 : AL_FORMAT_STEREO_FLOAT32;
void printAlError(ALenum err, const char* situation)
{
if (err != AL_NO_ERROR)
@ -102,7 +100,7 @@ void OpenALThread::Open(const void* src, int size)
for (uint i = 0; i<g_al_buffers_count; ++i)
{
alBufferData(m_buffers[i], g_audio_format, src, m_buffer_size, 48000);
alBufferData(m_buffers[i], Ini.AudioConvertToU16.GetValue() ? AL_FORMAT_71CHN16 : AL_FORMAT_71CHN32, src, m_buffer_size, 48000);
checkForAlError("alBufferData");
}
@ -137,7 +135,7 @@ void OpenALThread::AddData(const void* src, int size)
int bsize = size < m_buffer_size ? size : m_buffer_size;
alBufferData(buffer, g_audio_format, bsrc, bsize, 48000);
alBufferData(buffer, Ini.AudioConvertToU16.GetValue() ? AL_FORMAT_71CHN16 : AL_FORMAT_71CHN32, bsrc, bsize, 48000);
checkForAlError("alBufferData");
alSourceQueueBuffers(m_source, 1, &buffer);

View File

@ -24,4 +24,4 @@ public:
virtual void Close();
virtual void Stop();
virtual void AddData(const void* src, int size);
};
};

View File

@ -1,22 +1,32 @@
#include "stdafx.h"
#include "AudioDumper.h"
AudioDumper::AudioDumper(u8 ch) : m_header(ch)
AudioDumper::AudioDumper() : m_header(0), m_init(false)
{
}
AudioDumper::~AudioDumper()
{
Finalize();
}
bool AudioDumper::Init()
bool AudioDumper::Init(u8 ch)
{
return m_output.Open("audio.wav", rFile::write);
if ((m_init = m_output.Open("audio.wav", rFile::write)))
{
m_header = WAVHeader(ch);
WriteHeader();
}
return m_init;
}
void AudioDumper::WriteHeader()
{
m_output.Write(&m_header, sizeof(m_header)); // write file header
if (m_init)
{
m_output.Write(&m_header, sizeof(m_header)); // write file header
}
}
size_t AudioDumper::WriteData(const void* buffer, size_t size)
@ -31,17 +41,27 @@ size_t AudioDumper::WriteData(const void* buffer, size_t size)
{
if (((u8*)buffer)[i + (size & ~7)]) do_save = true;
}
if (!do_save) return size; // ignore empty data
if (m_init && do_save)
#else
if (m_init)
#endif
size_t ret = m_output.Write(buffer, size);
m_header.Size += (u32)ret;
m_header.RIFF.Size += (u32)ret;
return ret;
{
size_t ret = m_output.Write(buffer, size);
m_header.Size += (u32)ret;
m_header.RIFF.Size += (u32)ret;
return ret;
}
return size;
}
void AudioDumper::Finalize()
{
m_output.Seek(0);
m_output.Write(&m_header, sizeof(m_header)); // write fixed file header
m_output.Close();
if (m_init)
{
m_output.Seek(0);
m_output.Write(&m_header, sizeof(m_header)); // write fixed file header
m_output.Close();
}
}

View File

@ -55,15 +55,16 @@ struct WAVHeader
class AudioDumper
{
private:
WAVHeader m_header;
rFile m_output;
bool m_init;
public:
AudioDumper(u8 ch);
AudioDumper();
~AudioDumper();
bool Init();
public:
bool Init(u8 ch);
void WriteHeader();
size_t WriteData(const void* buffer, size_t size);
void Finalize();

View File

@ -21,9 +21,9 @@ struct AudioInfo
void Init()
{
mode.type = CELL_AUDIO_OUT_CODING_TYPE_LPCM;
mode.channel = CELL_AUDIO_OUT_CHNUM_2;
mode.channel = CELL_AUDIO_OUT_CHNUM_8;
mode.fs = CELL_AUDIO_OUT_FS_48KHZ;
mode.layout = CELL_AUDIO_OUT_SPEAKER_LAYOUT_2CH;
mode.layout = CELL_AUDIO_OUT_SPEAKER_LAYOUT_8CH_LREClrxy;
mode.encoder = CELL_AUDIO_OUT_CODING_TYPE_LPCM;
mode.downMixer = CELL_AUDIO_OUT_DOWNMIXER_NONE;
}

View File

@ -15,4 +15,4 @@ public:
virtual void Close() {}
virtual void Stop() {}
virtual void AddData(const void* src, int size) {}
};
};

View File

@ -8,13 +8,14 @@
XAudio2Thread::~XAudio2Thread()
{
Quit();
if (m_source_voice) Quit();
}
void XAudio2Thread::Init()
{
HRESULT hr = S_OK;
#if (_WIN32_WINNT < 0x0602)
hr = CoInitializeEx(nullptr, COINIT_MULTITHREADED);
if (FAILED(hr))
{
@ -22,6 +23,7 @@ void XAudio2Thread::Init()
Emu.Pause();
return;
}
#endif
hr = XAudio2Create(&m_xaudio2_instance, 0, XAUDIO2_DEFAULT_PROCESSOR);
if (FAILED(hr))
@ -50,6 +52,10 @@ void XAudio2Thread::Quit()
m_xaudio2_instance->StopEngine();
m_xaudio2_instance->Release();
m_xaudio2_instance = nullptr;
#if (_WIN32_WINNT < 0x0602)
CoUninitialize();
#endif
}
void XAudio2Thread::Play()
@ -87,13 +93,16 @@ void XAudio2Thread::Open(const void* src, int size)
{
HRESULT hr;
WORD sample_size = Ini.AudioConvertToU16.GetValue() ? sizeof(u16) : sizeof(float);
WORD channels = 8;
WAVEFORMATEX waveformatex;
waveformatex.wFormatTag = WAVE_FORMAT_IEEE_FLOAT;
waveformatex.nChannels = 2;
waveformatex.wFormatTag = Ini.AudioConvertToU16.GetValue() ? WAVE_FORMAT_PCM : WAVE_FORMAT_IEEE_FLOAT;
waveformatex.nChannels = channels;
waveformatex.nSamplesPerSec = 48000;
waveformatex.nAvgBytesPerSec = 48000 * 2 * sizeof(float);
waveformatex.nBlockAlign = 2 * sizeof(float);
waveformatex.wBitsPerSample = 32;
waveformatex.nAvgBytesPerSec = 48000 * (DWORD)channels * (DWORD)sample_size;
waveformatex.nBlockAlign = channels * sample_size;
waveformatex.wBitsPerSample = sample_size * 8;
waveformatex.cbSize = 0;
hr = m_xaudio2_instance->CreateSourceVoice(&m_source_voice, &waveformatex, 0, XAUDIO2_DEFAULT_FREQ_RATIO);
@ -129,4 +138,4 @@ void XAudio2Thread::AddData(const void* src, int size)
Emu.Pause();
}
}
#endif
#endif

View File

@ -1,10 +1,11 @@
#include "stdafx.h"
#include "rpcs3/Ini.h"
#include "Emu/SysCalls/SysCalls.h"
#include "Utilities/Log.h"
#include "Emu/Memory/Memory.h"
#include "Emu/System.h"
#include "Emu/DbgCommand.h"
#include "Emu/SysCalls/SysCalls.h"
#include "Emu/ARMv7/PSVFuncList.h"
#include "CPUDecoder.h"
#include "CPUThread.h"
@ -256,6 +257,70 @@ void CPUThread::ExecOnce()
void CPUThread::Task()
{
auto get_syscall_name = [this](u64 syscall) -> std::string
{
switch (GetType())
{
case CPU_THREAD_ARMv7:
{
if ((u32)syscall == syscall)
{
if (syscall)
{
if (auto func = get_psv_func_by_nid((u32)syscall))
{
return func->name;
}
}
else
{
return{};
}
}
return "unknown function";
}
case CPU_THREAD_PPU:
{
if ((u32)syscall == syscall)
{
if (syscall)
{
if (syscall < 1024)
{
// TODO:
//return SysCalls::GetSyscallName((u32)syscall);
return "unknown syscall";
}
else
{
return SysCalls::GetHLEFuncName((u32)syscall);
}
}
else
{
return{};
}
}
return "unknown function";
}
case CPU_THREAD_SPU:
case CPU_THREAD_RAW_SPU:
default:
{
if (!syscall)
{
return{};
}
return "unknown function";
}
}
};
if (Ini.HLELogging.GetValue()) LOG_NOTICE(GENERAL, "%s enter", CPUThread::GetFName().c_str());
const std::vector<u64>& bp = Emu.GetBreakPoints();
@ -310,13 +375,13 @@ void CPUThread::Task()
}
catch (const std::string& e)
{
LOG_ERROR(GENERAL, "Exception: %s (is_alive=%d, m_last_syscall=0x%llx (%s))", e, IsAlive(), m_last_syscall, SysCalls::GetHLEFuncName((u32)m_last_syscall));
LOG_ERROR(GENERAL, "Exception: %s (is_alive=%d, m_last_syscall=0x%llx (%s))", e, IsAlive(), m_last_syscall, get_syscall_name(m_last_syscall));
LOG_NOTICE(GENERAL, RegsToString());
Emu.Pause();
}
catch (const char* e)
{
LOG_ERROR(GENERAL, "Exception: %s (is_alive=%d, m_last_syscall=0x%llx (%s))", e, IsAlive(), m_last_syscall, SysCalls::GetHLEFuncName((u32)m_last_syscall));
LOG_ERROR(GENERAL, "Exception: %s (is_alive=%d, m_last_syscall=0x%llx (%s))", e, IsAlive(), m_last_syscall, get_syscall_name(m_last_syscall));
LOG_NOTICE(GENERAL, RegsToString());
Emu.Pause();
}

View File

@ -841,9 +841,9 @@ public:
template<typename T, size_t size = sizeof(T)>
struct cast_ppu_gpr
{
static_assert(sizeof(T) <= 8, "Type for cast_ppu_gpr is invalid (too big)");
static_assert(sizeof(T) <= 8, "Invalid type for cast_ppu_gpr");
static u64 func(const T& value)
__forceinline static u64 to_gpr(const T& value)
{
u64 result = 0;
(T&)result = value;
@ -854,7 +854,7 @@ struct cast_ppu_gpr
template<typename T>
struct cast_ppu_gpr<T, 1>
{
static u64 func(const T& value)
__forceinline static u64 to_gpr(const T& value)
{
return (u8&)value;
}
@ -863,7 +863,7 @@ struct cast_ppu_gpr<T, 1>
template<typename T>
struct cast_ppu_gpr<T, 2>
{
static u64 func(const T& value)
__forceinline static u64 to_gpr(const T& value)
{
return (u16&)value;
}
@ -872,7 +872,7 @@ struct cast_ppu_gpr<T, 2>
template<typename T>
struct cast_ppu_gpr<T, 4>
{
static u64 func(const T& value)
__forceinline static u64 to_gpr(const T& value)
{
return (u32&)value;
}
@ -881,7 +881,7 @@ struct cast_ppu_gpr<T, 4>
template<typename T>
struct cast_ppu_gpr<T, 8>
{
static u64 func(const T& value)
__forceinline static u64 to_gpr(const T& value)
{
return (u64&)value;
}
@ -890,7 +890,7 @@ struct cast_ppu_gpr<T, 8>
template<>
struct cast_ppu_gpr<s8, 1>
{
static u64 func(const s8& value)
__forceinline static u64 to_gpr(const s8& value)
{
return value;
}
@ -899,7 +899,7 @@ struct cast_ppu_gpr<s8, 1>
template<>
struct cast_ppu_gpr<s16, 2>
{
static u64 func(const s16& value)
__forceinline static u64 to_gpr(const s16& value)
{
return value;
}
@ -908,7 +908,7 @@ struct cast_ppu_gpr<s16, 2>
template<>
struct cast_ppu_gpr<s32, 4>
{
static u64 func(const s32& value)
__forceinline static u64 to_gpr(const s32& value)
{
return value;
}
@ -917,8 +917,14 @@ struct cast_ppu_gpr<s32, 4>
template<>
struct cast_ppu_gpr<s64, 8>
{
static u64 func(const s64& value)
__forceinline static u64 to_gpr(const s64& value)
{
return value;
}
};
template<typename T>
__forceinline static u64 cast_to_ppu_gpr(const T& value)
{
return cast_ppu_gpr<T>::to_gpr(value);
}

View File

@ -2348,22 +2348,15 @@ void RSXThread::Task()
OnInitThread();
m_last_flip_time = get_system_time() - 1000000;
volatile bool is_vblank_stopped = false;
thread vblank("VBlank thread", [&]()
thread_t vblank("VBlank thread", true /* autojoin */, [this]()
{
const u64 start_time = get_system_time();
m_vblank_count = 0;
while (!TestDestroy())
while (!TestDestroy() && !Emu.IsStopped())
{
if (Emu.IsStopped())
{
LOG_WARNING(RSX, "VBlank thread aborted");
return;
}
if (get_system_time() - start_time > m_vblank_count * 1000000 / 60)
{
m_vblank_count++;
@ -2380,17 +2373,14 @@ void RSXThread::Task()
std::this_thread::sleep_for (std::chrono::milliseconds(1)); // hack
}
is_vblank_stopped = true;
});
vblank.detach();
while (!TestDestroy()) try
{
if (Emu.IsStopped())
{
LOG_WARNING(RSX, "RSX thread aborted");
return;
break;
}
std::lock_guard<std::mutex> lock(m_cs_main);
@ -2409,7 +2399,7 @@ void RSXThread::Task()
m_sem_flush.post_and_wait();
}
std::this_thread::sleep_for (std::chrono::milliseconds(1)); // hack
std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack
continue;
}
@ -2476,24 +2466,17 @@ void RSXThread::Task()
value += (count + 1) * 4;
});
}
catch (const std::string& e)
{
LOG_ERROR(RSX, "Exception: %s", e.c_str());
Emu.Pause();
}
catch (const char* e)
{
LOG_ERROR(RSX, "Exception: %s", e);
Emu.Pause();
}
while (!is_vblank_stopped)
{
std::this_thread::sleep_for (std::chrono::milliseconds(1)); // hack
}
LOG_NOTICE(RSX, "RSX thread ended");
OnExitThread();

View File

@ -26,7 +26,7 @@ namespace cb_detail
__forceinline static void set_value(PPUThread& CPU, const T& arg)
{
CPU.GPR[g_count + 2] = cast_ppu_gpr<T>::func(arg);
CPU.GPR[g_count + 2] = cast_to_ppu_gpr<T>(arg);
}
};
@ -63,7 +63,7 @@ namespace cb_detail
{
const int stack_pos = 0x70 + (g_count - 9) * 8 - FIXED_STACK_FRAME_SIZE;
static_assert(stack_pos < 0, "TODO: Increase fixed stack frame size (arg count limit broken)");
vm::write64(CPU.GPR[1] + stack_pos, cast_ppu_gpr<T>::func(arg));
vm::write64(CPU.GPR[1] + stack_pos, cast_to_ppu_gpr<T>(arg));
}
};

View File

@ -82,7 +82,7 @@ void CallbackManager::Init()
static_cast<PPUThread*>(m_cb_thread)->DoRun();
}
thread cb_async_thread("CallbackManager::Async() thread", [this]()
thread_t cb_async_thread("CallbackManager thread", [this]()
{
SetCurrentNamedThread(m_cb_thread);
@ -108,8 +108,6 @@ void CallbackManager::Init()
m_cb_thread->WaitForAnySignal();
}
});
cb_async_thread.detach();
}
void CallbackManager::Clear()
@ -119,3 +117,40 @@ void CallbackManager::Clear()
m_cb_list.clear();
m_async_list.clear();
}
u64 CallbackManager::AddPauseCallback(const std::function<PauseResumeCB>& func)
{
std::lock_guard<std::mutex> lock(m_mutex);
m_pause_cb_list.push_back({ func, next_tag });
return next_tag++;
}
void CallbackManager::RemovePauseCallback(const u64 tag)
{
std::lock_guard<std::mutex> lock(m_mutex);
for (auto& data : m_pause_cb_list)
{
if (data.tag == tag)
{
m_pause_cb_list.erase(m_pause_cb_list.begin() + (&data - m_pause_cb_list.data()));
return;
}
}
assert(!"CallbackManager()::RemovePauseCallback(): tag not found");
}
void CallbackManager::RunPauseCallbacks(const bool is_paused)
{
std::lock_guard<std::mutex> lock(m_mutex);
for (auto& data : m_pause_cb_list)
{
if (data.cb)
{
data.cb(is_paused);
}
}
}

View File

@ -3,21 +3,62 @@
class CPUThread;
class PPUThread;
typedef void(PauseResumeCB)(bool is_paused);
class CallbackManager
{
std::vector<std::function<s32(CPUThread& CPU)>> m_cb_list;
std::vector<std::function<void(CPUThread& CPU)>> m_async_list;
CPUThread* m_cb_thread;
std::mutex m_mutex;
std::vector<std::function<s32(CPUThread&)>> m_cb_list;
std::vector<std::function<void(CPUThread&)>> m_async_list;
CPUThread* m_cb_thread;
struct PauseResumeCBS
{
std::function<PauseResumeCB> cb;
u64 tag;
};
u64 next_tag; // not initialized, only increased
std::vector<PauseResumeCBS> m_pause_cb_list;
public:
void Register(const std::function<s32(PPUThread& PPU)>& func); // register callback (called in Check() method)
void Register(const std::function<s32(PPUThread& CPU)>& func); // register callback (called in Check() method)
void Async(const std::function<void(PPUThread& PPU)>& func); // register callback for callback thread (called immediately)
void Async(const std::function<void(PPUThread& CPU)>& func); // register callback for callback thread (called immediately)
bool Check(CPUThread& CPU, s32& result); // call one callback registered by Register() method
void Init();
void Clear();
u64 AddPauseCallback(const std::function<PauseResumeCB>& func); // register callback for pausing/resuming emulation events
void RemovePauseCallback(const u64 tag); // unregister callback (uses the result of AddPauseCallback() function)
void RunPauseCallbacks(const bool is_paused);
};
class PauseCallbackRegisterer
{
CallbackManager& cb_manager;
u64 cb_tag;
public:
PauseCallbackRegisterer(CallbackManager& cb_manager, const std::function<PauseResumeCB>& func)
: cb_manager(cb_manager)
, cb_tag(cb_manager.AddPauseCallback(func))
{
}
PauseCallbackRegisterer() = delete;
PauseCallbackRegisterer(const PauseCallbackRegisterer& right) = delete;
PauseCallbackRegisterer(PauseCallbackRegisterer&& right) = delete;
~PauseCallbackRegisterer()
{
cb_manager.RemovePauseCallback(cb_tag);
}
PauseCallbackRegisterer& operator =(const PauseCallbackRegisterer& right) = delete;
PauseCallbackRegisterer& operator =(PauseCallbackRegisterer&& right) = delete;
};

View File

@ -224,7 +224,7 @@ u32 adecOpen(AudioDecoder* adec_ptr)
adec.id = adec_id;
adec.adecCb = (PPUThread*)&Emu.GetCPU().AddThread(CPU_THREAD_PPU);
adec.adecCb->SetName("Audio Decoder[" + std::to_string(adec_id) + "] Callback");
adec.adecCb->SetName(fmt::format("AudioDecoder[%d] Callback", adec_id));
adec.adecCb->SetEntry(0);
adec.adecCb->SetPrio(1001);
adec.adecCb->SetStackSize(0x10000);
@ -232,11 +232,9 @@ u32 adecOpen(AudioDecoder* adec_ptr)
adec.adecCb->InitRegs();
adec.adecCb->DoRun();
thread t("Audio Decoder[" + std::to_string(adec_id) + "] Thread", [adec_ptr, sptr]()
thread_t t(fmt::format("AudioDecoder[%d] Thread", adec_id), [adec_ptr, sptr]()
{
AudioDecoder& adec = *adec_ptr;
cellAdec->Notice("Audio Decoder thread started");
AdecTask& task = adec.task;
while (true)
@ -471,18 +469,14 @@ u32 adecOpen(AudioDecoder* adec_ptr)
default:
{
ADEC_ERROR("Audio Decoder thread error: unknown task(%d)", task.type);
ADEC_ERROR("AudioDecoder thread error: unknown task(%d)", task.type);
}
}
}
adec.is_finished = true;
if (adec.is_closed) cellAdec->Notice("Audio Decoder thread ended");
if (Emu.IsStopped()) cellAdec->Warning("Audio Decoder thread aborted");
});
t.detach();
return adec_id;
}

File diff suppressed because it is too large Load Diff

View File

@ -72,51 +72,76 @@ struct CellAudioPortConfig
be_t<u32> portAddr;
};
enum : u32
{
BUFFER_NUM = 32,
BUFFER_SIZE = 256,
AUDIO_PORT_COUNT = 8,
AUDIO_PORT_OFFSET = 256 * 1024,
AUDIO_SAMPLES = CELL_AUDIO_BLOCK_SAMPLES,
};
enum AudioState : u32
{
AUDIO_STATE_NOT_INITIALIZED,
AUDIO_STATE_INITIALIZED,
AUDIO_STATE_FINALIZED,
};
enum AudioPortState : u32
{
AUDIO_PORT_STATE_CLOSED,
AUDIO_PORT_STATE_OPENED,
AUDIO_PORT_STATE_STARTED,
};
struct AudioPortConfig
{
bool m_is_audio_port_opened;
bool m_is_audio_port_started;
u8 channel;
u8 block;
float level;
std::mutex mutex;
atomic_le_t<AudioPortState> state;
u32 channel;
u32 block;
u64 attr;
u64 tag;
u64 counter; // copy of global counter
u32 addr;
u32 read_index_addr;
u32 size;
float level;
float level_set;
float level_inc;
};
struct AudioConfig //custom structure
{
enum
{
AUDIO_PORT_COUNT = 8,
};
AudioPortConfig m_ports[AUDIO_PORT_COUNT];
u32 m_buffer; // 1 MB memory for audio ports
u32 m_indexes; // current block indexes and other info
bool m_is_audio_initialized;
bool m_is_audio_finalized;
u32 m_port_in_use;
std::mutex mutex;
atomic_le_t<AudioState> state;
thread_t audio_thread;
AudioPortConfig ports[AUDIO_PORT_COUNT];
u32 buffer; // 1 MB memory for audio ports
u32 indexes; // current block indexes and other info
u64 counter;
u64 start_time;
std::vector<u64> m_keys;
std::vector<u64> keys;
AudioConfig()
: m_is_audio_initialized(false)
, m_is_audio_finalized(false)
, m_port_in_use(0)
, counter(0)
AudioConfig() : audio_thread("Audio Thread")
{
memset(&m_ports, 0, sizeof(AudioPortConfig) * AUDIO_PORT_COUNT);
}
void Clear()
u32 open_port()
{
memset(&m_ports, 0, sizeof(AudioPortConfig) * AUDIO_PORT_COUNT);
m_port_in_use = 0;
for (u32 i = 0; i < AUDIO_PORT_COUNT; i++)
{
if (ports[i].state.compare_and_swap_test(AUDIO_PORT_STATE_CLOSED, AUDIO_PORT_STATE_OPENED))
{
return i;
}
}
return ~0;
}
};
extern AudioConfig m_config;
extern AudioConfig g_audio;

View File

@ -306,7 +306,7 @@ u32 dmuxOpen(Demuxer* dmux_ptr)
dmux.id = dmux_id;
dmux.dmuxCb = (PPUThread*)&Emu.GetCPU().AddThread(CPU_THREAD_PPU);
dmux.dmuxCb->SetName("Demuxer[" + std::to_string(dmux_id) + "] Callback");
dmux.dmuxCb->SetName(fmt::format("Demuxer[%d] Callback", dmux_id));
dmux.dmuxCb->SetEntry(0);
dmux.dmuxCb->SetPrio(1001);
dmux.dmuxCb->SetStackSize(0x10000);
@ -314,10 +314,9 @@ u32 dmuxOpen(Demuxer* dmux_ptr)
dmux.dmuxCb->InitRegs();
dmux.dmuxCb->DoRun();
thread t("Demuxer[" + std::to_string(dmux_id) + "] Thread", [dmux_ptr, sptr]()
thread_t t(fmt::format("Demuxer[%d] Thread", dmux_id), [dmux_ptr, sptr]()
{
Demuxer& dmux = *dmux_ptr;
cellDmux->Notice("Demuxer thread started (mem=0x%x, size=0x%x, cb_addr=0x%x, arg=0x%x)", dmux.memAddr, dmux.memSize, dmux.cbFunc.addr(), dmux.cbArg);
DemuxerTask task;
DemuxerStream stream = {};
@ -760,12 +759,8 @@ u32 dmuxOpen(Demuxer* dmux_ptr)
}
dmux.is_finished = true;
if (Emu.IsStopped()) cellDmux->Warning("Demuxer thread aborted");
if (dmux.is_closed) cellDmux->Notice("Demuxer thread ended");
});
t.detach();
return dmux_id;
}

View File

@ -123,7 +123,7 @@ s32 cellMsgDialogOpen2(u32 type, vm::ptr<const char> msgString, vm::ptr<CellMsgD
std::string msg = msgString.get_ptr();
thread t("MsgDialog thread", [type, msg, callback, userData, extParam]()
thread_t t("MsgDialog Thread", [type, msg, callback, userData, extParam]()
{
switch (type & CELL_MSGDIALOG_TYPE_SE_TYPE)
{
@ -186,7 +186,6 @@ s32 cellMsgDialogOpen2(u32 type, vm::ptr<const char> msgString, vm::ptr<CellMsgD
g_msg_dialog_state = msgDialogNone;
});
});
t.detach();
return CELL_OK;
}

View File

@ -390,7 +390,7 @@ int cellAudioOutGetSoundAvailability(u32 audioOut, u32 type, u32 fs, u32 option)
option = 0;
int available = 2; // should be at least 2
int available = 8; // should be at least 2
switch(fs)
{
@ -431,7 +431,7 @@ int cellAudioOutGetSoundAvailability2(u32 audioOut, u32 type, u32 fs, u32 ch, u3
option = 0;
int available = 2; // should be at least 2
int available = 8; // should be at least 2
switch(fs)
{
@ -578,9 +578,9 @@ int cellAudioOutGetDeviceInfo(u32 audioOut, u32 deviceIndex, vm::ptr<CellAudioOu
info->state = CELL_AUDIO_OUT_DEVICE_STATE_AVAILABLE;
info->latency = 1000;
info->availableModes[0].type = CELL_AUDIO_IN_CODING_TYPE_LPCM;
info->availableModes[0].channel = CELL_AUDIO_OUT_CHNUM_2;
info->availableModes[0].channel = CELL_AUDIO_OUT_CHNUM_8;
info->availableModes[0].fs = CELL_AUDIO_OUT_FS_48KHZ;
info->availableModes[0].layout = CELL_AUDIO_OUT_SPEAKER_LAYOUT_2CH;
info->availableModes[0].layout = CELL_AUDIO_OUT_SPEAKER_LAYOUT_8CH_LREClrxy;
return CELL_AUDIO_OUT_SUCCEEDED;
}

View File

@ -214,7 +214,7 @@ u32 vdecOpen(VideoDecoder* vdec_ptr)
vdec.id = vdec_id;
vdec.vdecCb = (PPUThread*)&Emu.GetCPU().AddThread(CPU_THREAD_PPU);
vdec.vdecCb->SetName("Video Decoder[" + std::to_string(vdec_id) + "] Callback");
vdec.vdecCb->SetName(fmt::format("VideoDecoder[%d] Callback", vdec_id));
vdec.vdecCb->SetEntry(0);
vdec.vdecCb->SetPrio(1001);
vdec.vdecCb->SetStackSize(0x10000);
@ -222,11 +222,9 @@ u32 vdecOpen(VideoDecoder* vdec_ptr)
vdec.vdecCb->InitRegs();
vdec.vdecCb->DoRun();
thread t("Video Decoder[" + std::to_string(vdec_id) + "] Thread", [vdec_ptr, sptr]()
thread_t t(fmt::format("VideoDecoder[%d] Thread", vdec_id), [vdec_ptr, sptr]()
{
VideoDecoder& vdec = *vdec_ptr;
cellVdec->Notice("Video Decoder thread started");
VdecTask& task = vdec.task;
while (true)
@ -431,7 +429,15 @@ u32 vdecOpen(VideoDecoder* vdec_ptr)
{
if (vdec.last_pts == -1)
{
vdec.last_pts = 0x8000; //av_frame_get_best_effort_timestamp(frame.data);
u64 ts = av_frame_get_best_effort_timestamp(frame.data);
if (ts != AV_NOPTS_VALUE)
{
vdec.last_pts = ts;
}
else
{
vdec.last_pts = 0;
}
}
else switch (vdec.frc_set)
{
@ -539,18 +545,14 @@ u32 vdecOpen(VideoDecoder* vdec_ptr)
default:
{
VDEC_ERROR("Video Decoder thread error: unknown task(%d)", task.type);
VDEC_ERROR("VideoDecoder thread error: unknown task(%d)", task.type);
}
}
}
vdec.is_finished = true;
if (Emu.IsStopped()) cellVdec->Warning("Video Decoder thread aborted");
if (vdec.is_closed) cellVdec->Notice("Video Decoder thread ended");
});
t.detach();
return vdec_id;
}

View File

@ -5,14 +5,12 @@
#include "Emu/SysCalls/CB_FUNC.h"
#include "Emu/CPU/CPUThreadManager.h"
#include "Emu/Audio/cellAudio.h"
#include "cellAudio.h"
#include "libmixer.h"
Module *libmixer = nullptr;
CellSurMixerConfig surMixer;
#define SUR_PORT (7)
SurMixerConfig g_surmx;
vm::ptr<CellSurMixerNotifyCallbackFunction> surMixerCb;
vm::ptr<void> surMixerCbArg;
std::mutex mixer_mutex;
@ -31,13 +29,13 @@ int cellAANAddData(u32 aan_handle, u32 aan_port, u32 offset, vm::ptr<float> addr
switch (type)
{
case CELL_SURMIXER_CHSTRIP_TYPE1A:
if (port >= surMixer.chStrips1) type = 0; break;
if (port >= g_surmx.ch_strips_1) type = 0; break;
case CELL_SURMIXER_CHSTRIP_TYPE2A:
if (port >= surMixer.chStrips2) type = 0; break;
if (port >= g_surmx.ch_strips_2) type = 0; break;
case CELL_SURMIXER_CHSTRIP_TYPE6A:
if (port >= surMixer.chStrips6) type = 0; break;
if (port >= g_surmx.ch_strips_6) type = 0; break;
case CELL_SURMIXER_CHSTRIP_TYPE8A:
if (port >= surMixer.chStrips8) type = 0; break;
if (port >= g_surmx.ch_strips_8) type = 0; break;
default:
type = 0; break;
}
@ -296,35 +294,37 @@ int cellSurMixerCreate(vm::ptr<const CellSurMixerConfig> config)
{
libmixer->Warning("cellSurMixerCreate(config_addr=0x%x)", config.addr());
surMixer = *config;
g_surmx.audio_port = g_audio.open_port();
AudioPortConfig& port = m_config.m_ports[SUR_PORT];
if (port.m_is_audio_port_opened)
if (!~g_surmx.audio_port)
{
return CELL_LIBMIXER_ERROR_FULL;
}
g_surmx.priority = config->priority;
g_surmx.ch_strips_1 = config->chStrips1;
g_surmx.ch_strips_2 = config->chStrips2;
g_surmx.ch_strips_6 = config->chStrips6;
g_surmx.ch_strips_8 = config->chStrips8;
AudioPortConfig& port = g_audio.ports[g_surmx.audio_port];
port.channel = 8;
port.block = 16;
port.attr = 0;
port.level = 1.0f;
port.tag = 0;
libmixer->Warning("*** audio port opened(default)");
port.m_is_audio_port_opened = true;
port.tag = 0;
m_config.m_port_in_use++;
libmixer->Warning("*** surMixer created (ch1=%d, ch2=%d, ch6=%d, ch8=%d)",
(u32)surMixer.chStrips1, (u32)surMixer.chStrips2, (u32)surMixer.chStrips6, (u32)surMixer.chStrips8);
mixcount = 0;
surMixerCb.set(0);
thread t("Surmixer Thread", []()
libmixer->Warning("*** surMixer created (ch1=%d, ch2=%d, ch6=%d, ch8=%d)", config->chStrips1, config->chStrips2, config->chStrips6, config->chStrips8);
thread_t t("Surmixer Thread", []()
{
AudioPortConfig& port = m_config.m_ports[SUR_PORT];
AudioPortConfig& port = g_audio.ports[g_surmx.audio_port];
PPUThread& cb_thread = *(PPUThread*)&Emu.GetCPU().AddThread(CPU_THREAD_PPU);
cb_thread.SetName("Surmixer Callback Thread");
@ -335,21 +335,15 @@ int cellSurMixerCreate(vm::ptr<const CellSurMixerConfig> config)
cb_thread.InitRegs();
cb_thread.DoRun();
while (port.m_is_audio_port_opened)
while (port.state.read_relaxed() != AUDIO_PORT_STATE_CLOSED && !Emu.IsStopped())
{
if (Emu.IsStopped())
{
libmixer->Warning("Surmixer aborted");
break;
}
if (mixcount > (port.tag + 0)) // adding positive value (1-15): preemptive buffer filling (hack)
{
std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack
continue;
}
if (port.m_is_audio_port_started)
if (port.state.read_relaxed() == AUDIO_PORT_STATE_STARTED)
{
//u64 stamp0 = get_system_time();
@ -440,7 +434,7 @@ int cellSurMixerCreate(vm::ptr<const CellSurMixerConfig> config)
//u64 stamp2 = get_system_time();
auto buf = vm::get_ptr<be_t<float>>(m_config.m_buffer + (128 * 1024 * SUR_PORT) + (mixcount % port.block) * port.channel * 256 * sizeof(float));
auto buf = vm::get_ptr<be_t<float>>(port.addr + (mixcount % port.block) * port.channel * AUDIO_SAMPLES * sizeof(float));
for (u32 i = 0; i < (sizeof(mixdata) / sizeof(float)); i++)
{
@ -464,7 +458,6 @@ int cellSurMixerCreate(vm::ptr<const CellSurMixerConfig> config)
Emu.GetCPU().RemoveThread(cb_thread.GetId());
surMixerCb.set(0);
});
t.detach();
return CELL_OK;
}
@ -515,13 +508,13 @@ int cellSurMixerStart()
{
libmixer->Warning("cellSurMixerStart()");
AudioPortConfig& port = m_config.m_ports[SUR_PORT];
if (port.m_is_audio_port_opened)
if (g_surmx.audio_port >= AUDIO_PORT_COUNT)
{
port.m_is_audio_port_started = true;
return CELL_LIBMIXER_ERROR_NOT_INITIALIZED;
}
g_audio.ports[g_surmx.audio_port].state.compare_and_swap(AUDIO_PORT_STATE_OPENED, AUDIO_PORT_STATE_STARTED);
return CELL_OK;
}
@ -535,19 +528,17 @@ int cellSurMixerFinalize()
{
libmixer->Warning("cellSurMixerFinalize()");
AudioPortConfig& port = m_config.m_ports[SUR_PORT];
if (port.m_is_audio_port_opened)
if (g_surmx.audio_port >= AUDIO_PORT_COUNT)
{
port.m_is_audio_port_started = false;
port.m_is_audio_port_opened = false;
m_config.m_port_in_use--;
return CELL_LIBMIXER_ERROR_NOT_INITIALIZED;
}
g_audio.ports[g_surmx.audio_port].state.compare_and_swap(AUDIO_PORT_STATE_OPENED, AUDIO_PORT_STATE_CLOSED);
return CELL_OK;
}
int cellSurMixerSurBusAddData(u32 busNo, u32 offset, u32 addr, u32 samples)
int cellSurMixerSurBusAddData(u32 busNo, u32 offset, vm::ptr<float> addr, u32 samples)
{
if (busNo < 8 && samples == 256 && offset == 0)
{
@ -564,8 +555,7 @@ int cellSurMixerSurBusAddData(u32 busNo, u32 offset, u32 addr, u32 samples)
for (u32 i = 0; i < samples; i++)
{
// reverse byte order and mix
u32 v = vm::read32(addr + i * sizeof(float));
mixdata[i*8+busNo] += (float&)v;
mixdata[i * 8 + busNo] += addr[i];
}
return CELL_OK;
@ -581,13 +571,13 @@ int cellSurMixerPause(u32 type)
{
libmixer->Warning("cellSurMixerPause(type=%d)", type);
AudioPortConfig& port = m_config.m_ports[SUR_PORT];
if (port.m_is_audio_port_opened)
if (g_surmx.audio_port >= AUDIO_PORT_COUNT)
{
port.m_is_audio_port_started = false;
return CELL_LIBMIXER_ERROR_NOT_INITIALIZED;
}
g_audio.ports[g_surmx.audio_port].state.compare_and_swap(AUDIO_PORT_STATE_STARTED, AUDIO_PORT_STATE_OPENED);
return CELL_OK;
}
@ -603,7 +593,7 @@ int cellSurMixerGetTimestamp(u64 tag, vm::ptr<u64> stamp)
{
libmixer->Log("cellSurMixerGetTimestamp(tag=0x%llx, stamp_addr=0x%x)", tag, stamp.addr());
*stamp = m_config.start_time + (tag) * 256000000 / 48000; // ???
*stamp = g_audio.start_time + (tag) * 256000000 / 48000; // ???
return CELL_OK;
}
@ -638,6 +628,8 @@ void libmixer_init(Module *pxThis)
{
libmixer = pxThis;
g_surmx.audio_port = ~0;
REG_SUB(libmixer, "surmxAAN", cellAANAddData,
0xffffffff7c691b78,
0xffffffff7c0802a6,

View File

@ -1,6 +1,7 @@
#pragma once
enum //libmixer Error Codes
// Error Codes
enum
{
CELL_LIBMIXER_ERROR_NOT_INITIALIZED = 0x80310002,
CELL_LIBMIXER_ERROR_INVALID_PARAMATER = 0x80310003,
@ -164,6 +165,16 @@ struct CellSurMixerChStripParam
be_t<s32> intVal;
};
struct SurMixerConfig
{
u32 audio_port;
s32 priority;
u32 ch_strips_1;
u32 ch_strips_2;
u32 ch_strips_6;
u32 ch_strips_8;
};
struct SSPlayer
{
bool m_created; // SSPlayerCreate/Remove

View File

@ -77,7 +77,7 @@ namespace detail
static __forceinline void func(PPUThread& CPU, const T& result)
{
CPU.GPR[3] = cast_ppu_gpr<T>::func(result);
CPU.GPR[3] = cast_to_ppu_gpr<T>(result);
}
};
@ -88,7 +88,7 @@ namespace detail
static __forceinline void func(PPUThread& CPU, const T& result)
{
CPU.FPR[1] = (double)result;
CPU.FPR[1] = result;
}
};

View File

@ -966,11 +966,7 @@ int cellFsAioRead(vm::ptr<CellFsAio> aio, vm::ptr<u32> id, vm::ptr<void(*)(vm::p
const u32 xid = g_FsAioReadID++;
*id = xid;
{
thread t("fsAioRead", std::bind(fsAioRead, fd, aio, xid, func));
t.detach();
}
thread_t t("CellFsAio Reading Thread", std::bind(fsAioRead, fd, aio, xid, func));
return CELL_OK;
}

View File

@ -1,6 +1,9 @@
#pragma once
#define MHZ (1000000)
enum : u32
{
MHZ = 1000000,
};
// Auxiliary functions
u64 get_time();

View File

@ -328,6 +328,8 @@ void Emulator::Pause()
if (InterlockedCompareExchange((volatile u32*)&m_status, Paused, Running) == Running)
{
SendDbgCommand(DID_PAUSED_EMU);
GetCallbackManager().RunPauseCallbacks(true);
}
}
@ -341,6 +343,8 @@ void Emulator::Resume()
CheckStatus();
SendDbgCommand(DID_RESUMED_EMU);
GetCallbackManager().RunPauseCallbacks(false);
}
void Emulator::Stop()
@ -350,17 +354,13 @@ void Emulator::Stop()
SendDbgCommand(DID_STOP_EMU);
m_status = Stopped;
u32 uncounted = 0;
while (true)
while (g_thread_count)
{
if (g_thread_count <= uncounted)
{
LOG_NOTICE(HLE, "All threads stopped...");
break;
}
std::this_thread::sleep_for(std::chrono::milliseconds(1));
}
LOG_NOTICE(HLE, "All threads stopped...");
m_rsx_callback = 0;
// TODO: check finalization order

View File

@ -187,9 +187,8 @@ namespace loader
LOG_ERROR(LOADER, "Unimplemented function 0x%08x (addr=0x%x)", nid, addr);
vm::psv::write16(addr + 0, 0xf870); // HACK instruction (Thumb)
vm::psv::write16(addr + 2, 0x0000); // index 0
vm::psv::write16(addr + 4, 0x4770); // BX LR
vm::psv::write16(addr + 6, 0); // null
vm::psv::write16(addr + 2, 0); // index 0 (unimplemented stub)
vm::psv::write32(addr + 4, nid); // nid
}
}
}

View File

@ -385,6 +385,7 @@
<ClInclude Include="Emu\SysCalls\Modules.h" />
<ClInclude Include="Emu\SysCalls\Modules\cellAdec.h" />
<ClInclude Include="Emu\SysCalls\Modules\cellAtrac.h" />
<ClInclude Include="Emu\SysCalls\Modules\cellAudio.h" />
<ClInclude Include="Emu\SysCalls\Modules\cellCamera.h" />
<ClInclude Include="Emu\SysCalls\Modules\cellDmux.h" />
<ClInclude Include="Emu\SysCalls\Modules\cellFiber.h" />

View File

@ -1279,5 +1279,8 @@
<ClInclude Include="Emu\Audio\XAudio2\XAudio2Thread.h">
<Filter>Emu\Audio\XAudio2</Filter>
</ClInclude>
<ClInclude Include="Emu\SysCalls\Modules\cellAudio.h">
<Filter>Emu\SysCalls\Modules</Filter>
</ClInclude>
</ItemGroup>
</Project>