Merge pull request #94 from Nekotekina/master

Different changes
This commit is contained in:
Alexandro Sánchez Bach 2014-03-08 00:20:43 +01:00
commit 2f65e84562
37 changed files with 2747 additions and 620 deletions

View File

@ -145,15 +145,19 @@ public:
{ {
if (!tid) if (!tid)
{ {
ConLog.Error("SMutexLockerBase: thread id == 0"); if (!Emu.IsStopped())
Emu.Pause(); {
ConLog.Error("SMutexLockerBase: thread id == 0");
Emu.Pause();
}
return;
} }
sm.lock(tid); sm.lock(tid);
} }
~SMutexLockerBase() ~SMutexLockerBase()
{ {
sm.unlock(tid); if (tid) sm.unlock(tid);
} }
}; };

View File

@ -19,11 +19,6 @@ public:
{ {
while (true) while (true)
{ {
if (Emu.IsStopped())
{
return false;
}
if (m_mutex.GetOwner() == m_mutex.GetDeadValue()) if (m_mutex.GetOwner() == m_mutex.GetDeadValue())
{ {
return false; return false;
@ -31,6 +26,10 @@ public:
if (m_count >= SQSize) if (m_count >= SQSize)
{ {
if (Emu.IsStopped())
{
return false;
}
Sleep(1); Sleep(1);
continue; continue;
} }
@ -51,11 +50,6 @@ public:
{ {
while (true) while (true)
{ {
if (Emu.IsStopped())
{
return false;
}
if (m_mutex.GetOwner() == m_mutex.GetDeadValue()) if (m_mutex.GetOwner() == m_mutex.GetDeadValue())
{ {
return false; return false;
@ -63,6 +57,10 @@ public:
if (!m_count) if (!m_count)
{ {
if (Emu.IsStopped())
{
return false;
}
Sleep(1); Sleep(1);
continue; continue;
} }
@ -96,4 +94,10 @@ public:
SMutexLocker lock(m_mutex); SMutexLocker lock(m_mutex);
m_count = 0; m_count = 0;
} }
T& Peek(u32 pos = 0)
{
SMutexLocker lock(m_mutex);
return m_data[(m_pos + pos) % SQSize];
}
}; };

View File

@ -108,7 +108,7 @@ struct CellAudioPortConfig
struct AudioPortConfig struct AudioPortConfig
{ {
SMutex m_mutex; SMutexGeneral m_mutex;
bool m_is_audio_port_opened; bool m_is_audio_port_opened;
bool m_is_audio_port_started; bool m_is_audio_port_started;
u8 channel; u8 channel;
@ -152,64 +152,6 @@ struct AudioConfig //custom structure
} }
} m_config; } m_config;
//libmixer datatypes
typedef void * CellAANHandle;
struct CellSSPlayerConfig
{
be_t<u32> channels;
be_t<u32> outputMode;
};
struct CellSSPlayerWaveParam
{
void *addr;
be_t<s32> format;
be_t<u32> samples;
be_t<u32> loopStartOffset;
be_t<u32> startOffset;
};
struct CellSSPlayerCommonParam
{
be_t<u32> loopMode;
be_t<u32> attackMode;
};
struct CellSurMixerPosition
{
be_t<float> x;
be_t<float> y;
be_t<float> z;
};
struct CellSSPlayerRuntimeInfo
{
be_t<float> level;
be_t<float> speed;
CellSurMixerPosition position;
};
struct CellSurMixerConfig
{
be_t<s32> priority;
be_t<u32> chStrips1;
be_t<u32> chStrips2;
be_t<u32> chStrips6;
be_t<u32> chStrips8;
};
struct CellSurMixerChStripParam
{
be_t<u32> param;
void *attribute;
be_t<s32> dBSwitch;
be_t<float> floatVal;
be_t<s32> intVal;
};
CellSSPlayerWaveParam current_SSPlayerWaveParam;
//libsnd3 datatypes //libsnd3 datatypes
struct CellSnd3DataCtx struct CellSnd3DataCtx
{ {

View File

@ -360,3 +360,44 @@ void CPUThread::Task()
if (Ini.HLELogging.GetValue()) ConLog.Write("%s leave", CPUThread::GetFName().wx_str()); if (Ini.HLELogging.GetValue()) ConLog.Write("%s leave", CPUThread::GetFName().wx_str());
} }
s64 CPUThread::ExecAsCallback(u64 pc, bool wait, u64 a1, u64 a2, u64 a3, u64 a4) // not multithread-safe
{
while (m_alive)
{
if (Emu.IsStopped())
{
ConLog.Warning("ExecAsCallback() aborted");
return CELL_ECANCELED; // doesn't mean anything
}
Sleep(1);
}
Stop();
Reset();
SetEntry(pc);
SetPrio(1001);
SetStackSize(0x10000);
SetExitStatus(CELL_OK);
SetArg(0, a1);
SetArg(1, a2);
SetArg(2, a3);
SetArg(3, a4);
Run();
Exec();
while (wait && m_alive)
{
if (Emu.IsStopped())
{
ConLog.Warning("ExecAsCallback() aborted");
return CELL_EABORT; // doesn't mean anything
}
Sleep(1);
}
return wait * m_exit_status;
}

View File

@ -57,7 +57,7 @@ protected:
u64 m_stack_size; u64 m_stack_size;
u64 m_stack_point; u64 m_stack_point;
u32 m_exit_status; u64 m_exit_status;
CPUDecoder* m_dec; CPUDecoder* m_dec;
@ -80,10 +80,10 @@ public:
void SetName(const std::string& name); void SetName(const std::string& name);
void SetPrio(const u64 prio) { m_prio = prio; } void SetPrio(const u64 prio) { m_prio = prio; }
void SetOffset(const u64 offset) { m_offset = offset; } void SetOffset(const u64 offset) { m_offset = offset; }
void SetExitStatus(const u32 status) { m_exit_status = status; } void SetExitStatus(const u64 status) { m_exit_status = status; }
u64 GetOffset() const { return m_offset; } u64 GetOffset() const { return m_offset; }
u32 GetExitStatus() const { return m_exit_status; } u64 GetExitStatus() const { return m_exit_status; }
u64 GetPrio() const { return m_prio; } u64 GetPrio() const { return m_prio; }
std::string GetName() const { return NamedThreadBase::GetThreadName(); } std::string GetName() const { return NamedThreadBase::GetThreadName(); }
@ -234,6 +234,8 @@ public:
return pc + 4; return pc + 4;
} }
s64 ExecAsCallback(u64 pc, bool wait, u64 a1 = 0, u64 a2 = 0, u64 a3 = 0, u64 a4 = 0);
protected: protected:
virtual void DoReset()=0; virtual void DoReset()=0;
virtual void DoRun()=0; virtual void DoRun()=0;

View File

@ -71,10 +71,16 @@ private:
if(Ini.HLELogging.GetValue()) if(Ini.HLELogging.GetValue())
{ {
ConLog.Warning("SysCall[%lld] done with code [0x%llx]! #pc: 0x%llx", CPU.GPR[11], CPU.GPR[3], CPU.PC); ConLog.Warning("SysCall[0x%llx] done with code [0x%llx]! #pc: 0x%llx", CPU.GPR[11], CPU.GPR[3], CPU.PC);
if(CPU.GPR[11] > 1024) if(CPU.GPR[11] > 1024)
SysCalls::DoFunc(CPU.GPR[11]); SysCalls::DoFunc(CPU.GPR[11]);
} }
/*else if ((s64)CPU.GPR[3] < 0) // probably, error code
{
ConLog.Error("SysCall[0x%llx] done with code [0x%llx]! #pc: 0x%llx", CPU.GPR[11], CPU.GPR[3], CPU.PC);
if(CPU.GPR[11] > 1024)
SysCalls::DoFunc(CPU.GPR[11]);
}*/
#ifdef HLE_CALL_DEBUG #ifdef HLE_CALL_DEBUG
ConLog.Write("SysCall[%lld] done with code [0x%llx]! #pc: 0x%llx", CPU.GPR[11], CPU.GPR[3], CPU.PC); ConLog.Write("SysCall[%lld] done with code [0x%llx]! #pc: 0x%llx", CPU.GPR[11], CPU.GPR[3], CPU.PC);
#endif #endif
@ -2088,6 +2094,14 @@ private:
{ {
case 0x1: UNK(wxString::Format("HyperCall %d", CPU.GPR[0])); break; case 0x1: UNK(wxString::Format("HyperCall %d", CPU.GPR[0])); break;
case 0x2: SysCall(); break; case 0x2: SysCall(); break;
case 0x3:
StaticExecute(CPU.GPR[11]);
if (Ini.HLELogging.GetValue())
{
ConLog.Write("'%s' done with code[0x%llx]! #pc: 0x%llx",
wxString(g_static_funcs_list[CPU.GPR[11]].name).wx_str(), CPU.GPR[3], CPU.PC);
}
break;
case 0x22: UNK("HyperCall LV1"); break; case 0x22: UNK("HyperCall LV1"); break;
default: UNK(wxString::Format("Unknown sc: %x", sc_code)); default: UNK(wxString::Format("Unknown sc: %x", sc_code));
} }

View File

@ -17,6 +17,7 @@ PPUThread& GetCurrentPPUThread()
PPUThread::PPUThread() : PPCThread(CPU_THREAD_PPU) PPUThread::PPUThread() : PPCThread(CPU_THREAD_PPU)
{ {
owned_mutexes = 0;
Reset(); Reset();
} }
@ -118,14 +119,11 @@ void PPUThread::InitRegs()
GPR[6] = m_args[3]; GPR[6] = m_args[3];
} }
u32 prx_mem = Memory.PRXMem.AllocAlign(0x10000);
Memory.Write64(prx_mem, 0xDEADBEEFABADCAFE);
GPR[0] = pc; GPR[0] = pc;
GPR[8] = entry; GPR[8] = entry;
GPR[11] = 0x80; GPR[11] = 0x80;
GPR[12] = Emu.GetMallocPageSize(); GPR[12] = Emu.GetMallocPageSize();
GPR[13] = prx_mem + 0x7060; GPR[13] = Memory.PRXMem.GetStartAddr() + 0x7060;
GPR[28] = GPR[4]; GPR[28] = GPR[4];
GPR[29] = GPR[3]; GPR[29] = GPR[3];
GPR[31] = GPR[5]; GPR[31] = GPR[5];

View File

@ -525,6 +525,9 @@ static const s32 MAX_INT_VALUE = 0x7fffffff;
class PPUThread : public PPCThread class PPUThread : public PPCThread
{ {
public:
std::atomic<u32> owned_mutexes;
public: public:
PPCdouble FPR[32]; //Floating Point Register PPCdouble FPR[32]; //Floating Point Register
FPSCRhdr FPSCR; //Floating Point Status and Control Register FPSCRhdr FPSCR; //Floating Point Status and Control Register

View File

@ -53,7 +53,7 @@ void Callback::Branch(bool wait)
{ {
m_has_data = false; m_has_data = false;
static SMutexGeneral cb_mutex; static std::mutex cb_mutex;
CPUThread& thr = Emu.GetCallbackThread(); CPUThread& thr = Emu.GetCallbackThread();
@ -69,7 +69,7 @@ again:
Sleep(1); Sleep(1);
} }
SMutexGeneralLocker lock(cb_mutex); std::lock_guard<std::mutex> lock(cb_mutex);
if (thr.IsAlive()) if (thr.IsAlive())
{ {

View File

@ -8,6 +8,7 @@ uint g_max_module_id = 0;
uint g_module_2_count = 0; uint g_module_2_count = 0;
ArrayF<ModuleFunc> g_modules_funcs_list; ArrayF<ModuleFunc> g_modules_funcs_list;
std::mutex g_funcs_lock; std::mutex g_funcs_lock;
ArrayF<SFunc> g_static_funcs_list;
struct ModuleInfo struct ModuleInfo
{ {

View File

@ -25,6 +25,21 @@ struct ModuleFunc
} }
}; };
struct SFuncOp
{
u32 crc;
u32 mask;
};
struct SFunc
{
func_caller* func;
char* name;
Array<SFuncOp> ops;
};
extern ArrayF<SFunc> g_static_funcs_list;
class Module class Module
{ {
std::string m_name; std::string m_name;
@ -94,6 +109,8 @@ public:
} }
template<typename T> __forceinline void AddFunc(u32 id, T func); template<typename T> __forceinline void AddFunc(u32 id, T func);
template<typename T> __forceinline void AddFuncSub(const u64 ops[], char* name, T func);
}; };
template<typename T> template<typename T>
@ -102,6 +119,29 @@ __forceinline void Module::AddFunc(u32 id, T func)
m_funcs_list.Move(new ModuleFunc(id, bind_func(func))); m_funcs_list.Move(new ModuleFunc(id, bind_func(func)));
} }
template<typename T>
__forceinline void Module::AddFuncSub(const u64 ops[], char* name, T func)
{
if (!ops[0]) return;
SFunc* sf = new SFunc;
sf->func = bind_func(func);
sf->name = name;
// TODO: check for self-inclusions, use CRC
for (u32 i = 0; ops[i]; i++)
{
SFuncOp op;
op.mask = ops[i] >> 32;
op.crc = ops[i] & op.mask;
op.mask = re(op.mask);
op.crc = re(op.crc);
sf->ops.AddCpy(op);
}
g_static_funcs_list.Add(sf);
}
bool IsLoadedFunc(u32 id); bool IsLoadedFunc(u32 id);
bool CallFunc(u32 num); bool CallFunc(u32 num);
bool UnloadFunc(u32 id); bool UnloadFunc(u32 id);

View File

