mirror of
https://github.com/libretro/Play-.git
synced 2025-02-08 10:06:43 +00:00
552 lines
11 KiB
C++
552 lines
11 KiB
C++
#pragma once
|
|
|
|
#include <functional>
|
|
#include "Types.h"
|
|
#include "BitStream.h"
|
|
#include "MemStream.h"
|
|
#include "mpeg2/VLCTable.h"
|
|
#include "mpeg2/DctCoefficientTable.h"
|
|
#include "../MailBox.h"
|
|
#include "Convertible.h"
|
|
|
|
class CINTC;
|
|
|
|
class CIPU
|
|
{
|
|
public:
|
|
typedef std::function<uint32 (const void*, uint32)> Dma3ReceiveHandler;
|
|
|
|
CIPU(CINTC&);
|
|
virtual ~CIPU();
|
|
|
|
enum REGISTER
|
|
{
|
|
IPU_CMD = 0x10002000,
|
|
IPU_CTRL = 0x10002010,
|
|
IPU_BP = 0x10002020,
|
|
IPU_TOP = 0x10002030,
|
|
IPU_OUT_FIFO = 0x10007000,
|
|
IPU_IN_FIFO = 0x10007010,
|
|
};
|
|
|
|
void Reset();
|
|
uint32 GetRegister(uint32);
|
|
void SetRegister(uint32, uint32);
|
|
void SetDMA3ReceiveHandler(const Dma3ReceiveHandler&);
|
|
uint32 ReceiveDMA4(uint32, uint32, bool, uint8*);
|
|
|
|
void CountTicks(uint32);
|
|
void ExecuteCommand();
|
|
bool WillExecuteCommand() const;
|
|
bool IsCommandDelayed() const;
|
|
bool HasPendingOUTFIFOData() const;
|
|
|
|
private:
|
|
enum IPU_CTRL_BITS
|
|
{
|
|
IPU_CTRL_ECD = 0x00004000,
|
|
IPU_CTRL_SCD = 0x00008000,
|
|
IPU_CTRL_RST = 0x40000000,
|
|
};
|
|
|
|
enum IPU_CMD_TYPE
|
|
{
|
|
IPU_CMD_BCLR,
|
|
IPU_CMD_IDEC,
|
|
IPU_CMD_BDEC,
|
|
IPU_CMD_VDEC,
|
|
IPU_CMD_FDEC,
|
|
IPU_CMD_SETIQ,
|
|
IPU_CMD_SETVQ,
|
|
IPU_CMD_CSC,
|
|
IPU_CMD_PACK,
|
|
IPU_CMD_SETTH,
|
|
};
|
|
|
|
struct FIFO_STATE
|
|
{
|
|
uint32 bp = 0;
|
|
uint32 ifc = 0;
|
|
uint32 fp = 0;
|
|
};
|
|
|
|
struct CMD_IDEC : public convertible<uint32>
|
|
{
|
|
unsigned int fb : 6;
|
|
unsigned int unused0 : 10;
|
|
unsigned int qsc : 5;
|
|
unsigned int unused1 : 3;
|
|
unsigned int dtd : 1;
|
|
unsigned int sgn : 1;
|
|
unsigned int dte : 1;
|
|
unsigned int ofm : 1;
|
|
unsigned int cmdId : 4;
|
|
};
|
|
static_assert(sizeof(CMD_IDEC) == 4, "Size of CMD_IDEC must be 4.");
|
|
|
|
struct CMD_BDEC : public convertible<uint32>
|
|
{
|
|
unsigned int fb : 6;
|
|
unsigned int unused0 : 10;
|
|
unsigned int qsc : 5;
|
|
unsigned int unused1 : 4;
|
|
unsigned int dt : 1;
|
|
unsigned int dcr : 1;
|
|
unsigned int mbi : 1;
|
|
unsigned int cmdId : 4;
|
|
};
|
|
static_assert(sizeof(CMD_BDEC) == 4, "Size of CMD_BDEC must be 4.");
|
|
|
|
struct CMD_CSC : public convertible<uint32>
|
|
{
|
|
unsigned int mbc : 11;
|
|
unsigned int unused0 : 15;
|
|
unsigned int dte : 1;
|
|
unsigned int ofm : 1;
|
|
unsigned int cmdId : 4;
|
|
};
|
|
static_assert(sizeof(CMD_CSC) == 4, "Size of CMD_CSC must be 4.");
|
|
|
|
struct DECODER_CONTEXT
|
|
{
|
|
bool isMpeg1CoeffVLCTable = false;
|
|
bool isMpeg2 = false;
|
|
bool isLinearQScale = false;
|
|
bool isZigZag = false;
|
|
uint8* intraIq = nullptr;
|
|
uint8* nonIntraIq = nullptr;
|
|
int16* dcPredictor = nullptr;
|
|
uint32 dcPrecision = 0;
|
|
};
|
|
|
|
class COUTFIFO
|
|
{
|
|
public:
|
|
COUTFIFO();
|
|
virtual ~COUTFIFO();
|
|
|
|
uint32 GetSize() const;
|
|
void Write(const void*, unsigned int);
|
|
void Flush();
|
|
void SetReceiveHandler(const Dma3ReceiveHandler&);
|
|
|
|
void Reset();
|
|
|
|
private:
|
|
void RequestGrow(unsigned int);
|
|
|
|
enum GROWSIZE
|
|
{
|
|
GROWSIZE = 0x200,
|
|
};
|
|
|
|
unsigned int m_size;
|
|
unsigned int m_alloc;
|
|
uint8* m_buffer;
|
|
Dma3ReceiveHandler m_receiveHandler;
|
|
};
|
|
|
|
class CINFIFO : public Framework::CBitStream
|
|
{
|
|
public:
|
|
CINFIFO();
|
|
virtual ~CINFIFO();
|
|
|
|
void Write(void*, unsigned int);
|
|
|
|
void Advance(uint8) override;
|
|
uint8 GetBitIndex() const override;
|
|
|
|
bool TryPeekBits_LSBF(uint8, uint32&) override;
|
|
bool TryPeekBits_MSBF(uint8, uint32&) override;
|
|
|
|
void SetBitPosition(unsigned int);
|
|
unsigned int GetSize() const;
|
|
unsigned int GetAvailableBits() const;
|
|
void Reset();
|
|
|
|
enum BUFFERSIZE
|
|
{
|
|
BUFFERSIZE = 0xF0,
|
|
};
|
|
|
|
private:
|
|
void SyncLookupBits();
|
|
|
|
uint8 m_buffer[BUFFERSIZE];
|
|
uint64 m_lookupBits;
|
|
bool m_lookupBitsDirty;
|
|
unsigned int m_size;
|
|
unsigned int m_bitPosition;
|
|
};
|
|
|
|
class CStartCodeException : public std::exception
|
|
{
|
|
|
|
};
|
|
|
|
class CCommand
|
|
{
|
|
public:
|
|
virtual ~CCommand() {}
|
|
virtual bool Execute() = 0;
|
|
virtual void CountTicks(uint32) {}
|
|
virtual bool IsDelayed() const { return false; }
|
|
|
|
private:
|
|
|
|
};
|
|
|
|
//0x00 ------------------------------------------------------------
|
|
class CBCLRCommand : public CCommand
|
|
{
|
|
public:
|
|
CBCLRCommand();
|
|
void Initialize(CINFIFO*, uint32);
|
|
bool Execute() override;
|
|
|
|
private:
|
|
CINFIFO* m_IN_FIFO;
|
|
uint32 m_commandCode;
|
|
};
|
|
|
|
//0x01 ------------------------------------------------------------
|
|
class CBDECCommand;
|
|
class CCSCCommand;
|
|
|
|
class CIDECCommand : public CCommand
|
|
{
|
|
public:
|
|
CIDECCommand();
|
|
|
|
void Initialize(CBDECCommand*, CCSCCommand*, CINFIFO*, COUTFIFO*, uint32, const DECODER_CONTEXT&, uint16, uint16);
|
|
bool Execute() override;
|
|
void CountTicks(uint32) override;
|
|
bool IsDelayed() const override;
|
|
|
|
private:
|
|
enum STATE
|
|
{
|
|
STATE_DELAY,
|
|
STATE_ADVANCE,
|
|
STATE_READMBTYPE,
|
|
STATE_READDCTTYPE,
|
|
STATE_READQSC,
|
|
STATE_INITREADBLOCK,
|
|
STATE_READBLOCK,
|
|
STATE_CHECKSTARTCODE,
|
|
STATE_READMBINCREMENT,
|
|
STATE_CSCINIT,
|
|
STATE_CSC,
|
|
STATE_DONE
|
|
};
|
|
|
|
void ConvertRawBlock();
|
|
|
|
CMD_IDEC m_command = make_convertible<CMD_IDEC>(0);
|
|
STATE m_state = STATE_DONE;
|
|
|
|
CBDECCommand* m_BDECCommand = nullptr;
|
|
CCSCCommand* m_CSCCommand = nullptr;
|
|
CINFIFO* m_IN_FIFO = nullptr;
|
|
COUTFIFO* m_OUT_FIFO = nullptr;
|
|
|
|
CINFIFO m_temp_IN_FIFO;
|
|
COUTFIFO m_temp_OUT_FIFO;
|
|
|
|
Framework::CMemStream m_blockStream;
|
|
|
|
DECODER_CONTEXT m_context;
|
|
uint16 m_TH0 = 0;
|
|
uint16 m_TH1 = 0;
|
|
uint32 m_mbType = 0;
|
|
uint32 m_qsc = 0;
|
|
uint32 m_mbCount = 0;
|
|
int32 m_delayTicks = 0;
|
|
};
|
|
|
|
//0x02 ------------------------------------------------------------
|
|
class CBDECCommand_ReadDcDiff : public CCommand
|
|
{
|
|
public:
|
|
CBDECCommand_ReadDcDiff();
|
|
|
|
void Initialize(CINFIFO*, unsigned int, int16*);
|
|
bool Execute() override;
|
|
|
|
private:
|
|
enum STATE
|
|
{
|
|
STATE_READSIZE,
|
|
STATE_READDIFF,
|
|
STATE_DONE
|
|
};
|
|
|
|
STATE m_state;
|
|
CINFIFO* m_IN_FIFO;
|
|
unsigned int m_channelId;
|
|
uint8 m_dcSize;
|
|
int16* m_result;
|
|
};
|
|
|
|
class CBDECCommand_ReadDct : public CCommand
|
|
{
|
|
public:
|
|
CBDECCommand_ReadDct();
|
|
|
|
void Initialize(CINFIFO*, int16* block, unsigned int channelId, int16* dcPredictor, bool mbi, bool isMpeg1CoeffVLCTable, bool isMpeg2);
|
|
bool Execute() override;
|
|
|
|
private:
|
|
enum STATE
|
|
{
|
|
STATE_INIT,
|
|
STATE_READDCDIFF,
|
|
STATE_CHECKEOB,
|
|
STATE_READCOEFF,
|
|
STATE_SKIPEOB
|
|
};
|
|
|
|
CINFIFO* m_IN_FIFO;
|
|
STATE m_state;
|
|
int16* m_block;
|
|
unsigned int m_channelId;
|
|
bool m_mbi;
|
|
bool m_isMpeg1CoeffVLCTable;
|
|
bool m_isMpeg2;
|
|
unsigned int m_blockIndex;
|
|
MPEG2::CDctCoefficientTable* m_coeffTable;
|
|
int16* m_dcPredictor;
|
|
int16 m_dcDiff;
|
|
CBDECCommand_ReadDcDiff m_readDcDiffCommand;
|
|
};
|
|
|
|
class CBDECCommand : public CCommand
|
|
{
|
|
public:
|
|
CBDECCommand();
|
|
|
|
void Initialize(CINFIFO*, COUTFIFO*, uint32, bool, const DECODER_CONTEXT&);
|
|
bool Execute() override;
|
|
|
|
private:
|
|
enum STATE
|
|
{
|
|
STATE_ADVANCE,
|
|
STATE_READCBP,
|
|
STATE_RESETDC,
|
|
STATE_DECODEBLOCK_BEGIN,
|
|
STATE_DECODEBLOCK_READCOEFFS,
|
|
STATE_DECODEBLOCK_GOTONEXT,
|
|
STATE_DONE
|
|
};
|
|
|
|
struct BLOCKENTRY
|
|
{
|
|
int16* block;
|
|
unsigned int channel;
|
|
};
|
|
|
|
CMD_BDEC m_command = make_convertible<CMD_BDEC>(0);
|
|
STATE m_state = STATE_DONE;
|
|
|
|
CINFIFO* m_IN_FIFO = nullptr;
|
|
COUTFIFO* m_OUT_FIFO = nullptr;
|
|
bool m_checkStartCode = false;
|
|
|
|
uint8 m_codedBlockPattern = 0;
|
|
|
|
BLOCKENTRY m_blocks[6];
|
|
|
|
int16 m_yBlock[4][64];
|
|
int16 m_cbBlock[64];
|
|
int16 m_crBlock[64];
|
|
|
|
unsigned int m_currentBlockIndex = 0;
|
|
|
|
DECODER_CONTEXT m_context;
|
|
CBDECCommand_ReadDct m_readDctCoeffsCommand;
|
|
};
|
|
|
|
//0x03 ------------------------------------------------------------
|
|
class CVDECCommand : public CCommand
|
|
{
|
|
public:
|
|
CVDECCommand();
|
|
|
|
void Initialize(CINFIFO*, uint32, uint32, uint32*);
|
|
bool Execute() override;
|
|
|
|
private:
|
|
enum STATE
|
|
{
|
|
STATE_ADVANCE,
|
|
STATE_DECODE,
|
|
STATE_DONE
|
|
};
|
|
|
|
uint32 m_commandCode;
|
|
uint32* m_result;
|
|
CINFIFO* m_IN_FIFO;
|
|
STATE m_state;
|
|
MPEG2::CVLCTable* m_table;
|
|
};
|
|
|
|
//0x04 ------------------------------------------------------------
|
|
class CFDECCommand : public CCommand
|
|
{
|
|
public:
|
|
CFDECCommand();
|
|
|
|
void Initialize(CINFIFO*, uint32, uint32*);
|
|
bool Execute() override;
|
|
|
|
private:
|
|
enum STATE
|
|
{
|
|
STATE_ADVANCE,
|
|
STATE_DECODE,
|
|
STATE_DONE
|
|
};
|
|
|
|
uint32 m_commandCode;
|
|
uint32* m_result;
|
|
CINFIFO* m_IN_FIFO;
|
|
STATE m_state;
|
|
};
|
|
|
|
//0x05 ------------------------------------------------------------
|
|
class CSETIQCommand : public CCommand
|
|
{
|
|
public:
|
|
CSETIQCommand();
|
|
|
|
void Initialize(CINFIFO*, uint8*);
|
|
bool Execute() override;
|
|
|
|
private:
|
|
CINFIFO* m_IN_FIFO;
|
|
uint8* m_matrix;
|
|
unsigned int m_currentIndex;
|
|
};
|
|
|
|
//0x06 ------------------------------------------------------------
|
|
class CSETVQCommand : public CCommand
|
|
{
|
|
public:
|
|
CSETVQCommand();
|
|
|
|
void Initialize(CINFIFO*, uint16*);
|
|
bool Execute() override;
|
|
|
|
private:
|
|
CINFIFO* m_IN_FIFO;
|
|
uint16* m_clut;
|
|
unsigned int m_currentIndex;
|
|
};
|
|
|
|
//0x07 ------------------------------------------------------------
|
|
class CCSCCommand : public CCommand
|
|
{
|
|
public:
|
|
enum
|
|
{
|
|
BLOCK_SIZE = 0x180,
|
|
};
|
|
|
|
CCSCCommand();
|
|
|
|
void Initialize(CINFIFO*, COUTFIFO*, uint32, uint16, uint16);
|
|
bool Execute() override;
|
|
|
|
private:
|
|
enum STATE
|
|
{
|
|
STATE_READBLOCKSTART,
|
|
STATE_READBLOCK,
|
|
STATE_CONVERTBLOCK,
|
|
STATE_FLUSHBLOCK,
|
|
STATE_DONE,
|
|
};
|
|
|
|
void GenerateCbCrMap();
|
|
|
|
STATE m_state = STATE_DONE;
|
|
CMD_CSC m_command = make_convertible<CMD_CSC>(0);
|
|
|
|
CINFIFO* m_IN_FIFO = nullptr;
|
|
COUTFIFO* m_OUT_FIFO = nullptr;
|
|
|
|
uint16 m_TH0 = 0;
|
|
uint16 m_TH1 = 0;
|
|
unsigned int m_currentIndex = 0;
|
|
unsigned int m_mbCount = 0;
|
|
|
|
unsigned int m_nCbCrMap[0x100];
|
|
|
|
uint8 m_block[BLOCK_SIZE];
|
|
};
|
|
|
|
//0x09 ------------------------------------------------------------
|
|
class CSETTHCommand : public CCommand
|
|
{
|
|
public:
|
|
CSETTHCommand();
|
|
|
|
void Initialize(uint32, uint16*, uint16*);
|
|
bool Execute() override;
|
|
|
|
private:
|
|
uint32 m_commandCode;
|
|
uint16* m_TH0;
|
|
uint16* m_TH1;
|
|
};
|
|
|
|
void InitializeCommand(uint32);
|
|
|
|
DECODER_CONTEXT GetDecoderContext();
|
|
uint32 GetPictureType();
|
|
uint32 GetDcPrecision();
|
|
bool GetIsMPEG2();
|
|
bool GetIsLinearQScale();
|
|
bool GetIsZigZagScan();
|
|
bool GetIsMPEG1CoeffVLCTable();
|
|
|
|
static void DequantiseBlock(int16*, uint8, uint8, bool isLinearQScale, uint32 dcPrecision, uint8* intraIq, uint8* nonIntraIq);
|
|
static void InverseScan(int16*, bool isZigZag);
|
|
|
|
uint32 GetBusyBit(bool) const;
|
|
FIFO_STATE GetFifoState() const;
|
|
|
|
void DisassembleGet(uint32);
|
|
void DisassembleSet(uint32, uint32);
|
|
void DisassembleCommand(uint32);
|
|
|
|
CINTC& m_intc;
|
|
|
|
uint8 m_nIntraIQ[0x40];
|
|
uint8 m_nNonIntraIQ[0x40];
|
|
uint16 m_nVQCLUT[0x10];
|
|
uint16 m_nTH0;
|
|
uint16 m_nTH1;
|
|
|
|
int16 m_nDcPredictor[3];
|
|
|
|
uint32 m_IPU_CMD[2];
|
|
uint32 m_IPU_CTRL;
|
|
COUTFIFO m_OUT_FIFO;
|
|
CINFIFO m_IN_FIFO;
|
|
bool m_isBusy;
|
|
|
|
CCommand* m_currentCmd;
|
|
CBCLRCommand m_BCLRCommand;
|
|
CIDECCommand m_IDECCommand;
|
|
CBDECCommand m_BDECCommand;
|
|
CVDECCommand m_VDECCommand;
|
|
CFDECCommand m_FDECCommand;
|
|
CSETIQCommand m_SETIQCommand;
|
|
CSETVQCommand m_SETVQCommand;
|
|
CCSCCommand m_CSCCommand;
|
|
CSETTHCommand m_SETTHCommand;
|
|
};
|