s32 inet_pton(s32 af, vm::cptr<char> src, vm::ptr<char> dst) { libnet.warning("inet_pton(af=%d, src=*0x%x, dst=*0x%x)", af, src, dst); return ::inet_pton(af, src.get_ptr(), dst.get_ptr()); }
s64 cellSpursSetPriorities(vm::ptr<CellSpurs> spurs, u32 workloadId, vm::ptr<const u8> priorities) { #ifdef PRX_DEBUG cellSpurs->Warning("cellSpursSetPriorities(spurs_addr=0x%x, workloadId=%d, priorities_addr=0x%x)", spurs.addr(), workloadId, priorities.addr()); return GetCurrentPPUThread().FastCall2(libsre + 0x8BC0, libsre_rtoc); #else UNIMPLEMENTED_FUNC(cellSpurs); return CELL_OK; #endif }
s64 cellSpursEnableExceptionEventHandler(vm::ptr<CellSpurs> spurs, bool flag) { #ifdef PRX_DEBUG cellSpurs->Warning("cellSpursEnableExceptionEventHandler(spurs_addr=0x%x, flag=%d)", spurs.addr(), flag); return GetCurrentPPUThread().FastCall2(libsre + 0xDCC0, libsre_rtoc); #else UNIMPLEMENTED_FUNC(cellSpurs); return CELL_OK; #endif }
s64 cellSpursGetSpuThreadGroupId(vm::ptr<CellSpurs> spurs, vm::ptr<be_t<u32>> group) { #ifdef PRX_DEBUG cellSpurs->Warning("cellSpursGetSpuThreadGroupId(spurs_addr=0x%x, group_addr=0x%x)", spurs.addr(), group.addr()); return GetCurrentPPUThread().FastCall2(libsre + 0x8B30, libsre_rtoc); #else UNIMPLEMENTED_FUNC(cellSpurs); return CELL_OK; #endif }
s64 cellSpursGetSpuThreadId(vm::ptr<CellSpurs> spurs, vm::ptr<be_t<u32>> thread, vm::ptr<be_t<u32>> nThreads) { #ifdef PRX_DEBUG cellSpurs->Warning("cellSpursGetSpuThreadId(spurs_addr=0x%x, thread_addr=0x%x, nThreads_addr=0x%x)", spurs.addr(), thread.addr(), nThreads.addr()); return GetCurrentPPUThread().FastCall2(libsre + 0x8A98, libsre_rtoc); #else UNIMPLEMENTED_FUNC(cellSpurs); return CELL_OK; #endif }
s32 cellVdecGetPicture(u32 handle, vm::cptr<CellVdecPicFormat> format, vm::ptr<u8> outBuff) { cellVdec.trace("cellVdecGetPicture(handle=0x%x, format=*0x%x, outBuff=*0x%x)", handle, format, outBuff); const auto vdec = idm::get<VideoDecoder>(handle); if (!vdec || !format) { return CELL_VDEC_ERROR_ARG; } VdecFrame vf; if (!vdec->frames.try_pop(vf)) { //std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack return CELL_VDEC_ERROR_EMPTY; } if (!vf.data) { // hack return CELL_OK; } std::unique_ptr<AVFrame, void(*)(AVFrame*)> frame(vf.data, [](AVFrame* frame) { av_frame_unref(frame); av_frame_free(&frame); }); if (outBuff) { const auto f = vdec->ctx->pix_fmt; const auto w = vdec->ctx->width; const auto h = vdec->ctx->height; auto out_f = AV_PIX_FMT_YUV420P; std::unique_ptr<u8[]> alpha_plane; switch (const u32 type = format->formatType) { case CELL_VDEC_PICFMT_ARGB32_ILV: out_f = AV_PIX_FMT_ARGB; alpha_plane.reset(new u8[w * h]); break; case CELL_VDEC_PICFMT_RGBA32_ILV: out_f = AV_PIX_FMT_RGBA; alpha_plane.reset(new u8[w * h]); break; case CELL_VDEC_PICFMT_UYVY422_ILV: out_f = AV_PIX_FMT_UYVY422; break; case CELL_VDEC_PICFMT_YUV420_PLANAR: out_f = AV_PIX_FMT_YUV420P; break; default: { throw EXCEPTION("Unknown formatType(%d)", type); } } if (format->colorMatrixType != CELL_VDEC_COLOR_MATRIX_TYPE_BT709) { throw EXCEPTION("Unknown colorMatrixType(%d)", format->colorMatrixType); } if (alpha_plane) { memset(alpha_plane.get(), format->alpha, w * h); } auto in_f = AV_PIX_FMT_YUV420P; switch (f) { case AV_PIX_FMT_YUV420P: in_f = alpha_plane ? AV_PIX_FMT_YUVA420P : AV_PIX_FMT_YUV420P; break; default: { throw EXCEPTION("Unknown pix_fmt(%d)", f); } } std::unique_ptr<SwsContext, void(*)(SwsContext*)> sws(sws_getContext(w, h, in_f, w, h, out_f, SWS_POINT, NULL, NULL, NULL), sws_freeContext); u8* in_data[4] = { frame->data[0], frame->data[1], frame->data[2], alpha_plane.get() }; int in_line[4] = { frame->linesize[0], frame->linesize[1], frame->linesize[2], w * 1 }; u8* out_data[4] = { outBuff.get_ptr() }; int out_line[4] = { w * 4 }; if (!alpha_plane) { out_data[1] = out_data[0] + w * h; out_data[2] = out_data[0] + w * h * 5 / 4; out_line[0] = w; out_line[1] = w / 2; out_line[2] = w / 2; } sws_scale(sws.get(), in_data, in_line, 0, h, out_data, out_line); //const u32 buf_size = align(av_image_get_buffer_size(vdec->ctx->pix_fmt, vdec->ctx->width, vdec->ctx->height, 1), 128); //// TODO: zero padding bytes //int err = av_image_copy_to_buffer(outBuff.get_ptr(), buf_size, frame->data, frame->linesize, vdec->ctx->pix_fmt, frame->width, frame->height, 1); //if (err < 0) //{ // cellVdec.Fatal("cellVdecGetPicture: av_image_copy_to_buffer failed (err=0x%x)", err); //} } return CELL_OK; }
int cellNetCtlAddHandler(vm::ptr<cellNetCtlHandler> handler, vm::ptr<void> arg, vm::ptr<s32> hid) { cellNetCtl.Todo("cellNetCtlAddHandler(handler_addr=0x%x, arg_addr=0x%x, hid_addr=0x%x)", handler.addr(), arg.addr(), hid.addr()); return CELL_OK; }
s32 cellSailPlayerSetPaused(vm::ptr<CellSailPlayer> pSelf, bool paused) { cellSail.Todo("cellSailPlayerSetPaused(pSelf_addr=0x%x, paused=%d)", pSelf.addr(), paused); return CELL_OK; }
s32 cellSailPlayerIsPaused(vm::ptr<CellSailPlayer> pSelf) { cellSail.Warning("cellSailPlayerIsPaused(pSelf_addr=0x%x)", pSelf.addr()); return pSelf->paused; }
s32 cellSailPlayerGetDescriptorCount(vm::ptr<CellSailPlayer> pSelf) { cellSail.Warning("cellSailPlayerGetDescriptorCount(pSelf_addr=0x%x)", pSelf.addr()); return pSelf->descriptors; }
s32 cellSailDescriptorSetAutoSelection(vm::ptr<CellSailDescriptor> pSelf, bool autoSelection) { cellSail.Warning("cellSailDescriptorSetAutoSelection(pSelf_addr=0x%x, autoSelection=%s)", pSelf.addr(), autoSelection ? "true" : "false"); if (pSelf) { pSelf->autoSelection = autoSelection; return autoSelection; } return CELL_OK; }
s32 cellSailMemAllocatorInitialize(vm::ptr<CellSailMemAllocator> pSelf, vm::ptr<CellSailMemAllocatorFuncs> pCallbacks) { cellSail.Warning("cellSailMemAllocatorInitialize(pSelf_addr=0x%x, pCallbacks_addr=0x%x)", pSelf.addr(), pCallbacks.addr()); pSelf->callbacks = pCallbacks; // TODO: Create a cellSail thread return CELL_OK; }
int cellMsgDialogOpen2(u32 type, vm::ptr<const char> msgString, vm::ptr<CellMsgDialogCallback> callback, u32 userData, u32 extParam) { cellSysutil->Warning("cellMsgDialogOpen2(type=0x%x, msgString_addr=0x%x, callback_addr=0x%x, userData=0x%x, extParam=0x%x)", type, msgString.addr(), callback.addr(), userData, extParam); //type |= CELL_MSGDIALOG_TYPE_PROGRESSBAR_SINGLE | CELL_MSGDIALOG_TYPE_BG_INVISIBLE; //type |= CELL_MSGDIALOG_TYPE_BUTTON_TYPE_YESNO | CELL_MSGDIALOG_TYPE_DEFAULT_CURSOR_NO; MsgDialogState old = msgDialogNone; if (!g_msg_dialog_state.compare_exchange_strong(old, msgDialogOpen)) { return CELL_SYSUTIL_ERROR_BUSY; } g_msg_dialog_wait_until = get_system_time() + 31536000000000ull; // some big value switch (type & CELL_MSGDIALOG_TYPE_PROGRESSBAR) { case CELL_MSGDIALOG_TYPE_PROGRESSBAR_DOUBLE: g_msg_dialog_progress_bar_count = 2; break; case CELL_MSGDIALOG_TYPE_PROGRESSBAR_SINGLE: g_msg_dialog_progress_bar_count = 1; break; default: g_msg_dialog_progress_bar_count = 0; break; // ??? } std::string msg = msgString.get_ptr(); thread t("MsgDialog thread", [type, msg, callback, userData, extParam]() { switch (type & CELL_MSGDIALOG_TYPE_SE_TYPE) { case CELL_MSGDIALOG_TYPE_SE_TYPE_NORMAL: LOG_WARNING(TTY, "%s", msg.c_str()); break; case CELL_MSGDIALOG_TYPE_SE_TYPE_ERROR: LOG_ERROR(TTY, "%s", msg.c_str()); break; } switch (type & CELL_MSGDIALOG_TYPE_SE_MUTE) // TODO { case CELL_MSGDIALOG_TYPE_SE_MUTE_OFF: break; case CELL_MSGDIALOG_TYPE_SE_MUTE_ON: break; } g_msg_dialog_status = CELL_MSGDIALOG_BUTTON_NONE; volatile bool m_signal = false; CallAfter([type, msg, &m_signal]() { if (Emu.IsStopped()) return; MsgDialogCreate(type, msg.c_str(), g_msg_dialog_status); m_signal = true; }); while (!m_signal) { if (Emu.IsStopped()) { cellSysutil->Warning("MsgDialog thread aborted"); return; } std::this_thread::sleep_for(std::chrono::milliseconds(1)); } while (g_msg_dialog_state == msgDialogOpen || (s64)(get_system_time() - g_msg_dialog_wait_until) < 0) { if (Emu.IsStopped()) { g_msg_dialog_state = msgDialogAbort; break; } std::this_thread::sleep_for(std::chrono::milliseconds(1)); } if (callback && (g_msg_dialog_state != msgDialogAbort)) { Emu.GetCallbackManager().Register([callback, userData]() -> s32 { callback((s32)g_msg_dialog_status, userData); return CELL_OK; }); } CallAfter([]() { MsgDialogDestroy(); g_msg_dialog_state = msgDialogNone; }); }); t.detach(); return CELL_OK; }
int cellMsgDialogOpenErrorCode(u32 errorCode, vm::ptr<CellMsgDialogCallback> callback, u32 userData, u32 extParam) { cellSysutil->Warning("cellMsgDialogOpenErrorCode(errorCode=0x%x, callback_addr=0x%x, userData=0x%x, extParam=%d)", errorCode, callback.addr(), userData, extParam); std::string errorMessage; switch (errorCode) { // Generic errors case 0x80010001: errorMessage = "The resource is temporarily unavailable."; break; case 0x80010002: errorMessage = "Invalid argument or flag."; break; case 0x80010003: errorMessage = "The feature is not yet implemented."; break; case 0x80010004: errorMessage = "Memory allocation failed."; break; case 0x80010005: errorMessage = "The resource with the specified identifier does not exist."; break; case 0x80010006: errorMessage = "The file does not exist."; break; case 0x80010007: errorMessage = "The file is in unrecognized format / The file is not a valid ELF file."; break; case 0x80010008: errorMessage = "Resource deadlock is avoided."; break; case 0x80010009: errorMessage = "Operation not permitted."; break; case 0x8001000A: errorMessage = "The device or resource is bus."; break; case 0x8001000B: errorMessage = "The operation is timed ou."; break; case 0x8001000C: errorMessage = "The operation is aborte."; break; case 0x8001000D: errorMessage = "Invalid memory access."; break; case 0x8001000F: errorMessage = "State of the target thread is invalid."; break; case 0x80010010: errorMessage = "Alignment is invalid."; break; case 0x80010011: errorMessage = "Shortage of the kernel resources."; break; case 0x80010012: errorMessage = "The file is a directory."; break; case 0x80010013: errorMessage = "Operation canceled."; break; case 0x80010014: errorMessage = "Entry already exists."; break; case 0x80010015: errorMessage = "Port is already connected."; break; case 0x80010016: errorMessage = "Port is not connected."; break; case 0x80010017: errorMessage = "Failure in authorizing SELF. Program authentication fail."; break; case 0x80010018: errorMessage = "The file is not MSELF."; break; case 0x80010019: errorMessage = "System version error."; break; case 0x8001001A: errorMessage = "Fatal system error occurred while authorizing SELF. SELF auth failure."; break; case 0x8001001B: errorMessage = "Math domain violation."; break; case 0x8001001C: errorMessage = "Math range violation."; break; case 0x8001001D: errorMessage = "Illegal multi-byte sequence in input."; break; case 0x8001001E: errorMessage = "File position error."; break; case 0x8001001F: errorMessage = "Syscall was interrupted."; break; case 0x80010020: errorMessage = "File too large."; break; case 0x80010021: errorMessage = "Too many links."; break; case 0x80010022: errorMessage = "File table overflow."; break; case 0x80010023: errorMessage = "No space left on device."; break; case 0x80010024: errorMessage = "Not a TTY."; break; case 0x80010025: errorMessage = "Broken pipe."; break; case 0x80010026: errorMessage = "Read-only filesystem."; break; case 0x80010027: errorMessage = "Illegal seek."; break; case 0x80010028: errorMessage = "Arg list too long."; break; case 0x80010029: errorMessage = "Access violation."; break; case 0x8001002A: errorMessage = "Invalid file descriptor."; break; case 0x8001002B: errorMessage = "Filesystem mounting failed."; break; case 0x8001002C: errorMessage = "Too many files open."; break; case 0x8001002D: errorMessage = "No device."; break; case 0x8001002E: errorMessage = "Not a directory."; break; case 0x8001002F: errorMessage = "No such device or IO."; break; case 0x80010030: errorMessage = "Cross-device link error."; break; case 0x80010031: errorMessage = "Bad Message."; break; case 0x80010032: errorMessage = "In progress."; break; case 0x80010033: errorMessage = "Message size error."; break; case 0x80010034: errorMessage = "Name too long."; break; case 0x80010035: errorMessage = "No lock."; break; case 0x80010036: errorMessage = "Not empty."; break; case 0x80010037: errorMessage = "Not supported."; break; case 0x80010038: errorMessage = "File-system specific error."; break; case 0x80010039: errorMessage = "Overflow occured."; break; case 0x8001003A: errorMessage = "Filesystem not mounted."; break; case 0x8001003B: errorMessage = "Not SData."; break; case 0x8001003C: errorMessage = "Incorrect version in sys_load_param."; break; case 0x8001003D: errorMessage = "Pointer is null."; break; case 0x8001003E: errorMessage = "Pointer is null."; break; default: errorMessage = "An error has occurred."; break; } char errorCodeHex[12]; sprintf(errorCodeHex, "\n(%08x)", errorCode); errorMessage.append(errorCodeHex); u64 status; int res = rMessageBox(errorMessage, "Error", rICON_ERROR | rOK); switch (res) { case rOK: status = CELL_MSGDIALOG_BUTTON_OK; break; default: if (res) { status = CELL_MSGDIALOG_BUTTON_INVALID; break; } status = CELL_MSGDIALOG_BUTTON_NONE; break; } if (callback) callback((s32)status, userData); return CELL_OK; }
s32 sys_event_flag_wait(u32 eflag_id, u64 bitptn, u32 mode, vm::ptr<u64> result, u64 timeout) { sys_event_flag.Log("sys_event_flag_wait(eflag_id=%d, bitptn=0x%llx, mode=0x%x, result_addr=0x%x, timeout=%lld)", eflag_id, bitptn, mode, result.addr(), timeout); if (result) *result = 0; switch (mode & 0xf) { case SYS_EVENT_FLAG_WAIT_AND: break; case SYS_EVENT_FLAG_WAIT_OR: break; default: return CELL_EINVAL; } switch (mode & ~0xf) { case 0: break; // ??? case SYS_EVENT_FLAG_WAIT_CLEAR: break; case SYS_EVENT_FLAG_WAIT_CLEAR_ALL: break; default: return CELL_EINVAL; } EventFlag* ef; if (!sys_event_flag.CheckId(eflag_id, ef)) return CELL_ESRCH; const u32 tid = GetCurrentPPUThread().GetId(); { ef->m_mutex.lock(tid); if (ef->m_type == SYS_SYNC_WAITER_SINGLE && ef->waiters.size() > 0) { ef->m_mutex.unlock(tid); return CELL_EPERM; } EventFlagWaiter rec; rec.bitptn = bitptn; rec.mode = mode; rec.tid = tid; ef->waiters.push_back(rec); if (ef->check() == tid) { u64 flags = ef->flags; ef->waiters.erase(ef->waiters.end() - 1); if (mode & SYS_EVENT_FLAG_WAIT_CLEAR) { ef->flags &= ~bitptn; } else if (mode & SYS_EVENT_FLAG_WAIT_CLEAR_ALL) { ef->flags = 0; } if (result) *result = flags; ef->m_mutex.unlock(tid); return CELL_OK; } ef->m_mutex.unlock(tid); } u64 counter = 0; const u64 max_counter = timeout ? (timeout / 1000) : ~0; while (true) { if (ef->signal.unlock(tid, tid) == SMR_OK) { ef->m_mutex.lock(tid); u64 flags = ef->flags; for (u32 i = 0; i < ef->waiters.size(); i++) { if (ef->waiters[i].tid == tid) { ef->waiters.erase(ef->waiters.begin() + i); if (mode & SYS_EVENT_FLAG_WAIT_CLEAR) { ef->flags &= ~bitptn; } else if (mode & SYS_EVENT_FLAG_WAIT_CLEAR_ALL) { ef->flags = 0; } if (u32 target = ef->check()) { // if signal, leave both mutexes locked... ef->signal.unlock(tid, target); ef->m_mutex.unlock(tid, target); } else { ef->signal.unlock(tid); } if (result) *result = flags; ef->m_mutex.unlock(tid); return CELL_OK; } } ef->signal.unlock(tid); ef->m_mutex.unlock(tid); return CELL_ECANCELED; } std::this_thread::sleep_for(std::chrono::milliseconds(1)); if (counter++ > max_counter) { ef->m_mutex.lock(tid); for (u32 i = 0; i < ef->waiters.size(); i++) { if (ef->waiters[i].tid == tid) { ef->waiters.erase(ef->waiters.begin() + i); break; } } ef->m_mutex.unlock(tid); return CELL_ETIMEDOUT; } if (Emu.IsStopped()) { sys_event_flag.Warning("sys_event_flag_wait(id=%d) aborted", eflag_id); return CELL_OK; } } }
s32 cellSailPlayerGetRepeatMode(vm::ptr<CellSailPlayer> pSelf, vm::ptr<CellSailStartCommand> pCommand) { cellSail.Warning("cellSailPlayerGetRepeatMode(pSelf_addr=0x%x, pCommand_addr=0x%x)", pSelf.addr(), pCommand.addr()); pCommand = pSelf->playbackCommand; return pSelf->repeatMode; }
int cellVpostExec(u32 handle, vm::ptr<const u8> inPicBuff, vm::ptr<const CellVpostCtrlParam> ctrlParam, vm::ptr<u8> outPicBuff, vm::ptr<CellVpostPictureInfo> picInfo) { 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.addr(), outPicBuff.addr(), picInfo.addr()); VpostInstance* vpost; if (!Emu.GetIdManager().GetIDData(handle, vpost)) { return CELL_VPOST_ERROR_E_ARG_HDL_INVALID; } s32 w = ctrlParam->inWidth; u32 h = ctrlParam->inHeight; u32 ow = ctrlParam->outWidth; u32 oh = ctrlParam->outHeight; ctrlParam->inWindow; // ignored if (ctrlParam->inWindow.x) cellVpost->Notice("*** inWindow.x = %d", (u32)ctrlParam->inWindow.x); if (ctrlParam->inWindow.y) cellVpost->Notice("*** inWindow.y = %d", (u32)ctrlParam->inWindow.y); if (ctrlParam->inWindow.width != w) cellVpost->Notice("*** inWindow.width = %d", (u32)ctrlParam->inWindow.width); if (ctrlParam->inWindow.height != h) cellVpost->Notice("*** inWindow.height = %d", (u32)ctrlParam->inWindow.height); ctrlParam->outWindow; // ignored if (ctrlParam->outWindow.x) cellVpost->Notice("*** outWindow.x = %d", (u32)ctrlParam->outWindow.x); if (ctrlParam->outWindow.y) cellVpost->Notice("*** outWindow.y = %d", (u32)ctrlParam->outWindow.y); if (ctrlParam->outWindow.width != ow) cellVpost->Notice("*** outWindow.width = %d", (u32)ctrlParam->outWindow.width); if (ctrlParam->outWindow.height != oh) cellVpost->Notice("*** outWindow.height = %d", (u32)ctrlParam->outWindow.height); ctrlParam->execType; // ignored ctrlParam->scalerType; // ignored ctrlParam->ipcType; // ignored picInfo->inWidth = w; // copy picInfo->inHeight = h; // copy picInfo->inDepth = CELL_VPOST_PIC_DEPTH_8; // fixed picInfo->inScanType = CELL_VPOST_SCAN_TYPE_P; // TODO picInfo->inPicFmt = CELL_VPOST_PIC_FMT_IN_YUV420_PLANAR; // fixed picInfo->inChromaPosType = ctrlParam->inChromaPosType; // copy picInfo->inPicStruct = CELL_VPOST_PIC_STRUCT_PFRM; // TODO picInfo->inQuantRange = ctrlParam->inQuantRange; // copy picInfo->inColorMatrix = ctrlParam->inColorMatrix; // copy picInfo->outWidth = ow; // copy picInfo->outHeight = oh; // copy picInfo->outDepth = CELL_VPOST_PIC_DEPTH_8; // fixed picInfo->outScanType = CELL_VPOST_SCAN_TYPE_P; // TODO picInfo->outPicFmt = CELL_VPOST_PIC_FMT_OUT_RGBA_ILV; // TODO picInfo->outChromaPosType = ctrlParam->inChromaPosType; // ignored picInfo->outPicStruct = picInfo->inPicStruct; // ignored picInfo->outQuantRange = ctrlParam->inQuantRange; // ignored picInfo->outColorMatrix = ctrlParam->inColorMatrix; // ignored picInfo->userData = ctrlParam->userData; // copy picInfo->reserved1 = 0; picInfo->reserved2 = 0; //u64 stamp0 = get_system_time(); std::unique_ptr<u8[]> pA(new u8[w*h]); memset(pA.get(), (const u8)ctrlParam->outAlpha, w*h); //u64 stamp1 = get_system_time(); SwsContext* sws = sws_getContext(w, h, AV_PIX_FMT_YUVA420P, ow, oh, AV_PIX_FMT_RGBA, SWS_BILINEAR, NULL, NULL, NULL); //u64 stamp2 = get_system_time(); const u8* in_data[4] = { &inPicBuff[0], &inPicBuff[w * h], &inPicBuff[w * h * 5 / 4], pA.get() }; int in_line[4] = { w, w/2, w/2, w }; u8* out_data[4] = { outPicBuff.get_ptr(), NULL, NULL, NULL }; int out_line[4] = { static_cast<int>(ow*4), 0, 0, 0 }; sws_scale(sws, in_data, in_line, 0, h, out_data, out_line); //u64 stamp3 = get_system_time(); sws_freeContext(sws); //ConLog.Write("cellVpostExec() perf (access=%d, getContext=%d, scale=%d, finalize=%d)", //stamp1 - stamp0, stamp2 - stamp1, stamp3 - stamp2, get_system_time() - stamp3); return CELL_OK; }
s32 sys_fs_open(vm::ptr<const char> path, s32 flags, vm::ptr<u32> fd, s32 mode, vm::ptr<const void> arg, u64 size) { sys_fs.Warning("sys_fs_open(path=*0x%x, flags=%#o, fd=*0x%x, mode=%#o, arg=*0x%x, size=0x%llx)", path, flags, fd, mode, arg, size); sys_fs.Warning("*** path = '%s'", path.get_ptr()); if (!path[0]) { sys_fs.Error("sys_fs_open('%s') failed: path is invalid", path.get_ptr()); return CELL_FS_EINVAL; } std::string local_path; const auto device = Emu.GetVFS().GetDevice(path.get_ptr(), local_path); if (!device) { sys_fs.Error("sys_fs_open('%s') failed: device not mounted", path.get_ptr()); return CELL_FS_ENOTMOUNTED; } // TODO: other checks for path if (fs::is_dir(local_path)) { sys_fs.Error("sys_fs_open('%s') failed: path is a directory", path.get_ptr()); return CELL_FS_EISDIR; } u32 open_mode = 0; switch (flags & CELL_FS_O_ACCMODE) { case CELL_FS_O_RDONLY: open_mode |= o_read; break; case CELL_FS_O_WRONLY: open_mode |= o_write; break; case CELL_FS_O_RDWR: open_mode |= o_read | o_write; break; } if (flags & CELL_FS_O_CREAT) { open_mode |= o_create; } if (flags & CELL_FS_O_TRUNC) { open_mode |= o_trunc; } if (flags & CELL_FS_O_EXCL) { if (flags & CELL_FS_O_CREAT) { open_mode |= o_excl; } else { open_mode = 0; // error } } if (flags & ~(CELL_FS_O_ACCMODE | CELL_FS_O_CREAT | CELL_FS_O_TRUNC | CELL_FS_O_EXCL)) { open_mode = 0; // error } if ((flags & CELL_FS_O_ACCMODE) == CELL_FS_O_ACCMODE) { open_mode = 0; // error } if (!open_mode) { sys_fs.Fatal("sys_fs_open('%s'): invalid or unimplemented flags (%#o)", path.get_ptr(), flags); } std::shared_ptr<vfsStream> file(Emu.GetVFS().OpenFile(path.get_ptr(), open_mode)); if (!file || !file->IsOpened()) { sys_fs.Error("sys_fs_open('%s'): failed to open file (flags=%#o, mode=%#o)", path.get_ptr(), flags, mode); if (open_mode & o_excl) { return CELL_FS_EEXIST; // approximation } return CELL_FS_ENOENT; } *fd = Emu.GetIdManager().make<lv2_file_t>(file, mode, flags); return CELL_OK; }
s32 cellVdecGetPicItem(u32 handle, vm::pptr<CellVdecPicItem> picItem) { cellVdec.trace("cellVdecGetPicItem(handle=0x%x, picItem=**0x%x)", handle, picItem); const auto vdec = idm::get<VideoDecoder>(handle); if (!vdec) { return CELL_VDEC_ERROR_ARG; } VdecFrame vf; if (!vdec->frames.try_peek(vf)) { //std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack return CELL_VDEC_ERROR_EMPTY; } AVFrame& frame = *vf.data; const vm::ptr<CellVdecPicItem> info{ vdec->memAddr + vdec->memBias, vm::addr }; 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 = align(av_image_get_buffer_size(vdec->ctx->pix_fmt, vdec->ctx->width, vdec->ctx->height, 1), 128); info->auNum = 1; info->auPts[0].lower = (u32)(vf.pts); info->auPts[0].upper = (u32)(vf.pts >> 32); info->auPts[1].lower = (u32)CODEC_TS_INVALID; info->auPts[1].upper = (u32)CODEC_TS_INVALID; info->auDts[0].lower = (u32)(vf.dts); info->auDts[0].upper = (u32)(vf.dts >> 32); info->auDts[1].lower = (u32)CODEC_TS_INVALID; info->auDts[1].upper = (u32)CODEC_TS_INVALID; info->auUserData[0] = vf.userdata; info->auUserData[1] = 0; info->status = CELL_OK; info->attr = CELL_VDEC_PICITEM_ATTR_NORMAL; info->picInfo_addr = info.addr() + SIZE_32(CellVdecPicItem); if (vdec->type == CELL_VDEC_CODEC_TYPE_AVC) { const vm::ptr<CellVdecAvcInfo> avc{ info.addr() + SIZE_32(CellVdecPicItem), vm::addr }; 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; case AV_PICTURE_TYPE_B: avc->pictureType[0] = CELL_VDEC_AVC_PCT_B; break; default: cellVdec.error("cellVdecGetPicItem(AVC): unknown pict_type value (0x%x)", frame.pict_type); } avc->pictureType[1] = CELL_VDEC_AVC_PCT_UNKNOWN; // ??? avc->idrPictureFlag = false; // ??? avc->aspect_ratio_idc = CELL_VDEC_AVC_ARI_SAR_UNSPECIFIED; // ??? avc->sar_height = 0; avc->sar_width = 0; avc->pic_struct = CELL_VDEC_AVC_PSTR_FRAME; // ??? avc->picOrderCount[0] = 0; // ??? avc->picOrderCount[1] = 0; avc->vui_parameters_present_flag = true; // ??? avc->frame_mbs_only_flag = true; // ??? progressive avc->video_signal_type_present_flag = true; // ??? avc->video_format = CELL_VDEC_AVC_VF_COMPONENT; // ??? avc->video_full_range_flag = false; // ??? avc->colour_description_present_flag = true; avc->colour_primaries = CELL_VDEC_AVC_CP_ITU_R_BT_709_5; // ??? avc->transfer_characteristics = CELL_VDEC_AVC_TC_ITU_R_BT_709_5; avc->matrix_coefficients = CELL_VDEC_AVC_MXC_ITU_R_BT_709_5; // important avc->timing_info_present_flag = true; switch (vf.frc) { case CELL_VDEC_FRC_24000DIV1001: avc->frameRateCode = CELL_VDEC_AVC_FRC_24000DIV1001; break; case CELL_VDEC_FRC_24: avc->frameRateCode = CELL_VDEC_AVC_FRC_24; break; case CELL_VDEC_FRC_25: avc->frameRateCode = CELL_VDEC_AVC_FRC_25; break; case CELL_VDEC_FRC_30000DIV1001: avc->frameRateCode = CELL_VDEC_AVC_FRC_30000DIV1001; break; case CELL_VDEC_FRC_30: avc->frameRateCode = CELL_VDEC_AVC_FRC_30; break; case CELL_VDEC_FRC_50: avc->frameRateCode = CELL_VDEC_AVC_FRC_50; break; case CELL_VDEC_FRC_60000DIV1001: avc->frameRateCode = CELL_VDEC_AVC_FRC_60000DIV1001; break; case CELL_VDEC_FRC_60: avc->frameRateCode = CELL_VDEC_AVC_FRC_60; break; default: cellVdec.error("cellVdecGetPicItem(AVC): unknown frc value (0x%x)", vf.frc); } avc->fixed_frame_rate_flag = true; avc->low_delay_hrd_flag = true; // ??? avc->entropy_coding_mode_flag = true; // ??? avc->nalUnitPresentFlags = 0; // ??? avc->ccDataLength[0] = 0; avc->ccDataLength[1] = 0; avc->reserved[0] = 0; avc->reserved[1] = 0; } else if (vdec->type == CELL_VDEC_CODEC_TYPE_DIVX) { auto dvx = vm::ptr<CellVdecDivxInfo>::make(info.addr() + SIZE_32(CellVdecPicItem)); switch (frame.pict_type) { case AV_PICTURE_TYPE_I: dvx->pictureType = CELL_VDEC_DIVX_VCT_I; break; case AV_PICTURE_TYPE_P: dvx->pictureType = CELL_VDEC_DIVX_VCT_P; break; case AV_PICTURE_TYPE_B: dvx->pictureType = CELL_VDEC_DIVX_VCT_B; break; default: cellVdec.error("cellVdecGetPicItem(DivX): unknown pict_type value (0x%x)", frame.pict_type); } dvx->horizontalSize = frame.width; dvx->verticalSize = frame.height; dvx->pixelAspectRatio = CELL_VDEC_DIVX_ARI_PAR_1_1; // ??? dvx->parHeight = 0; dvx->parWidth = 0; dvx->colourDescription = false; // ??? dvx->colourPrimaries = CELL_VDEC_DIVX_CP_ITU_R_BT_709; // ??? dvx->transferCharacteristics = CELL_VDEC_DIVX_TC_ITU_R_BT_709; // ??? dvx->matrixCoefficients = CELL_VDEC_DIVX_MXC_ITU_R_BT_709; // ??? dvx->pictureStruct = CELL_VDEC_DIVX_PSTR_FRAME; // ??? switch (vf.frc) { case CELL_VDEC_FRC_24000DIV1001: dvx->frameRateCode = CELL_VDEC_DIVX_FRC_24000DIV1001; break; case CELL_VDEC_FRC_24: dvx->frameRateCode = CELL_VDEC_DIVX_FRC_24; break; case CELL_VDEC_FRC_25: dvx->frameRateCode = CELL_VDEC_DIVX_FRC_25; break; case CELL_VDEC_FRC_30000DIV1001: dvx->frameRateCode = CELL_VDEC_DIVX_FRC_30000DIV1001; break; case CELL_VDEC_FRC_30: dvx->frameRateCode = CELL_VDEC_DIVX_FRC_30; break; case CELL_VDEC_FRC_50: dvx->frameRateCode = CELL_VDEC_DIVX_FRC_50; break; case CELL_VDEC_FRC_60000DIV1001: dvx->frameRateCode = CELL_VDEC_DIVX_FRC_60000DIV1001; break; case CELL_VDEC_FRC_60: dvx->frameRateCode = CELL_VDEC_DIVX_FRC_60; break; default: cellVdec.error("cellVdecGetPicItem(DivX): unknown frc value (0x%x)", vf.frc); } } else if (vdec->type == CELL_VDEC_CODEC_TYPE_MPEG2) { auto mp2 = vm::ptr<CellVdecMpeg2Info>::make(info.addr() + SIZE_32(CellVdecPicItem)); throw EXCEPTION("MPEG2"); } *picItem = info; return CELL_OK; }
s32 sys_lwcond_wait(vm::ptr<sys_lwcond_t> lwcond, u64 timeout) { sys_lwcond.Log("sys_lwcond_wait(lwcond_addr=0x%x, timeout=%lld)", lwcond.addr(), timeout); Lwcond* lw; if (!Emu.GetIdManager().GetIDData((u32)lwcond->lwcond_queue, lw)) { return CELL_ESRCH; } auto mutex = vm::ptr<sys_lwmutex_t>::make(lwcond->lwmutex.addr()); u32 tid_le = GetCurrentPPUThread().GetId(); be_t<u32> tid = be_t<u32>::make(tid_le); SleepQueue* sq = nullptr; Emu.GetIdManager().GetIDData((u32)mutex->sleep_queue, sq); if (mutex->mutex.GetOwner() != tid) { sys_lwcond.Warning("sys_lwcond_wait(id=%d) failed (EPERM)", (u32)lwcond->lwcond_queue); return CELL_EPERM; // caller must own this lwmutex } lw->m_queue.push(tid_le); if (mutex->recursive_count.ToBE() != se32(1)) { sys_lwcond.Warning("sys_lwcond_wait(id=%d): associated mutex had wrong recursive value (%d)", (u32)lwcond->lwcond_queue, (u32)mutex->recursive_count); } mutex->recursive_count = 0; if (sq) { mutex->mutex.unlock(tid, be_t<u32>::make(mutex->attribute.ToBE() == se32(SYS_SYNC_PRIORITY) ? sq->pop_prio() : sq->pop())); } else if (mutex->attribute.ToBE() == se32(SYS_SYNC_RETRY)) { mutex->mutex.unlock(tid); // SYS_SYNC_RETRY } else { sys_lwcond.Warning("sys_lwcond_wait(id=%d): associated mutex had invalid sleep queue (%d)", (u32)lwcond->lwcond_queue, (u32)mutex->sleep_queue); } u64 counter = 0; const u64 max_counter = timeout ? (timeout / 1000) : ~0; while (true) { if (lw->signal.unlock(tid, tid) == SMR_OK) { switch (mutex->lock(tid, 0)) { case CELL_OK: break; case static_cast<int>(CELL_EDEADLK): sys_lwcond.Warning("sys_lwcond_wait(id=%d): associated mutex was locked", (u32)lwcond->lwcond_queue); return CELL_OK; case static_cast<int>(CELL_ESRCH): sys_lwcond.Warning("sys_lwcond_wait(id=%d): associated mutex not found (%d)", (u32)lwcond->lwcond_queue, (u32)mutex->sleep_queue); return CELL_ESRCH; case static_cast<int>(CELL_EINVAL): goto abort; } mutex->recursive_count = 1; lw->signal.unlock(tid); return CELL_OK; } std::this_thread::sleep_for(std::chrono::milliseconds(1)); if (counter++ > max_counter) { lw->m_queue.invalidate(tid_le); return CELL_ETIMEDOUT; } if (Emu.IsStopped()) { goto abort; } } abort: sys_lwcond.Warning("sys_lwcond_wait(id=%d) aborted", (u32)lwcond->lwcond_queue); return CELL_OK; }
s64 cellSpursAttributeSetSpuThreadGroupType(vm::ptr<CellSpursAttribute> attr, s32 type) { cellSpurs->Warning("cellSpursAttributeSetSpuThreadGroupType(attr_addr=0x%x, type=%d)", attr.addr(), type); #ifdef PRX_DEBUG return GetCurrentPPUThread().FastCall2(libsre + 0x70C8, libsre_rtoc); #else attr->attr->_setSpuThreadGroupType(type); return CELL_OK; #endif }
s32 cellSurMixerCreate(vm::cptr<CellSurMixerConfig> config) { libmixer.Warning("cellSurMixerCreate(config=*0x%x)", config); g_surmx.audio_port = g_audio.open_port(); if (!~g_surmx.audio_port) { return CELL_LIBMIXER_ERROR_FULL; } g_surmx.priority = config->priority; g_surmx.ch_strips_1 = config->chStrips1; g_surmx.ch_strips_2 = config->chStrips2; g_surmx.ch_strips_6 = config->chStrips6; g_surmx.ch_strips_8 = config->chStrips8; AudioPortConfig& port = g_audio.ports[g_surmx.audio_port]; port.channel = 8; port.block = 16; port.attr = 0; port.addr = g_audio.buffer + AUDIO_PORT_OFFSET * g_surmx.audio_port; port.read_index_addr = g_audio.indexes + sizeof(u64) * g_surmx.audio_port; port.size = port.channel * port.block * AUDIO_SAMPLES * sizeof(float); port.tag = 0; port.level = 1.0f; port.level_set.data = { 1.0f, 0.0f }; libmixer.Warning("*** audio port opened (port=%d)", g_surmx.audio_port); mixcount = 0; surMixerCb.set(0); libmixer.Warning("*** surMixer created (ch1=%d, ch2=%d, ch6=%d, ch8=%d)", config->chStrips1, config->chStrips2, config->chStrips6, config->chStrips8); auto ppu = Emu.GetIdManager().make_ptr<PPUThread>("Surmixer Thread"); ppu->prio = 1001; ppu->stack_size = 0x10000; ppu->custom_task = [](PPUThread& CPU) { AudioPortConfig& port = g_audio.ports[g_surmx.audio_port]; while (port.state.load() != AUDIO_PORT_STATE_CLOSED && !Emu.IsStopped()) { if (mixcount > (port.tag + 0)) // adding positive value (1-15): preemptive buffer filling (hack) { std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack continue; } if (port.state.load() == AUDIO_PORT_STATE_STARTED) { //u64 stamp0 = get_system_time(); memset(mixdata, 0, sizeof(mixdata)); if (surMixerCb) { surMixerCb(CPU, surMixerCbArg, (u32)mixcount, 256); } //u64 stamp1 = get_system_time(); { std::lock_guard<std::mutex> lock(mixer_mutex); for (auto& p : ssp) if (p.m_active && p.m_created) { auto v = vm::ptrl<s16>::make(p.m_addr); // 16-bit LE audio data float left = 0.0f; float right = 0.0f; float speed = fabs(p.m_speed); float fpos = 0.0f; for (s32 i = 0; i < 256; i++) if (p.m_active) { u32 pos = p.m_position; s32 pos_inc = 0; if (p.m_speed > 0.0f) // select direction { pos_inc = 1; } else if (p.m_speed < 0.0f) { pos_inc = -1; } s32 shift = i - (int)fpos; // change playback speed (simple and rough) if (shift > 0) { // slow playback pos_inc = 0; // duplicate one sample at this time fpos += 1.0f; fpos += speed; } else if (shift < 0) { // fast playback i--; // mix two sample into one at this time fpos -= 1.0f; } else { fpos += speed; } p.m_position += (u32)pos_inc; if (p.m_channels == 1) // get mono data { left = right = (float)v[pos] / 0x8000 * p.m_level; } else if (p.m_channels == 2) // get stereo data { left = (float)v[pos * 2 + 0] / 0x8000 * p.m_level; right = (float)v[pos * 2 + 1] / 0x8000 * p.m_level; } if (p.m_connected) // mix { // TODO: m_x, m_y, m_z ignored mixdata[i * 8 + 0] += left; mixdata[i * 8 + 1] += right; } if ((p.m_position == p.m_samples && p.m_speed > 0.0f) || (p.m_position == ~0 && p.m_speed < 0.0f)) // loop or stop { if (p.m_loop_mode == CELL_SSPLAYER_LOOP_ON) { p.m_position = p.m_loop_start; } else if (p.m_loop_mode == CELL_SSPLAYER_ONESHOT_CONT) { p.m_position -= (u32)pos_inc; // restore position } else // oneshot { p.m_active = false; p.m_position = p.m_loop_start; // TODO: check value } } } } } //u64 stamp2 = get_system_time(); auto buf = vm::get_ptr<be_t<float>>(port.addr + (mixcount % port.block) * port.channel * AUDIO_SAMPLES * sizeof(float)); for (u32 i = 0; i < (sizeof(mixdata) / sizeof(float)); i++) { // reverse byte order buf[i] = mixdata[i]; } //u64 stamp3 = get_system_time(); //ConLog.Write("Libmixer perf: start=%lld (cb=%lld, ssp=%lld, finalize=%lld)", stamp0 - m_config.start_time, stamp1 - stamp0, stamp2 - stamp1, stamp3 - stamp2); } mixcount++; } { std::lock_guard<std::mutex> lock(mixer_mutex); ssp.clear(); } surMixerCb.set(0); const u32 id = CPU.GetId(); CallAfter([id]() { Emu.GetIdManager().remove<PPUThread>(id); }); }; return CELL_OK; }
s64 cellSpursInitialize(vm::ptr<CellSpurs> spurs, s32 nSpus, s32 spuPriority, s32 ppuPriority, bool exitIfNoWork) { cellSpurs->Warning("cellSpursInitialize(spurs_addr=0x%x, nSpus=%d, spuPriority=%d, ppuPriority=%d, exitIfNoWork=%d)", spurs.addr(), nSpus, spuPriority, ppuPriority, exitIfNoWork); #ifdef PRX_DEBUG return GetCurrentPPUThread().FastCall2(libsre + 0x8480, libsre_rtoc); #else SPURSManagerAttribute *attr = new SPURSManagerAttribute(nSpus, spuPriority, ppuPriority, exitIfNoWork); spurs->spurs = new SPURSManager(attr); return CELL_OK; #endif }
s32 sys_ppu_thread_join(u64 thread_id, vm::ptr<be_t<u64>> vptr) { sys_ppu_thread.Warning("sys_ppu_thread_join(thread_id=%lld, vptr_addr=0x%x)", thread_id, vptr.addr()); CPUThread* thr = Emu.GetCPU().GetThread(thread_id); if(!thr) return CELL_ESRCH; while (thr->IsAlive()) { if (Emu.IsStopped()) { sys_ppu_thread.Warning("sys_ppu_thread_join(%d) aborted", thread_id); return CELL_OK; } std::this_thread::sleep_for(std::chrono::milliseconds(1)); } *vptr = thr->GetExitStatus(); return CELL_OK; }
s64 cellSpursSetMaxContention(vm::ptr<CellSpurs> spurs, u32 workloadId, u32 maxContention) { #ifdef PRX_DEBUG cellSpurs->Warning("cellSpursSetMaxContention(spurs_addr=0x%x, workloadId=%d, maxContention=%d)", spurs.addr(), workloadId, maxContention); return GetCurrentPPUThread().FastCall2(libsre + 0x8E90, libsre_rtoc); #else UNIMPLEMENTED_FUNC(cellSpurs); return CELL_OK; #endif }
void memcpy(vm::ptr<void> dst, vm::cptr<void> src, u32 size) { sceLibc.warning("memcpy(dst=*0x%x, src=*0x%x, size=0x%x)", dst, src, size); ::memcpy(dst.get_ptr(), src.get_ptr(), size); }
s64 cellSpursSetPreemptionVictimHints(vm::ptr<CellSpurs> spurs, vm::ptr<const bool> isPreemptible) { #ifdef PRX_DEBUG cellSpurs->Warning("cellSpursSetPreemptionVictimHints(spurs_addr=0x%x, isPreemptible_addr=0x%x)", spurs.addr(), isPreemptible.addr()); return GetCurrentPPUThread().FastCall2(libsre + 0xF5A4, libsre_rtoc); #else UNIMPLEMENTED_FUNC(cellSpurs); return CELL_OK; #endif }
void memset(vm::ptr<void> dst, s32 value, u32 size) { sceLibc.warning("memset(dst=*0x%x, value=%d, size=0x%x)", dst, value, size); ::memset(dst.get_ptr(), value, size); }
s64 cellSpursEventFlagWait(vm::ptr<CellSpursEventFlag> eventFlag, vm::ptr<be_t<u16>> mask, u32 mode) { #ifdef PRX_DEBUG cellSpurs->Warning("cellSpursEventFlagWait(eventFlag_addr=0x%x, mask_addr=0x%x, mode=%d)", eventFlag.addr(), mask.addr(), mode); return GetCurrentPPUThread().FastCall2(libsre + 0x15E68, libsre_rtoc); #else UNIMPLEMENTED_FUNC(cellSpurs); return CELL_OK; #endif }
vm::ref<s32> get_h_errno() { initialize_tls(); return g_tls_net_data.ref(&_tls_data_t::_h_errno); }