#include "stdafx.h" #include "Emu/IdManager.h" #include "Emu/Cell/PPUModule.h" #ifdef _MSC_VER #pragma warning(push, 0) #else #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wall" #pragma GCC diagnostic ignored "-Wextra" #pragma GCC diagnostic ignored "-Wold-style-cast" #endif extern "C" { #include "libswscale/swscale.h" } #ifdef _MSC_VER #pragma warning(pop) #else #pragma GCC diagnostic pop #endif #include "cellVpost.h" LOG_CHANNEL(cellVpost); template <> void fmt_class_string::format(std::string& out, u64 arg) { format_enum(out, arg, [](auto error) { switch (error) { STR_CASE(CELL_VPOST_ERROR_Q_ARG_CFG_NULL); STR_CASE(CELL_VPOST_ERROR_Q_ARG_CFG_INVALID); STR_CASE(CELL_VPOST_ERROR_Q_ARG_ATTR_NULL); STR_CASE(CELL_VPOST_ERROR_O_ARG_CFG_NULL); STR_CASE(CELL_VPOST_ERROR_O_ARG_CFG_INVALID); STR_CASE(CELL_VPOST_ERROR_O_ARG_RSRC_NULL); STR_CASE(CELL_VPOST_ERROR_O_ARG_RSRC_INVALID); STR_CASE(CELL_VPOST_ERROR_O_ARG_HDL_NULL); STR_CASE(CELL_VPOST_ERROR_O_FATAL_QUERY_FAIL); STR_CASE(CELL_VPOST_ERROR_O_FATAL_CREATEMON_FAIL); STR_CASE(CELL_VPOST_ERROR_O_FATAL_INITSPURS_FAIL); STR_CASE(CELL_VPOST_ERROR_C_ARG_HDL_NULL); STR_CASE(CELL_VPOST_ERROR_C_ARG_HDL_INVALID); STR_CASE(CELL_VPOST_ERROR_C_FATAL_LOCKMON_FAIL); STR_CASE(CELL_VPOST_ERROR_C_FATAL_UNLOCKMON_FAIL); STR_CASE(CELL_VPOST_ERROR_C_FATAL_DESTROYMON_FAIL); STR_CASE(CELL_VPOST_ERROR_C_FATAL_FINSPURS_FAIL); STR_CASE(CELL_VPOST_ERROR_E_ARG_HDL_NULL); STR_CASE(CELL_VPOST_ERROR_E_ARG_HDL_INVALID); STR_CASE(CELL_VPOST_ERROR_E_ARG_INPICBUF_NULL); STR_CASE(CELL_VPOST_ERROR_E_ARG_INPICBUF_INVALID); STR_CASE(CELL_VPOST_ERROR_E_ARG_CTRL_NULL); STR_CASE(CELL_VPOST_ERROR_E_ARG_CTRL_INVALID); STR_CASE(CELL_VPOST_ERROR_E_ARG_OUTPICBUF_NULL); STR_CASE(CELL_VPOST_ERROR_E_ARG_OUTPICBUF_INVALID); STR_CASE(CELL_VPOST_ERROR_E_ARG_PICINFO_NULL); STR_CASE(CELL_VPOST_ERROR_E_FATAL_LOCKMON_FAIL); STR_CASE(CELL_VPOST_ERROR_E_FATAL_UNLOCKMON_FAIL); STR_CASE(CELL_VPOST_ENT_ERROR_Q_ARG_ATTR_NULL); STR_CASE(CELL_VPOST_ENT_ERROR_O_ARG_RSRC_NULL); STR_CASE(CELL_VPOST_ENT_ERROR_O_ARG_RSRC_INVALID); STR_CASE(CELL_VPOST_ENT_ERROR_O_ARG_HDL_NULL); STR_CASE(CELL_VPOST_ENT_ERROR_O_FATAL_QUERY_FAIL); STR_CASE(CELL_VPOST_ENT_ERROR_O_FATAL_CSPUCORE_FAIL); STR_CASE(CELL_VPOST_ENT_ERROR_C_ARG_HDL_NULL); STR_CASE(CELL_VPOST_ENT_ERROR_C_ARG_HDL_INVALID); STR_CASE(CELL_VPOST_ENT_ERROR_C_FATAL_SNDCMD_FAIL); STR_CASE(CELL_VPOST_ENT_ERROR_C_FATAL_RCVRES_FAIL); STR_CASE(CELL_VPOST_ENT_ERROR_C_FATAL_DSPUCORE_FAIL); STR_CASE(CELL_VPOST_ENT_ERROR_E_ARG_HDL_NULL); STR_CASE(CELL_VPOST_ENT_ERROR_E_ARG_HDL_INVALID); STR_CASE(CELL_VPOST_ENT_ERROR_E_ARG_INPICBUF_NULL); STR_CASE(CELL_VPOST_ENT_ERROR_E_ARG_INPICBUF_INVALID); STR_CASE(CELL_VPOST_ENT_ERROR_E_ARG_INPICINFO_NULL); STR_CASE(CELL_VPOST_ENT_ERROR_E_ARG_INPICINFO_INVALID); STR_CASE(CELL_VPOST_ENT_ERROR_E_ARG_CTRL_NULL); STR_CASE(CELL_VPOST_ENT_ERROR_E_ARG_CTRL_INVALID); STR_CASE(CELL_VPOST_ENT_ERROR_E_ARG_COMB_INVALID); STR_CASE(CELL_VPOST_ENT_ERROR_E_ARG_OUTPICBUF_NULL); STR_CASE(CELL_VPOST_ENT_ERROR_E_ARG_OUTPICBUF_INVALID); STR_CASE(CELL_VPOST_ENT_ERROR_E_ARG_OUTPICINFO_NULL); STR_CASE(CELL_VPOST_ENT_ERROR_E_FATAL_SNDCMD_FAIL); STR_CASE(CELL_VPOST_ENT_ERROR_E_FATAL_RCVRES_FAIL); STR_CASE(CELL_VPOST_ENT_ERROR_E_FATAL_SPUCORE_FAIL); STR_CASE(CELL_VPOST_IPC_ERROR_Q_ARG_ATTR_NULL); STR_CASE(CELL_VPOST_IPC_ERROR_O_ARG_RSRC_NULL); STR_CASE(CELL_VPOST_IPC_ERROR_O_ARG_RSRC_INVALID); STR_CASE(CELL_VPOST_IPC_ERROR_O_ARG_HDL_NULL); STR_CASE(CELL_VPOST_IPC_ERROR_O_FATAL_QUERY_FAIL); STR_CASE(CELL_VPOST_IPC_ERROR_O_FATAL_CSPUCORE_FAIL); STR_CASE(CELL_VPOST_IPC_ERROR_C_ARG_HDL_NULL); STR_CASE(CELL_VPOST_IPC_ERROR_C_ARG_HDL_INVALID); STR_CASE(CELL_VPOST_IPC_ERROR_C_FATAL_SNDCMD_FAIL); STR_CASE(CELL_VPOST_IPC_ERROR_C_FATAL_RCVRES_FAIL); STR_CASE(CELL_VPOST_IPC_ERROR_C_FATAL_DSPUCORE_FAIL); STR_CASE(CELL_VPOST_IPC_ERROR_E_ARG_HDL_NULL); STR_CASE(CELL_VPOST_IPC_ERROR_E_ARG_HDL_INVALID); STR_CASE(CELL_VPOST_IPC_ERROR_E_ARG_INPICBUF_NULL); STR_CASE(CELL_VPOST_IPC_ERROR_E_ARG_INPICBUF_INVALID); STR_CASE(CELL_VPOST_IPC_ERROR_E_ARG_INPICINFO_NULL); STR_CASE(CELL_VPOST_IPC_ERROR_E_ARG_INPICINFO_INVALID); STR_CASE(CELL_VPOST_IPC_ERROR_E_ARG_CTRL_NULL); STR_CASE(CELL_VPOST_IPC_ERROR_E_ARG_CTRL_INVALID); STR_CASE(CELL_VPOST_IPC_ERROR_E_ARG_COMB_INVALID); STR_CASE(CELL_VPOST_IPC_ERROR_E_ARG_OUTPICBUF_NULL); STR_CASE(CELL_VPOST_IPC_ERROR_E_ARG_OUTPICBUF_INVALID); STR_CASE(CELL_VPOST_IPC_ERROR_E_ARG_OUTPICINFO_NULL); STR_CASE(CELL_VPOST_IPC_ERROR_E_FATAL_SNDCMD_FAIL); STR_CASE(CELL_VPOST_IPC_ERROR_E_FATAL_RCVRES_FAIL); STR_CASE(CELL_VPOST_IPC_ERROR_E_FATAL_SPUCORE_FAIL); STR_CASE(CELL_VPOST_VSC_ERROR_Q_ARG_ATTR_NULL); STR_CASE(CELL_VPOST_VSC_ERROR_O_ARG_RSRC_NULL); STR_CASE(CELL_VPOST_VSC_ERROR_O_ARG_RSRC_INVALID); STR_CASE(CELL_VPOST_VSC_ERROR_O_ARG_HDL_NULL); STR_CASE(CELL_VPOST_VSC_ERROR_O_FATAL_QUERY_FAIL); STR_CASE(CELL_VPOST_VSC_ERROR_O_FATAL_CSPUCORE_FAIL); STR_CASE(CELL_VPOST_VSC_ERROR_C_ARG_HDL_NULL); STR_CASE(CELL_VPOST_VSC_ERROR_C_ARG_HDL_INVALID); STR_CASE(CELL_VPOST_VSC_ERROR_C_FATAL_SNDCMD_FAIL); STR_CASE(CELL_VPOST_VSC_ERROR_C_FATAL_RCVRES_FAIL); STR_CASE(CELL_VPOST_VSC_ERROR_C_FATAL_DSPUCORE_FAIL); STR_CASE(CELL_VPOST_VSC_ERROR_E_ARG_HDL_NULL); STR_CASE(CELL_VPOST_VSC_ERROR_E_ARG_HDL_INVALID); STR_CASE(CELL_VPOST_VSC_ERROR_E_ARG_INPICBUF_NULL); STR_CASE(CELL_VPOST_VSC_ERROR_E_ARG_INPICBUF_INVALID); STR_CASE(CELL_VPOST_VSC_ERROR_E_ARG_INPICINFO_NULL); STR_CASE(CELL_VPOST_VSC_ERROR_E_ARG_INPICINFO_INVALID); STR_CASE(CELL_VPOST_VSC_ERROR_E_ARG_CTRL_NULL); STR_CASE(CELL_VPOST_VSC_ERROR_E_ARG_CTRL_INVALID); STR_CASE(CELL_VPOST_VSC_ERROR_E_ARG_COMB_INVALID); STR_CASE(CELL_VPOST_VSC_ERROR_E_ARG_OUTPICBUF_NULL); STR_CASE(CELL_VPOST_VSC_ERROR_E_ARG_OUTPICBUF_INVALID); STR_CASE(CELL_VPOST_VSC_ERROR_E_ARG_OUTPICINFO_NULL); STR_CASE(CELL_VPOST_VSC_ERROR_E_FATAL_SNDCMD_FAIL); STR_CASE(CELL_VPOST_VSC_ERROR_E_FATAL_RCVRES_FAIL); STR_CASE(CELL_VPOST_VSC_ERROR_E_FATAL_SPUCORE_FAIL); STR_CASE(CELL_VPOST_CSC_ERROR_Q_ARG_ATTR_NULL); STR_CASE(CELL_VPOST_CSC_ERROR_O_ARG_RSRC_NULL); STR_CASE(CELL_VPOST_CSC_ERROR_O_ARG_RSRC_INVALID); STR_CASE(CELL_VPOST_CSC_ERROR_O_ARG_HDL_NULL); STR_CASE(CELL_VPOST_CSC_ERROR_O_FATAL_QUERY_FAIL); STR_CASE(CELL_VPOST_CSC_ERROR_O_FATAL_CSPUCORE_FAIL); STR_CASE(CELL_VPOST_CSC_ERROR_C_ARG_HDL_NULL); STR_CASE(CELL_VPOST_CSC_ERROR_C_ARG_HDL_INVALID); STR_CASE(CELL_VPOST_CSC_ERROR_C_FATAL_SNDCMD_FAIL); STR_CASE(CELL_VPOST_CSC_ERROR_C_FATAL_RCVRES_FAIL); STR_CASE(CELL_VPOST_CSC_ERROR_C_FATAL_DSPUCORE_FAIL); STR_CASE(CELL_VPOST_CSC_ERROR_E_ARG_HDL_NULL); STR_CASE(CELL_VPOST_CSC_ERROR_E_ARG_HDL_INVALID); STR_CASE(CELL_VPOST_CSC_ERROR_E_ARG_INPICBUF_NULL); STR_CASE(CELL_VPOST_CSC_ERROR_E_ARG_INPICBUF_INVALID); STR_CASE(CELL_VPOST_CSC_ERROR_E_ARG_INPICINFO_NULL); STR_CASE(CELL_VPOST_CSC_ERROR_E_ARG_INPICINFO_INVALID); STR_CASE(CELL_VPOST_CSC_ERROR_E_ARG_CTRL_NULL); STR_CASE(CELL_VPOST_CSC_ERROR_E_ARG_CTRL_INVALID); STR_CASE(CELL_VPOST_CSC_ERROR_E_ARG_COMB_INVALID); STR_CASE(CELL_VPOST_CSC_ERROR_E_ARG_OUTPICBUF_NULL); STR_CASE(CELL_VPOST_CSC_ERROR_E_ARG_OUTPICBUF_INVALID); STR_CASE(CELL_VPOST_CSC_ERROR_E_ARG_OUTPICINFO_NULL); STR_CASE(CELL_VPOST_CSC_ERROR_E_FATAL_SNDCMD_FAIL); STR_CASE(CELL_VPOST_CSC_ERROR_E_FATAL_RCVRES_FAIL); STR_CASE(CELL_VPOST_CSC_ERROR_E_FATAL_SPUCORE_FAIL); } return unknown; }); } error_code cellVpostQueryAttr(vm::cptr cfgParam, vm::ptr attr) { cellVpost.warning("cellVpostQueryAttr(cfgParam=*0x%x, attr=*0x%x)", cfgParam, attr); // TODO: check cfgParam and output values attr->delay = 0; attr->memSize = 4 * 1024 * 1024; // 4 MB attr->vpostVerLower = 0x280000; // from dmux attr->vpostVerUpper = 0x260000; return CELL_OK; } error_code cellVpostOpen(vm::cptr cfgParam, vm::cptr resource, vm::ptr handle) { cellVpost.warning("cellVpostOpen(cfgParam=*0x%x, resource=*0x%x, handle=*0x%x)", cfgParam, resource, handle); // TODO: check values *handle = idm::make(cfgParam->outPicFmt == CELL_VPOST_PIC_FMT_OUT_RGBA_ILV); return CELL_OK; } error_code cellVpostOpenEx(vm::cptr cfgParam, vm::cptr resource, vm::ptr handle) { cellVpost.warning("cellVpostOpenEx(cfgParam=*0x%x, resource=*0x%x, handle=*0x%x)", cfgParam, resource, handle); // TODO: check values *handle = idm::make(cfgParam->outPicFmt == CELL_VPOST_PIC_FMT_OUT_RGBA_ILV); return CELL_OK; } error_code cellVpostClose(u32 handle) { cellVpost.warning("cellVpostClose(handle=0x%x)", handle); const auto vpost = idm::get_unlocked(handle); if (!vpost) { return CELL_VPOST_ERROR_C_ARG_HDL_INVALID; } idm::remove(handle); return CELL_OK; } error_code cellVpostExec(u32 handle, vm::cptr inPicBuff, vm::cptr ctrlParam, vm::ptr outPicBuff, vm::ptr picInfo) { cellVpost.trace("cellVpostExec(handle=0x%x, inPicBuff=*0x%x, ctrlParam=*0x%x, outPicBuff=*0x%x, picInfo=*0x%x)", handle, inPicBuff, ctrlParam, outPicBuff, picInfo); const auto vpost = idm::get_unlocked(handle); if (!vpost) { return CELL_VPOST_ERROR_E_ARG_HDL_INVALID; } u32 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", ctrlParam->inWindow.x); if (ctrlParam->inWindow.y) cellVpost.notice("*** inWindow.y = %d", ctrlParam->inWindow.y); if (ctrlParam->inWindow.width != w) cellVpost.notice("*** inWindow.width = %d", ctrlParam->inWindow.width); if (ctrlParam->inWindow.height != h) cellVpost.notice("*** inWindow.height = %d", ctrlParam->inWindow.height); // ctrlParam->outWindow; // ignored if (ctrlParam->outWindow.x) cellVpost.notice("*** outWindow.x = %d", ctrlParam->outWindow.x); if (ctrlParam->outWindow.y) cellVpost.notice("*** outWindow.y = %d", ctrlParam->outWindow.y); if (ctrlParam->outWindow.width != ow) cellVpost.notice("*** outWindow.width = %d", ctrlParam->outWindow.width); if (ctrlParam->outWindow.height != oh) cellVpost.notice("*** outWindow.height = %d", 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_guest_system_time(); std::unique_ptr pA(new u8[w * h]); memset(pA.get(), ctrlParam->outAlpha, w * h); // u64 stamp1 = get_guest_system_time(); vpost->sws = sws_getCachedContext(vpost->sws, w, h, AV_PIX_FMT_YUVA420P, ow, oh, AV_PIX_FMT_RGBA, SWS_BILINEAR, nullptr, nullptr, nullptr); // u64 stamp2 = get_guest_system_time(); const u8* in_data[4] = {&inPicBuff[0], &inPicBuff[w * h], &inPicBuff[w * h * 5 / 4], pA.get()}; int ws = w; int in_line[4] = {ws, ws / 2, ws / 2, ws}; u8* out_data[4] = {outPicBuff.get_ptr(), nullptr, nullptr, nullptr}; int out_line[4] = {static_cast(ow * 4), 0, 0, 0}; sws_scale(vpost->sws, in_data, in_line, 0, h, out_data, out_line); // ConLog.Write("cellVpostExec() perf (access=%d, getContext=%d, scale=%d, finalize=%d)", // stamp1 - stamp0, stamp2 - stamp1, stamp3 - stamp2, get_guest_system_time() - stamp3); return CELL_OK; } DECLARE(ppu_module_manager::cellVpost)("cellVpost", []() { REG_FUNC(cellVpost, cellVpostQueryAttr); REG_FUNC(cellVpost, cellVpostOpen); REG_FUNC(cellVpost, cellVpostOpenEx); // REG_FUNC(cellVpost, cellVpostOpenExt); // 0x9f1795df REG_FUNC(cellVpost, cellVpostClose); REG_FUNC(cellVpost, cellVpostExec); });