Implement cellPhotoDecode

This commit is contained in:
Megamouse 2022-07-27 22:09:16 +02:00
parent 4114f00c05
commit f31ffc4596
3 changed files with 128 additions and 6 deletions

View File

@ -1,9 +1,10 @@
#include "stdafx.h" #include "stdafx.h"
#include "Emu/Cell/PPUModule.h" #include "Emu/Cell/PPUModule.h"
#include "Emu/IdManager.h"
#include "Emu/VFS.h"
#include "Emu/System.h"
#include "cellSysutil.h" #include "cellSysutil.h"
LOG_CHANNEL(cellPhotoDecode); LOG_CHANNEL(cellPhotoDecode);
// Return Codes // Return Codes
@ -36,6 +37,11 @@ void fmt_class_string<CellPhotoDecodeError>::format(std::string& out, u64 arg)
}); });
} }
enum
{
CELL_PHOTO_DECODE_VERSION_CURRENT = 0
};
struct CellPhotoDecodeSetParam struct CellPhotoDecodeSetParam
{ {
vm::bptr<void> dstBuffer; vm::bptr<void> dstBuffer;
@ -57,7 +63,22 @@ using CellPhotoDecodeFinishCallback = void(s32 result, vm::ptr<void> userdata);
error_code cellPhotoDecodeInitialize(u32 version, u32 container1, u32 container2, vm::ptr<CellPhotoDecodeFinishCallback> funcFinish, vm::ptr<void> userdata) error_code cellPhotoDecodeInitialize(u32 version, u32 container1, u32 container2, vm::ptr<CellPhotoDecodeFinishCallback> funcFinish, vm::ptr<void> userdata)
{ {
cellPhotoDecode.todo("cellPhotoDecodeInitialize(version=0x%x, container1=0x%x, container2=0x%x, funcFinish=*0x%x, userdata=*0x%x)", version, container1, container2, funcFinish, userdata); cellPhotoDecode.warning("cellPhotoDecodeInitialize(version=0x%x, container1=0x%x, container2=0x%x, funcFinish=*0x%x, userdata=*0x%x)", version, container1, container2, funcFinish, userdata);
if (version != CELL_PHOTO_DECODE_VERSION_CURRENT || !funcFinish)
{
return CELL_PHOTO_DECODE_ERROR_PARAM;
}
if (container1 != 0xffffffff && false) // TODO: size < 0x300000
{
return CELL_PHOTO_DECODE_ERROR_PARAM;
}
if (container2 != 0xffffffff && false) // TODO: size depends on image type, width and height
{
return CELL_PHOTO_DECODE_ERROR_PARAM;
}
sysutil_register_cb([=](ppu_thread& ppu) -> s32 sysutil_register_cb([=](ppu_thread& ppu) -> s32
{ {
@ -70,7 +91,17 @@ error_code cellPhotoDecodeInitialize(u32 version, u32 container1, u32 container2
error_code cellPhotoDecodeInitialize2(u32 version, u32 container2, vm::ptr<CellPhotoDecodeFinishCallback> funcFinish, vm::ptr<void> userdata) error_code cellPhotoDecodeInitialize2(u32 version, u32 container2, vm::ptr<CellPhotoDecodeFinishCallback> funcFinish, vm::ptr<void> userdata)
{ {
cellPhotoDecode.todo("cellPhotoDecodeInitialize2(version=0x%x, container2=0x%x, funcFinish=*0x%x, userdata=*0x%x)", version, container2, funcFinish, userdata); cellPhotoDecode.warning("cellPhotoDecodeInitialize2(version=0x%x, container2=0x%x, funcFinish=*0x%x, userdata=*0x%x)", version, container2, funcFinish, userdata);
if (version != CELL_PHOTO_DECODE_VERSION_CURRENT || !funcFinish)
{
return CELL_PHOTO_DECODE_ERROR_PARAM;
}
if (container2 != 0xffffffff && false) // TODO: size depends on image type, width and height
{
return CELL_PHOTO_DECODE_ERROR_PARAM;
}
sysutil_register_cb([=](ppu_thread& ppu) -> s32 sysutil_register_cb([=](ppu_thread& ppu) -> s32
{ {
@ -83,7 +114,12 @@ error_code cellPhotoDecodeInitialize2(u32 version, u32 container2, vm::ptr<CellP
error_code cellPhotoDecodeFinalize(vm::ptr<CellPhotoDecodeFinishCallback> funcFinish, vm::ptr<void> userdata) error_code cellPhotoDecodeFinalize(vm::ptr<CellPhotoDecodeFinishCallback> funcFinish, vm::ptr<void> userdata)
{ {
cellPhotoDecode.todo("cellPhotoDecodeFinalize(funcFinish=*0x%x, userdata=*0x%x)", funcFinish, userdata); cellPhotoDecode.warning("cellPhotoDecodeFinalize(funcFinish=*0x%x, userdata=*0x%x)", funcFinish, userdata);
if (!funcFinish)
{
return CELL_PHOTO_DECODE_ERROR_PARAM;
}
sysutil_register_cb([=](ppu_thread& ppu) -> s32 sysutil_register_cb([=](ppu_thread& ppu) -> s32
{ {
@ -96,7 +132,45 @@ error_code cellPhotoDecodeFinalize(vm::ptr<CellPhotoDecodeFinishCallback> funcFi
error_code cellPhotoDecodeFromFile(vm::cptr<char> srcHddDir, vm::cptr<char> srcHddFile, vm::ptr<CellPhotoDecodeSetParam> set_param, vm::ptr<CellPhotoDecodeReturnParam> return_param) error_code cellPhotoDecodeFromFile(vm::cptr<char> srcHddDir, vm::cptr<char> srcHddFile, vm::ptr<CellPhotoDecodeSetParam> set_param, vm::ptr<CellPhotoDecodeReturnParam> return_param)
{ {
cellPhotoDecode.todo("cellPhotoDecodeFromFile(srcHddDir=%s, srcHddFile=%s, set_param=*0x%x, return_param=*0x%x)", srcHddDir, srcHddFile, set_param, return_param); cellPhotoDecode.warning("cellPhotoDecodeFromFile(srcHddDir=%s, srcHddFile=%s, set_param=*0x%x, return_param=*0x%x)", srcHddDir, srcHddFile, set_param, return_param);
if (!srcHddDir || !srcHddFile || !set_param || !return_param)
{
return CELL_PHOTO_DECODE_ERROR_PARAM;
}
*return_param = {};
const std::string vpath = fmt::format("%s/%s", srcHddDir.get_ptr(), srcHddFile.get_ptr());
const std::string path = vfs::get(vpath);
if (!vpath.starts_with("/dev_hdd0"))
{
cellPhotoDecode.error("Destination '%s' is not inside dev_hdd0", srcHddDir);
return CELL_PHOTO_DECODE_ERROR_ACCESS_ERROR; // TODO: is this correct?
}
if (!fs::is_file(path))
{
// TODO: check if the dir is user accessible and can be written to
cellPhotoDecode.error("Source '%s' is not a file (vfs='%s')", path, vpath);
return CELL_PHOTO_DECODE_ERROR_ACCESS_ERROR; // TODO: is this correct?
}
cellPhotoDecode.notice("About to decode '%s' (set_param: width=%d, height=%d, dstBuffer=*0x%x)", path, set_param->width, set_param->height, set_param->dstBuffer);
s32 width{};
s32 height{};
if (!Emu.GetCallbacks().get_scaled_image(path, set_param->width, set_param->height, width, height, static_cast<u8*>(set_param->dstBuffer.get_ptr())))
{
cellPhotoDecode.error("Failed to decode '%s'", path);
return CELL_PHOTO_DECODE_ERROR_DECODE;
}
return_param->width = width;
return_param->height = height;
return CELL_OK; return CELL_OK;
} }

View File

@ -97,6 +97,7 @@ struct EmuCallbacks
std::function<std::u32string(localized_string_id, const char*)> get_localized_u32string; std::function<std::u32string(localized_string_id, const char*)> get_localized_u32string;
std::function<void(const std::string&)> play_sound; std::function<void(const std::string&)> play_sound;
std::function<bool(const std::string&, std::string&, s32&, s32&, s32&)> get_image_info; // (filename, sub_type, width, height, CellSearchOrientation) std::function<bool(const std::string&, std::string&, s32&, s32&, s32&)> get_image_info; // (filename, sub_type, width, height, CellSearchOrientation)
std::function<bool(const std::string&, s32, s32, s32&, s32&, u8*)> get_scaled_image; // (filename, target_width, target_height, width, height, dst)
std::string(*resolve_path)(std::string_view) = [](std::string_view arg){ return std::string{arg}; }; // Resolve path using Qt std::string(*resolve_path)(std::string_view) = [](std::string_view arg){ return std::string{arg}; }; // Resolve path using Qt
}; };

View File

@ -5,6 +5,7 @@
#include "util/sysinfo.hpp" #include "util/sysinfo.hpp"
#include "Utilities/Thread.h" #include "Utilities/Thread.h"
#include "Utilities/File.h"
#include "Input/pad_thread.h" #include "Input/pad_thread.h"
#include "Emu/System.h" #include "Emu/System.h"
#include "Emu/system_config.h" #include "Emu/system_config.h"
@ -192,6 +193,52 @@ EmuCallbacks main_application::CreateCallbacks()
return success; return success;
}; };
callbacks.get_scaled_image = [](const std::string& path, s32 target_width, s32 target_height, s32& width, s32& height, u8* dst) -> bool
{
width = 0;
height = 0;
if (target_width <= 0 || target_height <= 0 || !dst || !fs::is_file(path))
{
return false;
}
bool success = false;
Emu.BlockingCallFromMainThread([&]()
{
QImage image{};
success = image.load(QString::fromStdString(path)) && !image.isNull();
if (success)
{
width = image.width();
height = image.height();
if (width <= 0 || height <= 0)
{
success = false;
return;
}
if (width > target_width || height > target_height)
{
const QSize size(target_width, target_height);
image = image.scaled(QSize(target_width, target_height), Qt::AspectRatioMode::KeepAspectRatio, Qt::TransformationMode::SmoothTransformation);
width = image.width();
height = image.height();
}
if (image.format() != QImage::Format::Format_RGBA8888)
{
image = image.convertToFormat(QImage::Format::Format_RGBA8888);
}
std::memcpy(dst, image.constBits(), std::min(4 * target_width * target_height, image.height() * image.bytesPerLine()));
}
});
return success;
};
callbacks.resolve_path = [](std::string_view sv) callbacks.resolve_path = [](std::string_view sv)
{ {
return QFileInfo(QString::fromUtf8(sv.data(), static_cast<int>(sv.size()))).canonicalFilePath().toStdString(); return QFileInfo(QString::fromUtf8(sv.data(), static_cast<int>(sv.size()))).canonicalFilePath().toStdString();