@ -1,64 +1,586 @@
#include "stdafx.h" #include "stdafx.h"
#include "Emu/SysCalls/SysCalls.h" #include "Emu/SysCalls/SysCalls.h"
#include "Emu/SysCalls/SC_FUNC.h" #include "Emu/SysCalls/SC_FUNC.h"
#include "cellPamf.h"
extern SMutexGeneral g_mutex_avcodec_open2;
extern "C"
{
#include "libavcodec/avcodec.h"
#include "libavformat/avformat.h"
}
#include "cellAdec.h" #include "cellAdec.h"
void cellAdec_init(); void cellAdec_init();
Module cellAdec(0x0006, cellAdec_init); Module cellAdec(0x0006, cellAdec_init);
int adecRead(void* opaque, u8* buf, int buf_size)
{
AudioDecoder& adec = *(AudioDecoder*)opaque;
if (adec.reader.size < (u32)buf_size)
{
buf_size = adec.reader.size;
}
if (!buf_size)
{
return 0;
}
else if (!Memory.CopyToReal(buf, adec.reader.addr, buf_size))
{
ConLog.Error("adecRead: data reading failed (buf_size=0x%x)", buf_size);
Emu.Pause();
return 0;
}
else
{
adec.reader.addr += buf_size;
adec.reader.size -= buf_size;
return 0 + buf_size;
}
}
u32 adecOpen(AudioDecoder* data)
{
AudioDecoder& adec = *data;
adec.adecCb = &Emu.GetCPU().AddThread(CPU_THREAD_PPU);
u32 adec_id = cellAdec.GetNewId(data);
adec.id = adec_id;
adec.adecCb->SetName("Audio Decoder[" + std::to_string(adec_id) + "] Callback");
thread t("Audio Decoder[" + std::to_string(adec_id) + "] Thread", [&]()
{
ConLog.Write("Audio Decoder enter()");
AdecTask task;
while (true)
{
if (Emu.IsStopped())
{
break;
}
if (adec.job.IsEmpty() && adec.is_running)
{
Sleep(1);
continue;
}
/*if (adec.frames.GetCount() >= 50)
{
Sleep(1);
continue;
}*/
if (!adec.job.Pop(task))
{
break;
}
switch (task.type)
{
case adecStartSeq:
{
// TODO: reset data
ConLog.Warning("adecStartSeq:");
adec.reader.addr = 0;
adec.reader.size = 0;
adec.is_running = true;
adec.just_started = true;
}
break;
case adecEndSeq:
{
// TODO: finalize
ConLog.Warning("adecEndSeq:");
/*Callback cb;
cb.SetAddr(adec.cbFunc);
cb.Handle(adec.id, CELL_ADEC_MSG_TYPE_SEQDONE, CELL_OK, adec.cbArg);
cb.Branch(true); // ???*/
adec.adecCb->ExecAsCallback(adec.cbFunc, true, adec.id, CELL_ADEC_MSG_TYPE_SEQDONE, CELL_OK, adec.cbArg);
avcodec_close(adec.ctx);
avformat_close_input(&adec.fmt);
adec.is_running = false;
}
break;
case adecDecodeAu:
{
int err;
adec.reader.addr = task.au.addr;
adec.reader.size = task.au.size;
u64 last_pts = task.au.pts;
struct AVPacketHolder : AVPacket
{
AVPacketHolder(u32 size)
{
av_init_packet(this);
if (size)
{
data = (u8*)av_malloc(size + FF_INPUT_BUFFER_PADDING_SIZE);
memset(data + size, 0, FF_INPUT_BUFFER_PADDING_SIZE);
this->size = size + FF_INPUT_BUFFER_PADDING_SIZE;
}
else
{
data = NULL;
size = 0;
}
}
~AVPacketHolder()
{
av_free(data);
//av_free_packet(this);
}
} au(0);
/*{
wxFile dump;
dump.Open(wxString::Format("audio pts-0x%llx.dump", task.au.pts), wxFile::write);
u8* buf = (u8*)malloc(task.au.size);
if (Memory.CopyToReal(buf, task.au.addr, task.au.size)) dump.Write(buf, task.au.size);
free(buf);
dump.Close();
}
if (adec.just_started) // deferred initialization
{
err = avformat_open_input(&adec.fmt, NULL, NULL, NULL);
if (err)
{
ConLog.Error("adecDecodeAu: avformat_open_input() failed");
Emu.Pause();
break;
}
err = avformat_find_stream_info(adec.fmt, NULL);
if (err)
{
ConLog.Error("adecDecodeAu: avformat_find_stream_info() failed");
Emu.Pause();
break;
}
if (!adec.fmt->nb_streams)
{
ConLog.Error("adecDecodeAu: no stream found");
Emu.Pause();
break;
}
adec.ctx = adec.fmt->streams[0]->codec; // TODO: check data
AVCodec* codec = avcodec_find_decoder(adec.ctx->codec_id); // ???
if (!codec)
{
ConLog.Error("adecDecodeAu: avcodec_find_decoder() failed");
Emu.Pause();
break;
}
AVDictionary* opts;
av_dict_set(&opts, "refcounted_frames", "1", 0);
{
SMutexGeneralLocker lock(g_mutex_avcodec_open2);
// not multithread-safe
err = avcodec_open2(adec.ctx, codec, &opts);
}
if (err)
{
ConLog.Error("adecDecodeAu: avcodec_open2() failed");
Emu.Pause();
break;
}
adec.just_started = false;
}
while (av_read_frame(adec.fmt, &au) >= 0)*/ while (true)
{
if (!adec.ctx) // fake
{
AdecFrame frame;
frame.pts = task.au.pts;
frame.auAddr = task.au.addr;
frame.auSize = task.au.size;
frame.userdata = task.au.userdata;
frame.size = 4096;
frame.data = nullptr;
adec.frames.Push(frame);
/*Callback cb;
cb.SetAddr(adec.cbFunc);
cb.Handle(adec.id, CELL_ADEC_MSG_TYPE_PCMOUT, CELL_OK, adec.cbArg);
cb.Branch(false);*/
adec.adecCb->ExecAsCallback(adec.cbFunc, false, adec.id, CELL_ADEC_MSG_TYPE_PCMOUT, CELL_OK, adec.cbArg);
break;
}
struct VdecFrameHolder : AdecFrame
{
VdecFrameHolder()
{
data = av_frame_alloc();
}
~VdecFrameHolder()
{
if (data)
{
av_frame_unref(data);
av_frame_free(&data);
}
}
} frame;
if (!frame.data)
{
ConLog.Error("adecDecodeAu: av_frame_alloc() failed");
Emu.Pause();
break;
}
int got_frame = 0;
int decode = avcodec_decode_audio4(adec.ctx, frame.data, &got_frame, &au);
if (decode < 0)
{
ConLog.Error("adecDecodeAu: AU decoding error(0x%x)", decode);
break;
}
if (got_frame)
{
ConLog.Write("got_frame (%d, vdec: pts=0x%llx, dts=0x%llx)", got_frame, au.pts, au.dts);
frame.pts = task.au.pts; // ???
frame.auAddr = task.au.addr;
frame.auSize = task.au.size;
frame.userdata = task.au.userdata;
frame.size = 32768; // ????
adec.frames.Push(frame);
frame.data = nullptr; // to prevent destruction
/*Callback cb;
cb.SetAddr(adec.cbFunc);
cb.Handle(adec.id, CELL_ADEC_MSG_TYPE_PCMOUT, CELL_OK, adec.cbArg);
cb.Branch(false);*/
adec.adecCb->ExecAsCallback(adec.cbFunc, false, adec.id, CELL_ADEC_MSG_TYPE_PCMOUT, CELL_OK, adec.cbArg);
}
}
/*Callback cb;
cb.SetAddr(adec.cbFunc);
cb.Handle(adec.id, CELL_ADEC_MSG_TYPE_AUDONE, task.au.auInfo_addr, adec.cbArg);
cb.Branch(false);*/
adec.adecCb->ExecAsCallback(adec.cbFunc, false, adec.id, CELL_ADEC_MSG_TYPE_AUDONE, task.au.auInfo_addr, adec.cbArg);
}
break;
case adecClose:
{
adec.is_finished = true;
ConLog.Write("Audio Decoder exit");
return;
}
default:
ConLog.Error("Audio Decoder error: unknown task(%d)", task.type);
}
}
adec.is_finished = true;
ConLog.Warning("Audio Decoder aborted");
});
t.detach();
return adec_id;
}
bool adecCheckType(AudioCodecType type)
{
switch (type)
{
case CELL_ADEC_TYPE_ATRACX: ConLog.Write("*** (???) type: ATRAC3plus"); break;
case CELL_ADEC_TYPE_ATRACX_2CH: ConLog.Write("*** type: ATRAC3plus 2ch"); break;
case CELL_ADEC_TYPE_ATRACX_6CH:
case CELL_ADEC_TYPE_ATRACX_8CH:
case CELL_ADEC_TYPE_LPCM_PAMF:
case CELL_ADEC_TYPE_AC3:
case CELL_ADEC_TYPE_MP3:
case CELL_ADEC_TYPE_ATRAC3:
case CELL_ADEC_TYPE_MPEG_L2:
case CELL_ADEC_TYPE_CELP:
case CELL_ADEC_TYPE_M4AAC:
case CELL_ADEC_TYPE_CELP8:
cellAdec.Error("Unimplemented audio codec type (%d)", type);
break;
default:
return false;
}
return true;
}
int cellAdecQueryAttr(mem_ptr_t<CellAdecType> type, mem_ptr_t<CellAdecAttr> attr) int cellAdecQueryAttr(mem_ptr_t<CellAdecType> type, mem_ptr_t<CellAdecAttr> attr)
{ {
cellAdec.Error("cellAdecQueryAttr(type_addr=0x%x, attr_addr=0x%x)", type.GetAddr(), attr.GetAddr()); cellAdec.Warning("cellAdecQueryAttr(type_addr=0x%x, attr_addr=0x%x)", type.GetAddr(), attr.GetAddr());
if (!type.IsGood() || !attr.IsGood())
{
return CELL_ADEC_ERROR_FATAL;
}
if (!adecCheckType(type->audioCodecType)) return CELL_ADEC_ERROR_ARG;
// TODO: check values
attr->adecVerLower = 0x280000; // from dmux
attr->adecVerUpper = 0x260000;
attr->workMemSize = 4 * 1024 * 1024;
return CELL_OK; return CELL_OK;
} }
int cellAdecOpen(mem_ptr_t<CellAdecType> type, mem_ptr_t<CellAdecResource> res, mem_ptr_t<CellAdecCb> cb, mem32_t handle) int cellAdecOpen(mem_ptr_t<CellAdecType> type, mem_ptr_t<CellAdecResource> res, mem_ptr_t<CellAdecCb> cb, mem32_t handle)
{ {
cellAdec.Error("cellAdecOpen(type_addr=0x%x, res_addr=0x%x, cb_addr=0x%x, handle_addr=0x%x)", cellAdec.Warning("cellAdecOpen(type_addr=0x%x, res_addr=0x%x, cb_addr=0x%x, handle_addr=0x%x)",
type.GetAddr(), res.GetAddr(), cb.GetAddr(), handle.GetAddr()); type.GetAddr(), res.GetAddr(), cb.GetAddr(), handle.GetAddr());
if (!type.IsGood() || !res.IsGood() || !cb.IsGood() || !handle.IsGood())
{
return CELL_ADEC_ERROR_FATAL;
}
if (!adecCheckType(type->audioCodecType)) return CELL_ADEC_ERROR_ARG;
handle = adecOpen(new AudioDecoder(type->audioCodecType, res->startAddr, res->totalMemSize, cb->cbFunc, cb->cbArg));
return CELL_OK; return CELL_OK;
} }
int cellAdecOpenEx(mem_ptr_t<CellAdecType> type, mem_ptr_t<CellAdecResourceEx> res, mem_ptr_t<CellAdecCb> cb, mem32_t handle) int cellAdecOpenEx(mem_ptr_t<CellAdecType> type, mem_ptr_t<CellAdecResourceEx> res, mem_ptr_t<CellAdecCb> cb, mem32_t handle)
{ {
cellAdec.Error("cellAdecOpenEx(type_addr=0x%x, res_addr=0x%x, cb_addr=0x%x, handle_addr=0x%x)", cellAdec.Warning("cellAdecOpenEx(type_addr=0x%x, res_addr=0x%x, cb_addr=0x%x, handle_addr=0x%x)",
type.GetAddr(), res.GetAddr(), cb.GetAddr(), handle.GetAddr()); type.GetAddr(), res.GetAddr(), cb.GetAddr(), handle.GetAddr());
if (!type.IsGood() || !res.IsGood() || !cb.IsGood() || !handle.IsGood())
{
return CELL_ADEC_ERROR_FATAL;
}
if (!adecCheckType(type->audioCodecType)) return CELL_ADEC_ERROR_ARG;
handle = adecOpen(new AudioDecoder(type->audioCodecType, res->startAddr, res->totalMemSize, cb->cbFunc, cb->cbArg));
return CELL_OK; return CELL_OK;
} }
int cellAdecClose(u32 handle) int cellAdecClose(u32 handle)
{ {
cellAdec.Error("cellAdecClose(handle=0x%x)", handle); cellAdec.Warning("cellAdecClose(handle=%d)", handle);
AudioDecoder* adec;
if (!Emu.GetIdManager().GetIDData(handle, adec))
{
return CELL_ADEC_ERROR_ARG;
}
adec->job.Push(AdecTask(adecClose));
while (!adec->is_finished || !adec->frames.IsEmpty())
{
if (Emu.IsStopped())
{
ConLog.Warning("cellAdecClose(%d) aborted", handle);
break;
}
Sleep(1);
}
if (adec->adecCb) Emu.GetCPU().RemoveThread(adec->adecCb->GetId());
Emu.GetIdManager().RemoveID(handle);
return CELL_OK; return CELL_OK;
} }
int cellAdecStartSeq(u32 handle, u32 param_addr) int cellAdecStartSeq(u32 handle, u32 param_addr)
{ {
cellAdec.Error("cellAdecStartSeq(handle=0x%x, param_addr=0x%x)", handle, param_addr); cellAdec.Log("cellAdecStartSeq(handle=%d, param_addr=0x%x)", handle, param_addr);
AudioDecoder* adec;
if (!Emu.GetIdManager().GetIDData(handle, adec))
{
return CELL_ADEC_ERROR_ARG;
}
AdecTask task(adecStartSeq);
/*if (adec->type == CELL_ADEC_TYPE_ATRACX_2CH)
{
}
else*/
{
cellAdec.Warning("cellAdecStartSeq: (TODO) initialization");
}
adec->job.Push(task);
return CELL_OK; return CELL_OK;
} }
int cellAdecEndSeq(u32 handle) int cellAdecEndSeq(u32 handle)
{ {
cellAdec.Error("cellAdecEndSeq(handle=0x%x)", handle); cellAdec.Warning("cellAdecEndSeq(handle=%d)", handle);
AudioDecoder* adec;
if (!Emu.GetIdManager().GetIDData(handle, adec))
{
return CELL_ADEC_ERROR_ARG;
}
adec->job.Push(AdecTask(adecEndSeq));
return CELL_OK; return CELL_OK;
} }
int cellAdecDecodeAu(u32 handle, mem_ptr_t<CellAdecAuInfo> auInfo) int cellAdecDecodeAu(u32 handle, mem_ptr_t<CellAdecAuInfo> auInfo)
{ {
cellAdec.Error("cellAdecDecodeAu(handle=0x%x, auInfo_addr=0x%x)", handle, auInfo.GetAddr()); cellAdec.Log("cellAdecDecodeAu(handle=%d, auInfo_addr=0x%x)", handle, auInfo.GetAddr());
AudioDecoder* adec;
if (!Emu.GetIdManager().GetIDData(handle, adec))
{
return CELL_ADEC_ERROR_ARG;
}
if (!auInfo.IsGood())
{
return CELL_ADEC_ERROR_FATAL;
}
AdecTask task(adecDecodeAu);
task.au.auInfo_addr = auInfo.GetAddr();
task.au.addr = auInfo->startAddr;
task.au.size = auInfo->size;
task.au.pts = ((u64)auInfo->pts.upper << 32) | (u64)auInfo->pts.lower;
task.au.userdata = auInfo->userData;
adec->job.Push(task);
return CELL_OK; return CELL_OK;
} }
int cellAdecGetPcm(u32 handle, u32 outBuffer_addr) int cellAdecGetPcm(u32 handle, u32 outBuffer_addr)
{ {
cellAdec.Error("cellAdecGetPcm(handle=0x%x, outBuffer_addr=0x%x)", handle, outBuffer_addr); cellAdec.Log("cellAdecGetPcm(handle=%d, outBuffer_addr=0x%x)", handle, outBuffer_addr);
return CELL_OK;
AudioDecoder* adec;
if (!Emu.GetIdManager().GetIDData(handle, adec))
{
return CELL_ADEC_ERROR_ARG;
}
if (adec->frames.IsEmpty())
{
return CELL_ADEC_ERROR_EMPTY;
}
AdecFrame af;
adec->frames.Pop(af);
//AVFrame& frame = *af.data;
int result = CELL_OK;
if (!Memory.IsGoodAddr(outBuffer_addr, af.size))
{
result = CELL_ADEC_ERROR_FATAL;
}
else
{
// copy data
if (!af.data) // fake: empty data
{
u8* buf = (u8*)malloc(4096);
memset(buf, 0, 4096);
Memory.CopyFromReal(outBuffer_addr, buf, 4096);
free(buf);
return CELL_OK;
}
}
if (af.data)
{
av_frame_unref(af.data);
av_frame_free(&af.data);
}
return result;
} }
int cellAdecGetPcmItem(u32 handle, u32 pcmItem_ptr_addr) int cellAdecGetPcmItem(u32 handle, mem32_t pcmItem_ptr)
{ {
cellAdec.Error("cellAdecGetPcmItem(handle=0x%x, pcmItem_ptr_addr=0x%x)", handle, pcmItem_ptr_addr); cellAdec.Log("cellAdecGetPcmItem(handle=%d, pcmItem_ptr_addr=0x%x)", handle, pcmItem_ptr.GetAddr());
AudioDecoder* adec;
if (!Emu.GetIdManager().GetIDData(handle, adec))
{
return CELL_ADEC_ERROR_ARG;
}
if (!pcmItem_ptr.IsGood())
{
return CELL_ADEC_ERROR_FATAL;
}
AdecFrame& af = adec->frames.Peek();
if (adec->frames.IsEmpty())
{
return CELL_ADEC_ERROR_EMPTY;
}
//AVFrame& frame = *af.data;
mem_ptr_t<CellAdecPcmItem> pcm(adec->memAddr + adec->memBias);
adec->memBias += 512;
if (adec->memBias + 512 > adec->memSize)
{
adec->memBias = 0;
}
pcm->pcmHandle = 0; // ???
pcm->pcmAttr.bsiInfo_addr = pcm.GetAddr() + sizeof(CellAdecPcmItem);
pcm->startAddr = 0x00000312; // invalid address (no output)
pcm->size = af.size;
pcm->status = CELL_OK;
pcm->auInfo.pts.lower = af.pts; // ???
pcm->auInfo.pts.upper = af.pts >> 32;
pcm->auInfo.size = af.auSize;
pcm->auInfo.startAddr = af.auAddr;
pcm->auInfo.userData = af.userdata;
mem_ptr_t<CellAdecAtracXInfo> atx(pcm.GetAddr() + sizeof(CellAdecPcmItem));
atx->samplingFreq = 48000; // ???
atx->nbytes = 2048; // ???
atx->channelConfigIndex = CELL_ADEC_CH_STEREO; // ???
pcmItem_ptr = pcm.GetAddr();
return CELL_OK; return CELL_OK;
} }
@ -73,4 +595,7 @@ void cellAdec_init()
cellAdec.AddFunc(0x1529e506, cellAdecDecodeAu); cellAdec.AddFunc(0x1529e506, cellAdecDecodeAu);
cellAdec.AddFunc(0x97ff2af1, cellAdecGetPcm); cellAdec.AddFunc(0x97ff2af1, cellAdecGetPcm);
cellAdec.AddFunc(0xbd75f78b, cellAdecGetPcmItem); cellAdec.AddFunc(0xbd75f78b, cellAdecGetPcmItem);
av_register_all();
avcodec_register_all();
} }

View File

@ -1,5 +1,6 @@
#pragma once #pragma once
#include "cellPamf.h"
#include "Utilities/SQueue.h"
// Error Codes // Error Codes
enum enum
@ -341,6 +342,17 @@ struct CellAdecResource
be_t<u32> ppuThreadStackSize; be_t<u32> ppuThreadStackSize;
}; };
struct CellAdecResourceEx
{
be_t<u32> totalMemSize;
be_t<u32> startAddr;
be_t<u32> ppuThreadPriority;
be_t<u32> ppuThreadStackSize;
be_t<u32> spurs_addr;
u8 priority[8];
be_t<u32> maxContention;
};
// Callback Messages // Callback Messages
enum CellAdecMsgType enum CellAdecMsgType
{ {
@ -348,12 +360,14 @@ enum CellAdecMsgType
CELL_ADEC_MSG_TYPE_PCMOUT, CELL_ADEC_MSG_TYPE_PCMOUT,
CELL_ADEC_MSG_TYPE_ERROR, CELL_ADEC_MSG_TYPE_ERROR,
CELL_ADEC_MSG_TYPE_SEQDONE, CELL_ADEC_MSG_TYPE_SEQDONE,
}; };
typedef mem_func_ptr_t<int (*)(u32 handle, CellAdecMsgType msgType, int msgData, u32 cbArg)> CellAdecCbMsg;
struct CellAdecCb struct CellAdecCb
{ {
be_t<mem_func_ptr_t<int (*)(u32 handle, CellAdecMsgType msgType, int msgData, u32 cbArg_addr)>> cbFunc; be_t<u32> cbFunc;
be_t<u32> cbArg_addr; be_t<u32> cbArg;
}; };
typedef CellCodecTimeStamp CellAdecTimeStamp; typedef CellCodecTimeStamp CellAdecTimeStamp;
@ -399,17 +413,6 @@ struct CellAdecLpcmInfo
be_t<u32> outputDataSize; be_t<u32> outputDataSize;
}; };
struct CellAdecResourceEx
{
be_t<u32> totalMemSize;
be_t<u32> startAddr;
be_t<u32> ppuThreadPriority;
be_t<u32> ppuThreadStackSize;
be_t<u32> spurs_addr;
u8 priority[8];
be_t<u32> maxContention;
};
// CELP Excitation Mode // CELP Excitation Mode
enum CELP_ExcitationMode enum CELP_ExcitationMode
{ {
@ -985,3 +988,143 @@ struct CellAdecMpmcInfo
be_t<u32> lfePresent; be_t<u32> lfePresent;
be_t<u32> channelCoufiguration; be_t<u32> channelCoufiguration;
}; };
/* Audio Decoder Thread Classes */
enum AdecJobType : u32
{
adecStartSeq,
adecEndSeq,
adecDecodeAu,
adecClose,
};
struct AdecTask
{
AdecJobType type;
union
{
struct
{
u32 auInfo_addr;
u32 addr;
u32 size;
u64 pts;
u64 userdata;
} au;
};
AdecTask(AdecJobType type)
: type(type)
{
}
AdecTask()
{
}
};
struct AdecFrame
{
AVFrame* data;
u64 pts;
u64 userdata;
u32 auAddr;
u32 auSize;
u32 size;
};
int adecRead(void* opaque, u8* buf, int buf_size);
class AudioDecoder
{
public:
SQueue<AdecTask> job;
u32 id;
volatile bool is_running;
volatile bool is_finished;
bool just_started;
AVCodecContext* ctx;
AVFormatContext* fmt;
u8* io_buf;
struct AudioReader
{
u32 addr;
u32 size;
} reader;
SQueue<AdecFrame> frames;
const AudioCodecType type;
const u32 memAddr;
const u32 memSize;
const u32 cbFunc;
const u32 cbArg;
u32 memBias;
CPUThread* adecCb;
AudioDecoder(AudioCodecType type, u32 addr, u32 size, u32 func, u32 arg)
: type(type)
, memAddr(addr)
, memSize(size)
, memBias(0)
, cbFunc(func)
, cbArg(arg)
, adecCb(nullptr)
, is_running(false)
, is_finished(false)
, just_started(false)
, ctx(nullptr)
, fmt(nullptr)
{
AVCodec* codec = avcodec_find_decoder(AV_CODEC_ID_ATRAC3P);
if (!codec)
{
ConLog.Error("AudioDecoder(): avcodec_find_decoder(ATRAC3P) failed");
Emu.Pause();
return;
}
fmt = avformat_alloc_context();
if (!fmt)
{
ConLog.Error("AudioDecoder(): avformat_alloc_context failed");
Emu.Pause();
return;
}
io_buf = (u8*)av_malloc(4096);
fmt->pb = avio_alloc_context(io_buf, 4096, 0, this, adecRead, NULL, NULL);
if (!fmt->pb)
{
ConLog.Error("AudioDecoder(): avio_alloc_context failed");
Emu.Pause();
return;
}
}
~AudioDecoder()
{
if (ctx)
{
for (u32 i = frames.GetCount() - 1; ~i; i--)
{
AdecFrame& af = frames.Peek(i);
av_frame_unref(af.data);
av_frame_free(&af.data);
}
avcodec_close(ctx);
avformat_close_input(&fmt);
}
if (fmt)
{
if (io_buf)
{
av_free(io_buf);
}
if (fmt->pb) av_free(fmt->pb);
avformat_free_context(fmt);
}
}
};

View File

@ -6,9 +6,8 @@
#include "Emu/Audio/AudioDumper.h" #include "Emu/Audio/AudioDumper.h"
void cellAudio_init(); void cellAudio_init();
void cellAudio_load();
void cellAudio_unload(); void cellAudio_unload();
Module cellAudio(0x0011, cellAudio_init, cellAudio_load, cellAudio_unload); Module cellAudio(0x0011, cellAudio_init, nullptr, cellAudio_unload);
extern u64 get_system_time(); extern u64 get_system_time();
@ -107,7 +106,7 @@ int cellAudioInit()
memset(Memory + buf_addr, 0, block_size * sizeof(float)); memset(Memory + buf_addr, 0, block_size * sizeof(float));
{ {
SMutexLocker lock(port.m_mutex); SMutexGeneralLocker lock(port.m_mutex);
port.counter = m_config.counter; port.counter = m_config.counter;
port.tag++; // absolute index of block that will be read port.tag++; // absolute index of block that will be read
index = (position + 1) % port.block; // write new value index = (position + 1) % port.block; // write new value
@ -371,7 +370,7 @@ int cellAudioGetPortTimestamp(u32 portNum, u64 tag, mem64_t stamp)
AudioPortConfig& port = m_config.m_ports[portNum]; AudioPortConfig& port = m_config.m_ports[portNum];
SMutexLocker lock(port.m_mutex); SMutexGeneralLocker lock(port.m_mutex);
stamp = m_config.start_time + (port.counter + (tag - port.tag)) * 256000000 / 48000; stamp = m_config.start_time + (port.counter + (tag - port.tag)) * 256000000 / 48000;
@ -405,7 +404,7 @@ int cellAudioGetPortBlockTag(u32 portNum, u64 blockNo, mem64_t tag)
return CELL_AUDIO_ERROR_PARAM; return CELL_AUDIO_ERROR_PARAM;
} }
SMutexLocker lock(port.m_mutex); SMutexGeneralLocker lock(port.m_mutex);
u64 tag_base = port.tag; u64 tag_base = port.tag;
if (tag_base % port.block > blockNo) if (tag_base % port.block > blockNo)
@ -546,168 +545,6 @@ int cellAudioUnsetPersonalDevice(int iPersonalStream)
return CELL_OK; return CELL_OK;
} }
//Callback Functions
typedef int (*CellSurMixerNotifyCallbackFunction)(void *arg, u32 counter, u32 samples); //Currently unused.
// libmixer Functions, NOT active in this moment
int cellAANConnect(CellAANHandle receive, u32 receivePortNo, CellAANHandle source, u32 sourcePortNo)
{
UNIMPLEMENTED_FUNC(cellAudio);
return 0;
}
int cellAANDisconnect(CellAANHandle receive, u32 receivePortNo, CellAANHandle source, u32 sourcePortNo)
{
UNIMPLEMENTED_FUNC(cellAudio);
return 0;
}
int cellAANAddData(CellAANHandle handle, u32 port, u32 offset, float *addr, u32 samples)
{
UNIMPLEMENTED_FUNC(cellAudio);
return 0;
}
int cellSSPlayerCreate(CellAANHandle *handle, CellSSPlayerConfig *config)
{
UNIMPLEMENTED_FUNC(cellAudio);
return 0;
}
int cellSSPlayerRemove(CellAANHandle handle)
{
UNIMPLEMENTED_FUNC(cellAudio);
return 0;
}
int cellSSPlayerSetWave() //CellAANHandle handle, CellSSPlayerWaveParam *waveInfo, CellSSPlayerCommonParam *commonInfo //mem_class_t waveInfo
{
UNIMPLEMENTED_FUNC(cellAudio);
return 0;
}
int cellSSPlayerPlay() //CellAANHandle handle, CellSSPlayerRuntimeInfo *info
{
UNIMPLEMENTED_FUNC(cellAudio);
return 0;
}
int cellSSPlayerStop() //CellAANHandle handle, u32 mode
{
UNIMPLEMENTED_FUNC(cellAudio);
return 0;
}
int cellSSPlayerSetParam() //CellAANHandle handle, CellSSPlayerRuntimeInfo *info
{
UNIMPLEMENTED_FUNC(cellAudio);
return 0;
}
s32 cellSSPlayerGetState() //CellAANHandle handle
{
UNIMPLEMENTED_FUNC(cellAudio);
return 0;
}
int cellSurMixerCreate() //const CellSurMixerConfig *config
{
UNIMPLEMENTED_FUNC(cellAudio);
return 0;
}
int cellSurMixerGetAANHandle() //CellAANHandle *handle
{
UNIMPLEMENTED_FUNC(cellAudio);
return 0;
}
int cellSurMixerChStripGetAANPortNo() //u32 *port, u32 type, u32 index
{
UNIMPLEMENTED_FUNC(cellAudio);
return 0;
}
int cellSurMixerSetNotifyCallback() //CellSurMixerNotifyCallbackFunction callback, void *arg
{
UNIMPLEMENTED_FUNC(cellAudio);
return 0;
}
int cellSurMixerRemoveNotifyCallback() //CellSurMixerNotifyCallbackFunction callback
{
UNIMPLEMENTED_FUNC(cellAudio);
return 0;
}
int cellSurMixerStart()
{
UNIMPLEMENTED_FUNC(cellAudio);
return 0;
}
int cellSurMixerSurBusAddData() //u32 busNo, u32 offset, float *addr, u32 samples
{
UNIMPLEMENTED_FUNC(cellAudio);
return 0;
}
int cellSurMixerSetParameter() //u32 param, float value
{
UNIMPLEMENTED_FUNC(cellAudio);
return 0;
}
int cellSurMixerChStripSetParameter() //u32 type, u32 index, CellSurMixerChStripParam *param
{
UNIMPLEMENTED_FUNC(cellAudio);
return 0;
}
int cellSurMixerPause() //u32 switch
{
UNIMPLEMENTED_FUNC(cellAudio);
return 0;
}
int cellSurMixerGetCurrentBlockTag() //u64 *tag
{
UNIMPLEMENTED_FUNC(cellAudio);
return 0;
}
int cellSurMixerGetTimestamp() //u64 tag, u64 *stamp
{
UNIMPLEMENTED_FUNC(cellAudio);
return 0;
}
void cellSurMixerBeep(); //void *arg
float cellSurMixerUtilGetLevelFromDB() //float dB
{
UNIMPLEMENTED_FUNC(cellAudio);
return CELL_OK; //it's NOT real value
//TODO;
}
float cellSurMixerUtilGetLevelFromDBIndex() //int index
{
UNIMPLEMENTED_FUNC(cellAudio);
return CELL_OK; //it's NOT real value
//TODO;
}
float cellSurMixerUtilNoteToRatio() //unsigned char refNote, unsigned char note
{
UNIMPLEMENTED_FUNC(cellAudio);
return CELL_OK; //it's NOT real value
//TODO
}
int cellSurMixerFinalize(); //Currently unused. Returns 0 (in the current release).
//*libsnd3 Functions, NOT active in this moment //*libsnd3 Functions, NOT active in this moment
s32 cellSnd3Init() //u32 maxVoice, u32 samples, CellSnd3RequestQueueCtx *queue s32 cellSnd3Init() //u32 maxVoice, u32 samples, CellSnd3RequestQueueCtx *queue
{ {
@ -1149,14 +986,7 @@ void cellAudio_init()
//TODO: Find addresses for libmixer, libsnd3 and libsynth2 functions //TODO: Find addresses for libmixer, libsnd3 and libsynth2 functions
} }
void cellAudio_load()
{
m_config.m_is_audio_initialized = false;
m_config.Clear();
}
void cellAudio_unload() void cellAudio_unload()
{ {
m_config.m_is_audio_initialized = false; //StaticFinalize();
m_config.Clear();
} }

