Play-/Source/ee/IPU.h

564 lines
11 KiB
C
Raw Permalink Normal View History

#pragma once
2024-07-21 03:26:42 +02:00
#include <algorithm>
#include <array>
#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"
2023-12-08 13:10:20 -05:00
#include "zip/ZipArchiveWriter.h"
#include "zip/ZipArchiveReader.h"
2017-01-01 19:22:43 -05:00
class CINTC;
class CIPU
{
public:
2018-04-30 21:01:23 +01:00
typedef std::function<uint32(const void*, uint32)> Dma3ReceiveHandler;
2018-04-30 21:01:23 +01:00
CIPU(CINTC&);
2023-08-31 16:34:11 -04:00
virtual ~CIPU() = default;
enum REGISTER
{
2018-04-30 21:01:23 +01:00
IPU_CMD = 0x10002000,
IPU_CTRL = 0x10002010,
IPU_BP = 0x10002020,
IPU_TOP = 0x10002030,
IPU_OUT_FIFO = 0x10007000,
IPU_IN_FIFO = 0x10007010,
};
2018-04-30 21:01:23 +01:00
void Reset();
uint32 GetRegister(uint32);
void SetRegister(uint32, uint32);
2023-12-08 13:10:20 -05:00
void SaveState(Framework::CZipArchiveWriter&);
void LoadState(Framework::CZipArchiveReader&);
2018-04-30 21:01:23 +01:00
void SetDMA3ReceiveHandler(const Dma3ReceiveHandler&);
uint32 ReceiveDMA4(uint32, uint32, bool, uint8*, uint8*);
2018-04-30 21:01:23 +01:00
void CountTicks(uint32);
void ExecuteCommand();
bool WillExecuteCommand() const;
bool IsCommandDelayed() const;
bool HasPendingOUTFIFOData() const;
2019-10-28 08:05:46 -04:00
void FlushOUTFIFOData();
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,
IPU_CMD_MAX,
};
static constexpr uint32 IPU_INVALID_CMDID = ~0U;
struct FIFO_STATE
{
uint32 bp = 0;
uint32 ifc = 0;
uint32 fp = 0;
};
struct CMD_IDEC : public convertible<uint32>
{
2018-04-30 21:01:23 +01:00
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>
{
2018-04-30 21:01:23 +01:00
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>
{
2018-04-30 21:01:23 +01:00
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
{
2018-04-30 21:01:23 +01:00
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:
2018-04-30 21:01:23 +01:00
virtual ~COUTFIFO();
2018-04-30 21:01:23 +01:00
uint32 GetSize() const;
void Write(const void*, unsigned int);
void Flush();
void SetReceiveHandler(const Dma3ReceiveHandler&);
2018-04-30 21:01:23 +01:00
void Reset();
private:
2018-04-30 21:01:23 +01:00
void RequestGrow(unsigned int);
enum GROWSIZE
{
GROWSIZE = 0x200,
};
2023-05-02 08:56:25 -04:00
unsigned int m_size = 0;
unsigned int m_alloc = 0;
uint8* m_buffer = nullptr;
2018-04-30 21:01:23 +01:00
Dma3ReceiveHandler m_receiveHandler;
};
class CINFIFO : public Framework::CBitStream
{
public:
2018-04-30 21:01:23 +01:00
CINFIFO();
2023-12-07 09:52:18 -05:00
virtual ~CINFIFO() = default;
2018-04-30 21:01:23 +01:00
void Write(void*, unsigned int);
2018-04-30 21:01:23 +01:00
void Advance(uint8) override;
uint8 GetBitIndex() const override;
2018-04-30 21:01:23 +01:00
bool TryPeekBits_LSBF(uint8, uint32&) override;
bool TryPeekBits_MSBF(uint8, uint32&) override;
2018-04-30 21:01:23 +01:00
void SetBitPosition(unsigned int);
unsigned int GetSize() const;
unsigned int GetAvailableBits() const;
2023-12-08 13:10:20 -05:00
2018-04-30 21:01:23 +01:00
void Reset();
2023-12-08 13:10:20 -05:00
void SaveState(const char*, Framework::CZipArchiveWriter&);
void LoadState(const char*, Framework::CZipArchiveReader&);
enum BUFFERSIZE
{
BUFFERSIZE = 0xF0,
};
private:
2018-04-30 21:01:23 +01:00
void SyncLookupBits();
uint8 m_buffer[BUFFERSIZE] = {};
2018-04-30 21:01:23 +01:00
uint64 m_lookupBits;
bool m_lookupBitsDirty;
unsigned int m_size;
unsigned int m_bitPosition;
};
class CStartCodeException : public std::exception
{
};
class CCommand
{
public:
2023-12-07 09:52:18 -05:00
virtual ~CCommand() = default;
2018-04-30 21:01:23 +01:00
virtual bool Execute() = 0;
virtual void CountTicks(uint32)
{
}
virtual bool IsDelayed() const
{
return false;
}
private:
};
//0x00 ------------------------------------------------------------
class CBCLRCommand : public CCommand
{
public:
2018-04-30 21:01:23 +01:00
CBCLRCommand();
void Initialize(CINFIFO*, uint32);
bool Execute() override;
private:
2018-04-30 21:01:23 +01:00
CINFIFO* m_IN_FIFO;
uint32 m_commandCode;
};
//0x01 ------------------------------------------------------------
class CBDECCommand;
class CCSCCommand;
class CIDECCommand : public CCommand
{
public:
2018-04-30 21:01:23 +01:00
CIDECCommand();
2018-04-30 21:01:23 +01:00
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_VALIDATESTARTCODE,
STATE_READMBINCREMENT,
STATE_CSCINIT,
STATE_CSC,
STATE_DONE
};
2018-04-30 21:01:23 +01:00
void ConvertRawBlock();
2018-04-30 21:01:23 +01:00
CMD_IDEC m_command = make_convertible<CMD_IDEC>(0);
STATE m_state = STATE_DONE;
2018-04-30 21:01:23 +01:00
CBDECCommand* m_BDECCommand = nullptr;
CCSCCommand* m_CSCCommand = nullptr;
CINFIFO* m_IN_FIFO = nullptr;
COUTFIFO* m_OUT_FIFO = nullptr;
2018-04-30 21:01:23 +01:00
CINFIFO m_temp_IN_FIFO;
COUTFIFO m_temp_OUT_FIFO;
2018-04-30 21:01:23 +01:00
Framework::CMemStream m_blockStream;
2018-04-30 21:01:23 +01:00
DECODER_CONTEXT m_context;
uint16 m_TH0 = 0;
uint16 m_TH1 = 0;
2018-10-10 13:08:59 -04:00
uint32 m_dt = 0;
2018-04-30 21:01:23 +01:00
uint32 m_mbType = 0;
uint32 m_qsc = 0;
uint32 m_mbCount = 0;
int32 m_delayTicks = 0;
};
//0x02 ------------------------------------------------------------
class CBDECCommand_ReadDcDiff : public CCommand
{
public:
2018-04-30 21:01:23 +01:00
void Initialize(CINFIFO*, unsigned int, int16*);
bool Execute() override;
private:
enum STATE
{
STATE_READSIZE,
STATE_READDIFF,
STATE_DONE
};
2023-05-02 08:56:25 -04:00
STATE m_state = STATE_READSIZE;
CINFIFO* m_IN_FIFO = nullptr;
unsigned int m_channelId = 0;
uint8 m_dcSize = 0;
int16* m_result = nullptr;
};
class CBDECCommand_ReadDct : public CCommand
{
public:
2018-04-30 21:01:23 +01:00
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
};
2023-05-02 08:56:25 -04:00
CINFIFO* m_IN_FIFO = nullptr;
STATE m_state = STATE_INIT;
int16* m_block = nullptr;
unsigned int m_channelId = 0;
bool m_mbi = false;
bool m_isMpeg1CoeffVLCTable = false;
bool m_isMpeg2 = true;
unsigned int m_blockIndex = 0;
MPEG2::CDctCoefficientTable* m_coeffTable = nullptr;
int16* m_dcPredictor = nullptr;
int16 m_dcDiff = 0;
2018-04-30 21:01:23 +01:00
CBDECCommand_ReadDcDiff m_readDcDiffCommand;
};
class CBDECCommand : public CCommand
{
public:
2018-04-30 21:01:23 +01:00
CBDECCommand();
2018-04-30 21:01:23 +01:00
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
{
2018-04-30 21:01:23 +01:00
int16* block;
unsigned int channel;
};
2018-04-30 21:01:23 +01:00
CMD_BDEC m_command = make_convertible<CMD_BDEC>(0);
STATE m_state = STATE_DONE;
2018-04-30 21:01:23 +01:00
CINFIFO* m_IN_FIFO = nullptr;
COUTFIFO* m_OUT_FIFO = nullptr;
bool m_checkStartCode = false;
2018-04-30 21:01:23 +01:00
uint8 m_codedBlockPattern = 0;
2018-04-30 21:01:23 +01:00
BLOCKENTRY m_blocks[6];
int16 m_yBlock[4][64] = {};
int16 m_cbBlock[64] = {};
int16 m_crBlock[64] = {};
2018-04-30 21:01:23 +01:00
unsigned int m_currentBlockIndex = 0;
2018-04-30 21:01:23 +01:00
DECODER_CONTEXT m_context;
CBDECCommand_ReadDct m_readDctCoeffsCommand;
};
//0x03 ------------------------------------------------------------
class CVDECCommand : public CCommand
{
public:
2018-04-30 21:01:23 +01:00
void Initialize(CINFIFO*, uint32, uint32, uint32*);
bool Execute() override;
private:
enum STATE
{
STATE_ADVANCE,
STATE_DECODE,
STATE_DONE
};
2023-05-02 08:56:25 -04:00
uint32 m_commandCode = 0;
uint32* m_result = nullptr;
CINFIFO* m_IN_FIFO = nullptr;
STATE m_state = STATE_ADVANCE;
MPEG2::CVLCTable* m_table = nullptr;
};
//0x04 ------------------------------------------------------------
class CFDECCommand : public CCommand
{
public:
2018-04-30 21:01:23 +01:00
void Initialize(CINFIFO*, uint32, uint32*);
bool Execute() override;
private:
enum STATE
{
STATE_ADVANCE,
STATE_DECODE,
STATE_DONE
};
2023-05-02 08:56:25 -04:00
uint32 m_commandCode = 0;
uint32* m_result = nullptr;
CINFIFO* m_IN_FIFO = nullptr;
STATE m_state = STATE_ADVANCE;
};
//0x05 ------------------------------------------------------------
class CSETIQCommand : public CCommand
{
public:
2018-04-30 21:01:23 +01:00
CSETIQCommand();
2018-04-30 21:01:23 +01:00
void Initialize(CINFIFO*, uint8*);
bool Execute() override;
private:
2018-04-30 21:01:23 +01:00
CINFIFO* m_IN_FIFO;
uint8* m_matrix;
unsigned int m_currentIndex;
};
//0x06 ------------------------------------------------------------
class CSETVQCommand : public CCommand
{
public:
2018-04-30 21:01:23 +01:00
CSETVQCommand();
2018-04-30 21:01:23 +01:00
void Initialize(CINFIFO*, uint16*);
bool Execute() override;
private:
2018-04-30 21:01:23 +01:00
CINFIFO* m_IN_FIFO;
uint16* m_clut;
unsigned int m_currentIndex;
};
//0x07 ------------------------------------------------------------
class CCSCCommand : public CCommand
{
public:
2017-01-03 18:54:04 -05:00
enum
{
BLOCK_SIZE = 0x180,
};
2018-04-30 21:01:23 +01:00
CCSCCommand();
2018-04-30 21:01:23 +01:00
void Initialize(CINFIFO*, COUTFIFO*, uint32, uint16, uint16);
bool Execute() override;
private:
enum STATE
{
STATE_READBLOCKSTART,
STATE_READBLOCK,
STATE_CONVERTBLOCK,
STATE_FLUSHBLOCK,
STATE_DONE,
};
2018-04-30 21:01:23 +01:00
void GenerateCbCrMap();
2018-04-30 21:01:23 +01:00
STATE m_state = STATE_DONE;
CMD_CSC m_command = make_convertible<CMD_CSC>(0);
2018-04-30 21:01:23 +01:00
CINFIFO* m_IN_FIFO = nullptr;
COUTFIFO* m_OUT_FIFO = nullptr;
2018-04-30 21:01:23 +01:00
uint16 m_TH0 = 0;
uint16 m_TH1 = 0;
unsigned int m_currentIndex = 0;
unsigned int m_mbCount = 0;
2018-04-30 21:01:23 +01:00
unsigned int m_nCbCrMap[0x100];
2018-04-30 21:01:23 +01:00
uint8 m_block[BLOCK_SIZE];
};
//0x09 ------------------------------------------------------------
class CSETTHCommand : public CCommand
{
public:
2018-04-30 21:01:23 +01:00
CSETTHCommand();
2018-04-30 21:01:23 +01:00
void Initialize(uint32, uint16*, uint16*);
bool Execute() override;
private:
2018-04-30 21:01:23 +01:00
uint32 m_commandCode;
uint16* m_TH0;
uint16* m_TH1;
};
2018-04-30 21:01:23 +01:00
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;
uint32 m_currentCmdId;
uint32 m_lastCmdId;
2018-04-30 21:01:23 +01:00
bool m_isBusy;
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;
std::array<CCommand*, IPU_CMD_MAX> m_commands;
};