2020-12-05 13:08:24 +01:00
# include "stdafx.h"
2020-02-15 23:36:20 +01:00
# include "Emu/VFS.h"
2015-03-06 23:58:42 +01:00
# include "Emu/IdManager.h"
2016-03-21 20:43:03 +01:00
# include "Emu/Cell/PPUModule.h"
2013-09-10 15:17:02 +02:00
2016-03-15 20:30:23 +01:00
// STB_IMAGE_IMPLEMENTATION is already defined in stb_image.cpp
2016-03-18 15:13:52 +01:00
# include <stb_image.h>
2015-03-12 20:02:02 +01:00
2016-03-21 20:43:03 +01:00
# include "Emu/Cell/lv2/sys_fs.h"
2014-08-23 22:40:04 +02:00
# include "cellGifDec.h"
2013-09-10 15:17:02 +02:00
2018-08-25 14:39:00 +02:00
LOG_CHANNEL ( cellGifDec ) ;
2013-09-10 15:17:02 +02:00
2020-07-16 12:14:57 +02:00
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 ;
} ) ;
}
2015-08-05 17:30:32 +02:00
// cellGifDec aliases (only for cellGifDec.cpp)
using PPMainHandle = vm : : pptr < GifDecoder > ;
using PMainHandle = vm : : ptr < GifDecoder > ;
using PThreadInParam = vm : : cptr < CellGifDecThreadInParam > ;
using PThreadOutParam = vm : : ptr < CellGifDecThreadOutParam > ;
using PExtThreadInParam = vm : : cptr < CellGifDecExtThreadInParam > ;
using PExtThreadOutParam = vm : : ptr < CellGifDecExtThreadOutParam > ;
using PPSubHandle = vm : : pptr < GifStream > ;
using PSubHandle = vm : : ptr < GifStream > ;
using PSrc = vm : : cptr < CellGifDecSrc > ;
using POpenInfo = vm : : ptr < CellGifDecOpnInfo > ;
using PInfo = vm : : ptr < CellGifDecInfo > ;
using PInParam = vm : : cptr < CellGifDecInParam > ;
using POutParam = vm : : ptr < CellGifDecOutParam > ;
using PDataCtrlParam = vm : : cptr < CellGifDecDataCtrlParam > ;
using PDataOutInfo = vm : : ptr < CellGifDecDataOutInfo > ;
2020-07-16 12:14:57 +02:00
error_code cellGifDecCreate ( PPMainHandle mainHandle , PThreadInParam threadInParam , PThreadOutParam threadOutParam )
2013-09-10 15:17:02 +02:00
{
UNIMPLEMENTED_FUNC ( cellGifDec ) ;
return CELL_OK ;
}
2020-07-16 12:14:57 +02:00
error_code cellGifDecExtCreate ( PPMainHandle mainHandle , PThreadInParam threadInParam , PThreadOutParam threadOutParam , PExtThreadInParam extThreadInParam , PExtThreadOutParam extThreadOutParam )
2013-09-10 15:17:02 +02:00
{
UNIMPLEMENTED_FUNC ( cellGifDec ) ;
return CELL_OK ;
}
2020-07-16 12:14:57 +02:00
error_code cellGifDecOpen ( PMainHandle mainHandle , PPSubHandle subHandle , PSrc src , POpenInfo openInfo )
2013-09-10 15:17:02 +02:00
{
2016-01-12 22:57:16 +01:00
cellGifDec . warning ( " cellGifDecOpen(mainHandle=*0x%x, subHandle=**0x%x, src=*0x%x, openInfo=*0x%x) " , mainHandle , subHandle , src , openInfo ) ;
2014-08-06 00:19:33 +02:00
2015-07-01 19:09:26 +02:00
GifStream current_subHandle ;
current_subHandle . fd = 0 ;
current_subHandle . src = * src ;
2013-10-06 14:07:42 +02:00
2015-09-26 22:46:04 +02:00
switch ( src - > srcSelect )
2013-10-06 14:07:42 +02:00
{
2015-06-24 18:25:37 +02:00
case CELL_GIFDEC_BUFFER :
2015-07-01 19:09:26 +02:00
current_subHandle . fileSize = src - > streamSize ;
2014-07-22 17:16:15 +02:00
break ;
2015-06-24 18:25:37 +02:00
case CELL_GIFDEC_FILE :
2015-03-12 20:02:02 +01:00
{
// Get file descriptor and size
2020-09-11 13:06:46 +02:00
const auto real_path = vfs : : get ( src - > fileName . get_ptr ( ) ) ;
fs : : file file_s ( real_path ) ;
2015-05-27 05:11:59 +02:00
if ( ! file_s ) return CELL_GIFDEC_ERROR_OPEN_FILE ;
2016-03-21 20:43:03 +01:00
current_subHandle . fileSize = file_s . size ( ) ;
2020-09-11 13:06:46 +02:00
current_subHandle . fd = idm : : make < lv2_fs_object , lv2_file > ( src - > fileName . get_ptr ( ) , std : : move ( file_s ) , 0 , 0 , real_path ) ;
2014-07-22 17:16:15 +02:00
break ;
2013-10-06 14:07:42 +02:00
}
2015-03-12 20:02:02 +01:00
}
2013-09-10 15:17:02 +02:00
2018-09-03 17:46:14 +02:00
subHandle - > set ( vm : : alloc ( sizeof ( GifStream ) , vm : : main ) ) ;
2015-08-05 17:30:32 +02:00
* * subHandle = current_subHandle ;
2013-09-14 20:20:57 +02:00
2013-09-10 15:17:02 +02:00
return CELL_OK ;
}
2020-07-16 12:14:57 +02:00
error_code cellGifDecExtOpen ( )
2015-07-29 17:39:34 +02:00
{
2019-09-02 13:41:57 +02:00
cellGifDec . todo ( " cellGifDecExtOpen() " ) ;
return CELL_OK ;
2015-07-29 17:39:34 +02:00
}
2020-07-16 12:14:57 +02:00
error_code cellGifDecReadHeader ( PMainHandle mainHandle , PSubHandle subHandle , PInfo info )
2013-09-10 15:17:02 +02:00
{
2016-01-12 22:57:16 +01:00
cellGifDec . warning ( " cellGifDecReadHeader(mainHandle=*0x%x, subHandle=*0x%x, info=*0x%x) " , mainHandle , subHandle , info ) ;
2013-10-06 14:07:42 +02:00
2015-08-05 17:30:32 +02:00
const u32 & fd = subHandle - > fd ;
CellGifDecInfo & current_info = subHandle - > info ;
2018-08-25 14:39:00 +02:00
2015-06-26 16:45:13 +02:00
// Write the header to buffer
u8 buffer [ 13 ] ;
2013-10-06 14:07:42 +02:00
2015-09-26 22:46:04 +02:00
switch ( subHandle - > src . srcSelect )
2014-07-22 17:16:15 +02:00
{
2015-06-24 18:25:37 +02:00
case CELL_GIFDEC_BUFFER :
2015-08-05 17:30:32 +02:00
std : : memcpy ( buffer , subHandle - > src . streamPtr . get_ptr ( ) , sizeof ( buffer ) ) ;
2014-07-22 17:16:15 +02:00
break ;
2015-06-24 18:25:37 +02:00
case CELL_GIFDEC_FILE :
2015-03-12 20:02:02 +01:00
{
2017-01-26 02:12:50 +01:00
auto file = idm : : get < lv2_fs_object , lv2_file > ( fd ) ;
2016-03-21 20:43:03 +01:00
file - > file . seek ( 0 ) ;
file - > file . read ( buffer , sizeof ( buffer ) ) ;
2014-07-22 17:16:15 +02:00
break ;
}
2015-03-12 20:02:02 +01:00
}
2013-10-06 14:07:42 +02:00
2020-02-19 16:26:41 +01:00
if ( * reinterpret_cast < be_t < u32 > * > ( buffer ) ! = 0x47494638u | |
( * reinterpret_cast < le_t < u16 > * > ( buffer + 4 ) ! = 0x6139u & & * reinterpret_cast < le_t < u16 > * > ( buffer + 4 ) ! = 0x6137u ) ) // Error: The first 6 bytes are not a valid GIF signature
2013-09-10 15:17:02 +02:00
{
2014-04-04 15:25:38 +02:00
return CELL_GIFDEC_ERROR_STREAM_FORMAT ; // Surprisingly there is no error code related with headerss
2013-09-10 15:17:02 +02:00
}
2013-10-06 14:07:42 +02:00
u8 packedField = buffer [ 10 ] ;
2014-04-04 15:25:38 +02:00
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 ] ;
2013-10-06 14:07:42 +02:00
2013-11-19 22:10:23 +01:00
* info = current_info ;
2018-08-25 14:39:00 +02:00
2013-09-10 15:17:02 +02:00
return CELL_OK ;
}
2020-07-16 12:14:57 +02:00
error_code cellGifDecExtReadHeader ( )
2015-07-29 17:39:34 +02:00
{
2019-09-02 13:41:57 +02:00
cellGifDec . todo ( " cellGifDecExtReadHeader() " ) ;
return CELL_OK ;
2015-07-29 17:39:34 +02:00
}
2020-07-16 12:14:57 +02:00
error_code cellGifDecSetParameter ( PMainHandle mainHandle , PSubHandle subHandle , PInParam inParam , POutParam outParam )
2013-09-10 15:17:02 +02:00
{
2016-01-12 22:57:16 +01:00
cellGifDec . warning ( " cellGifDecSetParameter(mainHandle=*0x%x, subHandle=*0x%x, inParam=*0x%x, outParam=*0x%x) " , mainHandle , subHandle , inParam , outParam ) ;
2013-10-06 14:07:42 +02:00
2015-08-05 17:30:32 +02:00
CellGifDecInfo & current_info = subHandle - > info ;
CellGifDecOutParam & current_outParam = subHandle - > outParam ;
2013-10-06 14:07:42 +02:00
2014-04-04 15:25:38 +02:00
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 ;
2019-12-01 18:14:58 +01:00
switch ( current_outParam . outputColorSpace )
2013-09-25 15:43:55 +02:00
{
2013-10-06 14:07:42 +02:00
case CELL_GIFDEC_RGBA :
case CELL_GIFDEC_ARGB : current_outParam . outputComponents = 4 ; break ;
2014-04-04 15:25:38 +02:00
default : return CELL_GIFDEC_ERROR_ARG ; // Not supported color space
2013-09-25 15:43:55 +02:00
}
2014-04-04 15:25:38 +02:00
current_outParam . outputBitDepth = 0 ; // Unimplemented
current_outParam . useMemorySpace = 0 ; // Unimplemented
2013-09-14 20:20:57 +02:00
2013-11-19 22:10:23 +01:00
* outParam = current_outParam ;
2013-09-14 20:20:57 +02:00
2013-09-10 15:17:02 +02:00
return CELL_OK ;
}
2020-07-16 12:14:57 +02:00
error_code cellGifDecExtSetParameter ( )
2015-07-29 17:39:34 +02:00
{
2019-09-02 13:41:57 +02:00
cellGifDec . todo ( " cellGifDecExtSetParameter() " ) ;
return CELL_OK ;
2015-07-29 17:39:34 +02:00
}
2020-07-16 12:14:57 +02:00
error_code cellGifDecDecodeData ( PMainHandle mainHandle , PSubHandle subHandle , vm : : ptr < u8 > data , PDataCtrlParam dataCtrlParam , PDataOutInfo dataOutInfo )
2013-09-10 15:17:02 +02:00
{
2016-01-12 22:57:16 +01:00
cellGifDec . warning ( " cellGifDecDecodeData(mainHandle=*0x%x, subHandle=*0x%x, data=*0x%x, dataCtrlParam=*0x%x, dataOutInfo=*0x%x) " , mainHandle , subHandle , data , dataCtrlParam , dataOutInfo ) ;
2014-08-06 00:19:33 +02:00
2013-10-06 14:07:42 +02:00
dataOutInfo - > status = CELL_GIFDEC_DEC_STATUS_STOP ;
2019-12-01 18:14:58 +01:00
const u32 fd = subHandle - > fd ;
const u64 fileSize = subHandle - > fileSize ;
2018-08-25 14:39:00 +02:00
const CellGifDecOutParam & current_outParam = subHandle - > outParam ;
2013-09-10 15:17:02 +02:00
//Copy the GIF file to a buffer
2015-06-26 16:45:13 +02:00
std : : unique_ptr < u8 [ ] > gif ( new u8 [ fileSize ] ) ;
2014-07-22 17:16:15 +02:00
2015-09-26 22:46:04 +02:00
switch ( subHandle - > src . srcSelect )
2014-07-22 17:16:15 +02:00
{
2015-06-24 18:25:37 +02:00
case CELL_GIFDEC_BUFFER :
2015-08-05 17:30:32 +02:00
std : : memcpy ( gif . get ( ) , subHandle - > src . streamPtr . get_ptr ( ) , fileSize ) ;
2014-07-22 17:16:15 +02:00
break ;
2015-06-24 18:25:37 +02:00
case CELL_GIFDEC_FILE :
2015-03-12 20:02:02 +01:00
{
2017-01-26 02:12:50 +01:00
auto file = idm : : get < lv2_fs_object , lv2_file > ( fd ) ;
2016-03-21 20:43:03 +01:00
file - > file . seek ( 0 ) ;
file - > file . read ( gif . get ( ) , fileSize ) ;
2014-07-22 17:16:15 +02:00
break ;
}
2015-03-12 20:02:02 +01:00
}
2013-09-10 15:17:02 +02:00
//Decode GIF file. (TODO: Is there any faster alternative? Can we do it without external libraries?)
int width , height , actual_components ;
2014-07-22 21:37:45 +02:00
auto image = std : : unique_ptr < unsigned char , decltype ( & : : free ) >
(
2019-12-01 18:14:58 +01:00
stbi_load_from_memory ( gif . get ( ) , : : narrow < int > ( fileSize ) , & width , & height , & actual_components , 4 ) ,
2014-07-22 21:37:45 +02:00
& : : free
) ;
2014-07-10 21:07:46 +02:00
if ( ! image )
return CELL_GIFDEC_ERROR_STREAM_FORMAT ;
2013-09-14 22:47:59 +02:00
2019-12-01 18:14:58 +01:00
const int bytesPerLine = static_cast < int > ( dataCtrlParam - > outputBytesPerLine ) ;
2014-07-22 21:37:45 +02:00
const char nComponents = 4 ;
uint image_size = width * height * nComponents ;
2013-10-06 14:07:42 +02:00
2019-12-01 18:14:58 +01:00
switch ( current_outParam . outputColorSpace )
2013-10-06 14:07:42 +02:00
{
case CELL_GIFDEC_RGBA :
2014-07-22 21:37:45 +02:00
{
if ( bytesPerLine > width * nComponents ) // Check if we need padding
2014-07-11 11:18:23 +02:00
{
2014-07-22 21:37:45 +02:00
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 ;
2014-09-05 22:26:36 +02:00
memcpy ( & data [ dstOffset ] , & image . get ( ) [ srcOffset ] , linesize ) ;
2014-07-22 21:37:45 +02:00
}
}
else
{
2014-09-05 22:26:36 +02:00
memcpy ( data . get_ptr ( ) , image . get ( ) , image_size ) ;
2014-07-11 11:18:23 +02:00
}
2014-07-22 21:37:45 +02:00
}
2013-10-06 14:07:42 +02:00
break ;
case CELL_GIFDEC_ARGB :
2014-07-22 21:37:45 +02:00
{
if ( bytesPerLine > width * nComponents ) // Check if we need padding
2013-10-06 14:07:42 +02:00
{
2014-07-22 21:37:45 +02:00
//TODO: find out if we can't do padding without an extra copy
const int linesize = std : : min ( bytesPerLine , width * nComponents ) ;
2019-12-01 18:14:58 +01:00
const auto output = std : : make_unique < char [ ] > ( linesize ) ;
2014-07-22 21:37:45 +02:00
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 ] ;
}
2019-12-01 18:14:58 +01:00
std : : memcpy ( & data [ dstOffset ] , output . get ( ) , linesize ) ;
2014-07-22 21:37:45 +02:00
}
2013-09-14 20:20:57 +02:00
}
2014-07-22 21:37:45 +02:00
else
{
2019-12-01 18:14:58 +01:00
const auto img = std : : make_unique < uint [ ] > ( image_size ) ;
uint * source_current = reinterpret_cast < uint * > ( image . get ( ) ) ;
uint * dest_current = img . get ( ) ;
2018-08-25 14:39:00 +02:00
for ( uint i = 0 ; i < image_size / nComponents ; i + + )
2014-07-22 21:37:45 +02:00
{
uint val = * source_current ;
* dest_current = ( val > > 24 ) | ( val < < 8 ) ; // set alpha (A8) as leftmost byte
source_current + + ;
dest_current + + ;
}
2019-12-01 18:14:58 +01:00
std : : memcpy ( data . get_ptr ( ) , img . get ( ) , image_size ) ;
2014-07-22 21:37:45 +02:00
}
}
2013-10-06 14:07:42 +02:00
break ;
default :
return CELL_GIFDEC_ERROR_ARG ;
2013-09-10 15:17:02 +02:00
}
2013-10-06 14:07:42 +02:00
dataOutInfo - > status = CELL_GIFDEC_DEC_STATUS_FINISH ;
dataOutInfo - > recordType = CELL_GIFDEC_RECORD_TYPE_IMAGE_DESC ;
2013-09-14 20:20:57 +02:00
2013-09-10 15:17:02 +02:00
return CELL_OK ;
}
2020-07-16 12:14:57 +02:00
error_code cellGifDecExtDecodeData ( )
2015-07-29 17:39:34 +02:00
{
2019-09-02 13:41:57 +02:00
cellGifDec . todo ( " cellGifDecExtDecodeData() " ) ;
return CELL_OK ;
2015-07-29 17:39:34 +02:00
}
2020-07-16 12:14:57 +02:00
error_code cellGifDecClose ( PMainHandle mainHandle , PSubHandle subHandle )
2013-09-10 15:17:02 +02:00
{
2016-01-12 22:57:16 +01:00
cellGifDec . warning ( " cellGifDecClose(mainHandle=*0x%x, subHandle=*0x%x) " , mainHandle , subHandle ) ;
2015-04-14 04:00:31 +02:00
2017-01-26 02:12:50 +01:00
idm : : remove < lv2_fs_object , lv2_file > ( subHandle - > fd ) ;
2013-10-06 14:07:42 +02:00
2015-08-05 17:30:32 +02:00
vm : : dealloc ( subHandle . addr ( ) ) ;
2013-09-10 15:17:02 +02:00
return CELL_OK ;
}
2020-07-16 12:14:57 +02:00
error_code cellGifDecDestroy ( PMainHandle mainHandle )
2013-09-10 15:17:02 +02:00
{
UNIMPLEMENTED_FUNC ( cellGifDec ) ;
return CELL_OK ;
}
2016-03-21 20:43:03 +01:00
DECLARE ( ppu_module_manager : : cellGifDec ) ( " cellGifDec " , [ ] ( )
2013-09-10 15:17:02 +02:00
{
2015-02-20 14:58:40 +01:00
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 ) ;
2018-08-25 14:39:00 +02:00
2015-07-29 17:39:34 +02:00
REG_FUNC ( cellGifDec , cellGifDecExtOpen ) ;
2015-02-20 14:58:40 +01:00
REG_FUNC ( cellGifDec , cellGifDecExtReadHeader ) ;
REG_FUNC ( cellGifDec , cellGifDecExtSetParameter ) ;
2015-07-29 17:39:34 +02:00
REG_FUNC ( cellGifDec , cellGifDecExtDecodeData ) ;
2015-02-18 17:22:06 +01:00
} ) ;