* Savestate mega-fix!  Removed all the old direct pointer types from decoder_t, which should fix the oddball random savestate crashes when IPU is active.
 * Moved iq/niq into decoder_t.
 * Moved all macroblocks into decoder_t (mb8, mb16, rgb16, rgb32).
 * Turned decoder.stride into a constant, since IPU can only decode in strides of 16 bytes only.
 * Added sanity checking to the ipu0_fifo stuff (was formerly g_nIPU0Data, etc).
 * Added some SSE moves to the Idct (very minor optimization).  There's a completely SSE from-ground-up implementation provided by newer versions of libmpeg2 that we should probably look into later, rather than rolling our own.

git-svn-id: http://pcsx2.googlecode.com/svn/trunk@3587 96395faa-99c1-11dd-bbfe-3dabce05a288
This commit is contained in:
Jake.Stine 2010-08-01 21:50:59 +00:00
parent 63a2d9c228
commit 61a4b537c4
12 changed files with 305 additions and 357 deletions

View File

@ -94,27 +94,7 @@ void __fastcall ReadFIFO_page_6(u32 mem, u64 *out)
out[1] = psHu64(GIF_FIFO + 8);
}
void __fastcall ReadFIFO_page_7(u32 mem, u64 *out)
{
pxAssert( (mem >= IPUout_FIFO) && (mem < D0_CHCR) );
// All addresses in this page map to 0x7000 and 0x7010:
mem &= 0x10;
if( mem == 0 ) // IPUout_FIFO
{
if( g_nIPU0Data > 0 )
{
out[0] = *(u64*)(g_pIPU0Pointer);
out[1] = *(u64*)(g_pIPU0Pointer+8);
ipu_fifo.out.readpos = (ipu_fifo.out.readpos + 4) & 31;
g_nIPU0Data--;
g_pIPU0Pointer += 16;
}
}
else // IPUin_FIFO
ipu_fifo.out.readsingle((void*)out);
}
// ReadFIFO_page_7 is contained in IPU_Fifo.cpp
//////////////////////////////////////////////////////////////////////////
// WriteFIFO Pages

View File

