mirror of
https://github.com/RPCS3/rpcs3.git
synced 2025-03-01 16:13:23 +00:00
commit
2f65e84562
@ -145,15 +145,19 @@ public:
|
||||
{
|
||||
if (!tid)
|
||||
{
|
||||
ConLog.Error("SMutexLockerBase: thread id == 0");
|
||||
Emu.Pause();
|
||||
if (!Emu.IsStopped())
|
||||
{
|
||||
ConLog.Error("SMutexLockerBase: thread id == 0");
|
||||
Emu.Pause();
|
||||
}
|
||||
return;
|
||||
}
|
||||
sm.lock(tid);
|
||||
}
|
||||
|
||||
~SMutexLockerBase()
|
||||
{
|
||||
sm.unlock(tid);
|
||||
if (tid) sm.unlock(tid);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -19,11 +19,6 @@ public:
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
if (Emu.IsStopped())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (m_mutex.GetOwner() == m_mutex.GetDeadValue())
|
||||
{
|
||||
return false;
|
||||
@ -31,6 +26,10 @@ public:
|
||||
|
||||
if (m_count >= SQSize)
|
||||
{
|
||||
if (Emu.IsStopped())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
Sleep(1);
|
||||
continue;
|
||||
}
|
||||
@ -51,11 +50,6 @@ public:
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
if (Emu.IsStopped())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (m_mutex.GetOwner() == m_mutex.GetDeadValue())
|
||||
{
|
||||
return false;
|
||||
@ -63,6 +57,10 @@ public:
|
||||
|
||||
if (!m_count)
|
||||
{
|
||||
if (Emu.IsStopped())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
Sleep(1);
|
||||
continue;
|
||||
}
|
||||
@ -96,4 +94,10 @@ public:
|
||||
SMutexLocker lock(m_mutex);
|
||||
m_count = 0;
|
||||
}
|
||||
|
||||
T& Peek(u32 pos = 0)
|
||||
{
|
||||
SMutexLocker lock(m_mutex);
|
||||
return m_data[(m_pos + pos) % SQSize];
|
||||
}
|
||||
};
|
||||
|
@ -108,7 +108,7 @@ struct CellAudioPortConfig
|
||||
|
||||
struct AudioPortConfig
|
||||
{
|
||||
SMutex m_mutex;
|
||||
SMutexGeneral m_mutex;
|
||||
bool m_is_audio_port_opened;
|
||||
bool m_is_audio_port_started;
|
||||
u8 channel;
|
||||
@ -152,64 +152,6 @@ struct AudioConfig //custom structure
|
||||
}
|
||||
} 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
|
||||
struct CellSnd3DataCtx
|
||||
{
|
||||
|
@ -360,3 +360,44 @@ void CPUThread::Task()
|
||||
|
||||
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;
|
||||
}
|
@ -57,7 +57,7 @@ protected:
|
||||
u64 m_stack_size;
|
||||
u64 m_stack_point;
|
||||
|
||||
u32 m_exit_status;
|
||||
u64 m_exit_status;
|
||||
|
||||
CPUDecoder* m_dec;
|
||||
|
||||
@ -80,10 +80,10 @@ public:
|
||||
void SetName(const std::string& name);
|
||||
void SetPrio(const u64 prio) { m_prio = prio; }
|
||||
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; }
|
||||
u32 GetExitStatus() const { return m_exit_status; }
|
||||
u64 GetExitStatus() const { return m_exit_status; }
|
||||
u64 GetPrio() const { return m_prio; }
|
||||
|
||||
std::string GetName() const { return NamedThreadBase::GetThreadName(); }
|
||||
@ -234,6 +234,8 @@ public:
|
||||
return pc + 4;
|
||||
}
|
||||
|
||||
s64 ExecAsCallback(u64 pc, bool wait, u64 a1 = 0, u64 a2 = 0, u64 a3 = 0, u64 a4 = 0);
|
||||
|
||||
protected:
|
||||
virtual void DoReset()=0;
|
||||
virtual void DoRun()=0;
|
||||
|
@ -71,10 +71,16 @@ private:
|
||||
|
||||
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)
|
||||
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
|
||||
ConLog.Write("SysCall[%lld] done with code [0x%llx]! #pc: 0x%llx", CPU.GPR[11], CPU.GPR[3], CPU.PC);
|
||||
#endif
|
||||
@ -2088,6 +2094,14 @@ private:
|
||||
{
|
||||
case 0x1: UNK(wxString::Format("HyperCall %d", CPU.GPR[0])); 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;
|
||||
default: UNK(wxString::Format("Unknown sc: %x", sc_code));
|
||||
}
|
||||
|
@ -17,6 +17,7 @@ PPUThread& GetCurrentPPUThread()
|
||||
|
||||
PPUThread::PPUThread() : PPCThread(CPU_THREAD_PPU)
|
||||
{
|
||||
owned_mutexes = 0;
|
||||
Reset();
|
||||
}
|
||||
|
||||
@ -118,14 +119,11 @@ void PPUThread::InitRegs()
|
||||
GPR[6] = m_args[3];
|
||||
}
|
||||
|
||||
u32 prx_mem = Memory.PRXMem.AllocAlign(0x10000);
|
||||
Memory.Write64(prx_mem, 0xDEADBEEFABADCAFE);
|
||||
|
||||
GPR[0] = pc;
|
||||
GPR[8] = entry;
|
||||
GPR[11] = 0x80;
|
||||
GPR[12] = Emu.GetMallocPageSize();
|
||||
GPR[13] = prx_mem + 0x7060;
|
||||
GPR[13] = Memory.PRXMem.GetStartAddr() + 0x7060;
|
||||
GPR[28] = GPR[4];
|
||||
GPR[29] = GPR[3];
|
||||
GPR[31] = GPR[5];
|
||||
|
@ -525,6 +525,9 @@ static const s32 MAX_INT_VALUE = 0x7fffffff;
|
||||
|
||||
class PPUThread : public PPCThread
|
||||
{
|
||||
public:
|
||||
std::atomic<u32> owned_mutexes;
|
||||
|
||||
public:
|
||||
PPCdouble FPR[32]; //Floating Point Register
|
||||
FPSCRhdr FPSCR; //Floating Point Status and Control Register
|
||||
|
@ -53,7 +53,7 @@ void Callback::Branch(bool wait)
|
||||
{
|
||||
m_has_data = false;
|
||||
|
||||
static SMutexGeneral cb_mutex;
|
||||
static std::mutex cb_mutex;
|
||||
|
||||
CPUThread& thr = Emu.GetCallbackThread();
|
||||
|
||||
@ -69,7 +69,7 @@ again:
|
||||
Sleep(1);
|
||||
}
|
||||
|
||||
SMutexGeneralLocker lock(cb_mutex);
|
||||
std::lock_guard<std::mutex> lock(cb_mutex);
|
||||
|
||||
if (thr.IsAlive())
|
||||
{
|
||||
|
@ -8,6 +8,7 @@ uint g_max_module_id = 0;
|
||||
uint g_module_2_count = 0;
|
||||
ArrayF<ModuleFunc> g_modules_funcs_list;
|
||||
std::mutex g_funcs_lock;
|
||||
ArrayF<SFunc> g_static_funcs_list;
|
||||
|
||||
struct ModuleInfo
|
||||
{
|
||||
|
@ -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
|
||||
{
|
||||
std::string m_name;
|
||||
@ -94,6 +109,8 @@ public:
|
||||
}
|
||||
|
||||
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>
|
||||
@ -102,6 +119,29 @@ __forceinline void Module::AddFunc(u32 id, T 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 CallFunc(u32 num);
|
||||
bool UnloadFunc(u32 id);
|
||||
|
@ -1,64 +1,586 @@
|
||||
#include "stdafx.h"
|
||||
#include "Emu/SysCalls/SysCalls.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"
|
||||
|
||||
void 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)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
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());
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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());
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
int cellAdecGetPcm(u32 handle, u32 outBuffer_addr)
|
||||
{
|
||||
cellAdec.Error("cellAdecGetPcm(handle=0x%x, outBuffer_addr=0x%x)", handle, outBuffer_addr);
|
||||
return CELL_OK;
|
||||
cellAdec.Log("cellAdecGetPcm(handle=%d, outBuffer_addr=0x%x)", handle, outBuffer_addr);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@ -73,4 +595,7 @@ void cellAdec_init()
|
||||
cellAdec.AddFunc(0x1529e506, cellAdecDecodeAu);
|
||||
cellAdec.AddFunc(0x97ff2af1, cellAdecGetPcm);
|
||||
cellAdec.AddFunc(0xbd75f78b, cellAdecGetPcmItem);
|
||||
|
||||
av_register_all();
|
||||
avcodec_register_all();
|
||||
}
|
@ -1,5 +1,6 @@
|
||||
#pragma once
|
||||
#include "cellPamf.h"
|
||||
|
||||
#include "Utilities/SQueue.h"
|
||||
|
||||
// Error Codes
|
||||
enum
|
||||
@ -341,6 +342,17 @@ struct CellAdecResource
|
||||
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
|
||||
enum CellAdecMsgType
|
||||
{
|
||||
@ -348,12 +360,14 @@ enum CellAdecMsgType
|
||||
CELL_ADEC_MSG_TYPE_PCMOUT,
|
||||
CELL_ADEC_MSG_TYPE_ERROR,
|
||||
CELL_ADEC_MSG_TYPE_SEQDONE,
|
||||
};
|
||||
};
|
||||
|
||||
typedef mem_func_ptr_t<int (*)(u32 handle, CellAdecMsgType msgType, int msgData, u32 cbArg)> CellAdecCbMsg;
|
||||
|
||||
struct CellAdecCb
|
||||
{
|
||||
be_t<mem_func_ptr_t<int (*)(u32 handle, CellAdecMsgType msgType, int msgData, u32 cbArg_addr)>> cbFunc;
|
||||
be_t<u32> cbArg_addr;
|
||||
be_t<u32> cbFunc;
|
||||
be_t<u32> cbArg;
|
||||
};
|
||||
|
||||
typedef CellCodecTimeStamp CellAdecTimeStamp;
|
||||
@ -399,17 +413,6 @@ struct CellAdecLpcmInfo
|
||||
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
|
||||
enum CELP_ExcitationMode
|
||||
{
|
||||
@ -985,3 +988,143 @@ struct CellAdecMpmcInfo
|
||||
be_t<u32> lfePresent;
|
||||
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);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -6,9 +6,8 @@
|
||||
#include "Emu/Audio/AudioDumper.h"
|
||||
|
||||
void cellAudio_init();
|
||||
void cellAudio_load();
|
||||
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();
|
||||
|
||||
@ -107,7 +106,7 @@ int cellAudioInit()
|
||||
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.tag++; // absolute index of block that will be read
|
||||
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];
|
||||
|
||||
SMutexLocker lock(port.m_mutex);
|
||||
SMutexGeneralLocker lock(port.m_mutex);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
SMutexLocker lock(port.m_mutex);
|
||||
SMutexGeneralLocker lock(port.m_mutex);
|
||||
|
||||
u64 tag_base = port.tag;
|
||||
if (tag_base % port.block > blockNo)
|
||||
@ -546,168 +545,6 @@ int cellAudioUnsetPersonalDevice(int iPersonalStream)
|
||||
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
|
||||
s32 cellSnd3Init() //u32 maxVoice, u32 samples, CellSnd3RequestQueueCtx *queue
|
||||
{
|
||||
@ -1149,14 +986,7 @@ void cellAudio_init()
|
||||
//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()
|
||||
{
|
||||
m_config.m_is_audio_initialized = false;
|
||||
m_config.Clear();
|
||||
//StaticFinalize();
|
||||
}
|
@ -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)
|
||||
{
|
||||
if (esFilterId->filterIdMajor >= 0xe0)
|
||||
attr->memSize = 0x600000; // 0x45fa49 from ps3
|
||||
attr->memSize = 0x1000000; // 0x45fa49 from ps3
|
||||
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,
|
||||
(u32)esFilterId->supplementalInfo1, (u32)esFilterId->supplementalInfo2);
|
||||
@ -30,10 +30,14 @@ u32 dmuxOpen(Demuxer* data)
|
||||
{
|
||||
Demuxer& dmux = *data;
|
||||
|
||||
dmux.dmuxCb = &Emu.GetCPU().AddThread(CPU_THREAD_PPU);
|
||||
|
||||
u32 dmux_id = cellDmux.GetNewId(data);
|
||||
|
||||
dmux.id = dmux_id;
|
||||
|
||||
dmux.dmuxCb->SetName("Demuxer[" + std::to_string(dmux_id) + "] Callback");
|
||||
|
||||
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);
|
||||
@ -50,6 +54,9 @@ u32 dmuxOpen(Demuxer* data)
|
||||
|
||||
u32 cb_add = 0;
|
||||
|
||||
u32 updates_count = 0;
|
||||
u32 updates_signaled = 0;
|
||||
|
||||
while (true)
|
||||
{
|
||||
if (Emu.IsStopped())
|
||||
@ -66,9 +73,17 @@ u32 dmuxOpen(Demuxer* data)
|
||||
|
||||
if (!stream.peek(code))
|
||||
{
|
||||
dmux.is_running = false;
|
||||
// demuxing finished
|
||||
task.type = dmuxResetStream;
|
||||
goto task;
|
||||
mem_ptr_t<CellDmuxMsg> dmuxMsg(a128(dmux.memAddr) + (cb_add ^= 16));
|
||||
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())
|
||||
{
|
||||
@ -102,12 +117,61 @@ u32 dmuxOpen(Demuxer* data)
|
||||
|
||||
case PRIVATE_STREAM_1:
|
||||
{
|
||||
DemuxerStream backup = stream;
|
||||
|
||||
// audio AT3+ (and probably LPCM or user data)
|
||||
stream.skip(4);
|
||||
stream.get(len);
|
||||
|
||||
// skipping...
|
||||
stream.skip(len);
|
||||
PesHeader pes(stream);
|
||||
|
||||
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;
|
||||
|
||||
@ -121,10 +185,14 @@ u32 dmuxOpen(Demuxer* data)
|
||||
if (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);
|
||||
continue;
|
||||
}
|
||||
|
||||
DemuxerStream backup = stream;
|
||||
@ -133,33 +201,28 @@ u32 dmuxOpen(Demuxer* data)
|
||||
stream.get(len);
|
||||
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 (es.hasunseen()) // hack, probably useless
|
||||
/*if (es.hasunseen()) // hack, probably useless
|
||||
{
|
||||
stream = backup;
|
||||
continue;
|
||||
}
|
||||
}*/
|
||||
es.finish(stream);
|
||||
// callback
|
||||
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;
|
||||
/*Callback cb;
|
||||
cb.SetAddr(es.cbFunc);
|
||||
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)
|
||||
{
|
||||
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())
|
||||
@ -167,8 +230,10 @@ u32 dmuxOpen(Demuxer* data)
|
||||
stream = backup;
|
||||
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
|
||||
{
|
||||
@ -218,24 +283,11 @@ u32 dmuxOpen(Demuxer* data)
|
||||
{
|
||||
break; // Emu is stopped
|
||||
}
|
||||
task:
|
||||
|
||||
switch (task.type)
|
||||
{
|
||||
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;
|
||||
ConLog.Write("*** stream updated(addr=0x%x, size=0x%x, discont=%d, userdata=0x%llx)",
|
||||
stream.addr, stream.size, stream.discontinuity, stream.userdata);
|
||||
@ -246,6 +298,7 @@ task:
|
||||
esALL[i]->reset();
|
||||
}
|
||||
}
|
||||
updates_count++;
|
||||
dmux.is_running = true;
|
||||
}
|
||||
break;
|
||||
@ -253,14 +306,16 @@ task:
|
||||
case dmuxResetStream:
|
||||
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));
|
||||
dmuxMsg->msgType = CELL_DMUX_MSG_TYPE_DEMUX_DONE;
|
||||
dmuxMsg->supplementalInfo = stream.userdata;
|
||||
Callback cb;
|
||||
/*Callback cb;
|
||||
cb.SetAddr(dmux.cbFunc);
|
||||
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;
|
||||
}
|
||||
break;
|
||||
@ -283,6 +338,13 @@ task:
|
||||
{
|
||||
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
|
||||
{
|
||||
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;
|
||||
|
||||
case dmuxReleaseAu:
|
||||
/*case dmuxReleaseAu:
|
||||
{
|
||||
task.es.es_ptr->release();
|
||||
}
|
||||
break;
|
||||
break;*/
|
||||
|
||||
case dmuxFlushEs:
|
||||
{
|
||||
@ -328,20 +390,22 @@ task:
|
||||
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;
|
||||
/*Callback cb;
|
||||
cb.SetAddr(es.cbFunc);
|
||||
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
|
||||
mem_ptr_t<CellDmuxEsMsg> esMsg(a128(dmux.memAddr) + (cb_add ^= 16));
|
||||
esMsg->msgType = CELL_DMUX_ES_MSG_TYPE_FLUSH_DONE;
|
||||
esMsg->supplementalInfo = stream.userdata;
|
||||
Callback cb;
|
||||
/*Callback cb;
|
||||
cb.SetAddr(es.cbFunc);
|
||||
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;
|
||||
|
||||
@ -507,6 +571,7 @@ int cellDmuxClose(u32 demuxerHandle)
|
||||
Sleep(1);
|
||||
}
|
||||
|
||||
if (dmux->dmuxCb) Emu.GetCPU().RemoveThread(dmux->dmuxCb->GetId());
|
||||
Emu.GetIdManager().RemoveID(demuxerHandle);
|
||||
return CELL_OK;
|
||||
}
|
||||
@ -527,9 +592,14 @@ int cellDmuxSetStream(u32 demuxerHandle, const u32 streamAddress, u32 streamSize
|
||||
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;
|
||||
}
|
||||
|
||||
@ -851,7 +921,7 @@ int cellDmuxPeekAuEx(u32 esHandle, mem32_t auInfoEx_ptr, mem32_t auSpecificInfo_
|
||||
|
||||
int cellDmuxReleaseAu(u32 esHandle)
|
||||
{
|
||||
cellDmux.Warning("(disabled) cellDmuxReleaseAu(esHandle=0x%x)", esHandle);
|
||||
cellDmux.Log("cellDmuxReleaseAu(esHandle=0x%x)", esHandle);
|
||||
|
||||
return CELL_OK;
|
||||
|
||||
@ -865,14 +935,19 @@ int cellDmuxReleaseAu(u32 esHandle)
|
||||
{
|
||||
cellDmux.Error("cellDmuxReleaseAu: no AU");
|
||||
return CELL_DMUX_ERROR_SEQ;
|
||||
//return CELL_OK;
|
||||
}
|
||||
|
||||
DemuxerTask task(dmuxReleaseAu);
|
||||
/*DemuxerTask task(dmuxReleaseAu);
|
||||
task.es.es = esHandle;
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -329,11 +329,11 @@ struct DemuxerStream
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@ -364,45 +364,54 @@ struct PesHeader
|
||||
{
|
||||
u64 pts;
|
||||
u64 dts;
|
||||
u8 ch;
|
||||
u8 size;
|
||||
bool new_au;
|
||||
|
||||
PesHeader(DemuxerStream& stream)
|
||||
: pts(0xffffffffffffffff)
|
||||
, dts(0xffffffffffffffff)
|
||||
, ch(0)
|
||||
, size(0)
|
||||
, new_au(true)
|
||||
, new_au(false)
|
||||
{
|
||||
u16 header;
|
||||
stream.get(header);
|
||||
stream.get(size);
|
||||
if (size)
|
||||
{
|
||||
//ConLog.Write(">>>>> Pes Header (size=%d)", size);
|
||||
if (size < 10)
|
||||
{
|
||||
stream.skip(size);
|
||||
return;
|
||||
}
|
||||
new_au = true;
|
||||
u8 empty = 0;
|
||||
u8 v;
|
||||
stream.get(v);
|
||||
if ((v & 0xF0) != 0x30)
|
||||
while (true)
|
||||
{
|
||||
ConLog.Error("Pts not found");
|
||||
Emu.Pause();
|
||||
}
|
||||
pts = stream.get_ts(v);
|
||||
stream.get(v);
|
||||
if ((v & 0xF0) != 0x10)
|
||||
stream.get(v);
|
||||
if (v != 0xFF) break; // skip padding bytes
|
||||
empty++;
|
||||
if (empty = size) return;
|
||||
};
|
||||
|
||||
if ((v & 0xF0) == 0x20 && (size - empty) >= 5) // pts only
|
||||
{
|
||||
ConLog.Error("Dts not found");
|
||||
Emu.Pause();
|
||||
new_au = true;
|
||||
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,
|
||||
dmuxDisableEs,
|
||||
dmuxResetEs,
|
||||
dmuxReleaseAu,
|
||||
dmuxFlushEs,
|
||||
dmuxClose,
|
||||
};
|
||||
@ -461,6 +469,7 @@ public:
|
||||
volatile bool is_finished;
|
||||
volatile bool is_running;
|
||||
|
||||
CPUThread* dmuxCb;
|
||||
|
||||
Demuxer(u32 addr, u32 size, u32 func, u32 arg)
|
||||
: is_finished(false)
|
||||
@ -469,6 +478,7 @@ public:
|
||||
, memSize(size)
|
||||
, cbFunc(func)
|
||||
, 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)
|
||||
: dmux(dmux)
|
||||
, memAddr(addr)
|
||||
, memSize(size)
|
||||
, memAddr(a128(addr))
|
||||
, memSize(size - (addr - memAddr))
|
||||
, fidMajor(fidMajor)
|
||||
, fidMinor(fidMinor)
|
||||
, sup1(sup1)
|
||||
@ -508,7 +518,7 @@ public:
|
||||
, spec(spec)
|
||||
, first_addr(0)
|
||||
, peek_addr(0)
|
||||
, last_addr(a128(addr))
|
||||
, last_addr(memAddr)
|
||||
, last_size(0)
|
||||
{
|
||||
}
|
||||
@ -523,8 +533,9 @@ public:
|
||||
return last_size;
|
||||
}
|
||||
|
||||
bool isfull() // not multithread-safe
|
||||
bool isfull()
|
||||
{
|
||||
SMutexLocker lock(mutex);
|
||||
if (first_addr)
|
||||
{
|
||||
if (first_addr > last_addr)
|
||||
@ -570,7 +581,24 @@ public:
|
||||
{
|
||||
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);
|
||||
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");
|
||||
Emu.Pause();
|
||||
@ -590,7 +618,7 @@ public:
|
||||
mem_ptr_t<CellDmuxAuInfoEx> info(last_addr);
|
||||
info->auAddr = last_addr + 128;
|
||||
info->auSize = last_size;
|
||||
if (pes.size)
|
||||
if (pes.new_au)
|
||||
{
|
||||
info->dts.lower = (u32)pes.dts;
|
||||
info->dts.upper = (u32)(pes.dts >> 32);
|
||||
@ -607,7 +635,7 @@ public:
|
||||
mem_ptr_t<CellDmuxAuInfo> inf(last_addr + 64);
|
||||
inf->auAddr = last_addr + 128;
|
||||
inf->auSize = last_size;
|
||||
if (pes.size)
|
||||
if (pes.new_au)
|
||||
{
|
||||
inf->dtsLower = (u32)pes.dts;
|
||||
inf->dtsUpper = (u32)(pes.dts >> 32);
|
||||
@ -623,20 +651,26 @@ public:
|
||||
return first_addr;
|
||||
}
|
||||
|
||||
void release()
|
||||
bool release()
|
||||
{
|
||||
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())
|
||||
{
|
||||
ConLog.Error("ElementaryStream::release(): buffer is empty");
|
||||
Emu.Pause();
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
u32 size = a128(Memory.Read32(first_addr + 4) + 128);
|
||||
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)
|
||||
{
|
||||
first_addr = 0;
|
||||
@ -649,6 +683,8 @@ public:
|
||||
{
|
||||
first_addr = new_addr;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool peek(u32& out_data, bool no_ex, u32& out_spec, bool update_index)
|
||||
@ -687,7 +723,7 @@ public:
|
||||
SMutexLocker lock(mutex);
|
||||
first_addr = 0;
|
||||
peek_addr = 0;
|
||||
last_addr = a128(memAddr);
|
||||
last_addr = memAddr;
|
||||
last_size = 0;
|
||||
}
|
||||
};
|
||||
|
235
rpcs3/Emu/SysCalls/Modules/cellSpurs.cpp
Normal file
235
rpcs3/Emu/SysCalls/Modules/cellSpurs.cpp
Normal 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
|
||||
}
|
296
rpcs3/Emu/SysCalls/Modules/cellSpurs.h
Normal file
296
rpcs3/Emu/SysCalls/Modules/cellSpurs.h
Normal 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;
|
||||
};
|
||||
|
@ -3,6 +3,8 @@
|
||||
#include "Emu/SysCalls/SC_FUNC.h"
|
||||
#include "cellPamf.h"
|
||||
|
||||
SMutexGeneral g_mutex_avcodec_open2;
|
||||
|
||||
extern "C"
|
||||
{
|
||||
#include "libavcodec/avcodec.h"
|
||||
@ -19,10 +21,68 @@ int vdecRead(void* opaque, u8* buf, int buf_size)
|
||||
{
|
||||
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)
|
||||
{
|
||||
return AVERROR_EOF;
|
||||
return res;
|
||||
}
|
||||
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.size -= buf_size;
|
||||
return buf_size;
|
||||
return res + buf_size;
|
||||
}
|
||||
}
|
||||
|
||||
@ -60,15 +120,19 @@ u32 vdecOpen(VideoDecoder* data)
|
||||
{
|
||||
VideoDecoder& vdec = *data;
|
||||
|
||||
vdec.vdecCb = &Emu.GetCPU().AddThread(CPU_THREAD_PPU);
|
||||
|
||||
u32 vdec_id = cellVdec.GetNewId(data);
|
||||
|
||||
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", [&]()
|
||||
{
|
||||
ConLog.Write("Video Decoder enter()");
|
||||
|
||||
VdecTask task;
|
||||
VdecTask& task = vdec.task;
|
||||
|
||||
while (true)
|
||||
{
|
||||
@ -79,12 +143,11 @@ u32 vdecOpen(VideoDecoder* data)
|
||||
|
||||
if (vdec.job.IsEmpty() && vdec.is_running)
|
||||
{
|
||||
// TODO: default task (not needed?)
|
||||
Sleep(1);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (vdec.has_picture) // hack
|
||||
if (vdec.frames.GetCount() >= 50)
|
||||
{
|
||||
Sleep(1);
|
||||
continue;
|
||||
@ -100,55 +163,36 @@ u32 vdecOpen(VideoDecoder* data)
|
||||
case vdecStartSeq:
|
||||
{
|
||||
// TODO: reset data
|
||||
ConLog.Warning("vdecStartSeq()");
|
||||
ConLog.Warning("vdecStartSeq:");
|
||||
|
||||
vdec.reader.addr = 0;
|
||||
vdec.reader.size = 0;
|
||||
vdec.is_running = true;
|
||||
vdec.just_started = true;
|
||||
}
|
||||
break;
|
||||
|
||||
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.Handle(vdec.id, CELL_VDEC_MSG_TYPE_SEQDONE, 0, vdec.cbArg);
|
||||
cb.Branch(false);
|
||||
ConLog.Warning("vdecEndSeq()");
|
||||
cb.Handle(vdec.id, CELL_VDEC_MSG_TYPE_SEQDONE, CELL_OK, vdec.cbArg);
|
||||
cb.Branch(true); // ???*/
|
||||
|
||||
avcodec_close(vdec.ctx);
|
||||
avformat_close_input(&vdec.fmt);
|
||||
|
||||
vdec.is_running = false;
|
||||
}
|
||||
break;
|
||||
|
||||
case vdecDecodeAu:
|
||||
{
|
||||
struct vdecPacket : AVPacket
|
||||
{
|
||||
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;
|
||||
}
|
||||
int err;
|
||||
|
||||
if (task.mode != CELL_VDEC_DEC_MODE_NORMAL)
|
||||
{
|
||||
@ -159,72 +203,166 @@ u32 vdecOpen(VideoDecoder* data)
|
||||
vdec.reader.addr = task.addr;
|
||||
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);
|
||||
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)
|
||||
AVPacketHolder(u32 size)
|
||||
{
|
||||
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();
|
||||
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;
|
||||
}
|
||||
|
||||
vdec.buf_size = err;
|
||||
last_frame = av_read_frame(vdec.fmt, &au) < 0;
|
||||
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,
|
||||
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));
|
||||
struct VdecFrameHolder : VdecFrame
|
||||
{
|
||||
VdecFrameHolder()
|
||||
{
|
||||
data = av_frame_alloc();
|
||||
}
|
||||
|
||||
vdec.userdata = task.userData;
|
||||
vdec.has_picture = true;
|
||||
~VdecFrameHolder()
|
||||
{
|
||||
if (data)
|
||||
{
|
||||
av_frame_unref(data);
|
||||
av_frame_free(&data);
|
||||
}
|
||||
}
|
||||
|
||||
Callback cb;
|
||||
cb.SetAddr(vdec.cbFunc);
|
||||
cb.Handle(vdec.id, CELL_VDEC_MSG_TYPE_PICOUT, 0, vdec.cbArg);
|
||||
cb.Branch(false);
|
||||
} frame;
|
||||
|
||||
if (!frame.data)
|
||||
{
|
||||
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.Handle(vdec.id, CELL_VDEC_MSG_TYPE_AUDONE, 0, vdec.cbArg);
|
||||
cb.Branch(false);
|
||||
cb.Handle(vdec.id, CELL_VDEC_MSG_TYPE_AUDONE, CELL_OK, vdec.cbArg);
|
||||
cb.Branch(false);*/
|
||||
}
|
||||
break;
|
||||
|
||||
@ -238,15 +376,15 @@ u32 vdecOpen(VideoDecoder* data)
|
||||
case vdecSetFrameRate:
|
||||
{
|
||||
ConLog.Error("TODO: vdecSetFrameRate(%d)", task.frc);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
ConLog.Error("Video Decoder error: unknown task(%d)", task.type);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
vdec.is_finished = true;
|
||||
ConLog.Warning("Video Decoder aborted");
|
||||
});
|
||||
|
||||
@ -331,7 +469,7 @@ int cellVdecClose(u32 handle)
|
||||
|
||||
vdec->job.Push(VdecTask(vdecClose));
|
||||
|
||||
while (!vdec->is_finished)
|
||||
while (!vdec->is_finished || !vdec->frames.IsEmpty())
|
||||
{
|
||||
if (Emu.IsStopped())
|
||||
{
|
||||
@ -341,6 +479,7 @@ int cellVdecClose(u32 handle)
|
||||
Sleep(1);
|
||||
}
|
||||
|
||||
if (vdec->vdecCb) Emu.GetCPU().RemoveThread(vdec->vdecCb->GetId());
|
||||
Emu.GetIdManager().RemoveID(handle);
|
||||
return CELL_OK;
|
||||
}
|
||||
@ -361,7 +500,7 @@ int cellVdecStartSeq(u32 handle)
|
||||
|
||||
int cellVdecEndSeq(u32 handle)
|
||||
{
|
||||
cellVdec.Log("cellVdecEndSeq(handle=%d)", handle);
|
||||
cellVdec.Warning("cellVdecEndSeq(handle=%d)", handle);
|
||||
|
||||
VideoDecoder* vdec;
|
||||
if (!Emu.GetIdManager().GetIDData(handle, vdec))
|
||||
@ -369,6 +508,28 @@ int cellVdecEndSeq(u32 handle)
|
||||
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));
|
||||
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)
|
||||
{
|
||||
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;
|
||||
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;
|
||||
}
|
||||
|
||||
if (!vdec->has_picture)
|
||||
if (vdec->frames.IsEmpty())
|
||||
{
|
||||
return CELL_VDEC_ERROR_EMPTY;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
@ -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);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
if (format->colorMatrixType != CELL_VDEC_COLOR_MATRIX_TYPE_BT709)
|
||||
{
|
||||
cellVdec.Error("cellVdecGetPicture: TODO: unknown colorMatrixType(%d)", (u32)format->colorMatrixType);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
AVFrame& frame = *vdec->frame;
|
||||
VdecFrame vf;
|
||||
|
||||
u8* buf = (u8*)malloc(vdec->buf_size);
|
||||
if (!buf)
|
||||
{
|
||||
cellVdec.Error("cellVdecGetPicture: malloc failed (out of memory)");
|
||||
Emu.Pause();
|
||||
return CELL_OK;
|
||||
}
|
||||
vdec->frames.Pop(vf);
|
||||
|
||||
AVFrame& frame = *vf.data;
|
||||
|
||||
u8* buf = (u8*)malloc(buf_size);
|
||||
|
||||
// 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)
|
||||
{
|
||||
cellVdec.Error("cellVdecGetPicture: av_image_copy_to_buffer failed(%d)", err);
|
||||
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");
|
||||
Emu.Pause();
|
||||
}
|
||||
|
||||
/*
|
||||
u32 size0 = frame.linesize[0] * frame.height;
|
||||
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);
|
||||
*/
|
||||
|
||||
av_frame_unref(vf.data);
|
||||
av_frame_free(&vf.data);
|
||||
free(buf);
|
||||
}
|
||||
|
||||
vdec->has_picture = false;
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
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;
|
||||
if (!Emu.GetIdManager().GetIDData(handle, vdec))
|
||||
@ -489,36 +645,47 @@ int cellVdecGetPicItem(u32 handle, mem32_t picItem_ptr)
|
||||
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;
|
||||
}
|
||||
|
||||
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->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->auPts[0].lower = vdec->pts;
|
||||
info->auPts[0].upper = vdec->pts >> 32;
|
||||
info->auPts[0].lower = vf.pts;
|
||||
info->auPts[0].upper = vf.pts >> 32;
|
||||
info->auPts[1].lower = 0xffffffff;
|
||||
info->auPts[1].upper = 0xffffffff;
|
||||
info->auDts[0].lower = vdec->dts;
|
||||
info->auDts[0].upper = vdec->dts >> 32;
|
||||
info->auDts[0].lower = vf.dts;
|
||||
info->auDts[0].upper = vf.dts >> 32;
|
||||
info->auDts[1].lower = 0xffffffff;
|
||||
info->auDts[1].upper = 0xffffffff;
|
||||
info->auUserData[0] = vdec->userdata;
|
||||
info->auUserData[0] = vf.userdata;
|
||||
info->auUserData[1] = 0;
|
||||
info->status = CELL_OK;
|
||||
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->verticalSize = vdec->frame->height;
|
||||
switch (vdec->frame->pict_type)
|
||||
avc->horizontalSize = frame.width;
|
||||
avc->verticalSize = frame.height;
|
||||
switch (frame.pict_type)
|
||||
{
|
||||
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;
|
||||
@ -590,5 +757,6 @@ void cellVdec_init()
|
||||
cellVdec.AddFunc(0x17c702b9, cellVdecGetPicItem);
|
||||
cellVdec.AddFunc(0xe13ef6fc, cellVdecSetFrameRate);
|
||||
|
||||
av_register_all();
|
||||
avcodec_register_all();
|
||||
}
|
@ -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);
|
||||
|
||||
class VideoDecoder
|
||||
@ -688,19 +696,11 @@ public:
|
||||
u32 id;
|
||||
volatile bool is_running;
|
||||
volatile bool is_finished;
|
||||
bool just_started;
|
||||
|
||||
AVCodec* codec;
|
||||
AVCodecContext* ctx;
|
||||
AVFormatContext* fmt;
|
||||
AVFrame* frame;
|
||||
AVDictionary* opts;
|
||||
u8* io_buf;
|
||||
u32 buf_size;
|
||||
u64 pts;
|
||||
u64 dts;
|
||||
u64 pos;
|
||||
u64 userdata;
|
||||
volatile bool has_picture;
|
||||
|
||||
struct VideoReader
|
||||
{
|
||||
@ -708,51 +708,39 @@ public:
|
||||
u32 size;
|
||||
} reader;
|
||||
|
||||
SQueue<VdecFrame> frames;
|
||||
|
||||
const CellVdecCodecType type;
|
||||
const u32 profile;
|
||||
const u32 memAddr;
|
||||
const u32 memSize;
|
||||
const u32 cbFunc;
|
||||
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)
|
||||
: type(type)
|
||||
, profile(profile)
|
||||
, memAddr(addr)
|
||||
, memSize(size)
|
||||
, memBias(0)
|
||||
, cbFunc(func)
|
||||
, cbArg(arg)
|
||||
, is_finished(false)
|
||||
, is_running(false)
|
||||
, has_picture(false)
|
||||
, pos(0)
|
||||
, just_started(false)
|
||||
, ctx(nullptr)
|
||||
, vdecCb(nullptr)
|
||||
{
|
||||
codec = avcodec_find_decoder(AV_CODEC_ID_H264);
|
||||
AVCodec* codec = avcodec_find_decoder(AV_CODEC_ID_H264);
|
||||
if (!codec)
|
||||
{
|
||||
ConLog.Error("VideoDecoder(): avcodec_find_decoder 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");
|
||||
ConLog.Error("VideoDecoder(): avcodec_find_decoder(H264) failed");
|
||||
Emu.Pause();
|
||||
return;
|
||||
}
|
||||
@ -771,23 +759,29 @@ public:
|
||||
Emu.Pause();
|
||||
return;
|
||||
}
|
||||
//memset(&out_data, 0, sizeof(out_data));
|
||||
//memset(&linesize, 0, sizeof(linesize));
|
||||
}
|
||||
|
||||
~VideoDecoder()
|
||||
{
|
||||
if (io_buf) av_free(io_buf);
|
||||
if (fmt)
|
||||
{
|
||||
avformat_free_context(fmt);
|
||||
}
|
||||
if (frame) av_frame_free(&frame);
|
||||
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);
|
||||
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]);
|
||||
}
|
||||
};
|
@ -77,7 +77,7 @@ int cellVpostClose(u32 handle)
|
||||
int cellVpostExec(u32 handle, const u32 inPicBuff_addr, const mem_ptr_t<CellVpostCtrlParam> ctrlParam,
|
||||
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());
|
||||
|
||||
VpostInstance* vpost;
|
||||
@ -139,31 +139,34 @@ int cellVpostExec(u32 handle, const u32 inPicBuff_addr, const mem_ptr_t<CellVpos
|
||||
picInfo->reserved1 = 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* 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;
|
||||
|
||||
if (!Memory.CopyToReal(pY, inPicBuff_addr, w*h))
|
||||
{
|
||||
cellVpost.Error("cellVpostExec: data copying failed(pY)");
|
||||
Emu.Pause();
|
||||
}
|
||||
|
||||
if (!Memory.CopyToReal(pU, inPicBuff_addr + w*h, w*h/4))
|
||||
{
|
||||
cellVpost.Error("cellVpostExec: data copying failed(pU)");
|
||||
Emu.Pause();
|
||||
}
|
||||
|
||||
if (!Memory.CopyToReal(pV, inPicBuff_addr + w*h + w*h/4, w*h/4))
|
||||
{
|
||||
cellVpost.Error("cellVpostExec: data copying failed(pV)");
|
||||
Emu.Pause();
|
||||
}
|
||||
|
||||
for (u32 i = 0; i < h; i++) for (u32 j = 0; j < w; j++)
|
||||
{
|
||||
float Cr = pV[(i/2)*(w/2)+j/2];
|
||||
float Cb = pU[(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] - 128;
|
||||
float Y = pY[i*w+j];
|
||||
|
||||
int R = Y + 1.5701f * Cr;
|
||||
|
478
rpcs3/Emu/SysCalls/Modules/libmixer.cpp
Normal file
478
rpcs3/Emu/SysCalls/Modules/libmixer.cpp
Normal 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);
|
||||
}
|
63
rpcs3/Emu/SysCalls/Modules/libmixer.h
Normal file
63
rpcs3/Emu/SysCalls/Modules/libmixer.h
Normal 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;
|
65
rpcs3/Emu/SysCalls/Static.cpp
Normal file
65
rpcs3/Emu/SysCalls/Static.cpp
Normal 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();
|
||||
}
|
@ -201,9 +201,9 @@ extern int sys_rwlock_trywlock(u32 rw_lock_id);
|
||||
extern int sys_rwlock_wunlock(u32 rw_lock_id);
|
||||
|
||||
//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_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 void sys_ppu_thread_get_join_state(u32 isjoinable_addr);
|
||||
extern int sys_ppu_thread_set_priority(u32 thread_id, int prio);
|
||||
@ -433,3 +433,7 @@ public:
|
||||
};
|
||||
|
||||
//extern SysCalls SysCallsManager;
|
||||
|
||||
void StaticAnalyse(void* ptr, u32 size);
|
||||
void StaticExecute(u32 code);
|
||||
void StaticFinalize();
|
||||
|
@ -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()))
|
||||
{
|
||||
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 (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->recursive = 1;
|
||||
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()))
|
||||
{
|
||||
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 (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->recursive = 1;
|
||||
mutex->m_mutex.unlock(tid, target);
|
||||
@ -130,11 +166,11 @@ int sys_cond_signal_all(u32 cond_id)
|
||||
mutex->m_mutex.lock(tid);
|
||||
mutex->recursive = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (Emu.IsStopped())
|
||||
{
|
||||
ConLog.Warning("sys_cond_signal_all(id=%d) aborted", cond_id);
|
||||
if (Emu.IsStopped())
|
||||
{
|
||||
ConLog.Warning("sys_cond_signal_all(id=%d) aborted", cond_id);
|
||||
}
|
||||
}
|
||||
|
||||
return CELL_OK;
|
||||
@ -169,6 +205,16 @@ int sys_cond_signal_to(u32 cond_id, u32 thread_id)
|
||||
{
|
||||
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->recursive = 1;
|
||||
mutex->m_mutex.unlock(tid, target);
|
||||
|
@ -74,17 +74,17 @@ int sys_event_queue_destroy(u32 equeue_id, int mode)
|
||||
|
||||
u32 tid = GetCurrentPPUThread().GetId();
|
||||
|
||||
eq->sq.m_mutex.lock(tid);
|
||||
eq->sq.m_mutex.lock();
|
||||
eq->owner.lock(tid);
|
||||
// check if some threads are waiting for an event
|
||||
if (!mode && eq->sq.list.GetCount())
|
||||
{
|
||||
eq->owner.unlock(tid);
|
||||
eq->sq.m_mutex.unlock(tid);
|
||||
eq->sq.m_mutex.unlock();
|
||||
return CELL_EBUSY;
|
||||
}
|
||||
eq->owner.unlock(tid, ~0);
|
||||
eq->sq.m_mutex.unlock(tid);
|
||||
eq->sq.m_mutex.unlock();
|
||||
while (eq->sq.list.GetCount())
|
||||
{
|
||||
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();
|
||||
|
||||
eq->sq.m_mutex.lock(tid);
|
||||
eq->sq.m_mutex.lock();
|
||||
eq->owner.lock(tid);
|
||||
if (eq->sq.list.GetCount())
|
||||
{
|
||||
number = 0;
|
||||
eq->owner.unlock(tid);
|
||||
eq->sq.m_mutex.unlock(tid);
|
||||
eq->sq.m_mutex.unlock();
|
||||
return CELL_OK;
|
||||
}
|
||||
number = eq->events.pop_all((sys_event_data*)(Memory + event_array.GetAddr()), size);
|
||||
eq->owner.unlock(tid);
|
||||
eq->sq.m_mutex.unlock(tid);
|
||||
eq->sq.m_mutex.unlock();
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
|
@ -57,7 +57,7 @@ int sys_lwmutex_destroy(mem_ptr_t<sys_lwmutex_t> lwmutex)
|
||||
{
|
||||
case CELL_OK:
|
||||
lwmutex->all_info() = 0;
|
||||
lwmutex->attribute = 0;
|
||||
lwmutex->attribute = 0xDEADBEEF;
|
||||
lwmutex->sleep_queue = 0;
|
||||
Emu.GetIdManager().RemoveID(sq_id);
|
||||
default: return res;
|
||||
@ -99,13 +99,13 @@ int sys_lwmutex_unlock(mem_ptr_t<sys_lwmutex_t> lwmutex)
|
||||
|
||||
void SleepQueue::push(u32 tid)
|
||||
{
|
||||
SMutexLocker lock(m_mutex);
|
||||
std::lock_guard<std::mutex> lock(m_mutex);
|
||||
list.AddCpy(tid);
|
||||
}
|
||||
|
||||
u32 SleepQueue::pop() // SYS_SYNC_FIFO
|
||||
{
|
||||
SMutexLocker lock(m_mutex);
|
||||
std::lock_guard<std::mutex> lock(m_mutex);
|
||||
|
||||
while (true)
|
||||
{
|
||||
@ -125,7 +125,7 @@ u32 SleepQueue::pop() // SYS_SYNC_FIFO
|
||||
|
||||
u32 SleepQueue::pop_prio() // SYS_SYNC_PRIORITY
|
||||
{
|
||||
SMutexLocker lock(m_mutex);
|
||||
std::lock_guard<std::mutex> lock(m_mutex);
|
||||
|
||||
while (true)
|
||||
{
|
||||
@ -171,7 +171,7 @@ u32 SleepQueue::pop_prio_inherit() // (TODO)
|
||||
|
||||
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++)
|
||||
{
|
||||
@ -187,15 +187,13 @@ bool SleepQueue::invalidate(u32 tid)
|
||||
|
||||
bool SleepQueue::finalize()
|
||||
{
|
||||
u32 tid = GetCurrentPPUThread().GetId();
|
||||
|
||||
m_mutex.lock(tid);
|
||||
if (!m_mutex.try_lock()) return false;
|
||||
|
||||
for (u32 i = 0; i < list.GetCount(); i++)
|
||||
{
|
||||
if (list[i])
|
||||
{
|
||||
m_mutex.unlock(tid);
|
||||
m_mutex.unlock();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@ -205,9 +203,42 @@ bool SleepQueue::finalize()
|
||||
|
||||
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))
|
||||
{
|
||||
@ -237,6 +268,11 @@ int sys_lwmutex_t::unlock(be_t<u32> tid)
|
||||
}
|
||||
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;
|
||||
if (!recursive_count.ToBE())
|
||||
{
|
||||
|
@ -47,7 +47,7 @@ struct SleepQueue
|
||||
q_rec(u32 tid, u64 prio): tid(tid), prio(prio) {}
|
||||
}; */
|
||||
Array<u32> list;
|
||||
SMutex m_mutex;
|
||||
std::mutex m_mutex;
|
||||
u64 m_name;
|
||||
|
||||
SleepQueue(u64 name = 0)
|
||||
@ -65,7 +65,7 @@ struct SleepQueue
|
||||
|
||||
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
|
||||
u64 &all_info(){return *(reinterpret_cast<u64*>(this));}
|
||||
be_t<u32> attribute;
|
||||
|
@ -52,12 +52,12 @@ int sys_memory_allocate(u32 size, u32 flags, u32 alloc_addr_addr)
|
||||
{
|
||||
case SYS_MEMORY_PAGE_SIZE_1M:
|
||||
if(size & 0xfffff) return CELL_EALIGN;
|
||||
addr = Memory.Alloc(size, 1);
|
||||
addr = Memory.Alloc(size, 0x100000);
|
||||
break;
|
||||
|
||||
case SYS_MEMORY_PAGE_SIZE_64K:
|
||||
if(size & 0xffff) return CELL_EALIGN;
|
||||
addr = Memory.Alloc(size, 1);
|
||||
addr = Memory.Alloc(size, 0x10000);
|
||||
break;
|
||||
|
||||
default: return CELL_EINVAL;
|
||||
|
@ -37,7 +37,13 @@ int sys_mutex_create(mem32_t mutex_id, mem_ptr_t<sys_mutex_attribute> attr)
|
||||
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",
|
||||
wxString(attr->name, 8).wx_str(), (u32)attr->protocol,
|
||||
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;
|
||||
}
|
||||
|
||||
u32 tid = GetCurrentPPUThread().GetId();
|
||||
PPUThread& t = GetCurrentPPUThread();
|
||||
u32 tid = t.GetId();
|
||||
u32 owner = mutex->m_mutex.GetOwner();
|
||||
|
||||
if (owner == tid)
|
||||
@ -108,17 +115,32 @@ int sys_mutex_lock(u32 mutex_id, u64 timeout)
|
||||
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);
|
||||
mutex->m_mutex.unlock(owner, tid);
|
||||
mutex->recursive = 1;
|
||||
return CELL_OK;
|
||||
if (CPUThread* tt = Emu.GetCPU().GetThread(owner))
|
||||
{
|
||||
if (!tt->IsAlive())
|
||||
{
|
||||
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))
|
||||
{
|
||||
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;
|
||||
default: goto abort;
|
||||
}
|
||||
@ -130,7 +152,7 @@ int sys_mutex_lock(u32 mutex_id, u64 timeout)
|
||||
case SMR_OK:
|
||||
mutex->m_queue.invalidate(tid);
|
||||
case SMR_SIGNAL:
|
||||
mutex->recursive = 1; return CELL_OK;
|
||||
mutex->recursive = 1; t.owned_mutexes++; return CELL_OK;
|
||||
case SMR_TIMEOUT:
|
||||
mutex->m_queue.invalidate(tid); return CELL_ETIMEDOUT;
|
||||
default:
|
||||
@ -156,7 +178,8 @@ int sys_mutex_trylock(u32 mutex_id)
|
||||
return CELL_ESRCH;
|
||||
}
|
||||
|
||||
u32 tid = GetCurrentPPUThread().GetId();
|
||||
PPUThread& t = GetCurrentPPUThread();
|
||||
u32 tid = t.GetId();
|
||||
u32 owner = mutex->m_mutex.GetOwner();
|
||||
|
||||
if (owner == tid)
|
||||
@ -174,17 +197,32 @@ int sys_mutex_trylock(u32 mutex_id)
|
||||
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);
|
||||
mutex->m_mutex.unlock(owner, tid);
|
||||
mutex->recursive = 1;
|
||||
return CELL_OK;
|
||||
if (CPUThread* tt = Emu.GetCPU().GetThread(owner))
|
||||
{
|
||||
if (!tt->IsAlive())
|
||||
{
|
||||
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))
|
||||
{
|
||||
case SMR_OK: mutex->recursive = 1; return CELL_OK;
|
||||
case SMR_OK: mutex->recursive = 1; t.owned_mutexes++; return CELL_OK;
|
||||
}
|
||||
|
||||
return CELL_EBUSY;
|
||||
@ -200,18 +238,21 @@ int sys_mutex_unlock(u32 mutex_id)
|
||||
return CELL_ESRCH;
|
||||
}
|
||||
|
||||
u32 tid = GetCurrentPPUThread().GetId();
|
||||
PPUThread& t = GetCurrentPPUThread();
|
||||
u32 tid = t.GetId();
|
||||
|
||||
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--;
|
||||
if (!mutex->recursive)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
@ -18,6 +18,7 @@ struct sys_mutex_attribute
|
||||
|
||||
struct Mutex
|
||||
{
|
||||
u32 id;
|
||||
SMutex m_mutex;
|
||||
SleepQueue m_queue;
|
||||
u32 recursive; // recursive locks count
|
||||
@ -33,4 +34,21 @@ struct Mutex
|
||||
, 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();
|
||||
}
|
||||
};
|
@ -10,24 +10,21 @@ enum
|
||||
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(errorcode=%d)", errorcode);
|
||||
}
|
||||
else
|
||||
{
|
||||
sysPrxForUser.Warning("sys_ppu_thread_exit(errorcode=%d)", errorcode);
|
||||
}
|
||||
sysPrxForUser.Log("sys_ppu_thread_exit(0x%llx)", errorcode);
|
||||
|
||||
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.Stop();
|
||||
|
||||
//Emu.GetCPU().RemoveThread(thr.GetId());
|
||||
|
||||
//throw errorcode;
|
||||
}
|
||||
|
||||
int sys_ppu_thread_yield()
|
||||
@ -37,14 +34,24 @@ int sys_ppu_thread_yield()
|
||||
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);
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -267,6 +267,8 @@ void Emulator::Load()
|
||||
ppu_thr_exit_data += ADDI(11, 0, 41);
|
||||
ppu_thr_exit_data += SC(2);
|
||||
ppu_thr_exit_data += BCLR(0x10 | 0x04, 0, 0, 0);
|
||||
|
||||
Memory.Write64(Memory.PRXMem.AllocAlign(0x10000), 0xDEADBEEFABADCAFE);
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -246,6 +246,7 @@ bool ELF64Loader::LoadPhdrData(u64 offset)
|
||||
{
|
||||
elf64_f.Seek(phdr_arr[i].p_offset);
|
||||
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;
|
||||
|
@ -299,17 +299,20 @@
|
||||
<ClCompile Include="Emu\SysCalls\Modules\cellPngDec.cpp" />
|
||||
<ClCompile Include="Emu\SysCalls\Modules\cellResc.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\cellSysmodule.cpp" />
|
||||
<ClCompile Include="Emu\SysCalls\Modules\cellSysutil.cpp" />
|
||||
<ClCompile Include="Emu\SysCalls\Modules\cellSysutilAp.cpp" />
|
||||
<ClCompile Include="Emu\SysCalls\Modules\cellVdec.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\sceNpTrophy.cpp" />
|
||||
<ClCompile Include="Emu\SysCalls\Modules\sysPrxForUser.cpp" />
|
||||
<ClCompile Include="Emu\SysCalls\Modules\sys_fs.cpp" />
|
||||
<ClCompile Include="Emu\SysCalls\Modules\sys_io.cpp" />
|
||||
<ClCompile Include="Emu\SysCalls\Static.cpp" />
|
||||
<ClCompile Include="Emu\SysCalls\SysCalls.cpp" />
|
||||
<ClCompile Include="Emu\System.cpp" />
|
||||
<ClCompile Include="Gui\CompilerELF.cpp" />
|
||||
|
@ -439,12 +439,21 @@
|
||||
<ClCompile Include="Crypto\utils.cpp">
|
||||
<Filter>Crypto</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Emu\SysCalls\Static.cpp">
|
||||
<Filter>Emu\SysCalls</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Emu\SysCalls\Modules\cellNetCtl.cpp">
|
||||
<Filter>Emu\SysCalls\Modules</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Emu\SysCalls\Modules\cellL10n.cpp">
|
||||
<Filter>Emu\SysCalls\Modules</Filter>
|
||||
</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">
|
||||
<Filter>Emu\Audio</Filter>
|
||||
</ClCompile>
|
||||
|
Loading…
x
Reference in New Issue
Block a user