From 4446d9ce4b662d1340980bbc375e637538f87f36 Mon Sep 17 00:00:00 2001 From: Megamouse Date: Tue, 9 Aug 2022 20:28:17 +0200 Subject: [PATCH] cellSubDisplay: add error checks --- rpcs3/Emu/Cell/Modules/cellSubDisplay.cpp | 278 +++++++++++++++++++++- rpcs3/Emu/Cell/Modules/cellSubDisplay.h | 9 + 2 files changed, 285 insertions(+), 2 deletions(-) diff --git a/rpcs3/Emu/Cell/Modules/cellSubDisplay.cpp b/rpcs3/Emu/Cell/Modules/cellSubDisplay.cpp index b57155053a..2a19d2e661 100644 --- a/rpcs3/Emu/Cell/Modules/cellSubDisplay.cpp +++ b/rpcs3/Emu/Cell/Modules/cellSubDisplay.cpp @@ -1,5 +1,6 @@ #include "stdafx.h" #include "Emu/Cell/PPUModule.h" +#include "Emu/IdManager.h" #include "cellSubDisplay.h" @@ -27,15 +28,147 @@ void fmt_class_string::format(std::string& out, u64 arg) }); } +enum class sub_display_status : u32 +{ + uninitialized = 0, + stopped = 1, + started = 2 +}; + +struct sub_display_manager +{ + shared_mutex mutex; + sub_display_status status = sub_display_status::uninitialized; + CellSubDisplayParam param{}; + vm::ptr func = vm::null; + vm::ptr userdata = vm::null; + + // Video data + vm::ptr video_buffer = vm::null; + u32 buf_size = 0; + + // Audio data + bool audio_is_busy = false; + + // Touch data + std::array touch_info{}; +}; + + +error_code check_param(CellSubDisplayParam* param) +{ + if (!param || + param->version < CELL_SUBDISPLAY_VERSION_0001 || + param->version > CELL_SUBDISPLAY_VERSION_0003 || + param->mode != CELL_SUBDISPLAY_MODE_REMOTEPLAY || + param->nGroup != 1 || + param->nPeer != 1 || + param->audioParam.ch != 2 || + param->audioParam.audioMode < CELL_SUBDISPLAY_AUDIO_MODE_SETDATA || + param->audioParam.audioMode > CELL_SUBDISPLAY_AUDIO_MODE_CAPTURE) + { + return CELL_SUBDISPLAY_ERROR_INVALID_VALUE; + } + + switch (param->videoParam.format) + { + case CELL_SUBDISPLAY_VIDEO_FORMAT_A8R8G8B8: + case CELL_SUBDISPLAY_VIDEO_FORMAT_R8G8B8A8: + { + if (param->version == CELL_SUBDISPLAY_VERSION_0003 || + param->videoParam.width != 480 || + param->videoParam.height != 272 || + (param->videoParam.pitch != 1920 && param->videoParam.pitch != 2048) || + param->videoParam.aspectRatio < CELL_SUBDISPLAY_VIDEO_ASPECT_RATIO_16_9 || + param->videoParam.aspectRatio > CELL_SUBDISPLAY_VIDEO_ASPECT_RATIO_4_3 || + param->videoParam.videoMode < CELL_SUBDISPLAY_VIDEO_MODE_SETDATA || + param->videoParam.videoMode > CELL_SUBDISPLAY_VIDEO_MODE_CAPTURE) + { + return CELL_SUBDISPLAY_ERROR_INVALID_VALUE; + } + + break; + } + case CELL_SUBDISPLAY_VIDEO_FORMAT_YUV420: + { + if (param->version != CELL_SUBDISPLAY_VERSION_0003 || + param->videoParam.width != CELL_SUBDISPLAY_0003_WIDTH || + param->videoParam.height != CELL_SUBDISPLAY_0003_HEIGHT || + param->videoParam.pitch != CELL_SUBDISPLAY_0003_PITCH || + param->videoParam.aspectRatio != CELL_SUBDISPLAY_VIDEO_ASPECT_RATIO_16_9 || + param->videoParam.videoMode != CELL_SUBDISPLAY_VIDEO_MODE_SETDATA) + { + return CELL_SUBDISPLAY_ERROR_INVALID_VALUE; + } + + break; + } + default: + { + return CELL_SUBDISPLAY_ERROR_INVALID_VALUE; + } + } + + return CELL_OK; +} + error_code cellSubDisplayInit(vm::ptr pParam, vm::ptr func, vm::ptr userdata, u32 container) { cellSubDisplay.todo("cellSubDisplayInit(pParam=*0x%x, func=*0x%x, userdata=*0x%x, container=0x%x)", pParam, func, userdata, container); - return CELL_SUBDISPLAY_ERROR_ZERO_REGISTERED; + + auto& manager = g_fxo->get(); + std::lock_guard lock(manager.mutex); + + if (manager.func) + { + return CELL_SUBDISPLAY_ERROR_NOT_INITIALIZED; + } + + if (error_code error = check_param(pParam.get_ptr())) + { + return error; + } + + if (!func) + { + return CELL_SUBDISPLAY_ERROR_INVALID_VALUE; + } + + manager.param = *pParam; + manager.func = func; + manager.userdata = userdata; + + if (true) // TODO + { + return CELL_SUBDISPLAY_ERROR_ZERO_REGISTERED; + } + + return CELL_OK; } error_code cellSubDisplayEnd() { cellSubDisplay.todo("cellSubDisplayEnd()"); + + auto& manager = g_fxo->get(); + std::lock_guard lock(manager.mutex); + + if (!manager.func) + { + return CELL_SUBDISPLAY_ERROR_NOT_INITIALIZED; + } + + if (manager.status == sub_display_status::started) + { + // TODO: + // cellSubDisplayStop(); + } + + manager.param = {}; + manager.func = vm::null; + manager.userdata = vm::null; + manager.status = sub_display_status::uninitialized; + return CELL_OK; } @@ -43,6 +176,11 @@ error_code cellSubDisplayGetRequiredMemory(vm::ptr pParam) { cellSubDisplay.warning("cellSubDisplayGetRequiredMemory(pParam=*0x%x)", pParam); + if (error_code error = check_param(pParam.get_ptr())) + { + return error; + } + switch (pParam->version) { case CELL_SUBDISPLAY_VERSION_0001: return not_an_error(CELL_SUBDISPLAY_0001_MEMORY_CONTAINER_SIZE); @@ -57,18 +195,61 @@ error_code cellSubDisplayGetRequiredMemory(vm::ptr pParam) error_code cellSubDisplayStart() { cellSubDisplay.todo("cellSubDisplayStart()"); + + auto& manager = g_fxo->get(); + std::lock_guard lock(manager.mutex); + + if (manager.status == sub_display_status::uninitialized) + { + return CELL_SUBDISPLAY_ERROR_NOT_INITIALIZED; + } + + manager.status = sub_display_status::started; + + // TODO + return CELL_OK; } error_code cellSubDisplayStop() { cellSubDisplay.todo("cellSubDisplayStop()"); + + auto& manager = g_fxo->get(); + std::lock_guard lock(manager.mutex); + + if (manager.status == sub_display_status::uninitialized) + { + return CELL_SUBDISPLAY_ERROR_NOT_INITIALIZED; + } + + manager.status = sub_display_status::stopped; + + // TODO + return CELL_OK; } error_code cellSubDisplayGetVideoBuffer(s32 groupId, vm::pptr ppVideoBuf, vm::ptr pSize) { cellSubDisplay.todo("cellSubDisplayGetVideoBuffer(groupId=%d, ppVideoBuf=**0x%x, pSize=*0x%x)", groupId, ppVideoBuf, pSize); + + auto& manager = g_fxo->get(); + std::lock_guard lock(manager.mutex); + + if (manager.status == sub_display_status::uninitialized) + { + return CELL_SUBDISPLAY_ERROR_NOT_INITIALIZED; + } + + if (groupId != 0 || !ppVideoBuf || !pSize) + { + return CELL_SUBDISPLAY_ERROR_INVALID_VALUE; + } + + *pSize = manager.buf_size; + *ppVideoBuf = manager.video_buffer; + return CELL_OK; } @@ -76,11 +257,26 @@ error_code cellSubDisplayAudioOutBlocking(s32 groupId, vm::ptr pvData, s32 { cellSubDisplay.todo("cellSubDisplayAudioOutBlocking(groupId=%d, pvData=*0x%x, samples=%d)", groupId, pvData, samples); + auto& manager = g_fxo->get(); + std::lock_guard lock(manager.mutex); + + if (manager.status == sub_display_status::uninitialized) + { + return CELL_SUBDISPLAY_ERROR_NOT_INITIALIZED; + } + + if (groupId != 0 || samples < 0) + { + return CELL_SUBDISPLAY_ERROR_INVALID_VALUE; + } + if (samples % 1024) { return CELL_SUBDISPLAY_ERROR_SET_SAMPLE; } + // TODO + return CELL_OK; } @@ -88,32 +284,110 @@ error_code cellSubDisplayAudioOutNonBlocking(s32 groupId, vm::ptr pvData, { cellSubDisplay.todo("cellSubDisplayAudioOutNonBlocking(groupId=%d, pvData=*0x%x, samples=%d)", groupId, pvData, samples); + auto& manager = g_fxo->get(); + std::lock_guard lock(manager.mutex); + + if (manager.status == sub_display_status::uninitialized) + { + return CELL_SUBDISPLAY_ERROR_NOT_INITIALIZED; + } + + if (groupId != 0 || samples < 0) + { + return CELL_SUBDISPLAY_ERROR_INVALID_VALUE; + } + if (samples % 1024) { return CELL_SUBDISPLAY_ERROR_SET_SAMPLE; } + if (manager.audio_is_busy) + { + return CELL_SUBDISPLAY_ERROR_AUDIOOUT_IS_BUSY; + } + + // TODO: fetch audio async + // manager.audio_is_busy = true; + return CELL_OK; } error_code cellSubDisplayGetPeerNum(s32 groupId) { cellSubDisplay.todo("cellSubDisplayGetPeerNum(groupId=%d)", groupId); - return CELL_OK; + + auto& manager = g_fxo->get(); + std::lock_guard lock(manager.mutex); + + if (manager.status == sub_display_status::uninitialized) + { + return CELL_SUBDISPLAY_ERROR_NOT_INITIALIZED; + } + + if (groupId != 0) + { + return CELL_SUBDISPLAY_ERROR_INVALID_VALUE; + } + + s32 peer_num = 0; // TODO + + return not_an_error(peer_num); } error_code cellSubDisplayGetPeerList(s32 groupId, vm::ptr pInfo, vm::ptr pNum) { cellSubDisplay.todo("cellSubDisplayGetPeerList(groupId=%d, pInfo=*0x%x, pNum=*0x%x)", groupId, pInfo, pNum); + auto& manager = g_fxo->get(); + std::lock_guard lock(manager.mutex); + + if (manager.status == sub_display_status::uninitialized) + { + return CELL_SUBDISPLAY_ERROR_NOT_INITIALIZED; + } + + if (groupId != 0) + { + return CELL_OK; + } + + if (!pInfo || !pNum || *pNum < 1) + { + return CELL_SUBDISPLAY_ERROR_INVALID_VALUE; + } + *pNum = 0; + // TODO + return CELL_OK; } error_code cellSubDisplayGetTouchInfo(s32 groupId, vm::ptr pTouchInfo, vm::ptr pNumTouchInfo) { cellSubDisplay.todo("cellSubDisplayGetTouchInfo(groupId=%d, pTouchInfo=*0x%x, pNumTouchInfo=*0x%x)", groupId, pTouchInfo, pNumTouchInfo); + + if (groupId != 0 || !pNumTouchInfo || !pTouchInfo) + { + return CELL_SUBDISPLAY_ERROR_INVALID_VALUE; + } + + auto& manager = g_fxo->get(); + std::lock_guard lock(manager.mutex); + + if (manager.param.version != CELL_SUBDISPLAY_VERSION_0003) + { + return CELL_SUBDISPLAY_ERROR_NOT_SUPPORTED; + } + + if (*pNumTouchInfo > CELL_SUBDISPLAY_TOUCH_MAX_TOUCH_INFO) + { + *pNumTouchInfo = CELL_SUBDISPLAY_TOUCH_MAX_TOUCH_INFO; + } + + std::memcpy(pTouchInfo.get_ptr(), manager.touch_info.data(), *pNumTouchInfo * sizeof(CellSubDisplayTouchInfo)); + return CELL_OK; } diff --git a/rpcs3/Emu/Cell/Modules/cellSubDisplay.h b/rpcs3/Emu/Cell/Modules/cellSubDisplay.h index feff510f77..3319b772ab 100644 --- a/rpcs3/Emu/Cell/Modules/cellSubDisplay.h +++ b/rpcs3/Emu/Cell/Modules/cellSubDisplay.h @@ -20,25 +20,34 @@ enum CELL_SUBDISPLAY_STATUS_JOIN = 1, CELL_SUBDISPLAY_STATUS_LEAVE = 2, CELL_SUBDISPLAY_STATUS_FATALERROR = 3, + CELL_SUBDISPLAY_VERSION_0001 = 1, CELL_SUBDISPLAY_VERSION_0002 = 2, CELL_SUBDISPLAY_VERSION_0003 = 3, + CELL_SUBDISPLAY_MODE_REMOTEPLAY = 1, + CELL_SUBDISPLAY_VIDEO_FORMAT_A8R8G8B8 = 1, CELL_SUBDISPLAY_VIDEO_FORMAT_R8G8B8A8 = 2, CELL_SUBDISPLAY_VIDEO_FORMAT_YUV420 = 3, + CELL_SUBDISPLAY_VIDEO_ASPECT_RATIO_16_9 = 0, CELL_SUBDISPLAY_VIDEO_ASPECT_RATIO_4_3 = 1, + CELL_SUBDISPLAY_VIDEO_MODE_SETDATA = 0, CELL_SUBDISPLAY_VIDEO_MODE_CAPTURE = 1, + CELL_SUBDISPLAY_AUDIO_MODE_SETDATA = 0, CELL_SUBDISPLAY_AUDIO_MODE_CAPTURE = 1, + CELL_SUBDISPLAY_0001_MEMORY_CONTAINER_SIZE = 8 * 1024 * 1024, CELL_SUBDISPLAY_0002_MEMORY_CONTAINER_SIZE = 10 * 1024 * 1024, CELL_SUBDISPLAY_0003_MEMORY_CONTAINER_SIZE = 10 * 1024 * 1024, + CELL_SUBDISPLAY_0003_WIDTH = 864, CELL_SUBDISPLAY_0003_PITCH = 864, CELL_SUBDISPLAY_0003_HEIGHT = 480, + CELL_SUBDISPLAY_NICKNAME_LEN = 256, CELL_SUBDISPLAY_PSPID_LEN = 16, };