View File

@ -18,9 +18,9 @@ void dmuxQueryEsAttr(u32 info_addr /* may be 0 */, const mem_ptr_t<CellCodecEsFi
const u32 esSpecificInfo_addr, mem_ptr_t<CellDmuxEsAttr> attr) const u32 esSpecificInfo_addr, mem_ptr_t<CellDmuxEsAttr> attr)
{ {
if (esFilterId->filterIdMajor >= 0xe0) if (esFilterId->filterIdMajor >= 0xe0)
attr->memSize = 0x600000; // 0x45fa49 from ps3 attr->memSize = 0x1000000; // 0x45fa49 from ps3
else else
attr->memSize = 0x10000; // 0x73d9 from ps3 attr->memSize = 0x200000; // 0x73d9 from ps3
cellDmux.Warning("*** filter(0x%x, 0x%x, 0x%x, 0x%x)", (u32)esFilterId->filterIdMajor, (u32)esFilterId->filterIdMinor, cellDmux.Warning("*** filter(0x%x, 0x%x, 0x%x, 0x%x)", (u32)esFilterId->filterIdMajor, (u32)esFilterId->filterIdMinor,
(u32)esFilterId->supplementalInfo1, (u32)esFilterId->supplementalInfo2); (u32)esFilterId->supplementalInfo1, (u32)esFilterId->supplementalInfo2);
@ -30,10 +30,14 @@ u32 dmuxOpen(Demuxer* data)
{ {
Demuxer& dmux = *data; Demuxer& dmux = *data;
dmux.dmuxCb = &Emu.GetCPU().AddThread(CPU_THREAD_PPU);
u32 dmux_id = cellDmux.GetNewId(data); u32 dmux_id = cellDmux.GetNewId(data);
dmux.id = dmux_id; dmux.id = dmux_id;
dmux.dmuxCb->SetName("Demuxer[" + std::to_string(dmux_id) + "] Callback");
thread t("Demuxer[" + std::to_string(dmux_id) + "] Thread", [&]() thread t("Demuxer[" + std::to_string(dmux_id) + "] Thread", [&]()
{ {
ConLog.Write("Demuxer enter (mem=0x%x, size=0x%x, cb=0x%x, arg=0x%x)", dmux.memAddr, dmux.memSize, dmux.cbFunc, dmux.cbArg); ConLog.Write("Demuxer enter (mem=0x%x, size=0x%x, cb=0x%x, arg=0x%x)", dmux.memAddr, dmux.memSize, dmux.cbFunc, dmux.cbArg);
@ -50,6 +54,9 @@ u32 dmuxOpen(Demuxer* data)
u32 cb_add = 0; u32 cb_add = 0;
u32 updates_count = 0;
u32 updates_signaled = 0;
while (true) while (true)
{ {
if (Emu.IsStopped()) if (Emu.IsStopped())
@ -66,9 +73,17 @@ u32 dmuxOpen(Demuxer* data)
if (!stream.peek(code)) if (!stream.peek(code))
{ {
dmux.is_running = false;
// demuxing finished // demuxing finished
task.type = dmuxResetStream; mem_ptr_t<CellDmuxMsg> dmuxMsg(a128(dmux.memAddr) + (cb_add ^= 16));
goto task; dmuxMsg->msgType = CELL_DMUX_MSG_TYPE_DEMUX_DONE;
dmuxMsg->supplementalInfo = stream.userdata;
/*Callback cb;
cb.SetAddr(dmux.cbFunc);
cb.Handle(dmux.id, dmuxMsg.GetAddr(), dmux.cbArg);
cb.Branch(task.type == dmuxResetStreamAndWaitDone);*/
dmux.dmuxCb->ExecAsCallback(dmux.cbFunc, true, dmux.id, dmuxMsg.GetAddr(), dmux.cbArg);
updates_signaled++;
} }
else switch (code.ToLE()) else switch (code.ToLE())
{ {
@ -102,12 +117,61 @@ u32 dmuxOpen(Demuxer* data)
case PRIVATE_STREAM_1: case PRIVATE_STREAM_1:
{ {
DemuxerStream backup = stream;
// audio AT3+ (and probably LPCM or user data) // audio AT3+ (and probably LPCM or user data)
stream.skip(4); stream.skip(4);
stream.get(len); stream.get(len);
// skipping... PesHeader pes(stream);
stream.skip(len);
if (!pes.new_au) // temporarily
{
ConLog.Error("No pts info found");
}
// read additional header:
stream.peek(ch);
//stream.skip(4);
//pes.size += 4;
if (esATX[ch])
{
ElementaryStream& es = *esATX[ch];
while (es.isfull())
{
if (Emu.IsStopped())
{
ConLog.Warning("esATX[%d] was full, waiting aborted", ch);
return;
}
Sleep(1);
}
/*if (es.hasunseen()) // hack, probably useless
{
stream = backup;
continue;
}*/
//ConLog.Write("*** AT3+ AU sent (pts=0x%llx, dts=0x%llx)", pes.pts, pes.dts);
es.push(stream, len - pes.size - 3, pes);
es.finish(stream);
mem_ptr_t<CellDmuxEsMsg> esMsg(a128(dmux.memAddr) + (cb_add ^= 16));
esMsg->msgType = CELL_DMUX_ES_MSG_TYPE_AU_FOUND;
esMsg->supplementalInfo = stream.userdata;
/*Callback cb;
cb.SetAddr(es.cbFunc);
cb.Handle(dmux.id, es.id, esMsg.GetAddr(), es.cbArg);
cb.Branch(false);*/
dmux.dmuxCb->ExecAsCallback(es.cbFunc, false, dmux.id, es.id, esMsg.GetAddr(), es.cbArg);
}
else
{
stream.skip(len - pes.size - 3);
}
} }
break; break;
@ -121,10 +185,14 @@ u32 dmuxOpen(Demuxer* data)
if (esAVC[ch]) if (esAVC[ch])
{ {
ElementaryStream& es = *esAVC[ch]; ElementaryStream& es = *esAVC[ch];
if (es.isfull()) while (es.isfull())
{ {
if (Emu.IsStopped())
{
ConLog.Warning("esAVC[%d] was full, waiting aborted", ch);
return;
}
Sleep(1); Sleep(1);
continue;
} }
DemuxerStream backup = stream; DemuxerStream backup = stream;
@ -133,33 +201,28 @@ u32 dmuxOpen(Demuxer* data)
stream.get(len); stream.get(len);
PesHeader pes(stream); PesHeader pes(stream);
if (!pes.new_au && !es.hasdata()) // fatal error
{
ConLog.Error("PES not found");
return;
}
if (pes.new_au && es.hasdata()) // new AU detected if (pes.new_au && es.hasdata()) // new AU detected
{ {
if (es.hasunseen()) // hack, probably useless /*if (es.hasunseen()) // hack, probably useless
{ {
stream = backup; stream = backup;
continue; continue;
} }*/
es.finish(stream); es.finish(stream);
// callback // callback
mem_ptr_t<CellDmuxEsMsg> esMsg(a128(dmux.memAddr) + (cb_add ^= 16)); mem_ptr_t<CellDmuxEsMsg> esMsg(a128(dmux.memAddr) + (cb_add ^= 16));
esMsg->msgType = CELL_DMUX_ES_MSG_TYPE_AU_FOUND; esMsg->msgType = CELL_DMUX_ES_MSG_TYPE_AU_FOUND;
esMsg->supplementalInfo = stream.userdata; esMsg->supplementalInfo = stream.userdata;
Callback cb; /*Callback cb;
cb.SetAddr(es.cbFunc); cb.SetAddr(es.cbFunc);
cb.Handle(dmux.id, es.id, esMsg.GetAddr(), es.cbArg); cb.Handle(dmux.id, es.id, esMsg.GetAddr(), es.cbArg);
cb.Branch(false); cb.Branch(false);*/
dmux.dmuxCb->ExecAsCallback(es.cbFunc, false, dmux.id, es.id, esMsg.GetAddr(), es.cbArg);
} }
if (pes.new_au) if (pes.new_au)
{ {
ConLog.Write("*** AVC AU detected (pts=0x%llx, dts=0x%llx)", pes.pts, pes.dts); //ConLog.Write("*** AVC AU detected (pts=0x%llx, dts=0x%llx)", pes.pts, pes.dts);
} }
if (es.isfull()) if (es.isfull())
@ -167,8 +230,10 @@ u32 dmuxOpen(Demuxer* data)
stream = backup; stream = backup;
continue; continue;
} }
//stream = backup;
es.push(stream, len - pes.size - 3, pes); //hack: reconstruction of MPEG2-PS stream for vdec module (seems it works without it too)
stream = backup;
es.push(stream, len + 6 /*- pes.size - 3*/, pes);
} }
else else
{ {
@ -218,24 +283,11 @@ u32 dmuxOpen(Demuxer* data)
{ {
break; // Emu is stopped break; // Emu is stopped
} }
task:
switch (task.type) switch (task.type)
{ {
case dmuxSetStream: case dmuxSetStream:
{ {
bool do_wait = false;
for (u32 i = 0; i < 192; i++)
{
if (esALL[i])
{
if (esALL[i]->hasunseen()) // hack, probably useless
{
do_wait = true;
break;
}
}
}
if (do_wait) continue;
stream = task.stream; stream = task.stream;
ConLog.Write("*** stream updated(addr=0x%x, size=0x%x, discont=%d, userdata=0x%llx)", ConLog.Write("*** stream updated(addr=0x%x, size=0x%x, discont=%d, userdata=0x%llx)",
stream.addr, stream.size, stream.discontinuity, stream.userdata); stream.addr, stream.size, stream.discontinuity, stream.userdata);
@ -246,6 +298,7 @@ task:
esALL[i]->reset(); esALL[i]->reset();
} }
} }
updates_count++;
dmux.is_running = true; dmux.is_running = true;
} }
break; break;
@ -253,14 +306,16 @@ task:
case dmuxResetStream: case dmuxResetStream:
case dmuxResetStreamAndWaitDone: case dmuxResetStreamAndWaitDone:
{ {
// TODO: send CELL_DMUX_MSG_TYPE_DEMUX_DONE callback and provide waiting condition
mem_ptr_t<CellDmuxMsg> dmuxMsg(a128(dmux.memAddr) + (cb_add ^= 16)); mem_ptr_t<CellDmuxMsg> dmuxMsg(a128(dmux.memAddr) + (cb_add ^= 16));
dmuxMsg->msgType = CELL_DMUX_MSG_TYPE_DEMUX_DONE; dmuxMsg->msgType = CELL_DMUX_MSG_TYPE_DEMUX_DONE;
dmuxMsg->supplementalInfo = stream.userdata; dmuxMsg->supplementalInfo = stream.userdata;
Callback cb; /*Callback cb;
cb.SetAddr(dmux.cbFunc); cb.SetAddr(dmux.cbFunc);
cb.Handle(dmux.id, dmuxMsg.GetAddr(), dmux.cbArg); cb.Handle(dmux.id, dmuxMsg.GetAddr(), dmux.cbArg);
cb.Branch(task.type == dmuxResetStreamAndWaitDone); cb.Branch(task.type == dmuxResetStreamAndWaitDone);*/
dmux.dmuxCb->ExecAsCallback(dmux.cbFunc, task.type == dmuxResetStreamAndWaitDone,
dmux.id, dmuxMsg.GetAddr(), dmux.cbArg);
updates_signaled++;
dmux.is_running = false; dmux.is_running = false;
} }
break; break;
@ -283,6 +338,13 @@ task:
{ {
esAVC[es.fidMajor - 0xe0] = task.es.es_ptr; esAVC[es.fidMajor - 0xe0] = task.es.es_ptr;
} }
else if (es.fidMajor == 0xbd &&
es.fidMinor == 0 &&
es.sup1 == 0 &&
es.sup2 == 0)
{
esATX[0] = task.es.es_ptr;
}
else else
{ {
ConLog.Warning("dmuxEnableEs: (TODO) unsupported filter (0x%x, 0x%x, 0x%x, 0x%x)", es.fidMajor, es.fidMinor, es.sup1, es.sup2); ConLog.Warning("dmuxEnableEs: (TODO) unsupported filter (0x%x, 0x%x, 0x%x, 0x%x)", es.fidMajor, es.fidMinor, es.sup1, es.sup2);
@ -311,11 +373,11 @@ task:
} }
break; break;
case dmuxReleaseAu: /*case dmuxReleaseAu:
{ {
task.es.es_ptr->release(); task.es.es_ptr->release();
} }
break; break;*/
case dmuxFlushEs: case dmuxFlushEs:
{ {
@ -328,20 +390,22 @@ task:
mem_ptr_t<CellDmuxEsMsg> esMsg(a128(dmux.memAddr) + (cb_add ^= 16)); mem_ptr_t<CellDmuxEsMsg> esMsg(a128(dmux.memAddr) + (cb_add ^= 16));
esMsg->msgType = CELL_DMUX_ES_MSG_TYPE_AU_FOUND; esMsg->msgType = CELL_DMUX_ES_MSG_TYPE_AU_FOUND;
esMsg->supplementalInfo = stream.userdata; esMsg->supplementalInfo = stream.userdata;
Callback cb; /*Callback cb;
cb.SetAddr(es.cbFunc); cb.SetAddr(es.cbFunc);
cb.Handle(dmux.id, es.id, esMsg.GetAddr(), es.cbArg); cb.Handle(dmux.id, es.id, esMsg.GetAddr(), es.cbArg);
cb.Branch(false); cb.Branch(false);*/
dmux.dmuxCb->ExecAsCallback(es.cbFunc, false, dmux.id, es.id, esMsg.GetAddr(), es.cbArg);
} }
// callback // callback
mem_ptr_t<CellDmuxEsMsg> esMsg(a128(dmux.memAddr) + (cb_add ^= 16)); mem_ptr_t<CellDmuxEsMsg> esMsg(a128(dmux.memAddr) + (cb_add ^= 16));
esMsg->msgType = CELL_DMUX_ES_MSG_TYPE_FLUSH_DONE; esMsg->msgType = CELL_DMUX_ES_MSG_TYPE_FLUSH_DONE;
esMsg->supplementalInfo = stream.userdata; esMsg->supplementalInfo = stream.userdata;
Callback cb; /*Callback cb;
cb.SetAddr(es.cbFunc); cb.SetAddr(es.cbFunc);
cb.Handle(dmux.id, es.id, esMsg.GetAddr(), es.cbArg); cb.Handle(dmux.id, es.id, esMsg.GetAddr(), es.cbArg);
cb.Branch(false); cb.Branch(false);*/
dmux.dmuxCb->ExecAsCallback(es.cbFunc, false, dmux.id, es.id, esMsg.GetAddr(), es.cbArg);
} }
break; break;
@ -507,6 +571,7 @@ int cellDmuxClose(u32 demuxerHandle)
Sleep(1); Sleep(1);
} }
if (dmux->dmuxCb) Emu.GetCPU().RemoveThread(dmux->dmuxCb->GetId());
Emu.GetIdManager().RemoveID(demuxerHandle); Emu.GetIdManager().RemoveID(demuxerHandle);
return CELL_OK; return CELL_OK;
} }
@ -527,9 +592,14 @@ int cellDmuxSetStream(u32 demuxerHandle, const u32 streamAddress, u32 streamSize
return CELL_DMUX_ERROR_FATAL; return CELL_DMUX_ERROR_FATAL;
} }
if (dmux->is_running) while (dmux->is_running) // !!!
{ {
Sleep(1); // performance hack if (Emu.IsStopped())
{
ConLog.Warning("cellDmuxSetStream(%d) aborted (waiting)", demuxerHandle);
break;
}
Sleep(1);
return CELL_DMUX_ERROR_BUSY; return CELL_DMUX_ERROR_BUSY;
} }
@ -851,7 +921,7 @@ int cellDmuxPeekAuEx(u32 esHandle, mem32_t auInfoEx_ptr, mem32_t auSpecificInfo_
int cellDmuxReleaseAu(u32 esHandle) int cellDmuxReleaseAu(u32 esHandle)
{ {
cellDmux.Warning("(disabled) cellDmuxReleaseAu(esHandle=0x%x)", esHandle); cellDmux.Log("cellDmuxReleaseAu(esHandle=0x%x)", esHandle);
return CELL_OK; return CELL_OK;
@ -865,14 +935,19 @@ int cellDmuxReleaseAu(u32 esHandle)
{ {
cellDmux.Error("cellDmuxReleaseAu: no AU"); cellDmux.Error("cellDmuxReleaseAu: no AU");
return CELL_DMUX_ERROR_SEQ; return CELL_DMUX_ERROR_SEQ;
//return CELL_OK;
} }
DemuxerTask task(dmuxReleaseAu); /*DemuxerTask task(dmuxReleaseAu);
task.es.es = esHandle; task.es.es = esHandle;
task.es.es_ptr = es; task.es.es_ptr = es;
es->dmux->job.Push(task); es->dmux->job.Push(task);*/
if (!es->release())
{
cellDmux.Error("cellDmuxReleaseAu failed");
return CELL_DMUX_ERROR_SEQ;
}
return CELL_OK; return CELL_OK;
} }

View File

@ -329,11 +329,11 @@ struct DemuxerStream
} }
template<typename T> template<typename T>
bool peek(T& out) bool peek(T& out, u32 shift = 0)
{ {
if (sizeof(T) > size) return false; if (sizeof(T) + shift > size) return false;
out = *(T*)Memory.VirtualToRealAddr(addr); out = *(T*)Memory.VirtualToRealAddr(addr + shift);
return true; return true;
} }
@ -364,45 +364,54 @@ struct PesHeader
{ {
u64 pts; u64 pts;
u64 dts; u64 dts;
u8 ch;
u8 size; u8 size;
bool new_au; bool new_au;
PesHeader(DemuxerStream& stream) PesHeader(DemuxerStream& stream)
: pts(0xffffffffffffffff) : pts(0xffffffffffffffff)
, dts(0xffffffffffffffff) , dts(0xffffffffffffffff)
, ch(0)
, size(0) , size(0)
, new_au(true) , new_au(false)
{ {
u16 header; u16 header;
stream.get(header); stream.get(header);
stream.get(size); stream.get(size);
if (size) if (size)
{ {
//ConLog.Write(">>>>> Pes Header (size=%d)", size); u8 empty = 0;
if (size < 10)
{
stream.skip(size);
return;
}
new_au = true;
u8 v; u8 v;
stream.get(v); while (true)
if ((v & 0xF0) != 0x30)
{ {
ConLog.Error("Pts not found"); stream.get(v);
Emu.Pause(); if (v != 0xFF) break; // skip padding bytes
} empty++;
pts = stream.get_ts(v); if (empty = size) return;
stream.get(v); };
if ((v & 0xF0) != 0x10)
if ((v & 0xF0) == 0x20 && (size - empty) >= 5) // pts only
{ {
ConLog.Error("Dts not found"); new_au = true;
Emu.Pause(); pts = stream.get_ts(v);
stream.skip(size - empty - 5);
}
else
{
new_au = true;
if ((v & 0xF0) != 0x30 || (size - empty) < 10)
{
ConLog.Error("PesHeader(): pts not found");
Emu.Pause();
}
pts = stream.get_ts(v);
stream.get(v);
if ((v & 0xF0) != 0x10)
{
ConLog.Error("PesHeader(): dts not found");
Emu.Pause();
}
dts = stream.get_ts(v);
stream.skip(size - empty - 10);
} }
dts = stream.get_ts(v);
stream.skip(size - 10);
} }
} }
}; };
@ -417,7 +426,6 @@ enum DemuxerJobType
dmuxEnableEs, dmuxEnableEs,
dmuxDisableEs, dmuxDisableEs,
dmuxResetEs, dmuxResetEs,
dmuxReleaseAu,
dmuxFlushEs, dmuxFlushEs,
dmuxClose, dmuxClose,
}; };
@ -461,6 +469,7 @@ public:
volatile bool is_finished; volatile bool is_finished;
volatile bool is_running; volatile bool is_running;
CPUThread* dmuxCb;
Demuxer(u32 addr, u32 size, u32 func, u32 arg) Demuxer(u32 addr, u32 size, u32 func, u32 arg)
: is_finished(false) : is_finished(false)
@ -469,6 +478,7 @@ public:
, memSize(size) , memSize(size)
, cbFunc(func) , cbFunc(func)
, cbArg(arg) , cbArg(arg)
, dmuxCb(nullptr)
{ {
} }
}; };
@ -497,8 +507,8 @@ public:
ElementaryStream(Demuxer* dmux, u32 addr, u32 size, u32 fidMajor, u32 fidMinor, u32 sup1, u32 sup2, u32 cbFunc, u32 cbArg, u32 spec) ElementaryStream(Demuxer* dmux, u32 addr, u32 size, u32 fidMajor, u32 fidMinor, u32 sup1, u32 sup2, u32 cbFunc, u32 cbArg, u32 spec)
: dmux(dmux) : dmux(dmux)
, memAddr(addr) , memAddr(a128(addr))
, memSize(size) , memSize(size - (addr - memAddr))
, fidMajor(fidMajor) , fidMajor(fidMajor)
, fidMinor(fidMinor) , fidMinor(fidMinor)
, sup1(sup1) , sup1(sup1)
@ -508,7 +518,7 @@ public:
, spec(spec) , spec(spec)
, first_addr(0) , first_addr(0)
, peek_addr(0) , peek_addr(0)
, last_addr(a128(addr)) , last_addr(memAddr)
, last_size(0) , last_size(0)
{ {
} }
@ -523,8 +533,9 @@ public:
return last_size; return last_size;
} }
bool isfull() // not multithread-safe bool isfull()
{ {
SMutexLocker lock(mutex);
if (first_addr) if (first_addr)
{ {
if (first_addr > last_addr) if (first_addr > last_addr)
@ -570,7 +581,24 @@ public:
{ {
SMutexLocker lock(mutex); SMutexLocker lock(mutex);
//ConLog.Write("es::push(): peek=0x%x, first=0x%x, last=0x%x, size=0x%x", peek_addr, first_addr, last_addr, last_size); //ConLog.Write("es::push(): peek=0x%x, first=0x%x, last=0x%x, size=0x%x", peek_addr, first_addr, last_addr, last_size);
if (isfull()) bool is_full;
if (first_addr)
{
if (first_addr > last_addr)
{
is_full = (first_addr - last_addr) < MAX_AU;
}
else
{
is_full = (first_addr + MAX_AU) > (memAddr + memSize);
}
}
else
{
is_full = false;
}
if (is_full)
{ {
ConLog.Error("ElementaryStream::push(): buffer is full"); ConLog.Error("ElementaryStream::push(): buffer is full");
Emu.Pause(); Emu.Pause();
@ -590,7 +618,7 @@ public:
mem_ptr_t<CellDmuxAuInfoEx> info(last_addr); mem_ptr_t<CellDmuxAuInfoEx> info(last_addr);
info->auAddr = last_addr + 128; info->auAddr = last_addr + 128;
info->auSize = last_size; info->auSize = last_size;
if (pes.size) if (pes.new_au)
{ {
info->dts.lower = (u32)pes.dts; info->dts.lower = (u32)pes.dts;
info->dts.upper = (u32)(pes.dts >> 32); info->dts.upper = (u32)(pes.dts >> 32);
@ -607,7 +635,7 @@ public:
mem_ptr_t<CellDmuxAuInfo> inf(last_addr + 64); mem_ptr_t<CellDmuxAuInfo> inf(last_addr + 64);
inf->auAddr = last_addr + 128; inf->auAddr = last_addr + 128;
inf->auSize = last_size; inf->auSize = last_size;
if (pes.size) if (pes.new_au)
{ {
inf->dtsLower = (u32)pes.dts; inf->dtsLower = (u32)pes.dts;
inf->dtsUpper = (u32)(pes.dts >> 32); inf->dtsUpper = (u32)(pes.dts >> 32);
@ -623,20 +651,26 @@ public:
return first_addr; return first_addr;
} }
void release() bool release()
{ {
SMutexLocker lock(mutex); SMutexLocker lock(mutex);
ConLog.Write("es::release(): peek=0x%x, first=0x%x, last=0x%x, size=0x%x", peek_addr, first_addr, last_addr, last_size); //ConLog.Write("es::release(): peek=0x%x, first=0x%x, last=0x%x, size=0x%x", peek_addr, first_addr, last_addr, last_size);
if (!canrelease()) if (!canrelease())
{ {
ConLog.Error("ElementaryStream::release(): buffer is empty"); ConLog.Error("ElementaryStream::release(): buffer is empty");
Emu.Pause(); return false;
return;
} }
u32 size = a128(Memory.Read32(first_addr + 4) + 128); u32 size = a128(Memory.Read32(first_addr + 4) + 128);
u32 new_addr = first_addr + size; u32 new_addr = first_addr + size;
if (peek_addr <= first_addr) peek_addr = new_addr;
if (peek_addr == first_addr)
{
ConLog.Error("ElementaryStream::release(): buffer has not been seen yet");
return false;
}
//if (peek_addr <= first_addr) peek_addr = new_addr;
if (new_addr == last_addr) if (new_addr == last_addr)
{ {
first_addr = 0; first_addr = 0;
@ -649,6 +683,8 @@ public:
{ {
first_addr = new_addr; first_addr = new_addr;
} }
return true;
} }
bool peek(u32& out_data, bool no_ex, u32& out_spec, bool update_index) bool peek(u32& out_data, bool no_ex, u32& out_spec, bool update_index)
@ -687,7 +723,7 @@ public:
SMutexLocker lock(mutex); SMutexLocker lock(mutex);
first_addr = 0; first_addr = 0;
peek_addr = 0; peek_addr = 0;
last_addr = a128(memAddr); last_addr = memAddr;
last_size = 0; last_size = 0;
} }
}; };

View File

@ -0,0 +1,235 @@
#include "stdafx.h"
#include "cellSpurs.h"
#include "Emu/SysCalls/SysCalls.h"
#include "Emu/SysCalls/SC_FUNC.h"
void cellSpurs_init();
Module cellSpurs(0x000a, cellSpurs_init);
int _cellSpursAttributeInitialize(mem_ptr_t<CellSpursAttribute> attr, int nSpus, int spuPriority,
int ppuPriority, bool exitIfNoWork)
{
cellSpurs.Warning("cellSpursAttributeInitialize(attr_addr=0x%x, nSpus=%u, spuPriority=%u, ppuPriority=%u, exitIfNoWork=%u)",
attr.GetAddr(), nSpus, spuPriority, ppuPriority, exitIfNoWork);
if(!attr.IsGood()) return CELL_SPURS_CORE_ERROR_NULL_POINTER;
return CELL_OK;
}
int cellSpursAttributeSetMemoryContainerForSpuThread(mem_ptr_t<CellSpursAttribute> attr, u32 container)
{
cellSpurs.Warning("cellSpursAttributeSetMemoryContainerForSpuThread(attr_addr=0x%x, container=0x%x)",
attr.GetAddr(), container);
if(!attr.IsGood()) return CELL_SPURS_CORE_ERROR_NULL_POINTER;
return CELL_OK;
}
int cellSpursAttributeSetNamePrefix(mem_ptr_t<CellSpursAttribute> attr, const mem8_t prefix, u32 size)
{
cellSpurs.Warning("cellSpursAttributeSetNamePrefix(attr_addr=0x%x, prefix_addr=0x%x, size=0x%x)",
attr.GetAddr(), prefix.GetAddr(), size);
if(!attr.IsGood() || !prefix.IsGood()) return CELL_SPURS_CORE_ERROR_NULL_POINTER;
if(size > 15) return CELL_SPURS_CORE_ERROR_INVAL;
return CELL_OK;
}
int cellSpursAttributeEnableSpuPrintfIfAvailable(mem_ptr_t<CellSpursAttribute> attr)
{
cellSpurs.Warning("cellSpursAttributeEnableSpuPrintfIfAvailable(attr_addr=0x%x)", attr.GetAddr());
if(!attr.IsGood()) return CELL_SPURS_CORE_ERROR_NULL_POINTER;
return CELL_OK;
}
int cellSpursAttributeSetSpuThreadGroupType(mem_ptr_t<CellSpursAttribute> attr, int type)
{
cellSpurs.Warning("cellSpursAttributeSetSpuThreadGroupType(attr_addr=0x%x, type=%u)", attr.GetAddr(), type);
if(!attr.IsGood()) return CELL_SPURS_CORE_ERROR_NULL_POINTER;
return CELL_OK;
}
int cellSpursAttributeEnableSystemWorkload(mem_ptr_t<CellSpursAttribute> attr, const u8 priority[8],
uint maxSpu, const bool isPreemptible[8])
{
cellSpurs.Warning("cellSpursAttributeEnableSystemWorkload(attr_addr=0x%x, priority[%u], maxSpu=%u, isPreemptible[%u])",
attr.GetAddr(), priority, maxSpu, isPreemptible);
if(!attr.IsGood()) return CELL_SPURS_CORE_ERROR_NULL_POINTER;
for (int i=0; i<9; i++)
if(priority[i] != 1 || maxSpu == 0) return CELL_SPURS_CORE_ERROR_INVAL;
return CELL_OK;
}
int cellSpursInitializeWithAttribute2(mem_ptr_t<CellSpurs2> spurs, const mem_ptr_t<CellSpursAttribute> attr)
{
cellSpurs.Warning("cellSpursInitializeWithAttribute2(spurs_addr=0x%x, spurs_addr=0x%x)",
spurs.GetAddr(), attr.GetAddr());
if(!attr.IsGood() || !spurs.IsGood()) return CELL_SPURS_CORE_ERROR_NULL_POINTER;
return CELL_OK;
}
int cellSpursFinalize(mem_ptr_t<CellSpurs> spurs)
{
cellSpurs.Warning("cellSpursFinalize(spurs_addr=0x%x)", spurs.GetAddr());
if(!spurs.IsGood()) return CELL_SPURS_CORE_ERROR_NULL_POINTER;
return CELL_OK;
}
int cellSpursGetSpuThreadGroupId(mem_ptr_t<CellSpurs> spurs, mem32_t group)
{
cellSpurs.Warning("cellSpursGetSpuThreadGroupId(spurs_addr=0x%x, group_addr=0x%x)",
spurs.GetAddr(), group.GetAddr());
if(!spurs.IsGood() || group.IsGood()) return CELL_SPURS_CORE_ERROR_NULL_POINTER;
return CELL_OK;
}
int cellSpursGetNumSpuThread(mem_ptr_t<CellSpurs> spurs, mem32_t nThreads)
{
cellSpurs.Warning("cellSpursGetNumSpuThread(spurs_addr=0x%x, nThreads_addr=0x%x)",
spurs.GetAddr(), nThreads.GetAddr());
if(!spurs.IsGood() || nThreads.IsGood()) return CELL_SPURS_CORE_ERROR_NULL_POINTER;
return CELL_OK;
}
int cellSpursGetSpuThreadId(mem_ptr_t<CellSpurs> spurs, mem32_t thread, mem32_t nThreads)
{
cellSpurs.Warning("cellSpursGetSpuThreadId(spurs_addr=0x%x, thread_addr=0x%x, nThreads_addr=0x%x)",
spurs.GetAddr(), thread.GetAddr(), nThreads.GetAddr());
if(!spurs.IsGood() || !thread.IsGood() || nThreads.IsGood()) return CELL_SPURS_CORE_ERROR_NULL_POINTER;
return CELL_OK;
}
int cellSpursSetMaxContention(mem_ptr_t<CellSpurs> spurs, uint workloadId, uint maxContention)
{
cellSpurs.Warning("cellSpursSetMaxContention(spurs_addr=0x%x, workloadId=%u, maxContention=%u)",
spurs.GetAddr(), workloadId, maxContention);
if(!spurs.IsGood()) return CELL_SPURS_CORE_ERROR_NULL_POINTER;
return CELL_OK;
}
int cellSpursSetPriorities(mem_ptr_t<CellSpurs> spurs, uint workloadId, const u8 priorities[CELL_SPURS_MAX_SPU])
{
cellSpurs.Warning("cellSpursSetPriorities(spurs_addr=0x%x, workloadId=%u, priorities[%u])",
spurs.GetAddr(), workloadId, priorities);
if(!spurs.IsGood()) return CELL_SPURS_CORE_ERROR_NULL_POINTER;
return CELL_OK;
}
int cellSpursSetPriority(mem_ptr_t<CellSpurs> spurs, uint workloadId, uint spuId, uint priority)
{
cellSpurs.Warning("cellSpursSetPriority(spurs_addr=0x%x, workloadId=%u, spuId=%u, priority=%u)",
spurs.GetAddr(), workloadId, spuId, priority);
if(!spurs.IsGood()) return CELL_SPURS_CORE_ERROR_NULL_POINTER;
return CELL_OK;
}
int cellSpursSetPreemptionVictimHints(mem_ptr_t<CellSpurs> spurs, const bool isPreemptible[8])
{
cellSpurs.Warning("cellSpursSetPreemptionVictimHints(spurs_addr=0x%x, isPreemptible[%u])",
spurs.GetAddr(), isPreemptible);
if(!spurs.IsGood()) return CELL_SPURS_CORE_ERROR_NULL_POINTER;
return CELL_OK;
}
int cellSpursAttachLv2EventQueue(mem_ptr_t<CellSpurs> spurs, u32 queue, mem8_t port, int isDynamic)
{
cellSpurs.Warning("cellSpursAttachLv2EventQueue(spurs_addr=0x%x, queue=0x%x, port_addr=0x%x, isDynamic=%u)",
spurs.GetAddr(), queue, port.GetAddr(), isDynamic);
if(!spurs.IsGood() || !port.IsGood()) return CELL_SPURS_CORE_ERROR_NULL_POINTER;
return CELL_OK;
}
int cellSpursDetachLv2EventQueue(mem_ptr_t<CellSpurs> spurs, u8 port)
{
cellSpurs.Warning("cellSpursDetachLv2EventQueue(spurs_addr=0x%x, port=0x%x)", spurs.GetAddr(), port);
if(!spurs.IsGood()) return CELL_SPURS_CORE_ERROR_NULL_POINTER;
return CELL_OK;
}
int cellSpursEnableExceptionEventHandler(mem_ptr_t<CellSpurs> spurs, bool flag)
{
cellSpurs.Warning("cellSpursEnableExceptionEventHandler(spurs_addr=0x%x, flag=%u)", spurs.GetAddr(), flag);
if(!spurs.IsGood()) return CELL_SPURS_CORE_ERROR_NULL_POINTER;
return CELL_OK;
}
int cellSpursSetGlobalExceptionEventHandler(mem_ptr_t<CellSpurs> spurs,
mem_func_ptr_t<CellSpursGlobalExceptionEventHandler> eaHandler, mem_ptr_t<void> arg)
{
cellSpurs.Warning("cellSpursEnableExceptionEventHandler(spurs_addr=0x%x, eaHandler_addr=0x%x, arg_addr=0x%x,)",
spurs.GetAddr(), eaHandler.GetAddr(), arg.GetAddr());
if(!spurs.IsGood() || eaHandler.IsGood()) return CELL_SPURS_CORE_ERROR_NULL_POINTER;
return CELL_OK;
}
int cellSpursUnsetGlobalExceptionEventHandler(mem_ptr_t<CellSpurs> spurs)
{
cellSpurs.Warning("cellSpursUnsetGlobalExceptionEventHandler(spurs_addr=0x%x)", spurs.GetAddr());
if(!spurs.IsGood()) return CELL_SPURS_CORE_ERROR_NULL_POINTER;
return CELL_OK;
}
int cellSpursGetInfo(mem_ptr_t<CellSpurs> spurs, mem_ptr_t<CellSpursInfo> info)
{
cellSpurs.Warning("cellSpursGetInfo(spurs_addr=0x%x, info_addr=0x%x)", spurs.GetAddr(), info.GetAddr());
if(!spurs.IsGood() || !info.IsGood()) return CELL_SPURS_CORE_ERROR_NULL_POINTER;
return CELL_OK;
}
// Task functions
int cellSpursGetTasksetId(mem_ptr_t<CellSpursTaskset> taskset, mem32_t workloadId)
{
cellSpurs.Warning("cellSpursGetTasksetId(taskset_addr=0x%x, workloadId_addr=0x%x)", taskset.GetAddr(), workloadId.GetAddr());
if(!taskset.IsGood() || !taskset.IsGood()) return CELL_SPURS_TASK_ERROR_NULL_POINTER;
return CELL_OK;
}
void cellSpurs_init()
{
//libspurs core functions
cellSpurs.AddFunc(0x95180230, _cellSpursAttributeInitialize);
cellSpurs.AddFunc(0x82275c1c, cellSpursAttributeSetMemoryContainerForSpuThread);
cellSpurs.AddFunc(0x07529113, cellSpursAttributeSetNamePrefix);
cellSpurs.AddFunc(0x1051d134, cellSpursAttributeEnableSpuPrintfIfAvailable);
cellSpurs.AddFunc(0xa839a4d9, cellSpursAttributeSetSpuThreadGroupType);
cellSpurs.AddFunc(0x9dcbcb5d, cellSpursAttributeEnableSystemWorkload);
cellSpurs.AddFunc(0x30aa96c4, cellSpursInitializeWithAttribute2);
cellSpurs.AddFunc(0xca4c4600, cellSpursFinalize);
cellSpurs.AddFunc(0x39c173fb, cellSpursGetSpuThreadGroupId);
cellSpurs.AddFunc(0xc56defb5, cellSpursGetNumSpuThread);
cellSpurs.AddFunc(0x6c960f6d, cellSpursGetSpuThreadId);
cellSpurs.AddFunc(0x84d2f6d5,cellSpursSetMaxContention);
cellSpurs.AddFunc(0x80a29e27,cellSpursSetPriorities);
//cellSpurs.AddFunc(,cellSpursSetPriority);
cellSpurs.AddFunc(0x4de203e2, cellSpursSetPreemptionVictimHints);
cellSpurs.AddFunc(0xb9bc6207, cellSpursAttachLv2EventQueue);
cellSpurs.AddFunc(0x4e66d483, cellSpursDetachLv2EventQueue);
cellSpurs.AddFunc(0x32b94add, cellSpursEnableExceptionEventHandler);
cellSpurs.AddFunc(0x7517724a, cellSpursSetGlobalExceptionEventHandler);
cellSpurs.AddFunc(0x861237f8, cellSpursUnsetGlobalExceptionEventHandler);
cellSpurs.AddFunc(0x1f402f8f, cellSpursGetInfo);
//libspurs task functions
}

View File

@ -0,0 +1,296 @@
#pragma once
// return codes
enum
{
CELL_SPURS_CORE_ERROR_AGAIN = 0x80410701,
CELL_SPURS_CORE_ERROR_INVAL = 0x80410702,
CELL_SPURS_CORE_ERROR_NOMEM = 0x80410704,
CELL_SPURS_CORE_ERROR_SRCH = 0x80410705,
CELL_SPURS_CORE_ERROR_PERM = 0x80410709,
CELL_SPURS_CORE_ERROR_BUSY = 0x8041070A,
CELL_SPURS_CORE_ERROR_STAT = 0x8041070F,
CELL_SPURS_CORE_ERROR_ALIGN = 0x80410710,
CELL_SPURS_CORE_ERROR_NULL_POINTER = 0x80410711,
};
//defines
enum SPURSKernelInterfaces
{
CELL_SPURS_MAX_SPU = 8,
CELL_SPURS_MAX_WORKLOAD = 16,
CELL_SPURS_MAX_WORKLOAD2 = 32,
CELL_SPURS_MAX_PRIORITY = 16,
CELL_SPURS_NAME_MAX_LENGTH = 15,
CELL_SPURS_SIZE = 4096,
CELL_SPURS_SIZE2 = 8192,
CELL_SPURS_ALIGN = 128,
CELL_SPURS_ATTRIBUTE_SIZE = 512,
CELL_SPURS_ATTRIBUTE_ALIGN = 8,
CELL_SPURS_INTERRUPT_VECTOR = 0x0,
CELL_SPURS_LOCK_LINE = 0x80,
CELL_SPURS_KERNEL_DMA_TAG_ID = 31,
};
enum RangeofEventQueuePortNumbers
{
CELL_SPURS_STATIC_PORT_RANGE_BOTTOM = 15,
CELL_SPURS_DYNAMIC_PORT_RANGE_TOP = 16,
CELL_SPURS_DYNAMIC_PORT_RANGE_BOTTOM = 63,
};
enum SPURSTraceTypes
{
CELL_SPURS_TRACE_TAG_LOAD = 0x2a,
CELL_SPURS_TRACE_TAG_MAP = 0x2b,
CELL_SPURS_TRACE_TAG_START = 0x2c,
CELL_SPURS_TRACE_TAG_STOP = 0x2d,
CELL_SPURS_TRACE_TAG_USER = 0x2e,
CELL_SPURS_TRACE_TAG_GUID = 0x2f,
};
struct CellSpursInfo
{
be_t<int> nSpus;
be_t<int> spuThreadGroupPriority;
be_t<int> ppuThreadPriority;
bool exitIfNoWork;
bool spurs2;
be_t<u32> traceBuffer_addr; //void *traceBuffer;
be_t<u64> traceBufferSize;
be_t<u32> traceMode;
be_t<u32> spuThreadGroup; //typedef u32 sys_spu_thread_group_t;
be_t<u32> spuThreads[8]; //typedef u32 sys_spu_thread_t;
be_t<u32> spursHandlerThread0;
be_t<u32> spursHandlerThread1;
char namePrefix[CELL_SPURS_NAME_MAX_LENGTH+1];
be_t<u64> namePrefixLength;
be_t<u32> deadlineMissCounter;
be_t<u32> deadlineMeetCounter;
//u8 padding[];
};
struct CellSpursExceptionInfo
{
be_t<u32> spu_thread;
be_t<u32> spu_npc;
be_t<u32> cause;
be_t<u64> option;
};
struct CellSpursTraceInfo
{
be_t<u32> spu_thread[8];
be_t<u32> count[8];
be_t<u32> spu_thread_grp;
be_t<u32> nspu;
//u8 padding[];
};
__declspec(align(8)) struct CellTraceHeader
{
u8 tag;
u8 length;
u8 cpu;
u8 thread;
be_t<u32> time;
};
struct CellSpursTracePacket
{
struct header_struct
{
u8 tag;
u8 length;
u8 spu;
u8 workload;
be_t<u32> time;
} header;
struct data_struct
{
struct load_struct
{
be_t<u32> ea;
be_t<u16> ls;
be_t<u16> size;
} load;
struct map_struct
{
be_t<u32> offset;
be_t<u16> ls;
be_t<u16> size;
} map;
struct start_struct
{
char module[4];
be_t<u16> level;
be_t<u16> ls;
} start;
be_t<u64> user;
be_t<u64> guid;
} data;
};
__declspec(align(128)) struct CellSpurs
{
u8 skip[CELL_SPURS_SIZE];
};
__declspec(align(128)) struct CellSpurs2
{
u8 skip[CELL_SPURS_SIZE2 - CELL_SPURS_SIZE];
};
__declspec(align(8)) struct CellSpursAttribute
{
u8 skip[CELL_SPURS_ATTRIBUTE_SIZE];
};
//typedef unsigned CellSpursWorkloadId;
typedef void (*CellSpursGlobalExceptionEventHandler)(mem_ptr_t<CellSpurs> spurs, const mem_ptr_t<CellSpursExceptionInfo> info,
uint id, mem_ptr_t<void> arg);
// task datatypes and constans
enum TaskConstants
{
CELL_SPURS_MAX_TASK = 128,
CELL_SPURS_TASK_TOP = 0x3000,
CELL_SPURS_TASK_BOTTOM = 0x40000,
CELL_SPURS_MAX_TASK_NAME_LENGTH = 32,
};
enum
{
CELL_SPURS_TASK_ERROR_AGAIN = 0x80410901,
CELL_SPURS_TASK_ERROR_INVAL = 0x80410902,
CELL_SPURS_TASK_ERROR_NOMEM = 0x80410904,
CELL_SPURS_TASK_ERROR_SRCH = 0x80410905,
CELL_SPURS_TASK_ERROR_NOEXEC = 0x80410907,
CELL_SPURS_TASK_ERROR_PERM = 0x80410909,
CELL_SPURS_TASK_ERROR_BUSY = 0x8041090A,
CELL_SPURS_TASK_ERROR_FAULT = 0x8041090D,
CELL_SPURS_TASK_ERROR_STAT = 0x8041090F,
CELL_SPURS_TASK_ERROR_ALIGN = 0x80410910,
CELL_SPURS_TASK_ERROR_NULL_POINTER = 0x80410911,
CELL_SPURS_TASK_ERROR_FATAL = 0x80410914,
CELL_SPURS_TASK_ERROR_SHUTDOWN = 0x80410920,
};
__declspec(align(128)) struct CellSpursTaskset
{
u8 skip[6400];
};
typedef void(*CellSpursTasksetExceptionEventHandler)(mem_ptr_t<CellSpurs> spurs, mem_ptr_t<CellSpursTaskset> taskset,
uint idTask, const mem_ptr_t<CellSpursExceptionInfo> info, mem_ptr_t<void> arg);
struct CellSpursTasksetInfo
{
//CellSpursTaskInfo taskInfo[CELL_SPURS_MAX_TASK];
be_t<u64> argument;
be_t<uint> idWorkload;
be_t<uint> idLastScheduledTask; //typedef unsigned CellSpursTaskId
be_t<u32> name_addr;
CellSpursTasksetExceptionEventHandler exceptionEventHandler;
be_t<u32> exceptionEventHandlerArgument_addr; //void *exceptionEventHandlerArgument
be_t<u64> sizeTaskset;
//be_t<u8> reserved[];
};
/*
#define CELL_SPURS_TASKSET_CLASS0_SIZE (128 * 50)
#define _CELL_SPURS_TASKSET_CLASS1_EXTENDED_SIZE (128 + 128 * 16 + 128 * 15)
#define CELL_SPURS_TASKSET_CLASS1_SIZE (CELL_SPURS_TASKSET_CLASS0_SIZE + _CELL_SPURS_TASKSET_CLASS1_EXTENDED_SIZE)
#define CELL_SPURS_TASKSET2_SIZE (CELL_SPURS_TASKSET_CLASS1_SIZE)
#define CELL_SPURS_TASKSET2_ALIGN 128
#define CELL_SPURS_TASKSET_ALIGN 128
#define CELL_SPURS_TASKSET_SIZE CELL_SPURS_TASKSET_CLASS0_SIZE
*/
__declspec(align(128)) struct CellSpursTaskset2
{
be_t<u8> skip[10496];
};
struct CellSpursTasksetAttribute2
{
be_t<u32> revision;
be_t<u32> name_addr;
be_t<u64> argTaskset;
u8 priority[8];
be_t<u32> maxContention;
be_t<s32> enableClearLs;
be_t<s32> CellSpursTaskNameBuffer_addr; //??? *taskNameBuffer
//be_t<u32> __reserved__[];
};
struct CellSpursTaskNameBuffer
{
char taskName[CELL_SPURS_MAX_TASK][CELL_SPURS_MAX_TASK_NAME_LENGTH];
};
struct CellSpursTraceTaskData
{
be_t<u32> incident;
be_t<u32> task;
};
struct CellSpursTaskArgument
{
be_t<u32> u32[4];
be_t<u64> u64[2];
};
struct CellSpursTaskLsPattern
{
be_t<u32> u32[4];
be_t<u64> u64[2];
};
struct CellSpursTaskAttribute2
{
be_t<u32> revision;
be_t<u32> sizeContext;
be_t<u64> eaContext;
CellSpursTaskLsPattern lsPattern; //???
be_t<u32> name_addr;
//be_t<u32> __reserved__[];
};
__declspec(align(128)) struct CellSpursTaskExitCode
{
unsigned char skip[128];
};
struct CellSpursTaskInfo
{
CellSpursTaskLsPattern lsPattern;
CellSpursTaskArgument argument;
const be_t<u32> eaElf_addr; //void *eaElf
const be_t<u32> eaContext_addr; //void *eaContext
be_t<u32> sizeContext;
be_t<u8> state;
be_t<u8> hasSignal;
const be_t<u32> CellSpursTaskExitCode_addr;
u8 guid[8];
//be_t<u8> reserved[];
};
struct CellSpursTaskBinInfo
{
be_t<u64> eaElf;
be_t<u32> sizeContext;
be_t<u32> __reserved__;
CellSpursTaskLsPattern lsPattern;
};

View File

@ -3,6 +3,8 @@
#include "Emu/SysCalls/SC_FUNC.h" #include "Emu/SysCalls/SC_FUNC.h"
#include "cellPamf.h" #include "cellPamf.h"
SMutexGeneral g_mutex_avcodec_open2;
extern "C" extern "C"
{ {
#include "libavcodec/avcodec.h" #include "libavcodec/avcodec.h"
@ -19,10 +21,68 @@ int vdecRead(void* opaque, u8* buf, int buf_size)
{ {
VideoDecoder& vdec = *(VideoDecoder*)opaque; VideoDecoder& vdec = *(VideoDecoder*)opaque;
if (vdec.reader.size < (u32)buf_size) buf_size = vdec.reader.size; int res = 0;
if (vdec.reader.size < (u32)buf_size && !vdec.just_started)
{
while (vdec.job.IsEmpty())
{
if (Emu.IsStopped())
{
ConLog.Warning("vdecRead() aborted");
return 0;
}
Sleep(1);
}
switch (vdec.job.Peek().type)
{
case vdecEndSeq:
{
buf_size = vdec.reader.size;
}
break;
case vdecDecodeAu:
{
if (!Memory.CopyToReal(buf, vdec.reader.addr, vdec.reader.size))
{
ConLog.Error("vdecRead: data reading failed (reader.size=0x%x)", vdec.reader.size);
Emu.Pause();
return 0;
}
buf += vdec.reader.size;
buf_size -= vdec.reader.size;
res += vdec.reader.size;
/*Callback cb;
cb.SetAddr(vdec.cbFunc);
cb.Handle(vdec.id, CELL_VDEC_MSG_TYPE_AUDONE, CELL_OK, vdec.cbArg);
cb.Branch(false);*/
vdec.vdecCb->ExecAsCallback(vdec.cbFunc, false, vdec.id, CELL_VDEC_MSG_TYPE_AUDONE, CELL_OK, vdec.cbArg);
vdec.job.Pop(vdec.task);
vdec.reader.addr = vdec.task.addr;
vdec.reader.size = vdec.task.size;
vdec.last_pts = vdec.task.pts;
vdec.last_dts = vdec.task.dts;
}
break;
default:
ConLog.Error("vdecRead(): sequence error (task %d)", vdec.job.Peek().type);
return 0;
}
}
else if (vdec.reader.size < (u32)buf_size)
{
buf_size = vdec.reader.size;
}
if (!buf_size) if (!buf_size)
{ {
return AVERROR_EOF; return res;
} }
else if (!Memory.CopyToReal(buf, vdec.reader.addr, buf_size)) else if (!Memory.CopyToReal(buf, vdec.reader.addr, buf_size))
{ {
@ -34,7 +94,7 @@ int vdecRead(void* opaque, u8* buf, int buf_size)
{ {
vdec.reader.addr += buf_size; vdec.reader.addr += buf_size;
vdec.reader.size -= buf_size; vdec.reader.size -= buf_size;
return buf_size; return res + buf_size;
} }
} }
@ -60,15 +120,19 @@ u32 vdecOpen(VideoDecoder* data)
{ {
VideoDecoder& vdec = *data; VideoDecoder& vdec = *data;
vdec.vdecCb = &Emu.GetCPU().AddThread(CPU_THREAD_PPU);
u32 vdec_id = cellVdec.GetNewId(data); u32 vdec_id = cellVdec.GetNewId(data);
vdec.id = vdec_id; vdec.id = vdec_id;
vdec.vdecCb->SetName("Video Decoder[" + std::to_string(vdec_id) + "] Callback");
thread t("Video Decoder[" + std::to_string(vdec_id) + "] Thread", [&]() thread t("Video Decoder[" + std::to_string(vdec_id) + "] Thread", [&]()
{ {
ConLog.Write("Video Decoder enter()"); ConLog.Write("Video Decoder enter()");
VdecTask task; VdecTask& task = vdec.task;
while (true) while (true)
{ {
@ -79,12 +143,11 @@ u32 vdecOpen(VideoDecoder* data)
if (vdec.job.IsEmpty() && vdec.is_running) if (vdec.job.IsEmpty() && vdec.is_running)
{ {
// TODO: default task (not needed?)
Sleep(1); Sleep(1);
continue; continue;
} }
if (vdec.has_picture) // hack if (vdec.frames.GetCount() >= 50)
{ {
Sleep(1); Sleep(1);
continue; continue;
@ -100,55 +163,36 @@ u32 vdecOpen(VideoDecoder* data)
case vdecStartSeq: case vdecStartSeq:
{ {
// TODO: reset data // TODO: reset data
ConLog.Warning("vdecStartSeq()"); ConLog.Warning("vdecStartSeq:");
vdec.reader.addr = 0;
vdec.reader.size = 0;
vdec.is_running = true; vdec.is_running = true;
vdec.just_started = true;
} }
break; break;
case vdecEndSeq: case vdecEndSeq:
{ {
Callback cb; // TODO: finalize
ConLog.Warning("vdecEndSeq:");
vdec.vdecCb->ExecAsCallback(vdec.cbFunc, false, vdec.id, CELL_VDEC_MSG_TYPE_SEQDONE, CELL_OK, vdec.cbArg);
/*Callback cb;
cb.SetAddr(vdec.cbFunc); cb.SetAddr(vdec.cbFunc);
cb.Handle(vdec.id, CELL_VDEC_MSG_TYPE_SEQDONE, 0, vdec.cbArg); cb.Handle(vdec.id, CELL_VDEC_MSG_TYPE_SEQDONE, CELL_OK, vdec.cbArg);
cb.Branch(false); cb.Branch(true); // ???*/
ConLog.Warning("vdecEndSeq()");
avcodec_close(vdec.ctx);
avformat_close_input(&vdec.fmt);
vdec.is_running = false; vdec.is_running = false;
} }
break; break;
case vdecDecodeAu: case vdecDecodeAu:
{ {
struct vdecPacket : AVPacket int err;
{
vdecPacket(u32 size)
{
av_init_packet(this);
data = (u8*)av_malloc(size + FF_INPUT_BUFFER_PADDING_SIZE);
memset(data + size, 0, FF_INPUT_BUFFER_PADDING_SIZE);
this->size = size + FF_INPUT_BUFFER_PADDING_SIZE;
}
~vdecPacket()
{
av_free(data);
//av_free_packet(this);
}
} au(task.size);
if ((task.pts || task.dts) && task.pts != ~0 && task.dts != ~0)
{
vdec.pts = task.pts;
vdec.dts = task.dts;
au.pts = vdec.pts;
au.dts = vdec.dts;
au.flags = AV_PKT_FLAG_KEY;
}
else
{
au.pts = vdec.pts;
au.dts = vdec.dts;
}
if (task.mode != CELL_VDEC_DEC_MODE_NORMAL) if (task.mode != CELL_VDEC_DEC_MODE_NORMAL)
{ {
@ -159,72 +203,166 @@ u32 vdecOpen(VideoDecoder* data)
vdec.reader.addr = task.addr; vdec.reader.addr = task.addr;
vdec.reader.size = task.size; vdec.reader.size = task.size;
if (!Memory.CopyToReal(au.data, task.addr, task.size)) vdec.last_pts = task.pts;
vdec.last_dts = task.dts;
struct AVPacketHolder : AVPacket
{ {
ConLog.Error("vdecDecodeAu: AU data accessing failed(addr=0x%x, size=0x%x)", task.addr, task.size); AVPacketHolder(u32 size)
break;
}
/*{
wxFile dump;
dump.Open(wxString::Format("0x%llx-0x%llx.dump", au.pts, au.dts), wxFile::write);
dump.Write(au.data, task.size + FF_INPUT_BUFFER_PADDING_SIZE);
dump.Close();
}*/
int got_picture = 0;
//vdec.ctx->flags |= CODEC_FLAG_TRUNCATED;
//vdec.ctx->flags2 |= CODEC_FLAG2_CHUNKS;
vdec.ctx->flags2 |= CODEC_FLAG2_LOCAL_HEADER;
vdec.ctx->codec_tag = *(u32*)"DAVC";
//vdec.ctx->stream_codec_tag = *(u32*)"DAVC";
//avcodec_get_frame_defaults(vdec.frame);
int decode = avcodec_decode_video2(vdec.ctx, vdec.frame, &got_picture, &au);
if (decode < 0)
{
ConLog.Error("vdecDecodeAu: AU decoding error(%d)", decode);
break;
}
if (got_picture)
{
ConLog.Write("got_picture (%d, vdec: pts=0x%llx, dts=0x%llx)", got_picture, vdec.pts, vdec.dts);
/*if (vdec.out_data[0]) av_freep(vdec.out_data[0]);
int err = av_image_alloc(vdec.out_data, vdec.linesize, vdec.ctx->width, vdec.ctx->height, vdec.ctx->pix_fmt, 1);
if (err < 0)
{ {
ConLog.Error("vdecDecodeAu: av_image_alloc failed(%d)", err); av_init_packet(this);
if (size)
{
data = (u8*)av_malloc(size + FF_INPUT_BUFFER_PADDING_SIZE);
memset(data + size, 0, FF_INPUT_BUFFER_PADDING_SIZE);
this->size = size + FF_INPUT_BUFFER_PADDING_SIZE;
}
else
{
data = NULL;
size = 0;
}
}
~AVPacketHolder()
{
av_free(data);
//av_free_packet(this);
}
} au(0);
if (vdec.just_started) // deferred initialization
{
err = avformat_open_input(&vdec.fmt, NULL, NULL, NULL);
if (err)
{
ConLog.Error("vdecDecodeAu: avformat_open_input() failed");
Emu.Pause(); Emu.Pause();
break;
}
err = avformat_find_stream_info(vdec.fmt, NULL);
if (err)
{
ConLog.Error("vdecDecodeAu: avformat_find_stream_info() failed");
Emu.Pause();
break;
}
if (!vdec.fmt->nb_streams)
{
ConLog.Error("vdecDecodeAu: no stream found");
Emu.Pause();
break;
}
vdec.ctx = vdec.fmt->streams[0]->codec; // TODO: check data
AVCodec* codec = avcodec_find_decoder(vdec.ctx->codec_id); // ???
if (!codec)
{
ConLog.Error("vdecDecodeAu: avcodec_find_decoder() failed");
Emu.Pause();
break;
}
AVDictionary* opts = nullptr;
av_dict_set(&opts, "refcounted_frames", "1", 0);
{
SMutexGeneralLocker lock(g_mutex_avcodec_open2);
// not multithread-safe
err = avcodec_open2(vdec.ctx, codec, &opts);
}
if (err)
{
ConLog.Error("vdecDecodeAu: avcodec_open2() failed");
Emu.Pause();
break;
}
//vdec.ctx->flags |= CODEC_FLAG_TRUNCATED;
//vdec.ctx->flags2 |= CODEC_FLAG2_CHUNKS;
vdec.just_started = false;
}
bool last_frame = false;
while (true)
{
if (Emu.IsStopped())
{
ConLog.Warning("vdecDecodeAu aborted");
return; return;
} }
last_frame = av_read_frame(vdec.fmt, &au) < 0;
vdec.buf_size = err; if (last_frame)
{
//break;
av_free(au.data);
au.data = NULL;
au.size = 0;
}
av_image_copy(vdec.out_data, vdec.linesize, (const u8**)(vdec.frame->data), vdec.frame->linesize, struct VdecFrameHolder : VdecFrame
vdec.ctx->pix_fmt, vdec.ctx->width, vdec.ctx->height);*/ {
vdec.buf_size = a128(av_image_get_buffer_size(vdec.ctx->pix_fmt, vdec.ctx->width, vdec.ctx->height, 1)); VdecFrameHolder()
{
data = av_frame_alloc();
}
vdec.userdata = task.userData; ~VdecFrameHolder()
vdec.has_picture = true; {
if (data)
{
av_frame_unref(data);
av_frame_free(&data);
}
}
Callback cb; } frame;
cb.SetAddr(vdec.cbFunc);
cb.Handle(vdec.id, CELL_VDEC_MSG_TYPE_PICOUT, 0, vdec.cbArg); if (!frame.data)
cb.Branch(false); {
ConLog.Error("vdecDecodeAu: av_frame_alloc() failed");
Emu.Pause();
break;
}
int got_picture = 0;
int decode = avcodec_decode_video2(vdec.ctx, frame.data, &got_picture, &au);
if (decode <= 0)
{
if (!last_frame && decode < 0)
{
ConLog.Error("vdecDecodeAu: AU decoding error(0x%x)", decode);
break;
}
if (!got_picture && vdec.reader.size == 0) break; // video end?
}
if (got_picture)
{
//ConLog.Write("got_picture (%d, vdec: pts=0x%llx, dts=0x%llx)", got_picture, au.pts, au.dts);
frame.dts = vdec.last_dts; vdec.last_dts += 3003; // + duration???
frame.pts = vdec.last_pts; vdec.last_pts += 3003;
frame.userdata = task.userData;
vdec.frames.Push(frame); // !!!!!!!!
frame.data = nullptr; // to prevent destruction
vdec.vdecCb->ExecAsCallback(vdec.cbFunc, false, vdec.id, CELL_VDEC_MSG_TYPE_PICOUT, CELL_OK, vdec.cbArg);
/*Callback cb;
cb.SetAddr(vdec.cbFunc);
cb.Handle(vdec.id, CELL_VDEC_MSG_TYPE_PICOUT, CELL_OK, vdec.cbArg);
cb.Branch(false);*/
}
} }
ConLog.Write("Frame decoded (pts=0x%llx, dts=0x%llx, addr=0x%x, result=0x%x)", au.pts, au.dts, task.addr, decode);
Callback cb; vdec.vdecCb->ExecAsCallback(vdec.cbFunc, false, vdec.id, CELL_VDEC_MSG_TYPE_AUDONE, CELL_OK, vdec.cbArg);
/*Callback cb;
cb.SetAddr(vdec.cbFunc); cb.SetAddr(vdec.cbFunc);
cb.Handle(vdec.id, CELL_VDEC_MSG_TYPE_AUDONE, 0, vdec.cbArg); cb.Handle(vdec.id, CELL_VDEC_MSG_TYPE_AUDONE, CELL_OK, vdec.cbArg);
cb.Branch(false); cb.Branch(false);*/
} }
break; break;
@ -238,15 +376,15 @@ u32 vdecOpen(VideoDecoder* data)
case vdecSetFrameRate: case vdecSetFrameRate:
{ {
ConLog.Error("TODO: vdecSetFrameRate(%d)", task.frc); ConLog.Error("TODO: vdecSetFrameRate(%d)", task.frc);
return;
} }
break;
default: default:
ConLog.Error("Video Decoder error: unknown task(%d)", task.type); ConLog.Error("Video Decoder error: unknown task(%d)", task.type);
return;
} }
} }
vdec.is_finished = true;
ConLog.Warning("Video Decoder aborted"); ConLog.Warning("Video Decoder aborted");
}); });
@ -331,7 +469,7 @@ int cellVdecClose(u32 handle)
vdec->job.Push(VdecTask(vdecClose)); vdec->job.Push(VdecTask(vdecClose));
while (!vdec->is_finished) while (!vdec->is_finished || !vdec->frames.IsEmpty())
{ {
if (Emu.IsStopped()) if (Emu.IsStopped())
{ {
@ -341,6 +479,7 @@ int cellVdecClose(u32 handle)
Sleep(1); Sleep(1);
} }
if (vdec->vdecCb) Emu.GetCPU().RemoveThread(vdec->vdecCb->GetId());
Emu.GetIdManager().RemoveID(handle); Emu.GetIdManager().RemoveID(handle);
return CELL_OK; return CELL_OK;
} }
@ -361,7 +500,7 @@ int cellVdecStartSeq(u32 handle)
int cellVdecEndSeq(u32 handle) int cellVdecEndSeq(u32 handle)
{ {
cellVdec.Log("cellVdecEndSeq(handle=%d)", handle); cellVdec.Warning("cellVdecEndSeq(handle=%d)", handle);
VideoDecoder* vdec; VideoDecoder* vdec;
if (!Emu.GetIdManager().GetIDData(handle, vdec)) if (!Emu.GetIdManager().GetIDData(handle, vdec))
@ -369,6 +508,28 @@ int cellVdecEndSeq(u32 handle)
return CELL_VDEC_ERROR_ARG; return CELL_VDEC_ERROR_ARG;
} }
/*if (!vdec->job.IsEmpty())
{
Sleep(1);
return CELL_VDEC_ERROR_BUSY; // ???
}
if (!vdec->frames.IsEmpty())
{
Sleep(1);
return CELL_VDEC_ERROR_BUSY; // ???
}*/
while (!vdec->job.IsEmpty() || !vdec->frames.IsEmpty())
{
if (Emu.IsStopped())
{
ConLog.Warning("cellVdecEndSeq(%d) aborted", handle);
return CELL_OK;
}
Sleep(1);
}
vdec->job.Push(VdecTask(vdecEndSeq)); vdec->job.Push(VdecTask(vdecEndSeq));
return CELL_OK; return CELL_OK;
} }
@ -399,7 +560,7 @@ int cellVdecDecodeAu(u32 handle, CellVdecDecodeMode mode, const mem_ptr_t<CellVd
int cellVdecGetPicture(u32 handle, const mem_ptr_t<CellVdecPicFormat> format, u32 out_addr) int cellVdecGetPicture(u32 handle, const mem_ptr_t<CellVdecPicFormat> format, u32 out_addr)
{ {
cellVdec.Warning("cellVdecGetPicture(handle=%d, format_addr=0x%x, out_addr=0x%x)", handle, format.GetAddr(), out_addr); cellVdec.Log("cellVdecGetPicture(handle=%d, format_addr=0x%x, out_addr=0x%x)", handle, format.GetAddr(), out_addr);
VideoDecoder* vdec; VideoDecoder* vdec;
if (!Emu.GetIdManager().GetIDData(handle, vdec)) if (!Emu.GetIdManager().GetIDData(handle, vdec))
@ -412,14 +573,16 @@ int cellVdecGetPicture(u32 handle, const mem_ptr_t<CellVdecPicFormat> format, u3
return CELL_VDEC_ERROR_FATAL; return CELL_VDEC_ERROR_FATAL;
} }
if (!vdec->has_picture) if (vdec->frames.IsEmpty())
{ {
return CELL_VDEC_ERROR_EMPTY; return CELL_VDEC_ERROR_EMPTY;
} }
if (out_addr) if (out_addr)
{ {
if (!Memory.IsGoodAddr(out_addr, vdec->buf_size)) u32 buf_size = a128(av_image_get_buffer_size(vdec->ctx->pix_fmt, vdec->ctx->width, vdec->ctx->height, 1));
if (!Memory.IsGoodAddr(out_addr, buf_size))
{ {
return CELL_VDEC_ERROR_FATAL; return CELL_VDEC_ERROR_FATAL;
} }
@ -429,54 +592,47 @@ int cellVdecGetPicture(u32 handle, const mem_ptr_t<CellVdecPicFormat> format, u3
cellVdec.Error("cellVdecGetPicture: TODO: unknown formatType(%d)", (u32)format->formatType); cellVdec.Error("cellVdecGetPicture: TODO: unknown formatType(%d)", (u32)format->formatType);
return CELL_OK; return CELL_OK;
} }
if (format->colorMatrixType != CELL_VDEC_COLOR_MATRIX_TYPE_BT709) if (format->colorMatrixType != CELL_VDEC_COLOR_MATRIX_TYPE_BT709)
{ {
cellVdec.Error("cellVdecGetPicture: TODO: unknown colorMatrixType(%d)", (u32)format->colorMatrixType); cellVdec.Error("cellVdecGetPicture: TODO: unknown colorMatrixType(%d)", (u32)format->colorMatrixType);
return CELL_OK; return CELL_OK;
} }
AVFrame& frame = *vdec->frame; VdecFrame vf;
u8* buf = (u8*)malloc(vdec->buf_size); vdec->frames.Pop(vf);
if (!buf)
{ AVFrame& frame = *vf.data;
cellVdec.Error("cellVdecGetPicture: malloc failed (out of memory)");
Emu.Pause(); u8* buf = (u8*)malloc(buf_size);
return CELL_OK;
}
// TODO: zero padding bytes // TODO: zero padding bytes
int err = av_image_copy_to_buffer(buf, vdec->buf_size, frame.data, frame.linesize, vdec->ctx->pix_fmt, frame.width, frame.height, 1); int err = av_image_copy_to_buffer(buf, buf_size, frame.data, frame.linesize, vdec->ctx->pix_fmt, frame.width, frame.height, 1);
if (err < 0) if (err < 0)
{ {
cellVdec.Error("cellVdecGetPicture: av_image_copy_to_buffer failed(%d)", err); cellVdec.Error("cellVdecGetPicture: av_image_copy_to_buffer failed(%d)", err);
Emu.Pause(); Emu.Pause();
} }
if (!Memory.CopyFromReal(out_addr, buf, vdec->buf_size)) if (!Memory.CopyFromReal(out_addr, buf, buf_size))
{ {
cellVdec.Error("cellVdecGetPicture: data copying failed"); cellVdec.Error("cellVdecGetPicture: data copying failed");
Emu.Pause(); Emu.Pause();
} }
/* av_frame_unref(vf.data);
u32 size0 = frame.linesize[0] * frame.height; av_frame_free(&vf.data);
u32 size1 = frame.linesize[1] * frame.height / 2;
u32 size2 = frame.linesize[2] * frame.height / 2;
ConLog.Write("*** size0=0x%x, size1=0x%x, size2=0x%x, buf_size=0x%x (res=0x%x)", size0, size1, size2, vdec->buf_size, err);
*/
free(buf); free(buf);
} }
vdec->has_picture = false;
return CELL_OK; return CELL_OK;
} }
int cellVdecGetPicItem(u32 handle, mem32_t picItem_ptr) int cellVdecGetPicItem(u32 handle, mem32_t picItem_ptr)
{ {
cellVdec.Warning("cellVdecGetPicItem(handle=%d, picItem_ptr_addr=0x%x)", handle, picItem_ptr.GetAddr()); cellVdec.Log("cellVdecGetPicItem(handle=%d, picItem_ptr_addr=0x%x)", handle, picItem_ptr.GetAddr());
VideoDecoder* vdec; VideoDecoder* vdec;
if (!Emu.GetIdManager().GetIDData(handle, vdec)) if (!Emu.GetIdManager().GetIDData(handle, vdec))
@ -489,36 +645,47 @@ int cellVdecGetPicItem(u32 handle, mem32_t picItem_ptr)
return CELL_VDEC_ERROR_FATAL; return CELL_VDEC_ERROR_FATAL;
} }
if (!vdec->has_picture) VdecFrame& vf = vdec->frames.Peek();
if (vdec->frames.IsEmpty())
{ {
Sleep(1);
return CELL_VDEC_ERROR_EMPTY; return CELL_VDEC_ERROR_EMPTY;
} }
mem_ptr_t<CellVdecPicItem> info(vdec->memAddr); AVFrame& frame = *vf.data;
mem_ptr_t<CellVdecPicItem> info(vdec->memAddr + vdec->memBias);
vdec->memBias += 512;
if (vdec->memBias + 512 > vdec->memSize)
{
vdec->memBias = 0;
}
info->codecType = vdec->type; info->codecType = vdec->type;
info->startAddr = 0x00000123; // invalid value (no address for picture) info->startAddr = 0x00000123; // invalid value (no address for picture)
info->size = vdec->buf_size; info->size = a128(av_image_get_buffer_size(vdec->ctx->pix_fmt, vdec->ctx->width, vdec->ctx->height, 1));
info->auNum = 1; info->auNum = 1;
info->auPts[0].lower = vdec->pts; info->auPts[0].lower = vf.pts;
info->auPts[0].upper = vdec->pts >> 32; info->auPts[0].upper = vf.pts >> 32;
info->auPts[1].lower = 0xffffffff; info->auPts[1].lower = 0xffffffff;
info->auPts[1].upper = 0xffffffff; info->auPts[1].upper = 0xffffffff;
info->auDts[0].lower = vdec->dts; info->auDts[0].lower = vf.dts;
info->auDts[0].upper = vdec->dts >> 32; info->auDts[0].upper = vf.dts >> 32;
info->auDts[1].lower = 0xffffffff; info->auDts[1].lower = 0xffffffff;
info->auDts[1].upper = 0xffffffff; info->auDts[1].upper = 0xffffffff;
info->auUserData[0] = vdec->userdata; info->auUserData[0] = vf.userdata;
info->auUserData[1] = 0; info->auUserData[1] = 0;
info->status = CELL_OK; info->status = CELL_OK;
info->attr = CELL_VDEC_PICITEM_ATTR_NORMAL; info->attr = CELL_VDEC_PICITEM_ATTR_NORMAL;
info->picInfo_addr = vdec->memAddr + sizeof(CellVdecPicItem); info->picInfo_addr = info.GetAddr() + sizeof(CellVdecPicItem);
mem_ptr_t<CellVdecAvcInfo> avc(vdec->memAddr + sizeof(CellVdecPicItem)); mem_ptr_t<CellVdecAvcInfo> avc(info.GetAddr() + sizeof(CellVdecPicItem));
avc->horizontalSize = vdec->frame->width; // ??? avc->horizontalSize = frame.width;
avc->verticalSize = vdec->frame->height; avc->verticalSize = frame.height;
switch (vdec->frame->pict_type) switch (frame.pict_type)
{ {
case AV_PICTURE_TYPE_I: avc->pictureType[0] = CELL_VDEC_AVC_PCT_I; break; case AV_PICTURE_TYPE_I: avc->pictureType[0] = CELL_VDEC_AVC_PCT_I; break;
case AV_PICTURE_TYPE_P: avc->pictureType[0] = CELL_VDEC_AVC_PCT_P; break; case AV_PICTURE_TYPE_P: avc->pictureType[0] = CELL_VDEC_AVC_PCT_P; break;
@ -590,5 +757,6 @@ void cellVdec_init()
cellVdec.AddFunc(0x17c702b9, cellVdecGetPicItem); cellVdec.AddFunc(0x17c702b9, cellVdecGetPicItem);
cellVdec.AddFunc(0xe13ef6fc, cellVdecSetFrameRate); cellVdec.AddFunc(0xe13ef6fc, cellVdecSetFrameRate);
av_register_all();
avcodec_register_all(); avcodec_register_all();
} }

View File

@ -679,6 +679,14 @@ struct VdecTask
} }
}; };
struct VdecFrame
{
AVFrame* data;
u64 dts;
u64 pts;
u64 userdata;
};
int vdecRead(void* opaque, u8* buf, int buf_size); int vdecRead(void* opaque, u8* buf, int buf_size);
class VideoDecoder class VideoDecoder
@ -688,19 +696,11 @@ public:
u32 id; u32 id;
volatile bool is_running; volatile bool is_running;
volatile bool is_finished; volatile bool is_finished;
bool just_started;
AVCodec* codec;
AVCodecContext* ctx; AVCodecContext* ctx;
AVFormatContext* fmt; AVFormatContext* fmt;
AVFrame* frame;
AVDictionary* opts;
u8* io_buf; u8* io_buf;
u32 buf_size;
u64 pts;
u64 dts;
u64 pos;
u64 userdata;
volatile bool has_picture;
struct VideoReader struct VideoReader
{ {
@ -708,51 +708,39 @@ public:
u32 size; u32 size;
} reader; } reader;
SQueue<VdecFrame> frames;
const CellVdecCodecType type; const CellVdecCodecType type;
const u32 profile; const u32 profile;
const u32 memAddr; const u32 memAddr;
const u32 memSize; const u32 memSize;
const u32 cbFunc; const u32 cbFunc;
const u32 cbArg; const u32 cbArg;
u32 memBias;
VdecTask task; // current task variable
u64 last_pts, last_dts;
CPUThread* vdecCb;
VideoDecoder(CellVdecCodecType type, u32 profile, u32 addr, u32 size, u32 func, u32 arg) VideoDecoder(CellVdecCodecType type, u32 profile, u32 addr, u32 size, u32 func, u32 arg)
: type(type) : type(type)
, profile(profile) , profile(profile)
, memAddr(addr) , memAddr(addr)
, memSize(size) , memSize(size)
, memBias(0)
, cbFunc(func) , cbFunc(func)
, cbArg(arg) , cbArg(arg)
, is_finished(false) , is_finished(false)
, is_running(false) , is_running(false)
, has_picture(false) , just_started(false)
, pos(0) , ctx(nullptr)
, vdecCb(nullptr)
{ {
codec = avcodec_find_decoder(AV_CODEC_ID_H264); AVCodec* codec = avcodec_find_decoder(AV_CODEC_ID_H264);
if (!codec) if (!codec)
{ {
ConLog.Error("VideoDecoder(): avcodec_find_decoder failed"); ConLog.Error("VideoDecoder(): avcodec_find_decoder(H264) failed");
Emu.Pause();
return;
}
ctx = avcodec_alloc_context3(codec);
if (!ctx)
{
ConLog.Error("VideoDecoder(): avcodec_alloc_context3 failed");
Emu.Pause();
return;
}
opts = nullptr;
int err = avcodec_open2(ctx, codec, &opts);
if (err) // TODO: not multithread safe
{
ConLog.Error("VideoDecoder(): avcodec_open2 failed(%d)", err);
Emu.Pause();
return;
}
frame = av_frame_alloc();
if (!frame)
{
ConLog.Error("VideoDecoder(): av_frame_alloc failed");
Emu.Pause(); Emu.Pause();
return; return;
} }
@ -771,23 +759,29 @@ public:
Emu.Pause(); Emu.Pause();
return; return;
} }
//memset(&out_data, 0, sizeof(out_data));
//memset(&linesize, 0, sizeof(linesize));
} }
~VideoDecoder() ~VideoDecoder()
{ {
if (io_buf) av_free(io_buf);
if (fmt)
{
avformat_free_context(fmt);
}
if (frame) av_frame_free(&frame);
if (ctx) if (ctx)
{ {
for (u32 i = frames.GetCount() - 1; ~i; i--)
{
VdecFrame& vf = frames.Peek(i);
av_frame_unref(vf.data);
av_frame_free(&vf.data);
}
avcodec_close(ctx); avcodec_close(ctx);
av_free(ctx); avformat_close_input(&fmt);
}
if (fmt)
{
if (io_buf)
{
av_free(io_buf);
}
if (fmt->pb) av_free(fmt->pb);
avformat_free_context(fmt);
} }
//if (out_data[0]) av_freep(out_data[0]);
} }
}; };

View File

@ -77,7 +77,7 @@ int cellVpostClose(u32 handle)
int cellVpostExec(u32 handle, const u32 inPicBuff_addr, const mem_ptr_t<CellVpostCtrlParam> ctrlParam, int cellVpostExec(u32 handle, const u32 inPicBuff_addr, const mem_ptr_t<CellVpostCtrlParam> ctrlParam,
u32 outPicBuff_addr, mem_ptr_t<CellVpostPictureInfo> picInfo) u32 outPicBuff_addr, mem_ptr_t<CellVpostPictureInfo> picInfo)
{ {
cellVpost.Warning("cellVpostExec(handle=0x%x, inPicBuff_addr=0x%x, ctrlParam_addr=0x%x, outPicBuff_addr=0x%x, picInfo_addr=0x%x)", cellVpost.Log("cellVpostExec(handle=0x%x, inPicBuff_addr=0x%x, ctrlParam_addr=0x%x, outPicBuff_addr=0x%x, picInfo_addr=0x%x)",
handle, inPicBuff_addr, ctrlParam.GetAddr(), outPicBuff_addr, picInfo.GetAddr()); handle, inPicBuff_addr, ctrlParam.GetAddr(), outPicBuff_addr, picInfo.GetAddr());
VpostInstance* vpost; VpostInstance* vpost;
@ -139,31 +139,34 @@ int cellVpostExec(u32 handle, const u32 inPicBuff_addr, const mem_ptr_t<CellVpos
picInfo->reserved1 = 0; picInfo->reserved1 = 0;
picInfo->reserved2 = 0; picInfo->reserved2 = 0;
u8* pY = (u8*)malloc(w*h); u8* pY = (u8*)malloc(w*h); // color planes
u8* pU = (u8*)malloc(w*h/4); u8* pU = (u8*)malloc(w*h/4);
u8* pV = (u8*)malloc(w*h/4); u8* pV = (u8*)malloc(w*h/4);
u32* res = (u32*)malloc(w*h*4); u32* res = (u32*)malloc(w*h*4); // RGBA interleaved output
const u8 alpha = ctrlParam->outAlpha; const u8 alpha = ctrlParam->outAlpha;
if (!Memory.CopyToReal(pY, inPicBuff_addr, w*h)) if (!Memory.CopyToReal(pY, inPicBuff_addr, w*h))
{ {
cellVpost.Error("cellVpostExec: data copying failed(pY)"); cellVpost.Error("cellVpostExec: data copying failed(pY)");
Emu.Pause();
} }
if (!Memory.CopyToReal(pU, inPicBuff_addr + w*h, w*h/4)) if (!Memory.CopyToReal(pU, inPicBuff_addr + w*h, w*h/4))
{ {
cellVpost.Error("cellVpostExec: data copying failed(pU)"); cellVpost.Error("cellVpostExec: data copying failed(pU)");
Emu.Pause();
} }
if (!Memory.CopyToReal(pV, inPicBuff_addr + w*h + w*h/4, w*h/4)) if (!Memory.CopyToReal(pV, inPicBuff_addr + w*h + w*h/4, w*h/4))
{ {
cellVpost.Error("cellVpostExec: data copying failed(pV)"); cellVpost.Error("cellVpostExec: data copying failed(pV)");
Emu.Pause();
} }
for (u32 i = 0; i < h; i++) for (u32 j = 0; j < w; j++) for (u32 i = 0; i < h; i++) for (u32 j = 0; j < w; j++)
{ {
float Cr = pV[(i/2)*(w/2)+j/2]; float Cr = pV[(i/2)*(w/2)+j/2] - 128;
float Cb = pU[(i/2)*(w/2)+j/2]; float Cb = pU[(i/2)*(w/2)+j/2] - 128;
float Y = pY[i*w+j]; float Y = pY[i*w+j];
int R = Y + 1.5701f * Cr; int R = Y + 1.5701f * Cr;

View File

@ -0,0 +1,478 @@
#include "stdafx.h"
#include "Emu/SysCalls/SysCalls.h"
#include "Emu/SysCalls/SC_FUNC.h"
#include "libmixer.h"
void libmixer_init();
Module libmixer("libmixer", libmixer_init);
int cellAANAddData(u32 handle, u32 port, u32 offset, u32 addr, u32 samples)
{
libmixer.Error("cellAANAddData(handle=0x%x, port=0x%x, offset=0x%x, addr=0x%x, samples=0x%x)",
handle, port, offset, addr, samples);
return CELL_OK;
}
int cellAANConnect(u32 receive, u32 receivePortNo, u32 source, u32 sourcePortNo)
{
libmixer.Error("cellAANConnect(receive=0x%x, receivePortNo=0x%x, source=0x%x, sourcrPortNo=0x%x)",
receive, receivePortNo, source, sourcePortNo);
return 0;
}
int cellAANDisconnect(u32 receive, u32 receivePortNo, u32 source, u32 sourcePortNo)
{
libmixer.Error("cellAANDisconnect(receive=0x%x, receivePortNo=0x%x, source=0x%x, sourcrPortNo=0x%x)",
receive, receivePortNo, source, sourcePortNo);
return 0;
}
/*int cellSSPlayerCreate(CellAANHandle *handle, CellSSPlayerConfig *config)
{
UNIMPLEMENTED_FUNC(libmixer);
return 0;
}
int cellSSPlayerRemove(CellAANHandle handle)
{
UNIMPLEMENTED_FUNC(libmixer);
return 0;
}
int cellSSPlayerSetWave() //CellAANHandle handle, CellSSPlayerWaveParam *waveInfo, CellSSPlayerCommonParam *commonInfo //mem_class_t waveInfo
{
UNIMPLEMENTED_FUNC(libmixer);
return 0;
}
int cellSSPlayerPlay() //CellAANHandle handle, CellSSPlayerRuntimeInfo *info
{
UNIMPLEMENTED_FUNC(libmixer);
return 0;
}
int cellSSPlayerStop() //CellAANHandle handle, u32 mode
{
UNIMPLEMENTED_FUNC(libmixer);
return 0;
}
int cellSSPlayerSetParam() //CellAANHandle handle, CellSSPlayerRuntimeInfo *info
{
UNIMPLEMENTED_FUNC(libmixer);
return 0;
}
s32 cellSSPlayerGetState() //CellAANHandle handle
{
UNIMPLEMENTED_FUNC(libmixer);
return 0;
}*/
int cellSurMixerCreate(const mem_ptr_t<CellSurMixerConfig> config)
{
libmixer.Error("cellSurMixerCreate(config_addr=0x%x)", config.GetAddr());
return CELL_OK;
}
int cellSurMixerGetAANHandle(mem32_t handle)
{
libmixer.Error("cellSurMixerGetAANHandle(handle_addr=0x%x)", handle.GetAddr());
return CELL_OK;
}
int cellSurMixerChStripGetAANPortNo(mem32_t port, u32 type, u32 index)
{
libmixer.Error("cellSurMixerChStripGetAANPortNo(port_addr=0x%x, type=0x%x, index=0x%x)", port.GetAddr(), type, index);
return CELL_OK;
}
int cellSurMixerSetNotifyCallback(u32 func, u32 arg)
{
libmixer.Error("cellSurMixerSetNotifyCallback(func_addr=0x%x, arg=0x%x)", func, arg);
return CELL_OK;
}
int cellSurMixerRemoveNotifyCallback(u32 func)
{
libmixer.Error("cellSurMixerSetNotifyCallback(func_addr=0x%x)", func);
return CELL_OK;
}
int cellSurMixerStart()
{
libmixer.Error("cellSurMixerStart()");
return CELL_OK;
}
int cellSurMixerSetParameter(u32 param, float value)
{
libmixer.Error("cellSurMixerSetParameter(param=0x%x, value=%f)", param, value);
return CELL_OK;
}
int cellSurMixerFinalize()
{
libmixer.Error("cellSurMixerFinalize()");
return CELL_OK;
}
/*int cellSurMixerSurBusAddData() //u32 busNo, u32 offset, float *addr, u32 samples
{
UNIMPLEMENTED_FUNC(libmixer);
return 0;
}
int cellSurMixerChStripSetParameter() //u32 type, u32 index, CellSurMixerChStripParam *param
{
UNIMPLEMENTED_FUNC(libmixer);
return 0;
}
int cellSurMixerPause() //u32 switch
{
UNIMPLEMENTED_FUNC(libmixer);
return 0;
}
int cellSurMixerGetCurrentBlockTag() //u64 *tag
{
UNIMPLEMENTED_FUNC(libmixer);
return 0;
}
int cellSurMixerGetTimestamp() //u64 tag, u64 *stamp
{
UNIMPLEMENTED_FUNC(libmixer);
return 0;
}
void cellSurMixerBeep(); //void *arg
float cellSurMixerUtilGetLevelFromDB() //float dB
{
UNIMPLEMENTED_FUNC(libmixer);
return CELL_OK; //it's NOT real value
//TODO;
}
float cellSurMixerUtilGetLevelFromDBIndex() //int index
{
UNIMPLEMENTED_FUNC(libmixer);
return CELL_OK; //it's NOT real value
//TODO;
}
float cellSurMixerUtilNoteToRatio() //unsigned char refNote, unsigned char note
{
UNIMPLEMENTED_FUNC(libmixer);
return CELL_OK; //it's NOT real value
//TODO
}*/
void libmixer_init()
{
static const u64 cellAANAddData_table[] = {
// TODO
0xffffffff7c691b78,
0xffffffff7c0802a6,
0xfffffffff821ff91,
0xfffffffff8010080,
0xffffffff7c802378,
0xffffffff7caa2b78,
0xffffffff81690000,
0xffffffff7c050378,
0xffffffff7cc43378,
0xffffffff7d465378,
0xffffffff812b0030,
0xffffffff80090000,
0xfffffffff8410028,
0xffffffff7c0903a6,
0xffffffff80490004,
0xffffffff4e800421,
0xffffffffe8410028,
0xffffffffe8010080,
0xffffffff7c6307b4,
0xffffffff7c0803a6,
0xffffffff38210070,
0xffffffff4e800020,
0
};
libmixer.AddFuncSub(cellAANAddData_table, "cellAANAddData", cellAANAddData);
u64 cellAANConnect_table[39] = {
0xfffffffff821ff71,
0xffffffff7c0802a6,
0xffffffff2f830000,
0xfffffffff80100a0,
0xffffffff3c008031,
0xffffffff7c691b78,
0xffffffff7c8a2378,
0xffffffff60000003,
0xffffff00409e0018, // bne
0xffffffff7c0307b4,
0xffffffffe80100a0,
0xffffffff38210090,
0xffffffff7c0803a6,
0xffffffff4e800020,
0xffffffff2f850000,
0xffffffff78630020,
0xffffffff38810070,
0xffffff00419effe0, // beq
0xffffffff81690000,
0xffffffff38000001,
0xffffffff91210074,
0xffffffff90a10070,
0xffffffff90c10078,
0xffffffff9141007c,
0xffffffff812b0018, // [24]
0xffffffff90010080,
0xffffffff80090000,
0xfffffffff8410028,
0xffffffff7c0903a6,
0xffffffff80490004,
0xffffffff4e800421,
0xffffffffe8410028,
0xffffffff7c601b78,
0xffffffff7c0307b4,
0xffffffffe80100a0,
0xffffffff38210090,
0xffffffff7c0803a6,
0xffffffff4e800020,
0, // [38]
};
libmixer.AddFuncSub(cellAANConnect_table, "cellAANConnect", cellAANConnect);
cellAANConnect_table[24] = 0xffffffff812b001c;
libmixer.AddFuncSub(cellAANConnect_table, "cellAANDisconnect", cellAANDisconnect);
static const u64 cellAANAddData_table1[] = {
// TODO
0xffffffff7c691b78,
0xffffffff7c0802a6,
0xfffffffff821ff91,
0xfffffffff8010080,
0xffffffff7c802378,
0xffffffff7caa2b78,
0xffffffff81690000,
0xffffffff7c050378,
0xffffffff7cc43378,
0xffffffff78630020, // clrldi r3,r3,32
0xffffffff7d465378,
0xffffffff812b0030,
0xffffffff80090000,
0xfffffffff8410028,
0xffffffff7c0903a6,
0xffffffff80490004,
0xffffffff4e800421,
0xffffffffe8410028,
0xffffffffe8010080,
0xffffffff7c6307b4,
0xffffffff7c0803a6,
0xffffffff38210070,
0xffffffff4e800020,
0
};
libmixer.AddFuncSub(cellAANAddData_table1, "cellAANAddData(1)", cellAANAddData);
static const u64 cellSurMixerCreate_table[] = {
0xffffffff2f830000,
0xffffffff7c0802a6,
0xfffffffff821ff51,
0xfffffffffbc100a0,
0xfffffffffb210078,
0xfffffffffb410080,
0xfffffffffb610088,
0xfffffffffb810090,
0xfffffffffba10098,
0xfffffffffbe100a8,
0xfffffffff80100c0,
0xffffffff7c7e1b78,
0xf000000040000000, // bne
0xffffffff3fe08031,
0xffffffff63ff0003,
0xffffffffe80100c0,
0xffffffff7fe307b4,
0xffffffffeb210078,
0xffffffffeb410080,
0xffffffff7c0803a6,
0xffffffffeb610088,
0xffffffffeb810090,
0xffffffffeba10098,
0xffffffffebc100a0,
0xffffffffebe100a8,
0xffffffff382100b0,
0
};
libmixer.AddFuncSub(cellSurMixerCreate_table, "cellSurMixerCreate", cellSurMixerCreate);
static const u64 cellSurMixerGetAANHandle_table[] = {
// first instruction ignored
0xffffffff3d607fce,
0xffffffff616bfffe,
0xffffffff812a0018,
0xffffffff7d2afe70,
0xffffffff91230000,
0xffffffff7d404a78,
0xffffffff7c005050,
0xffffffff7c00fe70,
0xffffffff7c035838,
0xffffffff3c638031,
0xffffffff38630002,
0xffffffff7c6307b4,
0xffffffff4e800020,
0
};
libmixer.AddFuncSub(cellSurMixerGetAANHandle_table, "cellSurMixerGetAANHandle", cellSurMixerGetAANHandle);
static const u64 cellSurMixerChStripGetAANPortNo_table[] = {
// first instruction ignored
0xffffffff7c661b78,
0xffffffff3c608031,
0xffffffff78c60020,
0xffffffff78840020,
0xffffffff60630002,
0xffffffff80090018,
0xffffffff78a50020,
0xffffffff2f800000,
0xffffffff4d9e0020,
0xffffffff78030020,
0xf000000040000000, // b
0
};
libmixer.AddFuncSub(cellSurMixerChStripGetAANPortNo_table, "cellSurMixerChStripGetAANPortNo", cellSurMixerChStripGetAANPortNo);
static const u64 cellSurMixerSetNotifyCallback_table[] = {
// first instruction ignored
0xffffffff7c0802a6,
0xfffffffff821ff81,
0xfffffffff8010090,
0xffffffff7c6b1b78,
0xffffffff3c608031,
0xffffffff812a0018,
0xffffffff7c882378,
0xffffffff60630003,
0xffffffff2f890000,
0xffffffff2f0b0000,
0xffffff00409e0020, // bne
0xffffffff3c608031,
0xffffffff60630002,
0xffffffffe8010090,
0xffffffff7c6307b4,
0xffffffff38210080,
0xffffffff7c0803a6,
0xffffffff4e800020,
0xffffff00419affec, // beq
0xf0000000800a001c, // lwz
0xffffffff79290020,
0xffffffff38810070,
0xffffffff2f800000,
0xffffffff7d234b78,
0
};
libmixer.AddFuncSub(cellSurMixerSetNotifyCallback_table, "cellSurMixerSetNotifyCallback", cellSurMixerSetNotifyCallback);
static const u64 cellSurMixerRemoveNotifyCallback_table[] = {
// first instruction ignored
0xffffffff7c0802a6,
0xfffffffff821ff81,
0xfffffffff8010090,
0xffffffff7c6a1b78,
0xffffffff3d208031,
0xffffffff806b0018,
0xffffffff61290002,
0xffffffff2f830000,
0xf0000000409e0018, // bne
0xffffffffe8010090,
0xffffffff7d2307b4,
0xffffffff38210080,
0xffffffff7c0803a6,
0xffffffff4e800020,
0
};
libmixer.AddFuncSub(cellSurMixerRemoveNotifyCallback_table, "cellSurMixerRemoveNotifyCallback", cellSurMixerRemoveNotifyCallback);
static const u64 cellSurMixerStart_table[] = {
0xfffffffff821ff71,
0xffffffff7c0802a6,
0xfffffffffbc10080,
0xf000000083c20000, // lwz
0xfffffffff80100a0,
0xfffffffffba10078,
0xfffffffffbe10088,
0xffffffff801e0018,
0xffffffff2f800000,
0xf0000000409e002c, // bne
0xffffffff3fe08031,
0xffffffff63ff0002,
0xffffffffe80100a0,
0xffffffff7fe307b4,
0xffffffffeba10078,
0xffffffffebc10080,
0xffffffff7c0803a6,
0xffffffffebe10088,
0xffffffff38210090,
0xffffffff4e800020,
0
};
libmixer.AddFuncSub(cellSurMixerStart_table, "cellSurMixerStart", cellSurMixerStart);
static const u64 cellSurMixerSetParameter_table[] = {
0xfffffffff821ff81,
0xffffffff7c0802a6,
0xfffffffffbc10070,
0xfffffffffc000890,
0xf000000083c28250, // lwz
0xffffffff3d208031,
0xfffffffff8010090,
0xfffffffffbe10078,
0xffffffff61290002,
0xffffffff7c7f1b78,
0xffffffff801e0018,
0xffffffff2f800000,
0xffff0000409e0020, // bne
0xffffffffe8010090,
0xffffffff7d2307b4,
0xffffffffebc10070,
0xffffffffebe10078,
0xffffffff7c0803a6,
0xffffffff38210080,
0xffffffff4e800020,
0xffffffff801e001c,
0xffffffff2b03001f,
0xffffffff2f800000,
0xffff0000419cffd8, // blt
0xffffffff2b83002b,
0xffff000040990008, // ble
0xffff0000409d0054, // ble
0
};
libmixer.AddFuncSub(cellSurMixerSetParameter_table, "cellSurMixerSetParameter", cellSurMixerSetParameter);
static const u64 cellSurMixerFinalize_table[] = {
0xfffffffff821ff91,
0xffffffff7c0802a6,
0xfffffffff8010080,
0xffffff004bfffde1, // bl
0xffffffffe8010080,
0xffffffff38600000,
0xffffffff38210070,
0xffffffff7c0803a6,
0xffffffff4e800020,
0xfffffffff821ff71,
0xffffffff7c0802a6,
0xfffffffffba10078,
0xf000000083a28250, // lwz
0xfffffffff80100a0,
0xffffffff817d0018,
0xffffffff7d635b78,
0xffffffff812b0000,
0xffffffff81490000,
0xffffffff800a0000,
0xfffffffff8410028,
0xffffffff7c0903a6,
0xffffffff804a0004,
0xffffffff4e800421,
0
};
libmixer.AddFuncSub(cellSurMixerFinalize_table, "cellSurMixerFinalize", cellSurMixerFinalize);
}

View File

@ -0,0 +1,63 @@
#pragma once
//Callback Functions
typedef int (*CellSurMixerNotifyCallbackFunction)(void *arg, u32 counter, u32 samples); //Currently unused.
//libmixer datatypes
typedef void * CellAANHandle;
struct CellSSPlayerConfig
{
be_t<u32> channels;
be_t<u32> outputMode;
};
struct CellSSPlayerWaveParam
{
void *addr;
be_t<s32> format;
be_t<u32> samples;
be_t<u32> loopStartOffset;
be_t<u32> startOffset;
};
struct CellSSPlayerCommonParam
{
be_t<u32> loopMode;
be_t<u32> attackMode;
};
struct CellSurMixerPosition
{
be_t<float> x;
be_t<float> y;
be_t<float> z;
};
struct CellSSPlayerRuntimeInfo
{
be_t<float> level;
be_t<float> speed;
CellSurMixerPosition position;
};
struct CellSurMixerConfig
{
be_t<s32> priority;
be_t<u32> chStrips1;
be_t<u32> chStrips2;
be_t<u32> chStrips6;
be_t<u32> chStrips8;
};
struct CellSurMixerChStripParam
{
be_t<u32> param;
void *attribute;
be_t<s32> dBSwitch;
be_t<float> floatVal;
be_t<s32> intVal;
};
CellSSPlayerWaveParam current_SSPlayerWaveParam;

View File

@ -0,0 +1,65 @@
#include "stdafx.h"
#include "Modules.h"
#include "Emu/SysCalls/SysCalls.h"
#include "Emu/SysCalls/SC_FUNC.h"
extern ArrayF<SFunc> g_static_funcs_list;
void StaticAnalyse(void* ptr, u32 size)
{
u32* data = (u32*)ptr; size /= 4;
return; // disabled
// TODO: optimize search
for (u32 i = 0; i < size; i++)
{
for (u32 j = 0; j < g_static_funcs_list.GetCount(); j++)
{
if ((data[i] & g_static_funcs_list[j].ops[0].mask) == g_static_funcs_list[j].ops[0].crc && (i + g_static_funcs_list[j].ops.GetCount()) < size)
{
bool found = true;
for (u32 k = i + 1, x = 1; x < g_static_funcs_list[j].ops.GetCount(); k++, x++)
{
// skip NOP
if (data[k] == se32(0x60000000))
{
k++;
continue;
}
if ((data[k] & g_static_funcs_list[j].ops[x].mask) != g_static_funcs_list[j].ops[x].crc)
{
found = false;
break;
}
}
if (found)
{
ConLog.Success("Function '%s' hooked", wxString(g_static_funcs_list[j].name).wx_str());
data[i] = re(0x39600000 | j); // li r11, j
data[i+1] = se32(0x44000003); // sc 3
data[i+2] = se32(0x4e800020); // blr
i += 2; // ???
}
}
}
}
}
void StaticExecute(u32 code)
{
if (code < g_static_funcs_list.GetCount())
{
(*g_static_funcs_list[code].func)();
}
else
{
ConLog.Error("StaticExecute(%d): unknown function or illegal opcode", code);
}
}
void StaticFinalize()
{
g_static_funcs_list.Clear();
}

View File

@ -201,9 +201,9 @@ extern int sys_rwlock_trywlock(u32 rw_lock_id);
extern int sys_rwlock_wunlock(u32 rw_lock_id); extern int sys_rwlock_wunlock(u32 rw_lock_id);
//ppu_thread //ppu_thread
extern void sys_ppu_thread_exit(int errorcode); extern void sys_ppu_thread_exit(u64 errorcode);
extern int sys_ppu_thread_yield(); extern int sys_ppu_thread_yield();
extern int sys_ppu_thread_join(u32 thread_id, u32 vptr_addr); extern int sys_ppu_thread_join(u32 thread_id, mem64_t vptr);
extern int sys_ppu_thread_detach(u32 thread_id); extern int sys_ppu_thread_detach(u32 thread_id);
extern void sys_ppu_thread_get_join_state(u32 isjoinable_addr); extern void sys_ppu_thread_get_join_state(u32 isjoinable_addr);
extern int sys_ppu_thread_set_priority(u32 thread_id, int prio); extern int sys_ppu_thread_set_priority(u32 thread_id, int prio);
@ -433,3 +433,7 @@ public:
}; };
//extern SysCalls SysCallsManager; //extern SysCalls SysCallsManager;
void StaticAnalyse(void* ptr, u32 size);
void StaticExecute(u32 code);
void StaticFinalize();

View File

@ -77,8 +77,26 @@ int sys_cond_signal(u32 cond_id)
if (u32 target = (mutex->protocol == SYS_SYNC_PRIORITY ? cond->m_queue.pop_prio() : cond->m_queue.pop())) if (u32 target = (mutex->protocol == SYS_SYNC_PRIORITY ? cond->m_queue.pop_prio() : cond->m_queue.pop()))
{ {
CPUThread* tt = Emu.GetCPU().GetThread(target);
bool valid = tt && tt->IsAlive();
if (!valid)
{
sys_cond.Error("sys_cond_signal(%d): signal to invalid thread(%d)", cond_id, target);
return CELL_OK;
}
if (!was_locked) // mutex hasn't been locked (don't care about mutex state) if (!was_locked) // mutex hasn't been locked (don't care about mutex state)
{ {
if (u32 owner = mutex->m_mutex.GetOwner())
{
tt = Emu.GetCPU().GetThread(owner);
valid = tt && tt->IsAlive();
if (!valid)
{
sys_cond.Error("sys_cond_signal(%d): deadlock on invalid thread(%d)", cond_id, owner);
return CELL_OK;
}
}
mutex->m_mutex.lock(tid); mutex->m_mutex.lock(tid);
mutex->recursive = 1; mutex->recursive = 1;
mutex->m_mutex.unlock(tid, target); mutex->m_mutex.unlock(tid, target);
@ -117,8 +135,26 @@ int sys_cond_signal_all(u32 cond_id)
while (u32 target = (mutex->protocol == SYS_SYNC_PRIORITY ? cond->m_queue.pop_prio() : cond->m_queue.pop())) while (u32 target = (mutex->protocol == SYS_SYNC_PRIORITY ? cond->m_queue.pop_prio() : cond->m_queue.pop()))
{ {
CPUThread* tt = Emu.GetCPU().GetThread(target);
bool valid = tt && tt->IsAlive();
if (!valid)
{
sys_cond.Error("sys_cond_signal_all(%d): signal to invalid thread(%d)", cond_id, target);
return CELL_OK;
}
if (!was_locked) if (!was_locked)
{ {
if (u32 owner = mutex->m_mutex.GetOwner())
{
tt = Emu.GetCPU().GetThread(owner);
valid = tt && tt->IsAlive();
if (!valid)
{
sys_cond.Error("sys_cond_signal_all(%d): deadlock on invalid thread(%d)", cond_id, owner);
return CELL_OK;
}
}
mutex->m_mutex.lock(tid); mutex->m_mutex.lock(tid);
mutex->recursive = 1; mutex->recursive = 1;
mutex->m_mutex.unlock(tid, target); mutex->m_mutex.unlock(tid, target);
@ -130,11 +166,11 @@ int sys_cond_signal_all(u32 cond_id)
mutex->m_mutex.lock(tid); mutex->m_mutex.lock(tid);
mutex->recursive = 1; mutex->recursive = 1;
} }
}
if (Emu.IsStopped()) if (Emu.IsStopped())
{ {
ConLog.Warning("sys_cond_signal_all(id=%d) aborted", cond_id); ConLog.Warning("sys_cond_signal_all(id=%d) aborted", cond_id);
}
} }
return CELL_OK; return CELL_OK;
@ -169,6 +205,16 @@ int sys_cond_signal_to(u32 cond_id, u32 thread_id)
{ {
if (!was_locked) if (!was_locked)
{ {
if (u32 owner = mutex->m_mutex.GetOwner())
{
CPUThread* tt = Emu.GetCPU().GetThread(owner);
bool valid = tt && tt->IsAlive();
if (!valid)
{
sys_cond.Error("sys_cond_signal_to(%d): deadlock on invalid thread(%d)", cond_id, owner);
return CELL_OK;
}
}
mutex->m_mutex.lock(tid); mutex->m_mutex.lock(tid);
mutex->recursive = 1; mutex->recursive = 1;
mutex->m_mutex.unlock(tid, target); mutex->m_mutex.unlock(tid, target);

View File

@ -74,17 +74,17 @@ int sys_event_queue_destroy(u32 equeue_id, int mode)
u32 tid = GetCurrentPPUThread().GetId(); u32 tid = GetCurrentPPUThread().GetId();
eq->sq.m_mutex.lock(tid); eq->sq.m_mutex.lock();
eq->owner.lock(tid); eq->owner.lock(tid);
// check if some threads are waiting for an event // check if some threads are waiting for an event
if (!mode && eq->sq.list.GetCount()) if (!mode && eq->sq.list.GetCount())
{ {
eq->owner.unlock(tid); eq->owner.unlock(tid);
eq->sq.m_mutex.unlock(tid); eq->sq.m_mutex.unlock();
return CELL_EBUSY; return CELL_EBUSY;
} }
eq->owner.unlock(tid, ~0); eq->owner.unlock(tid, ~0);
eq->sq.m_mutex.unlock(tid); eq->sq.m_mutex.unlock();
while (eq->sq.list.GetCount()) while (eq->sq.list.GetCount())
{ {
Sleep(1); Sleep(1);
@ -136,18 +136,18 @@ int sys_event_queue_tryreceive(u32 equeue_id, mem_ptr_t<sys_event_data> event_ar
u32 tid = GetCurrentPPUThread().GetId(); u32 tid = GetCurrentPPUThread().GetId();
eq->sq.m_mutex.lock(tid); eq->sq.m_mutex.lock();
eq->owner.lock(tid); eq->owner.lock(tid);
if (eq->sq.list.GetCount()) if (eq->sq.list.GetCount())
{ {
number = 0; number = 0;
eq->owner.unlock(tid); eq->owner.unlock(tid);
eq->sq.m_mutex.unlock(tid); eq->sq.m_mutex.unlock();
return CELL_OK; return CELL_OK;
} }
number = eq->events.pop_all((sys_event_data*)(Memory + event_array.GetAddr()), size); number = eq->events.pop_all((sys_event_data*)(Memory + event_array.GetAddr()), size);
eq->owner.unlock(tid); eq->owner.unlock(tid);
eq->sq.m_mutex.unlock(tid); eq->sq.m_mutex.unlock();
return CELL_OK; return CELL_OK;
} }

View File

@ -57,7 +57,7 @@ int sys_lwmutex_destroy(mem_ptr_t<sys_lwmutex_t> lwmutex)
{ {
case CELL_OK: case CELL_OK:
lwmutex->all_info() = 0; lwmutex->all_info() = 0;
lwmutex->attribute = 0; lwmutex->attribute = 0xDEADBEEF;
lwmutex->sleep_queue = 0; lwmutex->sleep_queue = 0;
Emu.GetIdManager().RemoveID(sq_id); Emu.GetIdManager().RemoveID(sq_id);
default: return res; default: return res;
@ -99,13 +99,13 @@ int sys_lwmutex_unlock(mem_ptr_t<sys_lwmutex_t> lwmutex)
void SleepQueue::push(u32 tid) void SleepQueue::push(u32 tid)
{ {
SMutexLocker lock(m_mutex); std::lock_guard<std::mutex> lock(m_mutex);
list.AddCpy(tid); list.AddCpy(tid);
} }
u32 SleepQueue::pop() // SYS_SYNC_FIFO u32 SleepQueue::pop() // SYS_SYNC_FIFO
{ {
SMutexLocker lock(m_mutex); std::lock_guard<std::mutex> lock(m_mutex);
while (true) while (true)
{ {
@ -125,7 +125,7 @@ u32 SleepQueue::pop() // SYS_SYNC_FIFO
u32 SleepQueue::pop_prio() // SYS_SYNC_PRIORITY u32 SleepQueue::pop_prio() // SYS_SYNC_PRIORITY
{ {
SMutexLocker lock(m_mutex); std::lock_guard<std::mutex> lock(m_mutex);
while (true) while (true)
{ {
@ -171,7 +171,7 @@ u32 SleepQueue::pop_prio_inherit() // (TODO)
bool SleepQueue::invalidate(u32 tid) bool SleepQueue::invalidate(u32 tid)
{ {
SMutexLocker lock(m_mutex); std::lock_guard<std::mutex> lock(m_mutex);
if (tid) for (u32 i = 0; i < list.GetCount(); i++) if (tid) for (u32 i = 0; i < list.GetCount(); i++)
{ {
@ -187,15 +187,13 @@ bool SleepQueue::invalidate(u32 tid)
bool SleepQueue::finalize() bool SleepQueue::finalize()
{ {
u32 tid = GetCurrentPPUThread().GetId(); if (!m_mutex.try_lock()) return false;
m_mutex.lock(tid);
for (u32 i = 0; i < list.GetCount(); i++) for (u32 i = 0; i < list.GetCount(); i++)
{ {
if (list[i]) if (list[i])
{ {
m_mutex.unlock(tid); m_mutex.unlock();
return false; return false;
} }
} }
@ -205,9 +203,42 @@ bool SleepQueue::finalize()
int sys_lwmutex_t::trylock(be_t<u32> tid) int sys_lwmutex_t::trylock(be_t<u32> tid)
{ {
if (!attribute.ToBE()) return CELL_EINVAL; if (attribute.ToBE() == se32(0xDEADBEEF)) return CELL_EINVAL;
if (tid == mutex.GetOwner()) be_t<u32> owner_tid = mutex.GetOwner();
if (owner_tid != mutex.GetFreeValue())
{
if (CPUThread* tt = Emu.GetCPU().GetThread(owner_tid))
{
if (!tt->IsAlive())
{
sc_lwmutex.Error("sys_lwmutex_t::(try)lock(%d): deadlock on invalid thread(%d)", (u32)sleep_queue, (u32)owner_tid);
mutex.unlock(owner_tid, tid);
recursive_count = 1;
return CELL_OK;
}
}
else
{
sc_lwmutex.Error("sys_lwmutex_t::(try)lock(%d): deadlock on invalid thread(%d)", (u32)sleep_queue, (u32)owner_tid);
mutex.unlock(owner_tid, tid);
recursive_count = 1;
return CELL_OK;
}
}
/*while ((attribute.ToBE() & se32(SYS_SYNC_ATTR_RECURSIVE_MASK)) == 0)
{
if (Emu.IsStopped())
{
ConLog.Warning("(hack) sys_lwmutex_t::(try)lock aborted (waiting for recursive attribute, attr=0x%x)", (u32)attribute);
return CELL_ESRCH;
}
Sleep(1);
}*/
if (tid == owner_tid)
{ {
if (attribute.ToBE() & se32(SYS_SYNC_RECURSIVE)) if (attribute.ToBE() & se32(SYS_SYNC_RECURSIVE))
{ {
@ -237,6 +268,11 @@ int sys_lwmutex_t::unlock(be_t<u32> tid)
} }
else else
{ {
if (!recursive_count || (recursive_count.ToBE() != se32(1) && (attribute.ToBE() & se32(SYS_SYNC_NOT_RECURSIVE))))
{
sc_lwmutex.Error("sys_lwmutex_t::unlock(%d): wrong recursive value (%d)", (u32)sleep_queue, (u32)recursive_count);
recursive_count = 1;
}
recursive_count -= 1; recursive_count -= 1;
if (!recursive_count.ToBE()) if (!recursive_count.ToBE())
{ {

View File

@ -47,7 +47,7 @@ struct SleepQueue
q_rec(u32 tid, u64 prio): tid(tid), prio(prio) {} q_rec(u32 tid, u64 prio): tid(tid), prio(prio) {}
}; */ }; */
Array<u32> list; Array<u32> list;
SMutex m_mutex; std::mutex m_mutex;
u64 m_name; u64 m_name;
SleepQueue(u64 name = 0) SleepQueue(u64 name = 0)
@ -65,7 +65,7 @@ struct SleepQueue
struct sys_lwmutex_t struct sys_lwmutex_t
{ {
/* volatile */ SMutexBase<be_t<u32>, ~0, 0> mutex; /* volatile */ SMutexBase<be_t<u32>> mutex;
/* volatile */ be_t<u32> waiter; // not used /* volatile */ be_t<u32> waiter; // not used
u64 &all_info(){return *(reinterpret_cast<u64*>(this));} u64 &all_info(){return *(reinterpret_cast<u64*>(this));}
be_t<u32> attribute; be_t<u32> attribute;

View File

@ -52,12 +52,12 @@ int sys_memory_allocate(u32 size, u32 flags, u32 alloc_addr_addr)
{ {
case SYS_MEMORY_PAGE_SIZE_1M: case SYS_MEMORY_PAGE_SIZE_1M:
if(size & 0xfffff) return CELL_EALIGN; if(size & 0xfffff) return CELL_EALIGN;
addr = Memory.Alloc(size, 1); addr = Memory.Alloc(size, 0x100000);
break; break;
case SYS_MEMORY_PAGE_SIZE_64K: case SYS_MEMORY_PAGE_SIZE_64K:
if(size & 0xffff) return CELL_EALIGN; if(size & 0xffff) return CELL_EALIGN;
addr = Memory.Alloc(size, 1); addr = Memory.Alloc(size, 0x10000);
break; break;
default: return CELL_EINVAL; default: return CELL_EINVAL;

View File

@ -37,7 +37,13 @@ int sys_mutex_create(mem32_t mutex_id, mem_ptr_t<sys_mutex_attribute> attr)
return CELL_EINVAL; return CELL_EINVAL;
} }
mutex_id = sys_mtx.GetNewId(new Mutex((u32)attr->protocol, is_recursive, attr->name_u64)); u32 tid = GetCurrentPPUThread().GetId();
Mutex* mutex = new Mutex((u32)attr->protocol, is_recursive, attr->name_u64);
u32 id = sys_mtx.GetNewId(mutex);
mutex->m_mutex.lock(tid);
mutex->id = id;
mutex_id = id;
mutex->m_mutex.unlock(tid);
sys_mtx.Warning("*** mutex created [%s] (protocol=0x%x, recursive=%s): id = %d", sys_mtx.Warning("*** mutex created [%s] (protocol=0x%x, recursive=%s): id = %d",
wxString(attr->name, 8).wx_str(), (u32)attr->protocol, wxString(attr->name, 8).wx_str(), (u32)attr->protocol,
wxString(is_recursive ? "true" : "false").wx_str(), mutex_id.GetValue()); wxString(is_recursive ? "true" : "false").wx_str(), mutex_id.GetValue());
@ -90,7 +96,8 @@ int sys_mutex_lock(u32 mutex_id, u64 timeout)
return CELL_ESRCH; return CELL_ESRCH;
} }
u32 tid = GetCurrentPPUThread().GetId(); PPUThread& t = GetCurrentPPUThread();
u32 tid = t.GetId();
u32 owner = mutex->m_mutex.GetOwner(); u32 owner = mutex->m_mutex.GetOwner();
if (owner == tid) if (owner == tid)
@ -108,17 +115,32 @@ int sys_mutex_lock(u32 mutex_id, u64 timeout)
return CELL_EDEADLK; return CELL_EDEADLK;
} }
} }
else if (owner && !Emu.GetIdManager().CheckID(owner)) else if (owner)
{ {
sys_mtx.Error("sys_mutex_lock(%d): deadlock on invalid thread(%d)", mutex_id, owner); if (CPUThread* tt = Emu.GetCPU().GetThread(owner))
mutex->m_mutex.unlock(owner, tid); {
mutex->recursive = 1; if (!tt->IsAlive())
return CELL_OK; {
if (owner == mutex->m_mutex.GetOwner()) sys_mtx.Error("sys_mutex_lock(%d): deadlock on invalid thread(%d)", mutex_id, owner);
/*mutex->m_mutex.unlock(owner, tid);
mutex->recursive = 1;
t.owned_mutexes++;
return CELL_OK;*/
}
}
else
{
sys_mtx.Error("sys_mutex_lock(%d): deadlock on invalid thread(%d)", mutex_id, owner);
/*mutex->m_mutex.unlock(owner, tid);
mutex->recursive = 1;
t.owned_mutexes++;
return CELL_OK;*/
}
} }
switch (mutex->m_mutex.trylock(tid)) switch (mutex->m_mutex.trylock(tid))
{ {
case SMR_OK: mutex->recursive = 1; return CELL_OK; case SMR_OK: mutex->recursive = 1; t.owned_mutexes++; return CELL_OK;
case SMR_FAILED: break; case SMR_FAILED: break;
default: goto abort; default: goto abort;
} }
@ -130,7 +152,7 @@ int sys_mutex_lock(u32 mutex_id, u64 timeout)
case SMR_OK: case SMR_OK:
mutex->m_queue.invalidate(tid); mutex->m_queue.invalidate(tid);
case SMR_SIGNAL: case SMR_SIGNAL:
mutex->recursive = 1; return CELL_OK; mutex->recursive = 1; t.owned_mutexes++; return CELL_OK;
case SMR_TIMEOUT: case SMR_TIMEOUT:
mutex->m_queue.invalidate(tid); return CELL_ETIMEDOUT; mutex->m_queue.invalidate(tid); return CELL_ETIMEDOUT;
default: default:
@ -156,7 +178,8 @@ int sys_mutex_trylock(u32 mutex_id)
return CELL_ESRCH; return CELL_ESRCH;
} }
u32 tid = GetCurrentPPUThread().GetId(); PPUThread& t = GetCurrentPPUThread();
u32 tid = t.GetId();
u32 owner = mutex->m_mutex.GetOwner(); u32 owner = mutex->m_mutex.GetOwner();
if (owner == tid) if (owner == tid)
@ -174,17 +197,32 @@ int sys_mutex_trylock(u32 mutex_id)
return CELL_EDEADLK; return CELL_EDEADLK;
} }
} }
else if (owner && !Emu.GetIdManager().CheckID(owner)) else if (owner)
{ {
sys_mtx.Error("sys_mutex_trylock(%d): deadlock on invalid thread(%d)", mutex_id, owner); if (CPUThread* tt = Emu.GetCPU().GetThread(owner))
mutex->m_mutex.unlock(owner, tid); {
mutex->recursive = 1; if (!tt->IsAlive())
return CELL_OK; {
if (owner == mutex->m_mutex.GetOwner()) sys_mtx.Error("sys_mutex_trylock(%d): deadlock on invalid thread(%d)", mutex_id, owner);
/*mutex->m_mutex.unlock(owner, tid);
mutex->recursive = 1;
t.owned_mutexes++;
return CELL_OK;*/
}
}
else
{
sys_mtx.Error("sys_mutex_trylock(%d): deadlock on invalid thread(%d)", mutex_id, owner);
/*mutex->m_mutex.unlock(owner, tid);
mutex->recursive = 1;
t.owned_mutexes++;
return CELL_OK;*/
}
} }
switch (mutex->m_mutex.trylock(tid)) switch (mutex->m_mutex.trylock(tid))
{ {
case SMR_OK: mutex->recursive = 1; return CELL_OK; case SMR_OK: mutex->recursive = 1; t.owned_mutexes++; return CELL_OK;
} }
return CELL_EBUSY; return CELL_EBUSY;
@ -200,18 +238,21 @@ int sys_mutex_unlock(u32 mutex_id)
return CELL_ESRCH; return CELL_ESRCH;
} }
u32 tid = GetCurrentPPUThread().GetId(); PPUThread& t = GetCurrentPPUThread();
u32 tid = t.GetId();
if (mutex->m_mutex.GetOwner() == tid) if (mutex->m_mutex.GetOwner() == tid)
{ {
if (!mutex->recursive || (mutex->recursive > 1 && !mutex->is_recursive)) if (!mutex->recursive || (mutex->recursive != 1 && !mutex->is_recursive))
{ {
sys_mtx.Warning("sys_mutex_unlock(%d): wrong recursive value (%d)", mutex_id, mutex->recursive); sys_mtx.Error("sys_mutex_unlock(%d): wrong recursive value fixed (%d)", mutex_id, mutex->recursive);
mutex->recursive = 1;
} }
mutex->recursive--; mutex->recursive--;
if (!mutex->recursive) if (!mutex->recursive)
{ {
mutex->m_mutex.unlock(tid, mutex->protocol == SYS_SYNC_PRIORITY ? mutex->m_queue.pop_prio() : mutex->m_queue.pop()); mutex->m_mutex.unlock(tid, mutex->protocol == SYS_SYNC_PRIORITY ? mutex->m_queue.pop_prio() : mutex->m_queue.pop());
t.owned_mutexes--;
} }
return CELL_OK; return CELL_OK;
} }

View File

@ -18,6 +18,7 @@ struct sys_mutex_attribute
struct Mutex struct Mutex
{ {
u32 id;
SMutex m_mutex; SMutex m_mutex;
SleepQueue m_queue; SleepQueue m_queue;
u32 recursive; // recursive locks count u32 recursive; // recursive locks count
@ -33,4 +34,21 @@ struct Mutex
, cond_count(0) , cond_count(0)
{ {
} }
~Mutex()
{
if (u32 owner = m_mutex.GetOwner())
{
ConLog.Write("Mutex(%d) was owned by thread %d (recursive=%d)", id, owner, recursive);
}
if (!m_queue.m_mutex.try_lock()) return;
for (u32 i = 0; i < m_queue.list.GetCount(); i++)
{
if (u32 owner = m_queue.list[i]) ConLog.Write("Mutex(%d) was waited by thread %d", id, owner);
}
m_queue.m_mutex.unlock();
}
}; };

View File

@ -10,24 +10,21 @@ enum
SYS_PPU_THREAD_DONE_INIT, SYS_PPU_THREAD_DONE_INIT,
}; };
void sys_ppu_thread_exit(int errorcode) void sys_ppu_thread_exit(u64 errorcode)
{ {
if(errorcode == 0) sysPrxForUser.Log("sys_ppu_thread_exit(0x%llx)", errorcode);
{
sysPrxForUser.Log("sys_ppu_thread_exit(errorcode=%d)", errorcode);
}
else
{
sysPrxForUser.Warning("sys_ppu_thread_exit(errorcode=%d)", errorcode);
}
PPUThread& thr = GetCurrentPPUThread(); PPUThread& thr = GetCurrentPPUThread();
u32 tid = thr.GetId();
if (thr.owned_mutexes)
{
ConLog.Error("Owned mutexes found (%d)", thr.owned_mutexes);
thr.owned_mutexes = 0;
}
thr.SetExitStatus(errorcode); thr.SetExitStatus(errorcode);
thr.Stop(); thr.Stop();
//Emu.GetCPU().RemoveThread(thr.GetId());
//throw errorcode;
} }
int sys_ppu_thread_yield() int sys_ppu_thread_yield()
@ -37,14 +34,24 @@ int sys_ppu_thread_yield()
return CELL_OK; return CELL_OK;
} }
int sys_ppu_thread_join(u32 thread_id, u32 vptr_addr) int sys_ppu_thread_join(u32 thread_id, mem64_t vptr)
{ {
sysPrxForUser.Warning("sys_ppu_thread_join(thread_id=%d, vptr_addr=0x%x)", thread_id, vptr_addr); sysPrxForUser.Warning("sys_ppu_thread_join(thread_id=%d, vptr_addr=0x%x)", thread_id, vptr.GetAddr());
CPUThread* thr = Emu.GetCPU().GetThread(thread_id); CPUThread* thr = Emu.GetCPU().GetThread(thread_id);
if(!thr) return CELL_ESRCH; if(!thr) return CELL_ESRCH;
GetCurrentPPUThread().Wait(*thr); while (thr->IsAlive())
{
if (Emu.IsStopped())
{
ConLog.Warning("sys_ppu_thread_join(%d) aborted", thread_id);
return CELL_OK;
}
Sleep(1);
}
vptr = thr->GetExitStatus();
return CELL_OK; return CELL_OK;
} }

View File

@ -267,6 +267,8 @@ void Emulator::Load()
ppu_thr_exit_data += ADDI(11, 0, 41); ppu_thr_exit_data += ADDI(11, 0, 41);
ppu_thr_exit_data += SC(2); ppu_thr_exit_data += SC(2);
ppu_thr_exit_data += BCLR(0x10 | 0x04, 0, 0, 0); ppu_thr_exit_data += BCLR(0x10 | 0x04, 0, 0, 0);
Memory.Write64(Memory.PRXMem.AllocAlign(0x10000), 0xDEADBEEFABADCAFE);
} }
break; break;

View File

@ -246,6 +246,7 @@ bool ELF64Loader::LoadPhdrData(u64 offset)
{ {
elf64_f.Seek(phdr_arr[i].p_offset); elf64_f.Seek(phdr_arr[i].p_offset);
elf64_f.Read(&Memory[offset + phdr_arr[i].p_vaddr], phdr_arr[i].p_filesz); elf64_f.Read(&Memory[offset + phdr_arr[i].p_vaddr], phdr_arr[i].p_filesz);
StaticAnalyse(&Memory[offset + phdr_arr[i].p_vaddr], phdr_arr[i].p_filesz);
} }
} }
break; break;

View File

@ -299,17 +299,20 @@
<ClCompile Include="Emu\SysCalls\Modules\cellPngDec.cpp" /> <ClCompile Include="Emu\SysCalls\Modules\cellPngDec.cpp" />
<ClCompile Include="Emu\SysCalls\Modules\cellResc.cpp" /> <ClCompile Include="Emu\SysCalls\Modules\cellResc.cpp" />
<ClCompile Include="Emu\SysCalls\Modules\cellRtc.cpp" /> <ClCompile Include="Emu\SysCalls\Modules\cellRtc.cpp" />
<ClCompile Include="Emu\SysCalls\Modules\cellSpurs.cpp" />
<ClCompile Include="Emu\SysCalls\Modules\cellSync.cpp" /> <ClCompile Include="Emu\SysCalls\Modules\cellSync.cpp" />
<ClCompile Include="Emu\SysCalls\Modules\cellSysmodule.cpp" /> <ClCompile Include="Emu\SysCalls\Modules\cellSysmodule.cpp" />
<ClCompile Include="Emu\SysCalls\Modules\cellSysutil.cpp" /> <ClCompile Include="Emu\SysCalls\Modules\cellSysutil.cpp" />
<ClCompile Include="Emu\SysCalls\Modules\cellSysutilAp.cpp" /> <ClCompile Include="Emu\SysCalls\Modules\cellSysutilAp.cpp" />
<ClCompile Include="Emu\SysCalls\Modules\cellVdec.cpp" /> <ClCompile Include="Emu\SysCalls\Modules\cellVdec.cpp" />
<ClCompile Include="Emu\SysCalls\Modules\cellVpost.cpp" /> <ClCompile Include="Emu\SysCalls\Modules\cellVpost.cpp" />
<ClCompile Include="Emu\SysCalls\Modules\libmixer.cpp" />
<ClCompile Include="Emu\SysCalls\Modules\sceNp.cpp" /> <ClCompile Include="Emu\SysCalls\Modules\sceNp.cpp" />
<ClCompile Include="Emu\SysCalls\Modules\sceNpTrophy.cpp" /> <ClCompile Include="Emu\SysCalls\Modules\sceNpTrophy.cpp" />
<ClCompile Include="Emu\SysCalls\Modules\sysPrxForUser.cpp" /> <ClCompile Include="Emu\SysCalls\Modules\sysPrxForUser.cpp" />
<ClCompile Include="Emu\SysCalls\Modules\sys_fs.cpp" /> <ClCompile Include="Emu\SysCalls\Modules\sys_fs.cpp" />
<ClCompile Include="Emu\SysCalls\Modules\sys_io.cpp" /> <ClCompile Include="Emu\SysCalls\Modules\sys_io.cpp" />
<ClCompile Include="Emu\SysCalls\Static.cpp" />
<ClCompile Include="Emu\SysCalls\SysCalls.cpp" /> <ClCompile Include="Emu\SysCalls\SysCalls.cpp" />
<ClCompile Include="Emu\System.cpp" /> <ClCompile Include="Emu\System.cpp" />
<ClCompile Include="Gui\CompilerELF.cpp" /> <ClCompile Include="Gui\CompilerELF.cpp" />

View File

@ -439,12 +439,21 @@
<ClCompile Include="Crypto\utils.cpp"> <ClCompile Include="Crypto\utils.cpp">
<Filter>Crypto</Filter> <Filter>Crypto</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="Emu\SysCalls\Static.cpp">
<Filter>Emu\SysCalls</Filter>
</ClCompile>
<ClCompile Include="Emu\SysCalls\Modules\cellNetCtl.cpp"> <ClCompile Include="Emu\SysCalls\Modules\cellNetCtl.cpp">
<Filter>Emu\SysCalls\Modules</Filter> <Filter>Emu\SysCalls\Modules</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="Emu\SysCalls\Modules\cellL10n.cpp"> <ClCompile Include="Emu\SysCalls\Modules\cellL10n.cpp">
<Filter>Emu\SysCalls\Modules</Filter> <Filter>Emu\SysCalls\Modules</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="Emu\SysCalls\Modules\libmixer.cpp">
<Filter>Emu\SysCalls\Modules</Filter>
</ClCompile>
<ClCompile Include="Emu\SysCalls\Modules\cellSpurs.cpp">
<Filter>Emu\SysCalls\Modules</Filter>
</ClCompile>
<ClCompile Include="Emu\Audio\AudioDumper.cpp"> <ClCompile Include="Emu\Audio\AudioDumper.cpp">
<Filter>Emu\Audio</Filter> <Filter>Emu\Audio</Filter>
</ClCompile> </ClCompile>