Play-/Source/ee/IPU.h
2017-01-06 19:18:28 -05:00

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