cellSubDisplay: add error checks

This commit is contained in:
Megamouse 2022-08-09 20:28:17 +02:00
parent 92b08a4faf
commit 4446d9ce4b
2 changed files with 285 additions and 2 deletions

View File

@ -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<CellSubDisplayError>::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<CellSubDisplayHandler> func = vm::null;
vm::ptr<void> userdata = vm::null;
// Video data
vm::ptr<void> video_buffer = vm::null;
u32 buf_size = 0;
// Audio data
bool audio_is_busy = false;
// Touch data
std::array<CellSubDisplayTouchInfo, CELL_SUBDISPLAY_TOUCH_MAX_TOUCH_INFO> 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<CellSubDisplayParam> pParam, vm::ptr<CellSubDisplayHandler> func, vm::ptr<void> 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<sub_display_manager>();
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<sub_display_manager>();
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<CellSubDisplayParam> 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<CellSubDisplayParam> pParam)
error_code cellSubDisplayStart()
{
cellSubDisplay.todo("cellSubDisplayStart()");
auto& manager = g_fxo->get<sub_display_manager>();
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<sub_display_manager>();
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<void> ppVideoBuf, vm::ptr<u32> pSize)
{
cellSubDisplay.todo("cellSubDisplayGetVideoBuffer(groupId=%d, ppVideoBuf=**0x%x, pSize=*0x%x)", groupId, ppVideoBuf, pSize);
auto& manager = g_fxo->get<sub_display_manager>();
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<void> pvData, s32
{
cellSubDisplay.todo("cellSubDisplayAudioOutBlocking(groupId=%d, pvData=*0x%x, samples=%d)", groupId, pvData, samples);
auto& manager = g_fxo->get<sub_display_manager>();
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<void> pvData,
{
cellSubDisplay.todo("cellSubDisplayAudioOutNonBlocking(groupId=%d, pvData=*0x%x, samples=%d)", groupId, pvData, samples);
auto& manager = g_fxo->get<sub_display_manager>();
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<sub_display_manager>();
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<CellSubDisplayPeerInfo> pInfo, vm::ptr<s32> pNum)
{
cellSubDisplay.todo("cellSubDisplayGetPeerList(groupId=%d, pInfo=*0x%x, pNum=*0x%x)", groupId, pInfo, pNum);
auto& manager = g_fxo->get<sub_display_manager>();
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<CellSubDisplayTouchInfo> pTouchInfo, vm::ptr<s32> 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<sub_display_manager>();
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;
}

View File

@ -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,
};