📄 idct_ap922tdn.cpp
字号:
movd [ OUTC + 5*16], mm5; // (6f) store y[5]
punpckhdq mm5, mm5; ;// (6f) mm3 = [y0c1 y0c0 y0c1 y0c0] <int16>
movd [ OUTC + 7*16], mm7; // (6f) store y[7]
punpckhdq mm7, mm7; ;// (6f) mm3 = [y6c1 y6c0 y6c1 y6c0] <int16>
movd [ OUTC + 0*16], mm5; // (6f) store y[0]
movd [ OUTC + 6*16], mm7; // (6f) store y[6]
jl acc_idct_colloop1;
// end for ( x=0; x < 8; x=x+2 )
FEMMS;
}
}
////////////////////////////////////////////////////////////////////////
//
//
// "Equivalent C-code" for 3DNow-AP922float
//
//
////////////////////////////////////////////////////////////////////////
void
idct_ap922float_amdx87( short *data )
{
// static tdnfloat fTempArray[64]; // intermediate (row-iDCT output) array
static tdnfloat a[8], b[8], e[8], dp[8]; // intermediate results
static tdnfloat tmp[2]; // temp calculation, scratch pad
static int xi[8]; // temp 32-bit ints for initial scale-up shift
short *x; // pointer to input
short *y; // pointer to final output
tdnfloat *yr, *xc; // pointer to output row
tdnfloat *ti; // pointer to IDCT row coefficient table
int i;
////////////////////////////////////////////////////////////////////////
//
// AP922float iDCT row transform (AMD 3DNow)
//
// Row IDCT operator :A_T*M_T*P_T
// Let Y=[output column data, 8 elements] 32-bit IEEE-754 float
// X=[input column data, 8 elements] 16-bit short integer
//
// Y= [ A_T*M_T*P_T ] * X
//
// (Y and X are both column vectors)
for ( i = 0; i < 8; ++i ) // row iDCT
{
ti = (float*)&tab_i_01234567tdn[ i * 32 ];
x = &data[ 8*i ];
yr = ((tdnfloat *) fTempArray) + 8*i; // intermediate output, select row#i
// 0) Prescale input values by left-shifting them, convert to float
//
// The prescaling operation duplicates the Intel-SSE code.
// The prescaling arises from an optimzation within the actual SSE
// code. Our 3D-Now code uses "pslld+pand" to convert 16-bit integers
// (short) to 32-bit integers(long.) On AMD's 3D-Now CPUs,
// pi2fd can be paired with any MMX instruction, hence "port-contention"
// is not an issue here as it is with Intel's Pentium3.
//
// Using pand/pslld applies an equivalent prescalar multiplier of 65536
// (left shift by 16.)
//
// Here, the prescaling is included in this C-Code to mimic the 3DN code.
// 1) apply P_T operator, permute input values
xi[0] = ROW_PRESCALE( x[0] );
xi[1] = ROW_PRESCALE( x[1] );
xi[2] = ROW_PRESCALE( x[2] );
xi[3] = ROW_PRESCALE( x[3] );
xi[4] = ROW_PRESCALE( x[4] );
xi[5] = ROW_PRESCALE( x[5] );
xi[6] = ROW_PRESCALE( x[6] );
xi[7] = ROW_PRESCALE( x[7] );
//////////////////////////////////////////////////////////////////////
//
// original table order,
// The scaled-int (MMX) iDCT implementation uses "PMADDWD", which
// simultaneously multiplies and adds adjacent data elements. The
// original AP922 w[] table is ordered for optimum execution
// with pmaddwd and paddd.
//
// a0 = x[0] * ti[0] + x[4] * ti[1] + x[2] * ti[4] + x[6] * ti[5];
// a1 = x[0] * ti[2] + x[4] * ti[3] + x[2] * ti[6] + x[6] * ti[7];
// a2 = x[0] * ti[8] + x[4] * ti[9] + x[2] * ti[12] + x[6] * ti[13];
// a3 = x[0] * ti[10] + x[4] * ti[11] + x[2] * ti[14] + x[6] * ti[15];
//
// b0 = x[1] * ti[16] + x[5] * ti[17] + x[3] * ti[20] + x[7] * ti[21];
// b1 = x[1] * ti[18] + x[5] * ti[19] + x[3] * ti[22] + x[7] * ti[23];
// b2 = x[1] * ti[24] + x[5] * ti[25] + x[3] * ti[28] + x[7] * ti[29];
// b3 = x[1] * ti[26] + x[5] * ti[27] + x[3] * ti[30] + x[7] * ti[31];
//
//////////////////////////////////////////////////////////////////////
// 2) Apply M_T operator
//
// Differences in the
// Although AMD 3D-Now lacks the floating-point equivalent of pmaddwd,
// 3D-Now does include a nifty PFACC instruction, which performs a
// "horizontal" pfadd. Pairing PFACC with PFMUL yields a 32-bit float
// equivalent of MMX PMADDWD. (Of course PFACC/PFMUL consumes a total
// of 4 MMX registers, versus 2 for PMADDWD.)
// The increase in MMX register consumption means that the 3D-Now
// implementation must spill intermediate results to memory.
// The w[] coefficient table is re-ordered for optimum 3D-Now
// execution.
//
// The SSE-iDCT packing and 3D-Now use *DIFFERENT* vector packing order!
// AMD 3D-Now packing :
//
// register mmX = [float1 float0] <2 floats per MMX register>
// a[0] = xi[0]*ti[0] + xi[2]*ti[1] + xi[4]*ti[2] + xi[6]*ti[3];
//
// ;// data has alreay been converted to float, and re-ordered
// ;//
//
// MOVQ mm0, [ INPUT] ; // mm0 <= [ xi[2] xi[0] ]
// MOVQ mm1, [ INPUT+1*8] ; // mm1 <= [ xi[6] xi[4] ]
//
// ;// mm0 <= [float<xi[2]*ti[1]> float<xi[0]*ti[0]>]
// ;// mm1 <= [float<xi[6]*ti[3]> float<xi[4]*ti[2]>]
// PFMUL( mm0, &TABLE[0] ); // address of ti[0]
// PFMUL( mm1, &TABLE[2] ); // address of ti[2]
//
// ;// mm0 <= [float< a0b > float< a0a > ]
// PFACC( mm0, mm1 ); // horizontal accumulate
//
// ;// repeat operations for a1b, a1a
// ;// mm2 <= [float< a1b > float< a1a > ]
//
// PFACC( mm0, mm2 ); // horizontal accumulate
// ;// mm2 <= [float< a1 > float< a0 > ]
//
a[0] = xi[0]*ti[0] + xi[2]*ti[1] + xi[4]*ti[2] + xi[6]*ti[3];
a[1] = xi[0]*ti[4] + xi[2]*ti[5] + xi[4]*ti[6] + xi[6]*ti[7];
a[2] = xi[0]*ti[8] + xi[2]*ti[9] + xi[4]*ti[10] + xi[6]*ti[11];
a[3] = xi[0]*ti[12]+ xi[2]*ti[13] + xi[4]*ti[14] + xi[6]*ti[15];
b[0] = xi[1]*ti[16]+ xi[3]*ti[17] + xi[5]*ti[18] + xi[7]*ti[19];
b[1] = xi[1]*ti[20]+ xi[3]*ti[21] + xi[5]*ti[22] + xi[7]*ti[23];
b[2] = xi[1]*ti[24]+ xi[3]*ti[25] + xi[5]*ti[26] + xi[7]*ti[27];
b[3] = xi[1]*ti[28]+ xi[3]*ti[29] + xi[5]*ti[30] + xi[7]*ti[31];
// 3) Apply A_T operator, store outputs
//
// 1 0 0 0 1 0 0 0
// 0 1 0 0 0 1 0 0
// 0 0 1 0 0 0 1 0
// 0 0 0 1 0 0 0 1
// 0 0 0 1 0 0 0 -1
// 0 0 1 0 0 0 -1 0
// 0 1 0 0 0 -1 0 0
// 1 0 0 0 -1 0 0 0
// Since the internal calculations produce floating-point results,
// the row-store operation does not round/scale the results.
yr[0] = ( a[0] + b[0] );
yr[1] = ( a[1] + b[1] );
yr[2] = ( a[2] + b[2] );
yr[3] = ( a[3] + b[3] );
yr[4] = ( a[3] - b[3] );
yr[5] = ( a[2] - b[2] );
yr[6] = ( a[1] - b[1] );
yr[7] = ( a[0] - b[0] );
} // end for( i = 0; i < 8; ++i ) // end of row iDCT
// AP922float iDCT row transform done
//
////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////
//
// Column IDCT operator :A_T*(F_T*E_T*B_T*D_T)*P_T
// Let Y=[output column data, 8 elements], 16-bit short integer
// X=[input column data, 8 elements], 32-bit IEEE-754 float
//
// Y= [ A_T*(F_T*E_T*B_T*D_T)*P_T ] * X
//
// (Y and X are both column vectors)
for ( i = 0; i < 8; ++i ) // column iDCT
{
xc = ((tdnfloat *) fTempArray) + i; // select column #i
y = &data[ i ];
// 1) Apply (D_T * P_T) - the cos() coefficients of D_T are implicit
// in the idct_row operation. But we still need to apply the
// shuffling operation of D_T.
//
// 1 0 0 0 0 0 0 0
// 0 0 0 0 1 0 0 0
// 0 0 1 0 0 0 0 0
// 0 0 0 0 0 0 1 0
// 0 1 0 0 0 0 0 0
// 0 0 0 0 0 0 0 1
// 0 0 0 1 0 0 0 0
// 0 0 0 0 0 1 0 0
dp[0] = xc[ 0 *8];
dp[1] = xc[ 4 *8];
dp[2] = xc[ 2 *8];
dp[3] = xc[ 6 *8];
dp[4] = xc[ 1 *8];
dp[5] = xc[ 7 *8];
dp[6] = xc[ 3 *8];
dp[7] = xc[ 5 *8];
// 2) Apply B_T
//
// 1 1 0 0
// 1 -1 0 0
// 0 0 1 t2
// 0 0 t2 -1
// 1 t1 0 0
// t1 -1 0 0
// 0 0 1 t3
// 0 0 t3 -1
b[0] = dp[1] + dp[0];
b[1] = dp[0] - dp[1];
b[2] = ( dp[3]*tg_2_16f ) + dp[2];
b[3] = ( dp[2]*tg_2_16f ) - dp[3];
b[4] = ( dp[5]*tg_1_16f ) + dp[4];
b[5] = ( dp[4]*tg_1_16f ) - dp[5];
b[6] = ( dp[7]*tg_3_16f ) + dp[6];
b[7] = ( dp[6]*tg_3_16f ) - dp[7];
// 3) Apply E_T
//
// 1 0 1 0
// 0 1 0 1
// 0 1 0 -1
// 1 0 -1 0
// 1 0 1 0
// 1 0 -1 0
// 0 1 0 1
// 0 1 0 -1
e[0] = b[0] + b[2];
e[1] = b[1] + b[3];
e[2] = b[1] - b[3];
e[3] = b[0] - b[2];
e[4] = b[4] + b[6];
e[5] = b[4] - b[6];
e[6] = b[5] + b[7];
e[7] = b[5] - b[7];
// 4) Apply F_T
//
// 1 0 0 0
// 0 1 0 0
// 0 0 1 0
// 0 0 0 1
// 1 0 0 0
// 0 1 0 0
// 0 0 1 0
// 0 0 0 1
#define _F0 e[0]
#define _F1 e[1]
#define _F2 e[2]
#define _F3 e[3]
#define _F4 e[4]
#define _F5 e[5]
#define _F6 e[6]
#define _F7 e[7]
tmp[0] = (e[5] + e[6]) * cos_4_16f;
tmp[1] = (e[5] - e[6]) * cos_4_16f;
_F5 = tmp[0];
_F6 = tmp[1];
// 5) Apply A_T
//
// 1 0 0 0 1 0 0 0
// 0 1 0 0 0 1 0 0
// 0 0 1 0 0 0 1 0
// 0 0 0 1 0 0 0 1
// 0 0 0 1 0 0 0 -1
// 0 0 1 0 0 0 -1 0
// 0 1 0 0 0 -1 0 0
// 1 0 0 0 -1 0 0 0
//
// yfloat[0]= F0 + F4
// yfloat[1]= F1 + F5
// yfloat[2]= F2 + F6
// yfloat[3]= F3 + F7
//
// yfloat[4]= F3 - F7
// yfloat[5]= F2 - F6
// yfloat[6]= F1 - F5
// yfloat[7]= F0 - F4
//
//
// 6) float -> int, shift/round to final output y[]
// The final shift&round operation reverses the row-input prescaling.
// It also applies the chosen rounding-mode (accurate or fast.)
//
// Note, the C-code below differs *substantially* from the AMD_3DNOW
// implementation. The 3D_Now code applies this basic sequence:
//
// ;// mm0 = [y1 y0] <float32>
// ;// mm1 = [y3 y2] <float32>
//
// PF2ID mm0, mm0; // mm0 <= [y1 y0] <int32>
// PF2ID mm1, mm1; // mm1 <= [y3 y2] <int32>
//
// ;// "0.5" is a 32-bit integer constant scaled up by some bitshift
// paddd mm0, [rnd_compensation]; // mm0 <=[y1+"0.5" y0+"0.5"]
// paddd mm1, [rnd_compensation]; // mm0 <=[y3+"0.5" y2+"0.5"]
//
// psrad mm0, DESCALE_SHIFT1; // stage1 shift
// psrad mm1, DESCALE_SHIFT1; // stage1 shift
//
// packssdw mm0, mm1; // mm0 <= [y3 y2 y1 y0] <int16>
//
// psraw mm0, DESCALE_SHIFT2; // clip y[] to the range {-256,+255}
//
// ;// DESCALE_SHIFT1 + DESCALE_SHIFT2 = PRESCALE_SHIFT
// ;// 9 + 7 = 16
//
// movq [OUTC+...*8], mm0;
y[0*8] = SHIFT_ROUND_COLF( _F0 + _F4 );
y[1*8] = SHIFT_ROUND_COLF( _F1 + _F5 );
y[2*8] = SHIFT_ROUND_COLF( _F2 + _F6 );
y[3*8] = SHIFT_ROUND_COLF( _F3 + _F7 );
y[4*8] = SHIFT_ROUND_COLF( _F3 - _F7 );
y[5*8] = SHIFT_ROUND_COLF( _F2 - _F6 );
y[6*8] = SHIFT_ROUND_COLF( _F1 - _F5 );
y[7*8] = SHIFT_ROUND_COLF( _F0 - _F4 );
} // end for ( i = 0; i < 8; ++i ) // end of 3DNow column iDCT
// AP922float iDCT column transform done
//
////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////
// Post transform clipping
//
// In standard-C, the output clip code adds significantly to
// execution time.
#define IDCT_CLIP_LOW -256 // IDCT output range is 9-bits
#define IDCT_CLIP_HIGH 255 // IDCT output range is 9-bits
for ( i = 0; i < 64; ++i )
{ // clip output to {-256,+255}
if ( data[ i ] < IDCT_CLIP_LOW )
data[ i ] = IDCT_CLIP_LOW;
if ( data[ i ] > IDCT_CLIP_HIGH )
data[ i ] = IDCT_CLIP_HIGH;
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -