diff --git a/Utilities/SMutex.h b/Utilities/SMutex.h index b92d67e614..5aa9a98f07 100644 --- a/Utilities/SMutex.h +++ b/Utilities/SMutex.h @@ -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); } }; diff --git a/Utilities/SQueue.h b/Utilities/SQueue.h index a7021365e1..8c0201d257 100644 --- a/Utilities/SQueue.h +++ b/Utilities/SQueue.h @@ -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]; + } }; diff --git a/rpcs3/Emu/Audio/cellAudio.h b/rpcs3/Emu/Audio/cellAudio.h index fcfe267438..e5ea8545fe 100644 --- a/rpcs3/Emu/Audio/cellAudio.h +++ b/rpcs3/Emu/Audio/cellAudio.h @@ -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 channels; - be_t outputMode; -}; - -struct CellSSPlayerWaveParam -{ - void *addr; - be_t format; - be_t samples; - be_t loopStartOffset; - be_t startOffset; -}; - -struct CellSSPlayerCommonParam -{ - be_t loopMode; - be_t attackMode; -}; - -struct CellSurMixerPosition -{ - be_t x; - be_t y; - be_t z; -}; - -struct CellSSPlayerRuntimeInfo -{ - be_t level; - be_t speed; - CellSurMixerPosition position; -}; - -struct CellSurMixerConfig -{ - be_t priority; - be_t chStrips1; - be_t chStrips2; - be_t chStrips6; - be_t chStrips8; -}; - -struct CellSurMixerChStripParam -{ - be_t param; - void *attribute; - be_t dBSwitch; - be_t floatVal; - be_t intVal; -}; - -CellSSPlayerWaveParam current_SSPlayerWaveParam; - //libsnd3 datatypes struct CellSnd3DataCtx { diff --git a/rpcs3/Emu/CPU/CPUThread.cpp b/rpcs3/Emu/CPU/CPUThread.cpp index 2d98e28e4b..1ec31434b2 100644 --- a/rpcs3/Emu/CPU/CPUThread.cpp +++ b/rpcs3/Emu/CPU/CPUThread.cpp @@ -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; +} \ No newline at end of file diff --git a/rpcs3/Emu/CPU/CPUThread.h b/rpcs3/Emu/CPU/CPUThread.h index 88470283bc..3c2bbafd3e 100644 --- a/rpcs3/Emu/CPU/CPUThread.h +++ b/rpcs3/Emu/CPU/CPUThread.h @@ -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; diff --git a/rpcs3/Emu/Cell/PPUInterpreter.h b/rpcs3/Emu/Cell/PPUInterpreter.h index 2a0090c251..ea916d43b1 100644 --- a/rpcs3/Emu/Cell/PPUInterpreter.h +++ b/rpcs3/Emu/Cell/PPUInterpreter.h @@ -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)); } diff --git a/rpcs3/Emu/Cell/PPUThread.cpp b/rpcs3/Emu/Cell/PPUThread.cpp index 91dce7d6a8..bd6c6570e5 100644 --- a/rpcs3/Emu/Cell/PPUThread.cpp +++ b/rpcs3/Emu/Cell/PPUThread.cpp @@ -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]; diff --git a/rpcs3/Emu/Cell/PPUThread.h b/rpcs3/Emu/Cell/PPUThread.h index b4a12efedf..fbb53bf1ae 100644 --- a/rpcs3/Emu/Cell/PPUThread.h +++ b/rpcs3/Emu/Cell/PPUThread.h @@ -525,6 +525,9 @@ static const s32 MAX_INT_VALUE = 0x7fffffff; class PPUThread : public PPCThread { +public: + std::atomic owned_mutexes; + public: PPCdouble FPR[32]; //Floating Point Register FPSCRhdr FPSCR; //Floating Point Status and Control Register diff --git a/rpcs3/Emu/SysCalls/Callback.cpp b/rpcs3/Emu/SysCalls/Callback.cpp index f64851b6c3..73e7896744 100644 --- a/rpcs3/Emu/SysCalls/Callback.cpp +++ b/rpcs3/Emu/SysCalls/Callback.cpp @@ -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 lock(cb_mutex); if (thr.IsAlive()) { diff --git a/rpcs3/Emu/SysCalls/Modules.cpp b/rpcs3/Emu/SysCalls/Modules.cpp index bdecfc62b8..07404f49ad 100644 --- a/rpcs3/Emu/SysCalls/Modules.cpp +++ b/rpcs3/Emu/SysCalls/Modules.cpp @@ -8,6 +8,7 @@ uint g_max_module_id = 0; uint g_module_2_count = 0; ArrayF g_modules_funcs_list; std::mutex g_funcs_lock; +ArrayF g_static_funcs_list; struct ModuleInfo { diff --git a/rpcs3/Emu/SysCalls/Modules.h b/rpcs3/Emu/SysCalls/Modules.h index faef27d9b7..165f59a49d 100644 --- a/rpcs3/Emu/SysCalls/Modules.h +++ b/rpcs3/Emu/SysCalls/Modules.h @@ -25,6 +25,21 @@ struct ModuleFunc } }; +struct SFuncOp +{ + u32 crc; + u32 mask; +}; + +struct SFunc +{ + func_caller* func; + char* name; + Array ops; +}; + +extern ArrayF g_static_funcs_list; + class Module { std::string m_name; @@ -94,6 +109,8 @@ public: } template __forceinline void AddFunc(u32 id, T func); + + template __forceinline void AddFuncSub(const u64 ops[], char* name, T func); }; template @@ -102,6 +119,29 @@ __forceinline void Module::AddFunc(u32 id, T func) m_funcs_list.Move(new ModuleFunc(id, bind_func(func))); } +template +__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); diff --git a/rpcs3/Emu/SysCalls/Modules/cellAdec.cpp b/rpcs3/Emu/SysCalls/Modules/cellAdec.cpp index 5829ac0e29..94a754d8e4 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellAdec.cpp +++ b/rpcs3/Emu/SysCalls/Modules/cellAdec.cpp @@ -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 type, mem_ptr_t 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 type, mem_ptr_t res, mem_ptr_t 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 type, mem_ptr_t res, mem_ptr_t 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 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 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 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(); } \ No newline at end of file diff --git a/rpcs3/Emu/SysCalls/Modules/cellAdec.h b/rpcs3/Emu/SysCalls/Modules/cellAdec.h index d2e034b9bb..bab8ccd6c9 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellAdec.h +++ b/rpcs3/Emu/SysCalls/Modules/cellAdec.h @@ -1,5 +1,6 @@ #pragma once -#include "cellPamf.h" + +#include "Utilities/SQueue.h" // Error Codes enum @@ -341,6 +342,17 @@ struct CellAdecResource be_t ppuThreadStackSize; }; +struct CellAdecResourceEx +{ + be_t totalMemSize; + be_t startAddr; + be_t ppuThreadPriority; + be_t ppuThreadStackSize; + be_t spurs_addr; + u8 priority[8]; + be_t 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 CellAdecCbMsg; struct CellAdecCb { - be_t> cbFunc; - be_t cbArg_addr; + be_t cbFunc; + be_t cbArg; }; typedef CellCodecTimeStamp CellAdecTimeStamp; @@ -399,17 +413,6 @@ struct CellAdecLpcmInfo be_t outputDataSize; }; -struct CellAdecResourceEx -{ - be_t totalMemSize; - be_t startAddr; - be_t ppuThreadPriority; - be_t ppuThreadStackSize; - be_t spurs_addr; - u8 priority[8]; - be_t maxContention; -}; - // CELP Excitation Mode enum CELP_ExcitationMode { @@ -985,3 +988,143 @@ struct CellAdecMpmcInfo be_t lfePresent; be_t 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 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 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); + } + } +}; diff --git a/rpcs3/Emu/SysCalls/Modules/cellAudio.cpp b/rpcs3/Emu/SysCalls/Modules/cellAudio.cpp index d65937c64d..486b1720a4 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellAudio.cpp +++ b/rpcs3/Emu/SysCalls/Modules/cellAudio.cpp @@ -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(); } \ No newline at end of file diff --git a/rpcs3/Emu/SysCalls/Modules/cellDmux.cpp b/rpcs3/Emu/SysCalls/Modules/cellDmux.cpp index aadfaf1a85..36b8ffef44 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellDmux.cpp +++ b/rpcs3/Emu/SysCalls/Modules/cellDmux.cpp @@ -18,9 +18,9 @@ void dmuxQueryEsAttr(u32 info_addr /* may be 0 */, const mem_ptr_t 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 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 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 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 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 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 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; } diff --git a/rpcs3/Emu/SysCalls/Modules/cellDmux.h b/rpcs3/Emu/SysCalls/Modules/cellDmux.h index 51e805ab07..cc504fe2f0 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellDmux.h +++ b/rpcs3/Emu/SysCalls/Modules/cellDmux.h @@ -329,11 +329,11 @@ struct DemuxerStream } template - 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 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 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; } }; diff --git a/rpcs3/Emu/SysCalls/Modules/cellSpurs.cpp b/rpcs3/Emu/SysCalls/Modules/cellSpurs.cpp new file mode 100644 index 0000000000..e6e9bbd98e --- /dev/null +++ b/rpcs3/Emu/SysCalls/Modules/cellSpurs.cpp @@ -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 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 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 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 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 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 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 spurs, const mem_ptr_t 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 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 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 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 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 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 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 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 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 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 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 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 spurs, + mem_func_ptr_t eaHandler, mem_ptr_t 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 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 spurs, mem_ptr_t 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 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 +} \ No newline at end of file diff --git a/rpcs3/Emu/SysCalls/Modules/cellSpurs.h b/rpcs3/Emu/SysCalls/Modules/cellSpurs.h new file mode 100644 index 0000000000..af9f4c4e6c --- /dev/null +++ b/rpcs3/Emu/SysCalls/Modules/cellSpurs.h @@ -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 nSpus; + be_t spuThreadGroupPriority; + be_t ppuThreadPriority; + bool exitIfNoWork; + bool spurs2; + be_t traceBuffer_addr; //void *traceBuffer; + be_t traceBufferSize; + be_t traceMode; + be_t spuThreadGroup; //typedef u32 sys_spu_thread_group_t; + be_t spuThreads[8]; //typedef u32 sys_spu_thread_t; + be_t spursHandlerThread0; + be_t spursHandlerThread1; + char namePrefix[CELL_SPURS_NAME_MAX_LENGTH+1]; + be_t namePrefixLength; + be_t deadlineMissCounter; + be_t deadlineMeetCounter; + //u8 padding[]; +}; + +struct CellSpursExceptionInfo +{ + be_t spu_thread; + be_t spu_npc; + be_t cause; + be_t option; +}; + +struct CellSpursTraceInfo +{ + be_t spu_thread[8]; + be_t count[8]; + be_t spu_thread_grp; + be_t nspu; + //u8 padding[]; +}; + +__declspec(align(8)) struct CellTraceHeader +{ + u8 tag; + u8 length; + u8 cpu; + u8 thread; + be_t time; +}; + +struct CellSpursTracePacket +{ + struct header_struct + { + u8 tag; + u8 length; + u8 spu; + u8 workload; + be_t time; + } header; + + struct data_struct + { + struct load_struct + { + be_t ea; + be_t ls; + be_t size; + } load; + + struct map_struct + { + be_t offset; + be_t ls; + be_t size; + } map; + + struct start_struct + { + char module[4]; + be_t level; + be_t ls; + } start; + + be_t user; + be_t 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 spurs, const mem_ptr_t info, + uint id, mem_ptr_t 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 spurs, mem_ptr_t taskset, + uint idTask, const mem_ptr_t info, mem_ptr_t arg); + + +struct CellSpursTasksetInfo +{ + //CellSpursTaskInfo taskInfo[CELL_SPURS_MAX_TASK]; + be_t argument; + be_t idWorkload; + be_t idLastScheduledTask; //typedef unsigned CellSpursTaskId + be_t name_addr; + CellSpursTasksetExceptionEventHandler exceptionEventHandler; + be_t exceptionEventHandlerArgument_addr; //void *exceptionEventHandlerArgument + be_t sizeTaskset; + //be_t 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 skip[10496]; +}; + +struct CellSpursTasksetAttribute2 +{ + be_t revision; + be_t name_addr; + be_t argTaskset; + u8 priority[8]; + be_t maxContention; + be_t enableClearLs; + be_t CellSpursTaskNameBuffer_addr; //??? *taskNameBuffer + //be_t __reserved__[]; +}; + +struct CellSpursTaskNameBuffer +{ + char taskName[CELL_SPURS_MAX_TASK][CELL_SPURS_MAX_TASK_NAME_LENGTH]; +}; + +struct CellSpursTraceTaskData +{ + be_t incident; + be_t task; +}; + +struct CellSpursTaskArgument +{ + be_t u32[4]; + be_t u64[2]; +}; + +struct CellSpursTaskLsPattern +{ + be_t u32[4]; + be_t u64[2]; +}; + +struct CellSpursTaskAttribute2 +{ + be_t revision; + be_t sizeContext; + be_t eaContext; + CellSpursTaskLsPattern lsPattern; //??? + be_t name_addr; + //be_t __reserved__[]; +}; + +__declspec(align(128)) struct CellSpursTaskExitCode +{ + unsigned char skip[128]; +}; + +struct CellSpursTaskInfo +{ + CellSpursTaskLsPattern lsPattern; + CellSpursTaskArgument argument; + const be_t eaElf_addr; //void *eaElf + const be_t eaContext_addr; //void *eaContext + be_t sizeContext; + be_t state; + be_t hasSignal; + const be_t CellSpursTaskExitCode_addr; + u8 guid[8]; + //be_t reserved[]; +}; + +struct CellSpursTaskBinInfo +{ + be_t eaElf; + be_t sizeContext; + be_t __reserved__; + CellSpursTaskLsPattern lsPattern; +}; + diff --git a/rpcs3/Emu/SysCalls/Modules/cellVdec.cpp b/rpcs3/Emu/SysCalls/Modules/cellVdec.cpp index 232e389f8e..31fab366d6 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellVdec.cpp +++ b/rpcs3/Emu/SysCalls/Modules/cellVdec.cpp @@ -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 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 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 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 info(vdec->memAddr); + AVFrame& frame = *vf.data; + + mem_ptr_t 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 avc(vdec->memAddr + sizeof(CellVdecPicItem)); + mem_ptr_t 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(); } \ No newline at end of file diff --git a/rpcs3/Emu/SysCalls/Modules/cellVdec.h b/rpcs3/Emu/SysCalls/Modules/cellVdec.h index f2ca2320fd..96534cdbe2 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellVdec.h +++ b/rpcs3/Emu/SysCalls/Modules/cellVdec.h @@ -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 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]); } }; \ No newline at end of file diff --git a/rpcs3/Emu/SysCalls/Modules/cellVpost.cpp b/rpcs3/Emu/SysCalls/Modules/cellVpost.cpp index 8073080424..92ead9c6a4 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellVpost.cpp +++ b/rpcs3/Emu/SysCalls/Modules/cellVpost.cpp @@ -77,7 +77,7 @@ int cellVpostClose(u32 handle) int cellVpostExec(u32 handle, const u32 inPicBuff_addr, const mem_ptr_t ctrlParam, u32 outPicBuff_addr, mem_ptr_t 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_treserved1 = 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; diff --git a/rpcs3/Emu/SysCalls/Modules/libmixer.cpp b/rpcs3/Emu/SysCalls/Modules/libmixer.cpp new file mode 100644 index 0000000000..cb2b3bb547 --- /dev/null +++ b/rpcs3/Emu/SysCalls/Modules/libmixer.cpp @@ -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 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); +} \ No newline at end of file diff --git a/rpcs3/Emu/SysCalls/Modules/libmixer.h b/rpcs3/Emu/SysCalls/Modules/libmixer.h new file mode 100644 index 0000000000..24c30c7b70 --- /dev/null +++ b/rpcs3/Emu/SysCalls/Modules/libmixer.h @@ -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 channels; + be_t outputMode; +}; + +struct CellSSPlayerWaveParam +{ + void *addr; + be_t format; + be_t samples; + be_t loopStartOffset; + be_t startOffset; +}; + +struct CellSSPlayerCommonParam +{ + be_t loopMode; + be_t attackMode; +}; + +struct CellSurMixerPosition +{ + be_t x; + be_t y; + be_t z; +}; + +struct CellSSPlayerRuntimeInfo +{ + be_t level; + be_t speed; + CellSurMixerPosition position; +}; + +struct CellSurMixerConfig +{ + be_t priority; + be_t chStrips1; + be_t chStrips2; + be_t chStrips6; + be_t chStrips8; +}; + +struct CellSurMixerChStripParam +{ + be_t param; + void *attribute; + be_t dBSwitch; + be_t floatVal; + be_t intVal; +}; + +CellSSPlayerWaveParam current_SSPlayerWaveParam; \ No newline at end of file diff --git a/rpcs3/Emu/SysCalls/Static.cpp b/rpcs3/Emu/SysCalls/Static.cpp new file mode 100644 index 0000000000..2628a77272 --- /dev/null +++ b/rpcs3/Emu/SysCalls/Static.cpp @@ -0,0 +1,65 @@ +#include "stdafx.h" +#include "Modules.h" +#include "Emu/SysCalls/SysCalls.h" +#include "Emu/SysCalls/SC_FUNC.h" + +extern ArrayF 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(); +} \ No newline at end of file diff --git a/rpcs3/Emu/SysCalls/SysCalls.h b/rpcs3/Emu/SysCalls/SysCalls.h index 51242b9b30..c97518f7a4 100644 --- a/rpcs3/Emu/SysCalls/SysCalls.h +++ b/rpcs3/Emu/SysCalls/SysCalls.h @@ -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(); diff --git a/rpcs3/Emu/SysCalls/lv2/SC_Condition.cpp b/rpcs3/Emu/SysCalls/lv2/SC_Condition.cpp index 97555928d8..8f0785ab96 100644 --- a/rpcs3/Emu/SysCalls/lv2/SC_Condition.cpp +++ b/rpcs3/Emu/SysCalls/lv2/SC_Condition.cpp @@ -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); diff --git a/rpcs3/Emu/SysCalls/lv2/SC_Event.cpp b/rpcs3/Emu/SysCalls/lv2/SC_Event.cpp index 2e0e9abc2b..b662ee10c5 100644 --- a/rpcs3/Emu/SysCalls/lv2/SC_Event.cpp +++ b/rpcs3/Emu/SysCalls/lv2/SC_Event.cpp @@ -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 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; } diff --git a/rpcs3/Emu/SysCalls/lv2/SC_Lwmutex.cpp b/rpcs3/Emu/SysCalls/lv2/SC_Lwmutex.cpp index 2a42841c31..10cd0af5ff 100644 --- a/rpcs3/Emu/SysCalls/lv2/SC_Lwmutex.cpp +++ b/rpcs3/Emu/SysCalls/lv2/SC_Lwmutex.cpp @@ -57,7 +57,7 @@ int sys_lwmutex_destroy(mem_ptr_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 lwmutex) void SleepQueue::push(u32 tid) { - SMutexLocker lock(m_mutex); + std::lock_guard lock(m_mutex); list.AddCpy(tid); } u32 SleepQueue::pop() // SYS_SYNC_FIFO { - SMutexLocker lock(m_mutex); + std::lock_guard 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 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 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 tid) { - if (!attribute.ToBE()) return CELL_EINVAL; + if (attribute.ToBE() == se32(0xDEADBEEF)) return CELL_EINVAL; - if (tid == mutex.GetOwner()) + be_t 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 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()) { diff --git a/rpcs3/Emu/SysCalls/lv2/SC_Lwmutex.h b/rpcs3/Emu/SysCalls/lv2/SC_Lwmutex.h index 971363a92f..2fa724b52d 100644 --- a/rpcs3/Emu/SysCalls/lv2/SC_Lwmutex.h +++ b/rpcs3/Emu/SysCalls/lv2/SC_Lwmutex.h @@ -47,7 +47,7 @@ struct SleepQueue q_rec(u32 tid, u64 prio): tid(tid), prio(prio) {} }; */ Array 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, ~0, 0> mutex; + /* volatile */ SMutexBase> mutex; /* volatile */ be_t waiter; // not used u64 &all_info(){return *(reinterpret_cast(this));} be_t attribute; diff --git a/rpcs3/Emu/SysCalls/lv2/SC_Memory.cpp b/rpcs3/Emu/SysCalls/lv2/SC_Memory.cpp index 04e2c958d3..5c4f5b9761 100644 --- a/rpcs3/Emu/SysCalls/lv2/SC_Memory.cpp +++ b/rpcs3/Emu/SysCalls/lv2/SC_Memory.cpp @@ -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; diff --git a/rpcs3/Emu/SysCalls/lv2/SC_Mutex.cpp b/rpcs3/Emu/SysCalls/lv2/SC_Mutex.cpp index 4ae474631b..ce1b3f51d3 100644 --- a/rpcs3/Emu/SysCalls/lv2/SC_Mutex.cpp +++ b/rpcs3/Emu/SysCalls/lv2/SC_Mutex.cpp @@ -37,7 +37,13 @@ int sys_mutex_create(mem32_t mutex_id, mem_ptr_t 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; } diff --git a/rpcs3/Emu/SysCalls/lv2/SC_Mutex.h b/rpcs3/Emu/SysCalls/lv2/SC_Mutex.h index 2366d1656a..735f20a240 100644 --- a/rpcs3/Emu/SysCalls/lv2/SC_Mutex.h +++ b/rpcs3/Emu/SysCalls/lv2/SC_Mutex.h @@ -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(); + } }; \ No newline at end of file diff --git a/rpcs3/Emu/SysCalls/lv2/SC_PPU_Thread.cpp b/rpcs3/Emu/SysCalls/lv2/SC_PPU_Thread.cpp index fb39296f6e..30c31bea17 100644 --- a/rpcs3/Emu/SysCalls/lv2/SC_PPU_Thread.cpp +++ b/rpcs3/Emu/SysCalls/lv2/SC_PPU_Thread.cpp @@ -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; } diff --git a/rpcs3/Emu/System.cpp b/rpcs3/Emu/System.cpp index e910413c66..08f356707e 100644 --- a/rpcs3/Emu/System.cpp +++ b/rpcs3/Emu/System.cpp @@ -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; diff --git a/rpcs3/Loader/ELF64.cpp b/rpcs3/Loader/ELF64.cpp index 0abf3866ea..6604d86d64 100644 --- a/rpcs3/Loader/ELF64.cpp +++ b/rpcs3/Loader/ELF64.cpp @@ -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; diff --git a/rpcs3/rpcs3.vcxproj b/rpcs3/rpcs3.vcxproj index 4cab3dadce..80630f36d2 100644 --- a/rpcs3/rpcs3.vcxproj +++ b/rpcs3/rpcs3.vcxproj @@ -299,17 +299,20 @@ + + + diff --git a/rpcs3/rpcs3.vcxproj.filters b/rpcs3/rpcs3.vcxproj.filters index dae9429118..c045ad6bbe 100644 --- a/rpcs3/rpcs3.vcxproj.filters +++ b/rpcs3/rpcs3.vcxproj.filters @@ -439,12 +439,21 @@ Crypto + + Emu\SysCalls + Emu\SysCalls\Modules Emu\SysCalls\Modules + + Emu\SysCalls\Modules + + + Emu\SysCalls\Modules + Emu\Audio