@ -43,12 +43,6 @@ tIPU_DMA g_nDMATransfer(0);
tIPU_cmd ipu_cmd;
IPUStatus IPU1Status;
// FIXME - g_nIPU0Data and Pointer are not saved in the savestate, which breaks savestates for some
// FMVs at random (if they get saved during the half frame of a 30fps rate). The fix is complicated
// since coroutine is such a pita. (air)
int g_nIPU0Data = 0; // data left to transfer
u8* g_pIPU0Pointer = NULL;
void ReorderBitstream();
// the BP doesn't advance and returns -1 if there is no data to be read
@ -59,31 +53,17 @@ void IPUWorker();
// Color conversion stuff, the memory layout is a total hack
// convert_data_buffer is a pointer to the internal rgb struct (the first param in convert_init_t)
//char convert_data_buffer[sizeof(convert_rgb_t)];
char convert_data_buffer[0x1C];
//char convert_data_buffer[0x1C]; // unused?
//u8 PCT[] = {'r', 'I', 'P', 'B', 'D', '-', '-', '-'}; // unused?
// Quantization matrix
// Pointers outside of IPU.cpp point to niq & iq. As such, all hell breaks loose under gcc if you make them static.
u8 niq[64]; //non-intraquant matrix
u8 iq[64]; //intraquant matrix
u16 vqclut[16]; //clut conversion table
static u16 vqclut[16]; //clut conversion table
static u8 s_thresh[2]; //thresholds for color conversions
int coded_block_pattern = 0;
__aligned16 macroblock_8 mb8;
__aligned16 macroblock_16 mb16;
__aligned16 macroblock_rgb32 rgb32;
__aligned16 macroblock_rgb16 rgb16;
u8 indx4[16*16/2];
bool mpeg2_inited = false; //mpeg2_idct_init() must be called only once
u8 PCT[] = {'r', 'I', 'P', 'B', 'D', '-', '-', '-'};
__aligned16 decoder_t decoder; //static, only to place it in bss
extern "C"
{
extern u8 mpeg2_scan_norm[64];
extern u8 mpeg2_scan_alt[64];
}
__aligned16 decoder_t decoder;
__aligned16 u8 _readbits[80]; //local buffer (ring buffer)
u8* readbits = _readbits; // always can decrement by one 1qw
@ -93,38 +73,16 @@ __forceinline void IPUProcessInterrupt()
if (ipuRegs->ctrl.BUSY && g_BP.IFC) IPUWorker();
}
void init_g_decoder()
{
//other stuff
decoder.intra_quantizer_matrix = (u8*)iq;
decoder.non_intra_quantizer_matrix = (u8*)niq;
decoder.picture_structure = FRAME_PICTURE; //default: progressive...my guess:P
decoder.stride = 16;
}
void mpeg2_init()
{
if (!mpeg2_inited)
{
mpeg2_idct_init();
yuv2rgb_init();
memzero(mb8.Y);
memzero(mb8.Cb);
memzero(mb8.Cr);
memzero(mb16.Y);
memzero(mb16.Cb);
memzero(mb16.Cr);
mpeg2_inited = true;
}
}
/////////////////////////////////////////////////////////
// Register accesses (run on EE thread)
int ipuInit()
{
memzero(*ipuRegs);
memzero(g_BP);
init_g_decoder();
memzero(decoder);
decoder.picture_structure = FRAME_PICTURE; //default: progressive...my guess:P
g_nDMATransfer.reset();
IPU1Status.InProgress = false;
IPU1Status.DMAMode = DMA_MODE_NORMAL;
@ -149,18 +107,16 @@ void ReportIPU()
Console.WriteLn(ipu_fifo.in.desc());
Console.WriteLn(ipu_fifo.out.desc());
Console.WriteLn(g_BP.desc());
Console.WriteLn("niq = 0x%x, iq = 0x%x.", niq, iq);
Console.WriteLn("vqclut = 0x%x.", vqclut);
Console.WriteLn("s_thresh = 0x%x.", s_thresh);
Console.WriteLn("coded_block_pattern = 0x%x.", coded_block_pattern);
Console.WriteLn("g_decoder = 0x%x.", decoder);
Console.WriteLn("mpeg2: scan_norm = 0x%x, alt = 0x%x.", mpeg2_scan_norm, mpeg2_scan_alt);
Console.WriteLn("g_decoder = 0x%x.", &decoder);
Console.WriteLn("mpeg2_scan = 0x%x.", &mpeg2_scan);
Console.WriteLn(ipu_cmd.desc());
Console.WriteLn("_readbits = 0x%x. readbits - _readbits, which is also frozen, is 0x%x.",
_readbits, readbits - _readbits);
Console.Newline();
}
// fixme - ipuFreeze looks fairly broken. Should probably take a closer look at some point.
void SaveStateBase::ipuFreeze()
{
@ -168,24 +124,15 @@ void SaveStateBase::ipuFreeze()
//ReportIPU();
FreezeTag("IPU");
// old versions saved the IPU regs, but they're already saved as part of HW!
//FreezeMem(ipuRegs, sizeof(IPUregisters));
Freeze(g_nDMATransfer);
Freeze(ipu_fifo);
Freeze(g_BP);
Freeze(niq);
Freeze(iq);
Freeze(vqclut);
Freeze(s_thresh);
Freeze(coded_block_pattern);
Freeze(decoder);
Freeze(mpeg2_scan_norm);
Freeze(mpeg2_scan_alt);
Freeze(ipu_cmd);
Freeze(_readbits);
int temp = readbits - _readbits;
@ -194,16 +141,9 @@ void SaveStateBase::ipuFreeze()
if (IsLoading())
{
readbits = _readbits;
init_g_decoder();
mpeg2_init();
}
}
bool ipuCanFreeze()
{
return (ipu_cmd.current == -1);
}
__forceinline u32 ipuRead32(u32 mem)
{
// Note: It's assumed that mem's input value is always in the 0x10002000 page
@ -232,6 +172,7 @@ __forceinline u32 ipuRead32(u32 mem)
IPU_LOG("Ipu read32: IPU_BP=0x%08X", ipuRegs->ipubp);
return ipuRegs->ipubp;
default:
IPU_LOG("Ipu read32: Addr=0x%x Value = 0x%08X", mem, *(u32*)(((u8*)ipuRegs) + mem));
}
@ -277,7 +218,6 @@ __forceinline u64 ipuRead64(u32 mem)
void ipuSoftReset()
{
mpeg2_init();
ipu_fifo.clear();
coded_block_pattern = 0;
@ -385,7 +325,7 @@ static BOOL ipuIDEC(u32 val, bool resume)
decoder.mpeg1 = ipuRegs->ctrl.MP1;
decoder.q_scale_type = ipuRegs->ctrl.QST;
decoder.intra_vlc_format = ipuRegs->ctrl.IVF;
decoder.scan = ipuRegs->ctrl.AS ? mpeg2_scan_alt : mpeg2_scan_norm;
decoder.scantype = ipuRegs->ctrl.AS;
decoder.intra_dc_precision = ipuRegs->ctrl.IDP;
//from IDEC value
@ -418,7 +358,7 @@ static __forceinline BOOL ipuBDEC(u32 val, bool resume)
decoder.mpeg1 = ipuRegs->ctrl.MP1;
decoder.q_scale_type = ipuRegs->ctrl.QST;
decoder.intra_vlc_format = ipuRegs->ctrl.IVF;
decoder.scan = ipuRegs->ctrl.AS ? mpeg2_scan_alt : mpeg2_scan_norm;
decoder.scantype = ipuRegs->ctrl.AS;
decoder.intra_dc_precision = ipuRegs->ctrl.IDP;
//from BDEC value
@ -427,8 +367,8 @@ static __forceinline BOOL ipuBDEC(u32 val, bool resume)
decoder.dcr = bdec.DCR;
decoder.macroblock_modes |= bdec.MBI ? MACROBLOCK_INTRA : MACROBLOCK_PATTERN;
memzero_sse_a(mb8);
memzero_sse_a(mb16);
memzero_sse_a(decoder.mb8);
memzero_sse_a(decoder.mb16);
}
return mpeg2_slice();
@ -516,6 +456,8 @@ static BOOL ipuSETIQ(u32 val)
if ((val >> 27) & 1)
{
u8 (&niq)[64] = decoder.niq;
for(;ipu_cmd.pos[0] < 8; ipu_cmd.pos[0]++)
{
if (!getBits64((u8*)niq + 8 * ipu_cmd.pos[0], 1)) return FALSE;
@ -531,6 +473,8 @@ static BOOL ipuSETIQ(u32 val)
}
else
{
u8 (&iq)[64] = decoder.iq;
for(;ipu_cmd.pos[0] < 8; ipu_cmd.pos[0]++)
{
if (!getBits64((u8*)iq + 8 * ipu_cmd.pos[0], 1)) return FALSE;
@ -552,7 +496,7 @@ static BOOL ipuSETVQ(u32 val)
{
for(;ipu_cmd.pos[0] < 4; ipu_cmd.pos[0]++)
{
if (!getBits64((u8*)vqclut + 8 * ipu_cmd.pos[0], 1)) return FALSE;
if (!getBits64(((u8*)vqclut) + 8 * ipu_cmd.pos[0], 1)) return FALSE;
}
IPU_LOG("IPU SETVQ command.\nRead VQCLUT table from IPU FIFO.");
@ -591,17 +535,17 @@ static BOOL __fastcall ipuCSC(u32 val)
{
for(;ipu_cmd.pos[0] < 48; ipu_cmd.pos[0]++)
{
if (!getBits64((u8*)&mb8 + 8 * ipu_cmd.pos[0], 1)) return FALSE;
if (!getBits64((u8*)&decoder.mb8 + 8 * ipu_cmd.pos[0], 1)) return FALSE;
}
ipu_csc(mb8, rgb32, 0);
if (csc.OFM) ipu_dither(rgb32, rgb16, csc.DTE);
ipu_csc(decoder.mb8, decoder.rgb32, 0);
if (csc.OFM) ipu_dither(decoder.rgb32, decoder.rgb16, csc.DTE);
if (csc.OFM)
{
while (ipu_cmd.pos[1] < 32)
{
ipu_cmd.pos[1] += ipu_fifo.out.write(((u32*) & rgb16) + 4 * ipu_cmd.pos[1], 32 - ipu_cmd.pos[1]);
ipu_cmd.pos[1] += ipu_fifo.out.write(((u32*) & decoder.rgb16) + 4 * ipu_cmd.pos[1], 32 - ipu_cmd.pos[1]);
if (ipu_cmd.pos[1] <= 0) return FALSE;
}
@ -610,7 +554,7 @@ static BOOL __fastcall ipuCSC(u32 val)
{
while (ipu_cmd.pos[1] < 64)
{
ipu_cmd.pos[1] += ipu_fifo.out.write(((u32*) & rgb32) + 4 * ipu_cmd.pos[1], 64 - ipu_cmd.pos[1]);
ipu_cmd.pos[1] += ipu_fifo.out.write(((u32*) & decoder.rgb32) + 4 * ipu_cmd.pos[1], 64 - ipu_cmd.pos[1]);
if (ipu_cmd.pos[1] <= 0) return FALSE;
}
@ -633,17 +577,17 @@ static BOOL ipuPACK(u32 val)
{
for(;ipu_cmd.pos[0] < 8; ipu_cmd.pos[0]++)
{
if (!getBits64((u8*)&mb8 + 8 * ipu_cmd.pos[0], 1)) return FALSE;
if (!getBits64((u8*)&decoder.mb8 + 8 * ipu_cmd.pos[0], 1)) return FALSE;
}
ipu_csc(mb8, rgb32, 0);
ipu_dither(rgb32, rgb16, csc.DTE);
ipu_csc(decoder.mb8, decoder.rgb32, 0);
ipu_dither(decoder.rgb32, decoder.rgb16, csc.DTE);
if (csc.OFM) ipu_vq(rgb16, indx4);
if (csc.OFM) ipu_vq(decoder.rgb16, indx4);
if (csc.OFM)
{
ipu_cmd.pos[1] += ipu_fifo.out.write(((u32*) & rgb16) + 4 * ipu_cmd.pos[1], 32 - ipu_cmd.pos[1]);
ipu_cmd.pos[1] += ipu_fifo.out.write(((u32*) & decoder.rgb16) + 4 * ipu_cmd.pos[1], 32 - ipu_cmd.pos[1]);
if (ipu_cmd.pos[1] < 32) return FALSE;
}

View File

@ -342,8 +342,6 @@ struct tIPU_cmd
extern tIPU_cmd ipu_cmd;
extern int coded_block_pattern;
extern int g_nIPU0Data; // or 0x80000000 whenever transferring
extern u8* g_pIPU0Pointer;
extern IPUStatus IPU1Status;
extern tIPU_DMA g_nDMATransfer;

View File

@ -19,7 +19,7 @@
#include "mpeg2lib/Mpeg.h"
IPU_Fifo ipu_fifo;
__aligned16 IPU_Fifo ipu_fifo;
void IPU_Fifo::init()
{
@ -167,3 +167,32 @@ void IPU_Fifo_Output::readsingle(void *value)
_readsingle(value);
}
}
__forceinline bool decoder_t::ReadIpuData(u128* out)
{
if(decoder.ipu0_data == 0) return false;
_mm_store_ps((float*)out, _mm_load_ps((float*)GetIpuDataPtr()));
--ipu0_data;
++ipu0_idx;
return true;
}
void __fastcall ReadFIFO_page_7(u32 mem, u64 *out)
{
pxAssert( (mem >= IPUout_FIFO) && (mem < D0_CHCR) );
// All addresses in this page map to 0x7000 and 0x7010:
mem &= 0x10;
if (mem == 0) // IPUout_FIFO
{
if (decoder.ReadIpuData((u128*)out))
{
ipu_fifo.out.readpos = (ipu_fifo.out.readpos + 4) & 31;
}
}
else // IPUin_FIFO
ipu_fifo.out.readsingle((void*)out);
}

View File

@ -16,12 +16,14 @@
#ifndef IPU_FIFO_H_INCLUDED
#define IPU_FIFO_H_INCLUDED
class IPU_Fifo_Input
{
public:
// Important! All FIFO containers in this header should be 'struct' type, not class type.
// They are saved into the savestate as-is, and keeping them as struct ensures that the
// layout of their contents is reliable.
int readpos, writepos;
struct IPU_Fifo_Input
{
__aligned16 u32 data[32];
int readpos, writepos;
int write(u32* pMem, int size);
int read(void *value);
@ -29,12 +31,10 @@ class IPU_Fifo_Input
wxString desc() const;
};
class IPU_Fifo_Output
struct IPU_Fifo_Output
{
public:
int readpos, writepos;
__aligned16 u32 data[32];
int readpos, writepos;
// returns number of qw read
int write(const u32 * value, int size);
@ -42,20 +42,19 @@ class IPU_Fifo_Output
void readsingle(void *value);
void clear();
wxString desc() const;
private:
void _readsingle(void *value);
};
class IPU_Fifo
struct IPU_Fifo
{
public:
IPU_Fifo_Input in;
IPU_Fifo_Output out;
__aligned16 IPU_Fifo_Input in;
__aligned16 IPU_Fifo_Output out;
void init();
void clear();
};
extern IPU_Fifo ipu_fifo;
extern __aligned16 IPU_Fifo ipu_fifo;
#endif // IPU_FIFO_H_INCLUDED

View File

@ -22,10 +22,15 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
// [TODO] : There are modern SSE versions of idct (idct_mmx.c) in the mpeg2 libs that we
// should probably upgrade to. They use their own raw-style intrinsics and not the intel
// compiler-integrated ones.
#include "PrecompiledHeader.h"
#include "Common.h"
#include "IPU/IPU.h"
#include "Mpeg.h"
#define W1 2841 /* 2048*sqrt (2)*cos (1*pi/16) */
#define W2 2676 /* 2048*sqrt (2)*cos (2*pi/16) */
@ -36,19 +41,14 @@
#define clp(val,res) res = (val < 0) ? 0 : ((val > 255) ? 255 : val);
#define clp2(val,res) res = (val < -255) ? -255 : ((val > 255) ? 255 : val);
/* idct main entry point */
void (__fastcall *mpeg2_idct_copy) (s16 * block, u8 * dest, int stride);
/* JayteeMaster: changed dest to 16 bit signed */
void (__fastcall *mpeg2_idct_add) (int last, s16 * block,
/*u8*/s16 * dest, int stride);
/*
* In legal streams, the IDCT output should be between -384 and +384.
* In corrupted streams, it is possible to force the IDCT output to go
* to +-3826 - this is the worst case for a column IDCT where the
* column inputs are 16-bit values.
*/
static u8 clip_lut[1024];
static __aligned16 u8 clip_lut[1024];
#define CLIP(i) ((clip_lut+384)[(i)])
#if 0
@ -160,8 +160,7 @@ static __forceinline void idct_col (s16 * const block)
block[8*7] = (a0 - b0) >> 17;
}
static void __fastcall mpeg2_idct_copy_c (s16 * block, u8 * dest,
const int stride)
__releaseinline void mpeg2_idct_copy(s16 * block, u8 * dest, const int stride)
{
int i;
@ -169,6 +168,8 @@ static void __fastcall mpeg2_idct_copy_c (s16 * block, u8 * dest,
idct_row (block + 8 * i);
for (i = 0; i < 8; i++)
idct_col (block + i);
__m128 zero = _mm_setzero_ps();
do {
dest[0] = CLIP (block[0]);
dest[1] = CLIP (block[1]);
@ -179,64 +180,53 @@ static void __fastcall mpeg2_idct_copy_c (s16 * block, u8 * dest,
dest[6] = CLIP (block[6]);
dest[7] = CLIP (block[7]);
block[0] = 0; block[1] = 0; block[2] = 0; block[3] = 0;
block[4] = 0; block[5] = 0; block[6] = 0; block[7] = 0;
_mm_store_ps((float*)block, zero);
dest += stride;
block += 8;
} while (--i);
}
/* JayteeMaster: changed dest to 16 bit signed */
static void __fastcall mpeg2_idct_add_c (const int last, s16 * block,
/*u8*/s16 * dest, const int stride)
// stride = increment for dest in 16-bit units (typically either 8 [128 bits] or 16 [256 bits]).
__releaseinline void mpeg2_idct_add (const int last, s16 * block, s16 * dest, const int stride)
{
// on the IPU, stride is always assured to be multiples of QWC (bottom 3 bits are 0).
if (last != 129 || (block[0] & 7) == 4)
{
int i;
if (last != 129 || (block[0] & 7) == 4) {
for (i = 0; i < 8; i++)
idct_row (block + 8 * i);
for (i = 0; i < 8; i++)
idct_col (block + i);
do {
dest[0] = block[0];
dest[1] = block[1];
dest[2] = block[2];
dest[3] = block[3];
dest[4] = block[4];
dest[5] = block[5];
dest[6] = block[6];
dest[7] = block[7];
block[0] = 0; block[1] = 0; block[2] = 0; block[3] = 0;
block[4] = 0; block[5] = 0; block[6] = 0; block[7] = 0;
__m128 zero = _mm_setzero_ps();
do {
_mm_store_ps((float*)dest, _mm_load_ps((float*)block));
_mm_store_ps((float*)block, zero);
dest += stride;
block += 8;
} while (--i);
} else {
int DC;
DC = (block[0] + 4) >> 3;
block[0] = block[63] = 0;
i = 8;
do {
dest[0] = DC;
dest[1] = DC;
dest[2] = DC;
dest[3] = DC;
dest[4] = DC;
dest[5] = DC;
dest[6] = DC;
dest[7] = DC;
dest += stride;
} while (--i);
}
}
extern "C"
else
{
u8 mpeg2_scan_norm[64] = {
int DC = (block[0] + 4) >> 3;
s16 dcf[2] = { DC, DC };
block[0] = block[63] = 0;
__m128 dc128 = _mm_set_ps1(*(float*)dcf);
for(int i=0; i<8; ++i)
_mm_store_ps((float*)(dest+(stride*i)), dc128);
}
}
mpeg2_scan_pack::mpeg2_scan_pack()
{
static const u8 mpeg2_scan_norm[64] = {
/* Zig-Zag scan pattern */
0, 1, 8, 16, 9, 2, 3, 10, 17, 24, 32, 25, 18, 11, 4, 5,
12, 19, 26, 33, 40, 48, 41, 34, 27, 20, 13, 6, 7, 14, 21, 28,
@ -244,38 +234,23 @@ u8 mpeg2_scan_norm[64] = {
58, 59, 52, 45, 38, 31, 39, 46, 53, 60, 61, 54, 47, 55, 62, 63
};
u8 mpeg2_scan_alt[64] = {
static const u8 mpeg2_scan_alt[64] = {
/* Alternate scan pattern */
0, 8, 16, 24, 1, 9, 2, 10, 17, 25, 32, 40, 48, 56, 57, 49,
41, 33, 26, 18, 3, 11, 4, 12, 19, 27, 34, 42, 50, 58, 35, 43,
51, 59, 20, 28, 5, 13, 6, 14, 21, 29, 36, 44, 52, 60, 37, 45,
53, 61, 22, 30, 7, 15, 23, 31, 38, 46, 54, 62, 39, 47, 55, 63
};
};
// The MMX verson wasn't being used and it was only available as a .obj,
// so I removed it (gigaherz).
///* idct_mmx.c */
//void mpeg2_idct_copy_mmxext (s16 * block, u8 * dest, int stride);
//void mpeg2_idct_add_mmxext (int last, s16 * block,
// s16 * dest, int stride);
//void mpeg2_idct_copy_mmx (s16 * block, u8 * dest, int stride);
//void mpeg2_idct_add_mmx (int last, s16 * block,
// s16 * dest, int stride);
//void mpeg2_idct_mmx_init (void);
void mpeg2_idct_init()
{
int i, j;
mpeg2_idct_copy = mpeg2_idct_copy_c;
mpeg2_idct_add = mpeg2_idct_add_c;
for (i = -384; i < 640; i++)
for (int i = -384; i < 640; i++)
clip_lut[i+384] = (i < 0) ? 0 : ((i > 255) ? 255 : i);
for (i = 0; i < 64; i++) {
j = mpeg2_scan_norm[i];
mpeg2_scan_norm[i] = ((j & 0x36) >> 1) | ((j & 0x09) << 2);
for (int i = 0; i < 64; i++) {
int j = mpeg2_scan_norm[i];
norm[i] = ((j & 0x36) >> 1) | ((j & 0x09) << 2);
j = mpeg2_scan_alt[i];
mpeg2_scan_alt[i] = ((j & 0x36) >> 1) | ((j & 0x09) << 2);
alt[i] = ((j & 0x36) >> 1) | ((j & 0x09) << 2);
}
}
const __aligned16 mpeg2_scan_pack mpeg2_scan;

View File

@ -33,7 +33,7 @@
#include "Mpeg.h"
#include "Vlc.h"
int non_linear_quantizer_scale [] =
const int non_linear_quantizer_scale [] =
{
0, 1, 2, 3, 4, 5, 6, 7,
8, 10, 12, 14, 16, 18, 20, 22,
@ -341,8 +341,8 @@ static __forceinline bool get_intra_block()
int i;
int j;
int val;
const u8 * scan = decoder.scan;
const u8 * quant_matrix = decoder.intra_quantizer_matrix;
const u8 * scan = decoder.scantype ? mpeg2_scan.alt : mpeg2_scan.norm;
const u8 (&quant_matrix)[64] = decoder.iq;
int quantizer_scale = decoder.quantizer_scale;
s16 * dest = decoder.DCTblock;
u16 code;
@ -493,8 +493,8 @@ static __forceinline bool get_non_intra_block(int * last)
int i;
int j;
int val;
const u8 * scan = decoder.scan;
const u8 * quant_matrix = decoder.non_intra_quantizer_matrix;
const u8 * scan = decoder.scantype ? mpeg2_scan.alt : mpeg2_scan.norm;
const u8 (&quant_matrix)[64] = decoder.niq;
int quantizer_scale = decoder.quantizer_scale;
s16 * dest = decoder.DCTblock;
u16 code;
@ -699,7 +699,6 @@ void __forceinline finishmpeg2sliceIDEC()
bool mpeg2sliceIDEC()
{
u32 read;
u16 code;
u8 bit8;
@ -725,6 +724,10 @@ bool mpeg2sliceIDEC()
ipu_cmd.pos[0] = 2;
while (1)
{
macroblock_8& mb8 = decoder.mb8;
macroblock_rgb16& rgb16 = decoder.rgb16;
macroblock_rgb32& rgb32 = decoder.rgb32;
int DCT_offset, DCT_stride;
const MBAtab * mba;
@ -747,13 +750,13 @@ bool mpeg2sliceIDEC()
if (decoder.macroblock_modes & DCT_TYPE_INTERLACED)
{
DCT_offset = decoder.stride;
DCT_stride = decoder.stride * 2;
DCT_offset = decoder_stride;
DCT_stride = decoder_stride * 2;
}
else
{
DCT_offset = decoder.stride * 8;
DCT_stride = decoder.stride;
DCT_offset = decoder_stride * 8;
DCT_stride = decoder_stride;
}
switch (ipu_cmd.pos[2])
@ -784,13 +787,13 @@ bool mpeg2sliceIDEC()
return false;
}
case 5:
if (!slice_intra_DCT(1, (u8*)mb8.Cb, decoder.stride >> 1, ipu_cmd.pos[2] == 5))
if (!slice_intra_DCT(1, (u8*)mb8.Cb, decoder_stride >> 1, ipu_cmd.pos[2] == 5))
{
ipu_cmd.pos[2] = 5;
return false;
}
case 6:
if (!slice_intra_DCT(2, (u8*)mb8.Cr, decoder.stride >> 1, ipu_cmd.pos[2] == 6))
if (!slice_intra_DCT(2, (u8*)mb8.Cr, decoder_stride >> 1, ipu_cmd.pos[2] == 6))
{
ipu_cmd.pos[2] = 6;
return false;
@ -801,22 +804,17 @@ bool mpeg2sliceIDEC()
ipu_csc(mb8, rgb32, decoder.sgn);
if (decoder.ofm == 0)
{
g_nIPU0Data = 64;
g_pIPU0Pointer = (u8*)&rgb32;
}
decoder.SetOutputTo(rgb32);
else
{
ipu_dither(rgb32, rgb16, decoder.dte);
g_nIPU0Data = 32;
g_pIPU0Pointer = (u8*)&rgb16;
decoder.SetOutputTo(rgb16);
}
case 2:
while (g_nIPU0Data > 0)
while (decoder.ipu0_data > 0)
{
read = ipu_fifo.out.write((u32*)g_pIPU0Pointer, g_nIPU0Data);
uint read = ipu_fifo.out.write((u32*)decoder.GetIpuDataPtr(), decoder.ipu0_data);
if (read == 0)
{
@ -825,9 +823,7 @@ bool mpeg2sliceIDEC()
}
else
{
g_pIPU0Pointer += read * 16;
g_nIPU0Data -= read;
decoder.AdvanceIpuDataBy(read);
}
}
@ -932,7 +928,9 @@ bool mpeg2_slice()
{
int DCT_offset, DCT_stride;
u8 bit8;
u32 size;
macroblock_8& mb8 = decoder.mb8;
macroblock_16& mb16 = decoder.mb16;
switch (ipu_cmd.pos[0])
{
@ -960,13 +958,13 @@ bool mpeg2_slice()
if (decoder.macroblock_modes & DCT_TYPE_INTERLACED)
{
DCT_offset = decoder.stride;
DCT_stride = decoder.stride * 2;
DCT_offset = decoder_stride;
DCT_stride = decoder_stride * 2;
}
else
{
DCT_offset = decoder.stride * 8;
DCT_stride = decoder.stride;
DCT_offset = decoder_stride * 8;
DCT_stride = decoder_stride;
}
if (decoder.macroblock_modes & MACROBLOCK_INTRA)
@ -1000,13 +998,13 @@ bool mpeg2_slice()
return false;
}
case 5:
if (!slice_intra_DCT(1, (u8*)mb8.Cb, decoder.stride >> 1, ipu_cmd.pos[1] == 5))
if (!slice_intra_DCT(1, (u8*)mb8.Cb, decoder_stride >> 1, ipu_cmd.pos[1] == 5))
{
ipu_cmd.pos[1] = 5;
return false;
}
case 6:
if (!slice_intra_DCT(2, (u8*)mb8.Cr, decoder.stride >> 1, ipu_cmd.pos[1] == 6))
if (!slice_intra_DCT(2, (u8*)mb8.Cr, decoder_stride >> 1, ipu_cmd.pos[1] == 6))
{
ipu_cmd.pos[1] = 6;
return false;
@ -1063,7 +1061,7 @@ bool mpeg2_slice()
case 5:
if (decoder.coded_block_pattern & 0x2)
{
if (!slice_non_intra_DCT((s16*)mb16.Cb, decoder.stride >> 1, ipu_cmd.pos[1] == 5))
if (!slice_non_intra_DCT((s16*)mb16.Cb, decoder_stride >> 1, ipu_cmd.pos[1] == 5))
{
ipu_cmd.pos[1] = 5;
return false;
@ -1072,7 +1070,7 @@ bool mpeg2_slice()
case 6:
if (decoder.coded_block_pattern & 0x1)
{
if (!slice_non_intra_DCT((s16*)mb16.Cr, decoder.stride >> 1, ipu_cmd.pos[1] == 6))
if (!slice_non_intra_DCT((s16*)mb16.Cr, decoder_stride >> 1, ipu_cmd.pos[1] == 6))
{
ipu_cmd.pos[1] = 6;
return false;
@ -1084,7 +1082,6 @@ bool mpeg2_slice()
}
// Send The MacroBlock via DmaIpuFrom
size = 0; // Reset
ipuRegs->ctrl.SCD = 0;
coded_block_pattern = decoder.coded_block_pattern;
g_BP.BP += (int)decoder.bitstream_bits - 16;
@ -1101,13 +1098,12 @@ bool mpeg2_slice()
}
decoder.mbc = 1;
g_nIPU0Data = 48;
g_pIPU0Pointer = (u8*)&mb16;
decoder.SetOutputTo(mb16);
case 3:
while (g_nIPU0Data > 0)
while (decoder.ipu0_data > 0)
{
size = ipu_fifo.out.write((u32*)g_pIPU0Pointer, g_nIPU0Data);
uint size = ipu_fifo.out.write((u32*)decoder.GetIpuDataPtr(), decoder.ipu0_data);
if (size == 0)
{
@ -1116,8 +1112,7 @@ bool mpeg2_slice()
}
else
{
g_pIPU0Pointer += size * 16;
g_nIPU0Data -= size;
decoder.AdvanceIpuDataBy(size);
}
}

View File

@ -66,6 +66,8 @@ __noinline void memzero_sse_a( T& dest )
#undef MZFqwc
};
// the IPU is fixed to 16 byte strides (128-bit / QWC resolution):
static const uint decoder_stride = 16;
enum macroblock_modes
{
@ -106,25 +108,25 @@ enum picture_coding_type
};
struct macroblock_8{
unsigned char Y[16][16]; //0
unsigned char Cb[8][8]; //1
unsigned char Cr[8][8]; //2
u8 Y[16][16]; //0
u8 Cb[8][8]; //1
u8 Cr[8][8]; //2
};
struct macroblock_16{
short Y[16][16]; //0
short Cb[8][8]; //1
short Cr[8][8]; //2
s16 Y[16][16]; //0
s16 Cb[8][8]; //1
s16 Cr[8][8]; //2
};
struct macroblock_rgb32{
struct {
unsigned char r, g, b, a;
u8 r, g, b, a;
} c[16][16];
};
struct rgb16_t{
unsigned short r:5, g:5, b:5, a:1;
u16 r:5, g:5, b:5, a:1;
};
struct macroblock_rgb16{
@ -138,24 +140,26 @@ struct decoder_t {
/* DCT coefficients - should be kept aligned ! */
s16 DCTblock[64];
u8 niq[64]; //non-intraquant matrix (sequence header)
u8 iq[64]; //intraquant matrix (sequence header)
macroblock_8 mb8;
macroblock_16 mb16;
macroblock_rgb32 rgb32;
macroblock_rgb16 rgb16;
uint ipu0_data;
uint ipu0_idx;
/* bit parsing stuff */
u32 bitstream_buf; /* current 32 bit working set */
int bitstream_bits; /* used bits in working set */
int stride;
/* predictor for DC coefficients in intra blocks */
s16 dc_dct_pred[3];
int quantizer_scale; /* remove */
int dmv_offset; /* remove */
/* now non-slice-specific information */
/* sequence header stuff */
u8 *intra_quantizer_matrix;
u8 *non_intra_quantizer_matrix;
/* picture header stuff */
/* what type of picture this is (I, P, B, D) */
@ -163,6 +167,9 @@ struct decoder_t {
/* picture coding extension stuff */
/* predictor for DC coefficients in intra blocks */
s16 dc_dct_pred[3];
/* quantization factor for intra dc coefficients */
int intra_dc_precision;
/* top/bottom/both fields */
@ -195,16 +202,47 @@ struct decoder_t {
/* stuff derived from bitstream */
/* pointer to the zigzag scan we're supposed to be using */
const u8 * scan;
/* the zigzag scan we're supposed to be using, true for alt, false for normal */
bool scantype;
int second_field;
int mpeg1;
template< typename T >
void SetOutputTo( T& obj )
{
uint mb_offset = ((uptr)&obj - (uptr)&mb8);
pxAssume( (mb_offset & 15) == 0 );
ipu0_idx = mb_offset / 16;
ipu0_data = sizeof(obj)/16;
}
u128* GetIpuDataPtr()
{
return ((u128*)&mb8) + ipu0_idx;
}
void AdvanceIpuDataBy(uint amt)
{
pxAssumeDev(ipu0_data>=amt, "IPU FIFO Overflow on advance!" );
ipu0_idx += amt;
ipu0_data -= amt;
}
bool ReadIpuData(u128* out);
};
extern void (__fastcall *mpeg2_idct_copy) (s16 * block, u8* dest, int stride);
extern void (__fastcall *mpeg2_idct_add) (int last, s16 * block, s16* dest, int stride);
struct mpeg2_scan_pack
{
u8 norm[64];
u8 alt[64];
mpeg2_scan_pack();
};
extern void mpeg2_idct_copy(s16 * block, u8* dest, int stride);
extern void mpeg2_idct_add(int last, s16 * block, s16* dest, int stride);
#define IDEC 0
#define BDEC 1
@ -217,16 +255,12 @@ extern int get_macroblock_modes();
extern int get_motion_delta(const int f_code);
extern int get_dmv();
extern int non_linear_quantizer_scale[];
extern void ipu_csc(macroblock_8& mb8, macroblock_rgb32& rgb32, int sgn);
extern void ipu_dither(const macroblock_rgb32& rgb32, macroblock_rgb16& rgb16, int dte);
extern void ipu_vq(macroblock_rgb16& rgb16, u8* indx4);
extern void ipu_copy(const macroblock_8& mb8, macroblock_16& mb16);
extern int slice (u8 * buffer);
/* idct.c */
extern void mpeg2_idct_init ();
#ifdef _MSC_VER
#define BigEndian(out, in) out = _byteswap_ulong(in)
@ -240,13 +274,12 @@ extern void mpeg2_idct_init ();
#define BigEndian64(out, in) out = __builtin_bswap64(in) // or we could use the asm function bswap...
#endif
extern __aligned16 const mpeg2_scan_pack mpeg2_scan;
extern const int non_linear_quantizer_scale[];
// The IPU can only do one task at once and never uses other buffers so all mpeg state variables
// are made available to mpeg/vlc modules as globals here:
extern __aligned16 tIPU_BP g_BP;
extern __aligned16 decoder_t decoder;
extern __aligned16 macroblock_8 mb8;
extern __aligned16 macroblock_16 mb16;
extern __aligned16 macroblock_rgb32 rgb32;
extern __aligned16 macroblock_rgb16 rgb16;

View File

@ -39,6 +39,9 @@
// conforming implementation for reference, do not optimise
void yuv2rgb_reference(void)
{
const macroblock_8& mb8 = decoder.mb8;
macroblock_rgb32& rgb32 = decoder.rgb32;
for (int y = 0; y < 16; y++)
for (int x = 0; x < 16; x++)
{
@ -124,8 +127,8 @@ __releaseinline void yuv2rgb_sse2(void)
align 16
tworows:
movq xmm3, qword ptr [mb8+256+esi]
movq xmm1, qword ptr [mb8+320+esi]
movq xmm3, qword ptr [decoder.mb8+256+esi]
movq xmm1, qword ptr [decoder.mb8+320+esi]
pxor xmm2, xmm2
pxor xmm0, xmm0
// could skip the movq but punpck requires 128-bit alignment
@ -170,7 +173,7 @@ ihatemsvc:
movaps xmm4, xmm1
movaps xmm5, xmm2
movaps xmm6, xmmword ptr [mb8+edi]
movaps xmm6, xmmword ptr [decoder.mb8+edi]
psubusb xmm6, xmmword ptr [edx+Y_BIAS]
movaps xmm7, xmm6
psllw xmm6, 8 // xmm6 <- Y << 8 for pixels 0,2,4,6,8,10,12,14
@ -235,10 +238,10 @@ ihatemsvc:
punpckhwd xmm4, xmm5
// at last
movaps xmmword ptr [rgb32+edi*4+0], xmm0
movaps xmmword ptr [rgb32+edi*4+16], xmm1
movaps xmmword ptr [rgb32+edi*4+32], xmm3
movaps xmmword ptr [rgb32+edi*4+48], xmm4
movaps xmmword ptr [decoder.rgb32+edi*4+0], xmm0
movaps xmmword ptr [decoder.rgb32+edi*4+16], xmm1
movaps xmmword ptr [decoder.rgb32+edi*4+32], xmm3
movaps xmmword ptr [decoder.rgb32+edi*4+48], xmm4
add edi, 16
@ -255,6 +258,8 @@ ihatemsvc:
// offset to the middle of the sse2 table, so that we can use 1-byte address displacement
// to access all fields:
static const u8* sse2_tableoffset = ((u8*)&sse2_tables) + 64;
static const macroblock_8* mb8 = (u8*)decoder.mb8;
static macroblock_rgb32* rgb32 = (u8*)decoder.rgb32;
__asm__ __volatile__ (
".intel_syntax noprefix\n"
@ -262,15 +267,10 @@ ihatemsvc:
"xor esi, esi\n"
"xor edi, edi\n"
// Use ecx and edx as base pointers, to allow for Mod/RM form on memOps.
// This saves 2-3 bytes per instruction where these are used. :)
//"mov ecx, offset %c[yuv2rgb_temp]\n"
//"mov edx, offset %c[sse2_tables]+64\n"
".align 16\n"
"tworows:\n"
"movq xmm3, qword ptr [mb8+256+esi]\n"
"movq xmm1, qword ptr [mb8+320+esi]\n"
"movq xmm3, qword ptr [%[mb8]+256+esi]\n"
"movq xmm1, qword ptr [%[mb8]+320+esi]\n"
"pxor xmm2, xmm2\n"
"pxor xmm0, xmm0\n"
// could skip the movq but punpck requires 128-bit alignment
@ -310,7 +310,7 @@ ihatemsvc:
"movaps xmm4, xmm1\n"
"movaps xmm5, xmm2\n"
"movaps xmm6, xmmword ptr [mb8+edi]\n"
"movaps xmm6, xmmword ptr [%[mb8]+edi]\n"
"psubusb xmm6, xmmword ptr [%[sse2_tables]+%c[Y_BIAS]]\n"
"movaps xmm7, xmm6\n"
"psllw xmm6, 8\n" // xmm6 <- Y << 8 for pixels 0,2,4,6,8,10,12,14
@ -375,10 +375,10 @@ ihatemsvc:
"punpckhwd xmm4, xmm5\n"
// at last
"movaps xmmword ptr [rgb32+edi*4+0], xmm0\n"
"movaps xmmword ptr [rgb32+edi*4+16], xmm1\n"
"movaps xmmword ptr [rgb32+edi*4+32], xmm3\n"
"movaps xmmword ptr [rgb32+edi*4+48], xmm4\n"
"movaps xmmword ptr [%[rgb32]+edi*4+0], xmm0\n"
"movaps xmmword ptr [%[rgb32]+edi*4+16], xmm1\n"
"movaps xmmword ptr [%[rgb32]+edi*4+32], xmm3\n"
"movaps xmmword ptr [%[rgb32]+edi*4+48], xmm4\n"
"add edi, 16\n"
@ -393,15 +393,11 @@ ihatemsvc:
:[C_BIAS]"i"(C_BIAS), [Y_BIAS]"i"(Y_BIAS), [Y_MASK]"i"(Y_MASK),
[ROUND_1BIT]"i"(ROUND_1BIT), [Y_COEFF]"i"(Y_COEFF), [GCr_COEFF]"i"(GCr_COEFF),
[GCb_COEFF]"i"(GCb_COEFF), [RCr_COEFF]"i"(RCr_COEFF), [BCb_COEFF]"i"(BCb_COEFF),
[yuv2rgb_temp]"r"(yuv2rgb_temp), [sse2_tables]"r"(sse2_tableoffset)
: "eax", "ebx", "esi", "edi", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7", "memory"
[yuv2rgb_temp]"r"(yuv2rgb_temp), [sse2_tables]"r"(sse2_tableoffset),
[mb8]"r"(mb8), [rgb32]"r"(rgb32)
: "eax", "esi", "edi", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7", "memory"
);
#else
# error Unsupported compiler
#endif
}
void yuv2rgb_init(void)
{
/* For later reimplementation of C version */
}

View File

@ -17,6 +17,5 @@
#define yuv2rgb yuv2rgb_sse2
extern void yuv2rgb_reference(void);
extern void yuv2rgb_sse2(void);
extern void yuv2rgb_init(void);
extern void yuv2rgb_reference();
extern void yuv2rgb_sse2();

View File

@ -24,7 +24,7 @@
// the lower 16 bit value. IF the change is breaking of all compatibility with old
// states, increment the upper 16 bit value, and clear the lower 16 bits to 0.
static const u32 g_SaveVersion = 0x8b470000;
static const u32 g_SaveVersion = 0x8b480000;
// this function is meant to be used in the place of GSfreeze, and provides a safe layer
// between the GS saving function and the MTGS's needs. :)