mirror of
https://github.com/RPCSX/rpcsx.git
synced 2026-01-08 17:50:31 +01:00
Replaces `std::shared_pointer` with `stx::atomic_ptr` and `stx::shared_ptr`. Notes to programmers: * This pr kills the use of `dynamic_cast`, `std::dynamic_pointer_cast` and `std::weak_ptr` on IDM objects, possible replacement is to save the object ID on the base object, then use idm::check/get_unlocked to the destination type via the saved ID which may be null. Null pointer check is how you can tell type mismatch (as dynamic cast) or object destruction (as weak_ptr locking). * Double-inheritance on IDM objects should be used with care, `stx::shared_ptr` does not support constant-evaluated pointer offsetting to parent/child type. * `idm::check/get_unlocked` can now be used anywhere. Misc fixes: * Fixes some segfaults with RPCN with interaction with IDM. * Fix deadlocks in access violation handler due locking recursion. * Fixes race condition in process exit-spawn on memory containers read. * Fix bug that theoretically can prevent RPCS3 from booting - fix `id_manager::typeinfo` comparison to compare members instead of `memcmp` which can fail spuriously on padding bytes. * Ensure all IDM inherited types of base, either has `id_base` or `id_type` defined locally, this allows to make getters such as `idm::get_unlocked<lv2_socket, lv2_socket_raw>()` which were broken before. (requires save-states invalidation) * Removes broken operator[] overload of `stx::shared_ptr` and `stx::single_ptr` for non-array types.
686 lines
18 KiB
C++
686 lines
18 KiB
C++
#include "stdafx.h"
|
|
#include "Emu/VFS.h"
|
|
#include "Emu/IdManager.h"
|
|
#include "Emu/Cell/PPUModule.h"
|
|
|
|
// STB_IMAGE_IMPLEMENTATION is already defined in stb_image.cpp
|
|
#include <stb_image.h>
|
|
|
|
#include "Emu/Cell/lv2/sys_fs.h"
|
|
#include "cellGifDec.h"
|
|
|
|
#include "util/asm.hpp"
|
|
|
|
LOG_CHANNEL(cellGifDec);
|
|
|
|
// Temporarily
|
|
#ifndef _MSC_VER
|
|
#pragma GCC diagnostic ignored "-Wunused-parameter"
|
|
#endif
|
|
|
|
template <>
|
|
void fmt_class_string<CellGifDecError>::format(std::string& out, u64 arg)
|
|
{
|
|
format_enum(out, arg, [](auto error)
|
|
{
|
|
switch (error)
|
|
{
|
|
STR_CASE(CELL_GIFDEC_ERROR_OPEN_FILE);
|
|
STR_CASE(CELL_GIFDEC_ERROR_STREAM_FORMAT);
|
|
STR_CASE(CELL_GIFDEC_ERROR_SEQ);
|
|
STR_CASE(CELL_GIFDEC_ERROR_ARG);
|
|
STR_CASE(CELL_GIFDEC_ERROR_FATAL);
|
|
STR_CASE(CELL_GIFDEC_ERROR_SPU_UNSUPPORT);
|
|
STR_CASE(CELL_GIFDEC_ERROR_SPU_ERROR);
|
|
STR_CASE(CELL_GIFDEC_ERROR_CB_PARAM);
|
|
}
|
|
|
|
return unknown;
|
|
});
|
|
}
|
|
|
|
error_code cellGifDecCreate(vm::ptr<GifDecoder> mainHandle, vm::cptr<CellGifDecThreadInParam> threadInParam, vm::ptr<CellGifDecThreadOutParam> threadOutParam)
|
|
{
|
|
cellGifDec.todo("cellGifDecCreate(mainHandle=*0x%x, threadInParam=*0x%x, threadOutParam=*0x%x)", mainHandle, threadInParam, threadOutParam);
|
|
|
|
if (!mainHandle)
|
|
{
|
|
return CELL_GIFDEC_ERROR_ARG;
|
|
}
|
|
|
|
*mainHandle = {};
|
|
|
|
if (!threadOutParam || !threadInParam || !threadInParam->cbCtrlMallocFunc || !threadInParam->cbCtrlFreeFunc ||
|
|
(threadInParam->spuThreadEnable != CELL_GIFDEC_SPU_THREAD_DISABLE &&
|
|
(threadInParam->spuThreadEnable != CELL_GIFDEC_SPU_THREAD_ENABLE ||
|
|
threadInParam->ppuThreadPriority > 3071 ||
|
|
threadInParam->spuThreadPriority > 255)))
|
|
{
|
|
return CELL_GIFDEC_ERROR_ARG;
|
|
}
|
|
|
|
threadOutParam->gifCodecVersion = 0x240000;
|
|
|
|
return CELL_OK;
|
|
}
|
|
|
|
error_code cellGifDecExtCreate(vm::ptr<GifDecoder> mainHandle, vm::cptr<CellGifDecThreadInParam> threadInParam, vm::ptr<CellGifDecThreadOutParam> threadOutParam, vm::cptr<CellGifDecExtThreadInParam> extThreadInParam, vm::ptr<CellGifDecExtThreadOutParam> extThreadOutParam)
|
|
{
|
|
cellGifDec.todo("cellGifDecExtCreate(mainHandle=*0x%x, threadInParam=*0x%x, threadOutParam=*0x%x, extThreadInParam=*0x%x, extThreadOutParam=*0x%x)", mainHandle, threadInParam, threadOutParam, extThreadInParam, extThreadOutParam);
|
|
|
|
if (!mainHandle)
|
|
{
|
|
return CELL_GIFDEC_ERROR_ARG;
|
|
}
|
|
|
|
*mainHandle = {};
|
|
|
|
if (!threadOutParam || !extThreadOutParam || !extThreadInParam || !threadInParam || !threadInParam->cbCtrlMallocFunc || !threadInParam->cbCtrlFreeFunc ||
|
|
(threadInParam->spuThreadEnable != CELL_GIFDEC_SPU_THREAD_DISABLE && threadInParam->spuThreadEnable != CELL_GIFDEC_SPU_THREAD_ENABLE))
|
|
{
|
|
return CELL_GIFDEC_ERROR_ARG;
|
|
}
|
|
|
|
if (threadInParam->spuThreadEnable == CELL_GIFDEC_SPU_THREAD_ENABLE && !extThreadInParam->spurs)
|
|
{
|
|
return CELL_GIFDEC_ERROR_ARG;
|
|
}
|
|
|
|
if (extThreadInParam->maxContention == 0u || extThreadInParam->maxContention >= 8u)
|
|
{
|
|
return CELL_GIFDEC_ERROR_ARG;
|
|
}
|
|
|
|
for (u32 i = 0; i < 8; i++)
|
|
{
|
|
if (extThreadInParam->priority[i] > 15)
|
|
{
|
|
return CELL_GIFDEC_ERROR_ARG;
|
|
}
|
|
}
|
|
|
|
threadOutParam->gifCodecVersion = 0x240000;
|
|
|
|
return CELL_OK;
|
|
}
|
|
|
|
error_code cellGifDecOpen(vm::ptr<GifDecoder> mainHandle, vm::pptr<GifStream> subHandle, vm::cptr<CellGifDecSrc> src, vm::ptr<CellGifDecOpnInfo> openInfo)
|
|
{
|
|
cellGifDec.warning("cellGifDecOpen(mainHandle=*0x%x, subHandle=**0x%x, src=*0x%x, openInfo=*0x%x)", mainHandle, subHandle, src, openInfo);
|
|
|
|
if (!mainHandle || !subHandle)
|
|
{
|
|
return CELL_GIFDEC_ERROR_ARG;
|
|
}
|
|
|
|
if (false) // TODO
|
|
{
|
|
return CELL_GIFDEC_ERROR_SEQ;
|
|
}
|
|
|
|
if (!openInfo || !src)
|
|
{
|
|
return CELL_GIFDEC_ERROR_ARG;
|
|
}
|
|
|
|
GifStream current_subHandle{};
|
|
current_subHandle.fd = 0;
|
|
current_subHandle.src = *src;
|
|
|
|
switch (src->srcSelect)
|
|
{
|
|
case CELL_GIFDEC_BUFFER:
|
|
{
|
|
if (!src->streamPtr || !src->streamSize)
|
|
{
|
|
return CELL_GIFDEC_ERROR_ARG;
|
|
}
|
|
|
|
current_subHandle.fileSize = src->streamSize;
|
|
break;
|
|
}
|
|
case CELL_GIFDEC_FILE:
|
|
{
|
|
if (!src->fileName)
|
|
{
|
|
return CELL_GIFDEC_ERROR_OPEN_FILE;
|
|
}
|
|
|
|
// Get file descriptor and size
|
|
const std::string real_path = vfs::get(src->fileName.get_ptr());
|
|
fs::file file_s(real_path);
|
|
if (!file_s)
|
|
{
|
|
return CELL_GIFDEC_ERROR_OPEN_FILE;
|
|
}
|
|
|
|
if (src->fileOffset < 0)
|
|
{
|
|
return CELL_GIFDEC_ERROR_ARG;
|
|
}
|
|
|
|
current_subHandle.fileSize = file_s.size();
|
|
current_subHandle.fd = idm::make<lv2_fs_object, lv2_file>(src->fileName.get_ptr(), std::move(file_s), 0, 0, real_path);
|
|
break;
|
|
}
|
|
default:
|
|
{
|
|
return CELL_GIFDEC_ERROR_ARG;
|
|
}
|
|
}
|
|
|
|
subHandle->set(vm::alloc(sizeof(GifStream), vm::main));
|
|
|
|
**subHandle = current_subHandle;
|
|
|
|
return CELL_OK;
|
|
}
|
|
|
|
error_code cellGifDecExtOpen(vm::ptr<GifDecoder> mainHandle, vm::pptr<GifStream> subHandle, vm::cptr<CellGifDecSrc> src, vm::ptr<CellGifDecOpnInfo> openInfo, vm::cptr<CellGifDecCbCtrlStrm> cbCtrlStrm)
|
|
{
|
|
cellGifDec.todo("cellGifDecExtOpen(mainHandle=*0x%x, subHandle=*0x%x, src=*0x%x, openInfo=*0x%x, cbCtrlStrm=*0x%x)", mainHandle, subHandle, src, openInfo, cbCtrlStrm);
|
|
|
|
if (!mainHandle || !subHandle)
|
|
{
|
|
return CELL_GIFDEC_ERROR_ARG;
|
|
}
|
|
|
|
if (false) // TODO
|
|
{
|
|
return CELL_GIFDEC_ERROR_SEQ;
|
|
}
|
|
|
|
if (!openInfo || !src)
|
|
{
|
|
return CELL_GIFDEC_ERROR_ARG;
|
|
}
|
|
|
|
GifStream current_subHandle{};
|
|
current_subHandle.fd = 0;
|
|
current_subHandle.src = *src;
|
|
|
|
switch (src->srcSelect)
|
|
{
|
|
case CELL_GIFDEC_BUFFER:
|
|
{
|
|
if (!src->streamPtr || !src->streamSize)
|
|
{
|
|
return CELL_GIFDEC_ERROR_ARG;
|
|
}
|
|
|
|
current_subHandle.fileSize = src->streamSize;
|
|
break;
|
|
}
|
|
case CELL_GIFDEC_FILE:
|
|
{
|
|
if (!src->fileName)
|
|
{
|
|
return CELL_GIFDEC_ERROR_OPEN_FILE;
|
|
}
|
|
|
|
// Get file descriptor and size
|
|
const std::string real_path = vfs::get(src->fileName.get_ptr());
|
|
fs::file file_s(real_path);
|
|
if (!file_s)
|
|
{
|
|
return CELL_GIFDEC_ERROR_OPEN_FILE;
|
|
}
|
|
|
|
if (src->fileOffset < 0)
|
|
{
|
|
return CELL_GIFDEC_ERROR_ARG;
|
|
}
|
|
|
|
current_subHandle.fileSize = file_s.size();
|
|
current_subHandle.fd = idm::make<lv2_fs_object, lv2_file>(src->fileName.get_ptr(), std::move(file_s), 0, 0, real_path);
|
|
break;
|
|
}
|
|
default:
|
|
{
|
|
return CELL_GIFDEC_ERROR_ARG;
|
|
}
|
|
}
|
|
|
|
return CELL_OK;
|
|
}
|
|
|
|
error_code cellGifDecReadHeader(vm::ptr<GifDecoder> mainHandle, vm::ptr<GifStream> subHandle, vm::ptr<CellGifDecInfo> info)
|
|
{
|
|
cellGifDec.warning("cellGifDecReadHeader(mainHandle=*0x%x, subHandle=*0x%x, info=*0x%x)", mainHandle, subHandle, info);
|
|
|
|
if (!mainHandle)
|
|
{
|
|
return CELL_GIFDEC_ERROR_ARG;
|
|
}
|
|
|
|
if (false) // TODO: check main handle
|
|
{
|
|
return CELL_GIFDEC_ERROR_SEQ;
|
|
}
|
|
|
|
if (!subHandle)
|
|
{
|
|
return CELL_GIFDEC_ERROR_ARG;
|
|
}
|
|
|
|
if (false) // TODO: check sub handle
|
|
{
|
|
return CELL_GIFDEC_ERROR_SEQ;
|
|
}
|
|
|
|
if (!info)
|
|
{
|
|
return CELL_GIFDEC_ERROR_ARG;
|
|
}
|
|
|
|
const u32& fd = subHandle->fd;
|
|
CellGifDecInfo& current_info = subHandle->info;
|
|
|
|
// Write the header to buffer
|
|
u8 buffer[13];
|
|
|
|
switch (subHandle->src.srcSelect)
|
|
{
|
|
case CELL_GIFDEC_BUFFER:
|
|
{
|
|
std::memcpy(buffer, subHandle->src.streamPtr.get_ptr(), sizeof(buffer));
|
|
break;
|
|
}
|
|
case CELL_GIFDEC_FILE:
|
|
{
|
|
auto file = idm::get_unlocked<lv2_fs_object, lv2_file>(fd);
|
|
file->file.seek(0);
|
|
file->file.read(buffer, sizeof(buffer));
|
|
break;
|
|
}
|
|
default: break; // TODO
|
|
}
|
|
|
|
if (read_from_ptr<be_t<u32>>(buffer + 0) != 0x47494638u ||
|
|
(read_from_ptr<le_t<u16>>(buffer + 4) != 0x6139u && read_from_ptr<le_t<u16>>(buffer + 4) != 0x6137u)) // Error: The first 6 bytes are not a valid GIF signature
|
|
{
|
|
return CELL_GIFDEC_ERROR_STREAM_FORMAT; // Surprisingly there is no error code related with headerss
|
|
}
|
|
|
|
u8 packedField = buffer[10];
|
|
current_info.SWidth = buffer[6] + buffer[7] * 0x100;
|
|
current_info.SHeight = buffer[8] + buffer[9] * 0x100;
|
|
current_info.SGlobalColorTableFlag = packedField >> 7;
|
|
current_info.SColorResolution = ((packedField >> 4) & 7)+1;
|
|
current_info.SSortFlag = (packedField >> 3) & 1;
|
|
current_info.SSizeOfGlobalColorTable = (packedField & 7)+1;
|
|
current_info.SBackGroundColor = buffer[11];
|
|
current_info.SPixelAspectRatio = buffer[12];
|
|
|
|
*info = current_info;
|
|
|
|
return CELL_OK;
|
|
}
|
|
|
|
error_code cellGifDecExtReadHeader(vm::ptr<GifDecoder> mainHandle, vm::cptr<GifStream> subHandle, vm::ptr<CellGifDecInfo> info, vm::ptr<CellGifDecExtInfo> extInfo)
|
|
{
|
|
cellGifDec.todo("cellGifDecExtReadHeader(mainHandle=*0x%x, subHandle=*0x%x, info=*0x%x, extInfo=*0x%x)", mainHandle, subHandle, info, extInfo);
|
|
|
|
if (!mainHandle)
|
|
{
|
|
return CELL_GIFDEC_ERROR_ARG;
|
|
}
|
|
|
|
if (false) // TODO: check main handle
|
|
{
|
|
return CELL_GIFDEC_ERROR_SEQ;
|
|
}
|
|
|
|
if (!subHandle)
|
|
{
|
|
return CELL_GIFDEC_ERROR_ARG;
|
|
}
|
|
|
|
if (false) // TODO: check sub handle
|
|
{
|
|
return CELL_GIFDEC_ERROR_SEQ;
|
|
}
|
|
|
|
if (!info || !extInfo)
|
|
{
|
|
return CELL_GIFDEC_ERROR_ARG;
|
|
}
|
|
|
|
return CELL_OK;
|
|
}
|
|
|
|
error_code cellGifDecSetParameter(vm::ptr<GifDecoder> mainHandle, vm::ptr<GifStream> subHandle, vm::cptr<CellGifDecInParam> inParam, vm::ptr<CellGifDecOutParam> outParam)
|
|
{
|
|
cellGifDec.warning("cellGifDecSetParameter(mainHandle=*0x%x, subHandle=*0x%x, inParam=*0x%x, outParam=*0x%x)", mainHandle, subHandle, inParam, outParam);
|
|
|
|
if (!mainHandle)
|
|
{
|
|
return CELL_GIFDEC_ERROR_ARG;
|
|
}
|
|
|
|
if (false) // TODO: check main handle
|
|
{
|
|
return CELL_GIFDEC_ERROR_SEQ;
|
|
}
|
|
|
|
if (!subHandle)
|
|
{
|
|
return CELL_GIFDEC_ERROR_ARG;
|
|
}
|
|
|
|
if (false) // TODO: check sub handle
|
|
{
|
|
return CELL_GIFDEC_ERROR_SEQ;
|
|
}
|
|
|
|
if (!inParam || !outParam)
|
|
{
|
|
return CELL_GIFDEC_ERROR_ARG;
|
|
}
|
|
|
|
CellGifDecInfo& current_info = subHandle->info;
|
|
CellGifDecOutParam& current_outParam = subHandle->outParam;
|
|
|
|
current_outParam.outputWidthByte = (current_info.SWidth * current_info.SColorResolution * 3) / 8;
|
|
current_outParam.outputWidth = current_info.SWidth;
|
|
current_outParam.outputHeight = current_info.SHeight;
|
|
current_outParam.outputColorSpace = inParam->colorSpace;
|
|
switch (current_outParam.outputColorSpace)
|
|
{
|
|
case CELL_GIFDEC_RGBA:
|
|
case CELL_GIFDEC_ARGB: current_outParam.outputComponents = 4; break;
|
|
default: return CELL_GIFDEC_ERROR_ARG; // Not supported color space
|
|
}
|
|
current_outParam.outputBitDepth = 0; // Unimplemented
|
|
current_outParam.useMemorySpace = 0; // Unimplemented
|
|
|
|
*outParam = current_outParam;
|
|
|
|
return CELL_OK;
|
|
}
|
|
|
|
error_code cellGifDecExtSetParameter(vm::ptr<GifDecoder> mainHandle, vm::ptr<GifStream> subHandle, vm::cptr<CellGifDecInParam> inParam, vm::ptr<CellGifDecOutParam> outParam, vm::cptr<CellGifDecExtInParam> extInParam, vm::ptr<CellGifDecExtOutParam> extOutParam)
|
|
{
|
|
cellGifDec.todo("cellGifDecExtSetParameter(mainHandle=*0x%x, subHandle=*0x%x, inParam=*0x%x, outParam=*0x%x, extInParam=*0x%x, extOutParam=*0x%x)", mainHandle, subHandle, inParam, outParam, extInParam, extOutParam);
|
|
|
|
if (!mainHandle)
|
|
{
|
|
return CELL_GIFDEC_ERROR_ARG;
|
|
}
|
|
|
|
if (false) // TODO: check main handle
|
|
{
|
|
return CELL_GIFDEC_ERROR_SEQ;
|
|
}
|
|
|
|
if (!subHandle)
|
|
{
|
|
return CELL_GIFDEC_ERROR_ARG;
|
|
}
|
|
|
|
if (false) // TODO: check sub handle
|
|
{
|
|
return CELL_GIFDEC_ERROR_SEQ;
|
|
}
|
|
|
|
if (!inParam || !outParam)
|
|
{
|
|
return CELL_GIFDEC_ERROR_ARG;
|
|
}
|
|
|
|
CellGifDecInfo& current_info = subHandle->info;
|
|
CellGifDecOutParam& current_outParam = subHandle->outParam;
|
|
|
|
current_outParam.outputWidthByte = (current_info.SWidth * current_info.SColorResolution * 3) / 8;
|
|
current_outParam.outputWidth = current_info.SWidth;
|
|
current_outParam.outputHeight = current_info.SHeight;
|
|
current_outParam.outputColorSpace = inParam->colorSpace;
|
|
switch (current_outParam.outputColorSpace)
|
|
{
|
|
case CELL_GIFDEC_RGBA:
|
|
case CELL_GIFDEC_ARGB: current_outParam.outputComponents = 4; break;
|
|
default: return CELL_GIFDEC_ERROR_ARG; // Not supported color space
|
|
}
|
|
current_outParam.outputBitDepth = 0; // Unimplemented
|
|
current_outParam.useMemorySpace = 0; // Unimplemented
|
|
|
|
*outParam = current_outParam;
|
|
|
|
if (!extInParam || extInParam->bufferMode != CELL_GIFDEC_LINE_MODE || !extOutParam)
|
|
{
|
|
return CELL_GIFDEC_ERROR_ARG;
|
|
}
|
|
|
|
return CELL_OK;
|
|
}
|
|
|
|
error_code cellGifDecDecodeData(vm::ptr<GifDecoder> mainHandle, vm::cptr<GifStream> subHandle, vm::ptr<u8> data, vm::cptr<CellGifDecDataCtrlParam> dataCtrlParam, vm::ptr<CellGifDecDataOutInfo> dataOutInfo)
|
|
{
|
|
cellGifDec.warning("cellGifDecDecodeData(mainHandle=*0x%x, subHandle=*0x%x, data=*0x%x, dataCtrlParam=*0x%x, dataOutInfo=*0x%x)", mainHandle, subHandle, data, dataCtrlParam, dataOutInfo);
|
|
|
|
if (!mainHandle)
|
|
{
|
|
return CELL_GIFDEC_ERROR_ARG;
|
|
}
|
|
|
|
if (false) // TODO: check main handle
|
|
{
|
|
return CELL_GIFDEC_ERROR_SEQ;
|
|
}
|
|
|
|
if (!subHandle)
|
|
{
|
|
return CELL_GIFDEC_ERROR_ARG;
|
|
}
|
|
|
|
if (false) // TODO: check sub handle
|
|
{
|
|
return CELL_GIFDEC_ERROR_SEQ;
|
|
}
|
|
|
|
if (!dataOutInfo || !dataCtrlParam)
|
|
{
|
|
return CELL_GIFDEC_ERROR_ARG;
|
|
}
|
|
|
|
dataOutInfo->status = CELL_GIFDEC_DEC_STATUS_STOP;
|
|
|
|
const u32 fd = subHandle->fd;
|
|
const u64 fileSize = subHandle->fileSize;
|
|
const CellGifDecOutParam& current_outParam = subHandle->outParam;
|
|
|
|
//Copy the GIF file to a buffer
|
|
std::unique_ptr<u8[]> gif(new u8[fileSize]);
|
|
|
|
switch (subHandle->src.srcSelect)
|
|
{
|
|
case CELL_GIFDEC_BUFFER:
|
|
std::memcpy(gif.get(), subHandle->src.streamPtr.get_ptr(), fileSize);
|
|
break;
|
|
|
|
case CELL_GIFDEC_FILE:
|
|
{
|
|
auto file = idm::get_unlocked<lv2_fs_object, lv2_file>(fd);
|
|
file->file.seek(0);
|
|
file->file.read(gif.get(), fileSize);
|
|
break;
|
|
}
|
|
default: break; // TODO
|
|
}
|
|
|
|
//Decode GIF file. (TODO: Is there any faster alternative? Can we do it without external libraries?)
|
|
int width, height, actual_components;
|
|
auto image = std::unique_ptr<unsigned char,decltype(&::free)>
|
|
(
|
|
stbi_load_from_memory(gif.get(), ::narrow<int>(fileSize), &width, &height, &actual_components, 4),
|
|
&::free
|
|
);
|
|
|
|
if (!image)
|
|
return CELL_GIFDEC_ERROR_STREAM_FORMAT;
|
|
|
|
const int bytesPerLine = static_cast<int>(dataCtrlParam->outputBytesPerLine);
|
|
const char nComponents = 4;
|
|
uint image_size = width * height * nComponents;
|
|
|
|
switch(current_outParam.outputColorSpace)
|
|
{
|
|
case CELL_GIFDEC_RGBA:
|
|
{
|
|
if (bytesPerLine > width * nComponents) // Check if we need padding
|
|
{
|
|
const int linesize = std::min(bytesPerLine, width * nComponents);
|
|
for (int i = 0; i < height; i++)
|
|
{
|
|
const int dstOffset = i * bytesPerLine;
|
|
const int srcOffset = width * nComponents * i;
|
|
memcpy(&data[dstOffset], &image.get()[srcOffset], linesize);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
memcpy(data.get_ptr(), image.get(), image_size);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case CELL_GIFDEC_ARGB:
|
|
{
|
|
if (bytesPerLine > width * nComponents) // Check if we need padding
|
|
{
|
|
//TODO: find out if we can't do padding without an extra copy
|
|
const int linesize = std::min(bytesPerLine, width * nComponents);
|
|
const auto output = std::make_unique<char[]>(linesize);
|
|
for (int i = 0; i < height; i++)
|
|
{
|
|
const int dstOffset = i * bytesPerLine;
|
|
const int srcOffset = width * nComponents * i;
|
|
for (int j = 0; j < linesize; j += nComponents)
|
|
{
|
|
output[j + 0] = image.get()[srcOffset + j + 3];
|
|
output[j + 1] = image.get()[srcOffset + j + 0];
|
|
output[j + 2] = image.get()[srcOffset + j + 1];
|
|
output[j + 3] = image.get()[srcOffset + j + 2];
|
|
}
|
|
std::memcpy(&data[dstOffset], output.get(), linesize);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
const auto img = std::make_unique<uint[]>(image_size);
|
|
uint* source_current = reinterpret_cast<uint*>(image.get());
|
|
uint* dest_current = img.get();
|
|
for (uint i = 0; i < image_size / nComponents; i++)
|
|
{
|
|
uint val = *source_current;
|
|
*dest_current = (val >> 24) | (val << 8); // set alpha (A8) as leftmost byte
|
|
source_current++;
|
|
dest_current++;
|
|
}
|
|
std::memcpy(data.get_ptr(), img.get(), image_size);
|
|
}
|
|
}
|
|
break;
|
|
|
|
default:
|
|
return CELL_GIFDEC_ERROR_ARG;
|
|
}
|
|
|
|
dataOutInfo->status = CELL_GIFDEC_DEC_STATUS_FINISH;
|
|
dataOutInfo->recordType = CELL_GIFDEC_RECORD_TYPE_IMAGE_DESC;
|
|
|
|
return CELL_OK;
|
|
}
|
|
|
|
error_code cellGifDecExtDecodeData(vm::ptr<GifDecoder> mainHandle, vm::cptr<GifStream> subHandle, vm::ptr<u8> data, vm::cptr<CellGifDecDataCtrlParam> dataCtrlParam, vm::ptr<CellGifDecDataOutInfo> dataOutInfo, vm::cptr<CellGifDecCbCtrlDisp> cbCtrlDisp, vm::ptr<CellGifDecDispParam> dispParam)
|
|
{
|
|
cellGifDec.todo("cellGifDecExtDecodeData(mainHandle=*0x%x, subHandle=*0x%x, data=*0x%x, dataCtrlParam=*0x%x, dataOutInfo=*0x%x, cbCtrlDisp=*0x%x, dispParam=*0x%x)", mainHandle, subHandle, data, dataCtrlParam, dataOutInfo, cbCtrlDisp, dispParam);
|
|
|
|
if (!mainHandle)
|
|
{
|
|
return CELL_GIFDEC_ERROR_ARG;
|
|
}
|
|
|
|
if (false) // TODO: check main handle
|
|
{
|
|
return CELL_GIFDEC_ERROR_SEQ;
|
|
}
|
|
|
|
if (!subHandle)
|
|
{
|
|
return CELL_GIFDEC_ERROR_ARG;
|
|
}
|
|
|
|
if (false) // TODO: check sub handle
|
|
{
|
|
return CELL_GIFDEC_ERROR_SEQ;
|
|
}
|
|
|
|
if (!dataOutInfo || !dataCtrlParam)
|
|
{
|
|
return CELL_GIFDEC_ERROR_ARG;
|
|
}
|
|
|
|
return CELL_OK;
|
|
}
|
|
|
|
error_code cellGifDecClose(vm::ptr<GifDecoder> mainHandle, vm::cptr<GifStream> subHandle)
|
|
{
|
|
cellGifDec.warning("cellGifDecClose(mainHandle=*0x%x, subHandle=*0x%x)", mainHandle, subHandle);
|
|
|
|
if (!mainHandle)
|
|
{
|
|
return CELL_GIFDEC_ERROR_ARG;
|
|
}
|
|
|
|
if (false) // TODO: check main handle
|
|
{
|
|
return CELL_GIFDEC_ERROR_SEQ;
|
|
}
|
|
|
|
if (!subHandle)
|
|
{
|
|
return CELL_GIFDEC_ERROR_ARG;
|
|
}
|
|
|
|
idm::remove<lv2_fs_object, lv2_file>(subHandle->fd);
|
|
|
|
vm::dealloc(subHandle.addr());
|
|
|
|
return CELL_OK;
|
|
}
|
|
|
|
error_code cellGifDecDestroy(vm::ptr<GifDecoder> mainHandle)
|
|
{
|
|
cellGifDec.todo("cellGifDecDestroy(mainHandle=*0x%x)", mainHandle);
|
|
|
|
if (!mainHandle)
|
|
{
|
|
return CELL_GIFDEC_ERROR_ARG;
|
|
}
|
|
|
|
if (false) // TODO: check main handle
|
|
{
|
|
return CELL_GIFDEC_ERROR_SEQ;
|
|
}
|
|
|
|
return CELL_OK;
|
|
}
|
|
|
|
DECLARE(ppu_module_manager::cellGifDec)("cellGifDec", []()
|
|
{
|
|
REG_FUNC(cellGifDec, cellGifDecCreate);
|
|
REG_FUNC(cellGifDec, cellGifDecExtCreate);
|
|
REG_FUNC(cellGifDec, cellGifDecOpen);
|
|
REG_FUNC(cellGifDec, cellGifDecReadHeader);
|
|
REG_FUNC(cellGifDec, cellGifDecSetParameter);
|
|
REG_FUNC(cellGifDec, cellGifDecDecodeData);
|
|
REG_FUNC(cellGifDec, cellGifDecClose);
|
|
REG_FUNC(cellGifDec, cellGifDecDestroy);
|
|
|
|
REG_FUNC(cellGifDec, cellGifDecExtOpen);
|
|
REG_FUNC(cellGifDec, cellGifDecExtReadHeader);
|
|
REG_FUNC(cellGifDec, cellGifDecExtSetParameter);
|
|
REG_FUNC(cellGifDec, cellGifDecExtDecodeData);
|
|
});
|