Newer
Older
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
"pminsw %%mm0, %%mm4 \n\t"
"pminsw %%mm1, %%mm5 \n\t"
#else
"movq %%mm4, %%mm2 \n\t"
"psubusw %%mm0, %%mm2 \n\t"
"psubw %%mm2, %%mm4 \n\t"
"movq %%mm5, %%mm2 \n\t"
"psubusw %%mm1, %%mm2 \n\t"
"psubw %%mm2, %%mm5 \n\t"
#endif
"pxor %%mm6, %%mm4 \n\t"
"pxor %%mm7, %%mm5 \n\t"
"psubw %%mm6, %%mm4 \n\t"
"psubw %%mm7, %%mm5 \n\t"
"packsswb %%mm5, %%mm4 \n\t"
"movq (%%eax, %1, 2), %%mm0 \n\t"
"paddb %%mm4, %%mm0 \n\t"
"movq %%mm0, (%%eax, %1, 2) \n\t"
"movq (%0, %1, 4), %%mm0 \n\t"
"psubb %%mm4, %%mm0 \n\t"
// "pxor %%mm0, %%mm0 \n\t"
"movq %%mm0, (%0, %1, 4) \n\t"
:
: "r" (src), "r" (stride), "r" (QP)
: "%eax", "%ebx"
);
#else
const int l1= stride;
const int l2= stride + l1;
const int l3= stride + l2;
const int l4= stride + l3;
const int l5= stride + l4;
const int l6= stride + l5;
const int l7= stride + l6;
const int l8= stride + l7;
// const int l9= stride + l8;
int x;
for(x=0; x<BLOCK_SIZE; x++)
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
{
const int middleEnergy= 5*(src[l5] - src[l4]) + 2*(src[l3] - src[l6]);
if(ABS(middleEnergy) < 8*QP)
{
const int q=(src[l4] - src[l5])/2;
const int leftEnergy= 5*(src[l3] - src[l2]) + 2*(src[l1] - src[l4]);
const int rightEnergy= 5*(src[l7] - src[l6]) + 2*(src[l5] - src[l8]);
int d= ABS(middleEnergy) - MIN( ABS(leftEnergy), ABS(rightEnergy) );
d= MAX(d, 0);
d= (5*d + 32) >> 6;
d*= SIGN(-middleEnergy);
if(q>0)
{
d= d<0 ? 0 : d;
d= d>q ? q : d;
}
else
{
d= d>0 ? 0 : d;
d= d<q ? q : d;
}
src[l4]-= d;
src[l5]+= d;
}
src++;
}
#endif
}
//FIXME? |255-0| = 1
/**
* Check if the given 8x8 Block is mostly "flat" and copy the unaliged data into tempBlock.
*/
static inline int isHorizDCAndCopy2Temp(uint8_t src[], int stride)
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
{
// src++;
int numEq= 0;
#ifdef HAVE_MMX
asm volatile (
// "int $3 \n\t"
"pushl %1\n\t"
"movq b7E, %%mm7 \n\t" // mm7 = 0x7F
"movq b7C, %%mm6 \n\t" // mm6 = 0x7D
"leal tempBlock, %%eax \n\t"
"pxor %%mm0, %%mm0 \n\t"
#define HDC_CHECK_AND_CPY(i) \
"movq -4(%1), %%mm2 \n\t"\
"psrlq $32, %%mm2 \n\t"\
"punpckldq 4(%1), %%mm2 \n\t" /* (%1) */\
"movq %%mm2, %%mm1 \n\t"\
"psrlq $8, %%mm2 \n\t"\
"psubb %%mm1, %%mm2 \n\t"\
"paddb %%mm7, %%mm2 \n\t"\
"pcmpgtb %%mm6, %%mm2 \n\t"\
"paddb %%mm2, %%mm0 \n\t"\
"movq %%mm1," #i "(%%eax) \n\t"
HDC_CHECK_AND_CPY(0)
"addl %2, %1 \n\t"
HDC_CHECK_AND_CPY(8)
"addl %2, %1 \n\t"
HDC_CHECK_AND_CPY(16)
"addl %2, %1 \n\t"
HDC_CHECK_AND_CPY(24)
"addl %2, %1 \n\t"
HDC_CHECK_AND_CPY(32)
"addl %2, %1 \n\t"
HDC_CHECK_AND_CPY(40)
"addl %2, %1 \n\t"
HDC_CHECK_AND_CPY(48)
"addl %2, %1 \n\t"
HDC_CHECK_AND_CPY(56)
"psllq $8, %%mm0 \n\t" // remove dummy value
"movq %%mm0, %%mm1 \n\t"
"psrlw $8, %%mm0 \n\t"
"paddb %%mm1, %%mm0 \n\t"
"movq %%mm0, %%mm1 \n\t"
"psrlq $16, %%mm0 \n\t"
"paddb %%mm1, %%mm0 \n\t"
"movq %%mm0, %%mm1 \n\t"
"psrlq $32, %%mm0 \n\t"
"paddb %%mm1, %%mm0 \n\t"
"popl %1\n\t"
"movd %%mm0, %0 \n\t"
: "=r" (numEq)
: "r" (src), "r" (stride)
: "%eax"
);
// printf("%d\n", numEq);
numEq= (256 - (numEq & 0xFF)) &0xFF;
#else
int y;
for(y=0; y<BLOCK_SIZE; y++)
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
{
if(((src[0] - src[1] + 1) & 0xFFFF) < 3) numEq++;
if(((src[1] - src[2] + 1) & 0xFFFF) < 3) numEq++;
if(((src[2] - src[3] + 1) & 0xFFFF) < 3) numEq++;
if(((src[3] - src[4] + 1) & 0xFFFF) < 3) numEq++;
if(((src[4] - src[5] + 1) & 0xFFFF) < 3) numEq++;
if(((src[5] - src[6] + 1) & 0xFFFF) < 3) numEq++;
if(((src[6] - src[7] + 1) & 0xFFFF) < 3) numEq++;
tempBlock[0 + y*TEMP_STRIDE] = src[0];
tempBlock[1 + y*TEMP_STRIDE] = src[1];
tempBlock[2 + y*TEMP_STRIDE] = src[2];
tempBlock[3 + y*TEMP_STRIDE] = src[3];
tempBlock[4 + y*TEMP_STRIDE] = src[4];
tempBlock[5 + y*TEMP_STRIDE] = src[5];
tempBlock[6 + y*TEMP_STRIDE] = src[6];
tempBlock[7 + y*TEMP_STRIDE] = src[7];
src+= stride;
}
#endif
/* if(abs(numEq - asmEq) > 0)
{
// printf("\nasm:%d c:%d\n", asmEq, numEq);
for(int y=0; y<8; y++)
{
for(int x=0; x<8; x++)
{
printf("%d ", src[x + y*stride]);
}
printf("\n");
}
}
*/
// printf("%d\n", numEq);
return numEq > hFlatnessThreshold;
}
static inline int isHorizMinMaxOk(uint8_t src[], int stride, int QP)
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
{
#ifdef MMX_FIXME
FIXME
int isOk;
asm volatile(
// "int $3 \n\t"
"movq (%1, %2), %%mm0 \n\t"
"movq (%1, %2, 8), %%mm1 \n\t"
"movq %%mm0, %%mm2 \n\t"
"psubusb %%mm1, %%mm0 \n\t"
"psubusb %%mm2, %%mm1 \n\t"
"por %%mm1, %%mm0 \n\t" // ABS Diff
"movq pQPb, %%mm7 \n\t" // QP,..., QP
"paddusb %%mm7, %%mm7 \n\t" // 2QP ... 2QP
"psubusb %%mm7, %%mm0 \n\t" // Diff <= 2QP -> 0
"pcmpeqd b00, %%mm0 \n\t"
"psrlq $16, %%mm0 \n\t"
"pcmpeqd bFF, %%mm0 \n\t"
// "movd %%mm0, (%1, %2, 4)\n\t"
"movd %%mm0, %0 \n\t"
: "=r" (isOk)
: "r" (src), "r" (stride)
);
return isOk;
#else
if(abs(src[0] - src[7]) > 2*QP) return 0;
return 1;
#endif
}
static inline void doHorizDefFilterAndCopyBack(uint8_t dst[], int stride, int QP)
{
asm volatile(
"pushl %0 \n\t"
"pxor %%mm7, %%mm7 \n\t"
"movq bm00001000, %%mm6 \n\t"
"movd %2, %%mm5 \n\t" // QP
"movq %%mm5, %%mm4 \n\t"
"paddusb %%mm5, %%mm5 \n\t" // 2QP
"paddusb %%mm5, %%mm4 \n\t" // 3QP
"psllq $24, %%mm4 \n\t"
"pxor %%mm5, %%mm5 \n\t" // 0
"psubb %%mm4, %%mm5 \n\t" // -QP
"leal tempBlock, %%eax \n\t"
//FIXME? "unroll by 2" and mix
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
#ifdef HAVE_MMX2
#define HDF(i) \
"movq " #i "(%%eax), %%mm0 \n\t"\
"movq %%mm0, %%mm1 \n\t"\
"movq %%mm0, %%mm2 \n\t"\
"psrlq $8, %%mm1 \n\t"\
"psubusb %%mm1, %%mm2 \n\t"\
"psubusb %%mm0, %%mm1 \n\t"\
"por %%mm2, %%mm1 \n\t" /* px = |px - p(x+1)| */\
"pcmpeqb %%mm7, %%mm2 \n\t" /* px = sgn[px - p(x+1)] */\
"pshufw $0x00, %%mm1, %%mm3 \n\t" /* p5 = |p1 - p2| */\
"pminub %%mm1, %%mm3 \n\t" /* p5 = min(|p2-p1|, |p6-p5|)*/\
"psrlq $16, %%mm3 \n\t" /* p3 = min(|p2-p1|, |p6-p5|)*/\
"psubusb %%mm3, %%mm1 \n\t" /* |p3-p4|-min(|p1-p2|,|p5-p6|) */\
"paddb %%mm5, %%mm1 \n\t"\
"psubusb %%mm5, %%mm1 \n\t"\
"psrlw $2, %%mm1 \n\t"\
"pxor %%mm2, %%mm1 \n\t"\
"psubb %%mm2, %%mm1 \n\t"\
"pand %%mm6, %%mm1 \n\t"\
"psubb %%mm1, %%mm0 \n\t"\
"psllq $8, %%mm1 \n\t"\
"paddb %%mm1, %%mm0 \n\t"\
"movd %%mm0, (%0) \n\t"\
"psrlq $32, %%mm0 \n\t"\
"movd %%mm0, 4(%0) \n\t"
#else
#define HDF(i)\
"movq " #i "(%%eax), %%mm0 \n\t"\
"movq %%mm0, %%mm1 \n\t"\
"movq %%mm0, %%mm2 \n\t"\
"psrlq $8, %%mm1 \n\t"\
"psubusb %%mm1, %%mm2 \n\t"\
"psubusb %%mm0, %%mm1 \n\t"\
"por %%mm2, %%mm1 \n\t" /* px = |px - p(x+1)| */\
"pcmpeqb %%mm7, %%mm2 \n\t" /* px = sgn[px - p(x+1)] */\
"movq %%mm1, %%mm3 \n\t"\
"psllq $32, %%mm3 \n\t"\
"movq %%mm3, %%mm4 \n\t"\
"psubusb %%mm1, %%mm4 \n\t"\
"psubb %%mm4, %%mm3 \n\t"\
"psrlq $16, %%mm3 \n\t" /* p3 = min(|p2-p1|, |p6-p5|)*/\
"psubusb %%mm3, %%mm1 \n\t" /* |p3-p4|-min(|p1-p2|,|p5,6|) */\
"paddb %%mm5, %%mm1 \n\t"\
"psubusb %%mm5, %%mm1 \n\t"\
"psrlw $2, %%mm1 \n\t"\
"pxor %%mm2, %%mm1 \n\t"\
"psubb %%mm2, %%mm1 \n\t"\
"pand %%mm6, %%mm1 \n\t"\
"psubb %%mm1, %%mm0 \n\t"\
"psllq $8, %%mm1 \n\t"\
"paddb %%mm1, %%mm0 \n\t"\
"movd %%mm0, (%0) \n\t"\
"psrlq $32, %%mm0 \n\t"\
"movd %%mm0, 4(%0) \n\t"
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
HDF(0)
"addl %1, %0 \n\t"
HDF(8)
"addl %1, %0 \n\t"
HDF(16)
"addl %1, %0 \n\t"
HDF(24)
"addl %1, %0 \n\t"
HDF(32)
"addl %1, %0 \n\t"
HDF(40)
"addl %1, %0 \n\t"
HDF(48)
"addl %1, %0 \n\t"
HDF(56)
"popl %0 \n\t"
:
: "r" (dst), "r" (stride), "r" (QP)
: "%eax"
);
#else
uint8_t *src= tempBlock;
int y;
for(y=0; y<BLOCK_SIZE; y++)
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
{
dst[0] = src[0];
dst[1] = src[1];
dst[2] = src[2];
dst[3] = src[3];
dst[4] = src[4];
dst[5] = src[5];
dst[6] = src[6];
dst[7] = src[7];
const int middleEnergy= 5*(src[4] - src[5]) + 2*(src[2] - src[5]);
if(ABS(middleEnergy) < 8*QP)
{
const int q=(src[3] - src[4])/2;
const int leftEnergy= 5*(src[2] - src[1]) + 2*(src[0] - src[3]);
const int rightEnergy= 5*(src[6] - src[5]) + 2*(src[4] - src[7]);
int d= ABS(middleEnergy) - MIN( ABS(leftEnergy), ABS(rightEnergy) );
d= MAX(d, 0);
d= (5*d + 32) >> 6;
d*= SIGN(-middleEnergy);
if(q>0)
{
d= d<0 ? 0 : d;
d= d>q ? q : d;
}
else
{
d= d>0 ? 0 : d;
d= d<q ? q : d;
}
dst[3]-= d;
dst[4]+= d;
}
dst+= stride;
src+= TEMP_STRIDE;
}
#endif
}
/**
* Do a horizontal low pass filter on the 8x8 block
* useing the 9-Tap Filter (1,1,2,2,4,2,2,1,1)/16 (C version)
* useing approximately the 7-Tap Filter (1,2,3,4,3,2,1)/16 (MMX2/3DNOW version)
*/
static inline void doHorizLowPassAndCopyBack(uint8_t dst[], int stride, int QP)
{
//return;
#if defined (HAVE_MMX2) || defined (HAVE_3DNOW)
asm volatile( //"movv %0 %1 %2\n\t"
"pushl %0\n\t"
"pxor %%mm7, %%mm7 \n\t"
"leal tempBlock, %%eax \n\t"
#define HLP1 "movq (%0), %%mm0 \n\t"\
"movq %%mm0, %%mm1 \n\t"\
"psllq $8, %%mm0 \n\t"\
"psrlw $8, %%mm0 \n\t"\
"pxor %%mm1, %%mm1 \n\t"\
"packuswb %%mm1, %%mm0 \n\t"\
"movq %%mm0, %%mm1 \n\t"\
"movq %%mm0, %%mm2 \n\t"\
"psllq $32, %%mm0 \n\t"\
"paddb %%mm0, %%mm1 \n\t"\
"psllq $16, %%mm2 \n\t"\
"movq %%mm0, %%mm3 \n\t"\
"pand bm11001100, %%mm0 \n\t"\
"paddusb %%mm0, %%mm3 \n\t"\
"psrlq $8, %%mm3 \n\t"\
PAVGB(%%mm1, %%mm4)\
PAVGB(%%mm3, %%mm2)\
"psrlq $16, %%mm2 \n\t"\
"punpcklbw %%mm2, %%mm2 \n\t"\
"movq %%mm2, (%0) \n\t"\
#define HLP2 "movq (%0), %%mm0 \n\t"\
"movq %%mm0, %%mm1 \n\t"\
"psllq $8, %%mm0 \n\t"\
"psrlw $8, %%mm0 \n\t"\
"pxor %%mm1, %%mm1 \n\t"\
"packuswb %%mm1, %%mm0 \n\t"\
"movq %%mm0, %%mm2 \n\t"\
"psllq $32, %%mm0 \n\t"\
"psllq $16, %%mm2 \n\t"\
"movq %%mm0, %%mm3 \n\t"\
"pand bm11001100, %%mm0 \n\t"\
"paddusb %%mm0, %%mm3 \n\t"\
"psrlq $8, %%mm3 \n\t"\
"psrlq $16, %%mm2 \n\t"\
"punpcklbw %%mm2, %%mm2 \n\t"\
"movq %%mm2, (%0) \n\t"\
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
// approximately a 7-Tap Filter with Vector (1,2,3,4,3,2,1)/16
/*
31
121
121
121
121
121
121
13
Implemented Exact 7-Tap
9421 A321
36421 64321
334321 =
1234321 =
1234321 =
123433 =
12463 12346
1249 123A
*/
#define HLP3(i) "movq " #i "(%%eax), %%mm0 \n\t"\
"movq %%mm0, %%mm1 \n\t"\
"movq %%mm0, %%mm2 \n\t"\
"movq %%mm0, %%mm3 \n\t"\
"movq %%mm0, %%mm4 \n\t"\
"psllq $8, %%mm1 \n\t"\
"psrlq $8, %%mm2 \n\t"\
"pand bm00000001, %%mm3 \n\t"\
"pand bm10000000, %%mm4 \n\t"\
"por %%mm3, %%mm1 \n\t"\
"por %%mm4, %%mm2 \n\t"\
PAVGB(%%mm2, %%mm1)\
PAVGB(%%mm1, %%mm0)\
\
"pshufw $0xF9, %%mm0, %%mm3 \n\t"\
"pshufw $0x90, %%mm0, %%mm4 \n\t"\
PAVGB(%%mm3, %%mm4)\
PAVGB(%%mm4, %%mm0)\
"movd %%mm0, (%0) \n\t"\
"psrlq $32, %%mm0 \n\t"\
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
"movd %%mm0, 4(%0) \n\t"
#else
#define HLP3(i) "movq " #i "(%%eax), %%mm0 \n\t"\
"movq %%mm0, %%mm1 \n\t"\
"movq %%mm0, %%mm2 \n\t"\
"movq %%mm0, %%mm3 \n\t"\
"movq %%mm0, %%mm4 \n\t"\
"psllq $8, %%mm1 \n\t"\
"psrlq $8, %%mm2 \n\t"\
"pand bm00000001, %%mm3 \n\t"\
"pand bm10000000, %%mm4 \n\t"\
"por %%mm3, %%mm1 \n\t"\
"por %%mm4, %%mm2 \n\t"\
PAVGB(%%mm2, %%mm1)\
PAVGB(%%mm1, %%mm0)\
\
"movq %%mm0, %%mm3 \n\t"\
"movq %%mm0, %%mm4 \n\t"\
"movq %%mm0, %%mm5 \n\t"\
"psrlq $16, %%mm3 \n\t"\
"psllq $16, %%mm4 \n\t"\
"pand bm11000000, %%mm5 \n\t"\
"por %%mm5, %%mm3 \n\t"\
"movq %%mm0, %%mm5 \n\t"\
"pand bm00000011, %%mm5 \n\t"\
"por %%mm5, %%mm4 \n\t"\
PAVGB(%%mm3, %%mm4)\
PAVGB(%%mm4, %%mm0)\
"movd %%mm0, (%0) \n\t"\
"psrlq $32, %%mm0 \n\t"\
"movd %%mm0, 4(%0) \n\t"
#endif
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
#define HLP(i) HLP3(i)
HLP(0)
"addl %1, %0 \n\t"
HLP(8)
"addl %1, %0 \n\t"
HLP(16)
"addl %1, %0 \n\t"
HLP(24)
"addl %1, %0 \n\t"
HLP(32)
"addl %1, %0 \n\t"
HLP(40)
"addl %1, %0 \n\t"
HLP(48)
"addl %1, %0 \n\t"
HLP(56)
"popl %0\n\t"
:
: "r" (dst), "r" (stride)
: "%eax", "%ebx"
);
#else
uint8_t *temp= tempBlock;
int y;
for(y=0; y<BLOCK_SIZE; y++)
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
{
const int first= ABS(dst[-1] - dst[0]) < QP ? dst[-1] : dst[0];
const int last= ABS(dst[8] - dst[7]) < QP ? dst[8] : dst[7];
int sums[9];
sums[0] = first + temp[0];
sums[1] = temp[0] + temp[1];
sums[2] = temp[1] + temp[2];
sums[3] = temp[2] + temp[3];
sums[4] = temp[3] + temp[4];
sums[5] = temp[4] + temp[5];
sums[6] = temp[5] + temp[6];
sums[7] = temp[6] + temp[7];
sums[8] = temp[7] + last;
dst[0]= ((sums[0]<<2) + ((first + sums[2])<<1) + sums[4] + 8)>>4;
dst[1]= ((dst[1]<<2) + (first + sums[0] + sums[3]<<1) + sums[5] + 8)>>4;
dst[2]= ((dst[2]<<2) + (first + sums[1] + sums[4]<<1) + sums[6] + 8)>>4;
dst[3]= ((dst[3]<<2) + (sums[2] + sums[5]<<1) + sums[0] + sums[7] + 8)>>4;
dst[4]= ((dst[4]<<2) + (sums[3] + sums[6]<<1) + sums[1] + sums[8] + 8)>>4;
dst[5]= ((dst[5]<<2) + (last + sums[7] + sums[4]<<1) + sums[2] + 8)>>4;
dst[6]= ((last + dst[6]<<2) + (dst[7] + sums[5]<<1) + sums[3] + 8)>>4;
dst[7]= ((sums[8]<<2) + (last + sums[6]<<1) + sums[4] + 8)>>4;
dst+= stride;
temp+= TEMP_STRIDE;
}
#endif
}
static inline void dering(uint8_t src[], int stride, int QP)
{
//FIXME
#ifdef HAVE_MMX2X
asm volatile(
"leal (%0, %1), %%eax \n\t"
"leal (%%eax, %1, 4), %%ebx \n\t"
// 0 1 2 3 4 5 6 7 8 9
// %0 eax eax+%1 eax+2%1 %0+4%1 ebx ebx+%1 ebx+2%1 %0+8%1 ebx+4%1
"pcmpeq %%mm6, %%mm6 \n\t"
"pxor %%mm7, %%mm7 \n\t"
#define FIND_MIN_MAX(addr)\
"movq (" #addr "), %%mm0, \n\t"\
"pminub %%mm0, %%mm6 \n\t"\
"pmaxub %%mm0, %%mm7 \n\t"
FIND_MIN_MAX(%0)
FIND_MIN_MAX(%%eax)
FIND_MIN_MAX(%%eax, %1)
FIND_MIN_MAX(%%eax, %1, 2)
FIND_MIN_MAX(%0, %1, 4)
FIND_MIN_MAX(%%ebx)
FIND_MIN_MAX(%%ebx, %1)
FIND_MIN_MAX(%%ebx, %1, 2)
FIND_MIN_MAX(%0, %1, 8)
FIND_MIN_MAX(%%ebx, %1, 2)
"movq %%mm6, %%mm4 \n\t"
"psrlq $32, %%mm6 \n\t"
"pminub %%mm4, %%mm6 \n\t"
"movq %%mm6, %%mm4 \n\t"
"psrlq $16, %%mm6 \n\t"
"pminub %%mm4, %%mm6 \n\t"
"movq %%mm6, %%mm4 \n\t"
"psrlq $8, %%mm6 \n\t"
"pminub %%mm4, %%mm6 \n\t" // min of pixels
"movq %%mm7, %%mm4 \n\t"
"psrlq $32, %%mm7 \n\t"
"pmaxub %%mm4, %%mm7 \n\t"
"movq %%mm7, %%mm4 \n\t"
"psrlq $16, %%mm7 \n\t"
"pmaxub %%mm4, %%mm7 \n\t"
"movq %%mm7, %%mm4 \n\t"
"psrlq $8, %%mm7 \n\t"
"pmaxub %%mm4, %%mm7 \n\t" // max of pixels
PAVGB(%%mm6, %%mm7) // (max + min)/2
: : "r" (src), "r" (stride), "r" (QP)
: "%eax", "%ebx"
);
#else
//FIXME
#endif
}
* the mode value is interpreted as a quality value if its negative, its range is then (-1 ... -63)
* -63 is best quality -1 is worst
void postprocess(unsigned char * src[], int src_stride,
unsigned char * dst[], int dst_stride,
int horizontal_size, int vertical_size,
QP_STORE_T *QP_store, int QP_stride,
int mode)
{
if(mode<0) mode= getModeForQuality(-mode);
/*
long long T= rdtsc();
for(int y=vertical_size-1; y>=0 ; y--)
memcpy(dst[0] + y*src_stride, src[0] + y*src_stride,src_stride);
// memcpy(dst[0], src[0],src_stride*vertical_size);
printf("%4dk\r", (rdtsc()-T)/1000);
return;
*/
/*
long long T= rdtsc();
while( (rdtsc() - T)/1000 < 4000);
return;
*/
postProcess(src[0], src_stride, dst[0], dst_stride,
horizontal_size, vertical_size, QP_store, QP_stride, 0, mode);
horizontal_size >>= 1;
vertical_size >>= 1;
src_stride >>= 1;
dst_stride >>= 1;
if(1)
{
postProcess(src[1], src_stride, dst[1], dst_stride,
horizontal_size, vertical_size, QP_store, QP_stride, 1, mode >>4);
postProcess(src[2], src_stride, dst[2], dst_stride,
horizontal_size, vertical_size, QP_store, QP_stride, 1, mode >>4);
}
else
{
memcpy(dst[1], src[1], src_stride*horizontal_size);
memcpy(dst[2], src[2], src_stride*horizontal_size);
}
}
/**
* gets the mode flags for a given quality (larger values mean slower but better postprocessing)
* 0 <= quality < 64
*/
int getModeForQuality(int quality){
int modes[6]= {
LUM_V_DEBLOCK,
LUM_V_DEBLOCK | LUM_H_DEBLOCK,
LUM_V_DEBLOCK | LUM_H_DEBLOCK | CHROM_V_DEBLOCK,
LUM_V_DEBLOCK | LUM_H_DEBLOCK | CHROM_V_DEBLOCK | CHROM_H_DEBLOCK,
LUM_V_DEBLOCK | LUM_H_DEBLOCK | CHROM_V_DEBLOCK | CHROM_H_DEBLOCK | LUM_DERING,
LUM_V_DEBLOCK | LUM_H_DEBLOCK | CHROM_V_DEBLOCK | CHROM_H_DEBLOCK | LUM_DERING | CHROM_DERING
};
return modes[ (quality*6) >>6 ];
/**
* Copies a block from src to dst and fixes the blacklevel
* numLines must be a multiple of 4
* levelFix == 0 -> dont touch the brighness & contrast
static inline void blockCopy(uint8_t dst[], int dstStride, uint8_t src[], int srcStride,
int numLines, int levelFix)
int i;
if(levelFix)
{
#ifdef HAVE_MMX
asm volatile(
"movl %4, %%eax \n\t"
"movl %%eax, temp0\n\t"
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
"pushl %0 \n\t"
"pushl %1 \n\t"
"leal (%2,%2), %%eax \n\t"
"leal (%3,%3), %%ebx \n\t"
"movq packedYOffset, %%mm2 \n\t"
"movq packedYScale, %%mm3 \n\t"
#define SCALED_CPY \
"movq (%0), %%mm0 \n\t"\
"movq (%0,%2), %%mm1 \n\t"\
"psubusb %%mm2, %%mm0 \n\t"\
"psubusb %%mm2, %%mm1 \n\t"\
"pxor %%mm4, %%mm4 \n\t"\
"pxor %%mm5, %%mm5 \n\t"\
"punpcklbw %%mm0, %%mm4 \n\t"\
"punpckhbw %%mm0, %%mm5 \n\t"\
"pmulhuw %%mm3, %%mm4 \n\t"\
"pmulhuw %%mm3, %%mm5 \n\t"\
"packuswb %%mm5, %%mm4 \n\t"\
"movq %%mm4, (%1) \n\t"\
"pxor %%mm4, %%mm4 \n\t"\
"pxor %%mm5, %%mm5 \n\t"\
"punpcklbw %%mm1, %%mm4 \n\t"\
"punpckhbw %%mm1, %%mm5 \n\t"\
"pmulhuw %%mm3, %%mm4 \n\t"\
"pmulhuw %%mm3, %%mm5 \n\t"\
"packuswb %%mm5, %%mm4 \n\t"\
"movq %%mm4, (%1, %3) \n\t"\
"1: \n\t"
SCALED_CPY
"addl %%eax, %0 \n\t"
"addl %%ebx, %1 \n\t"
SCALED_CPY
"addl %%eax, %0 \n\t"
"addl %%ebx, %1 \n\t"
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
"decl temp0 \n\t"
"jnz 1b \n\t"
"popl %1 \n\t"
"popl %0 \n\t"
: : "r" (src),
"r" (dst),
"r" (srcStride),
"r" (dstStride),
"m" (numLines>>2)
: "%eax", "%ebx"
);
#else
for(i=0; i<numLines; i++)
memcpy( &(dst[dstStride*i]),
&(src[srcStride*i]), BLOCK_SIZE);
#endif
}
else
{
#ifdef HAVE_MMX
asm volatile(
"movl %4, %%eax \n\t"
"movl %%eax, temp0\n\t"
"pushl %0 \n\t"
"pushl %1 \n\t"
"leal (%2,%2), %%eax \n\t"
"leal (%3,%3), %%ebx \n\t"
"movq packedYOffset, %%mm2 \n\t"
"movq packedYScale, %%mm3 \n\t"
#define SIMPLE_CPY \
"movq (%0), %%mm0 \n\t"\
"movq (%0,%2), %%mm1 \n\t"\
"movq %%mm0, (%1) \n\t"\
"movq %%mm1, (%1, %3) \n\t"\
"1: \n\t"
SIMPLE_CPY
"addl %%eax, %0 \n\t"
"addl %%ebx, %1 \n\t"
SIMPLE_CPY
"addl %%eax, %0 \n\t"
"addl %%ebx, %1 \n\t"
"decl temp0 \n\t"
"jnz 1b \n\t"
"popl %1 \n\t"
"popl %0 \n\t"
: : "r" (src),
"r" (dst),
"r" (srcStride),
"r" (dstStride),
"m" (numLines>>2)
: "%eax", "%ebx"
);
#else
for(i=0; i<numLines; i++)
memcpy( &(dst[dstStride*i]),
&(src[srcStride*i]), BLOCK_SIZE);
#endif
}
/**
* Filters array of bytes (Y or U or V values)
*/
void postProcess(uint8_t src[], int srcStride, uint8_t dst[], int dstStride, int width, int height,
QP_STORE_T QPs[], int QPStride, int isColor, int mode)
int x,y;
/* we need 64bit here otherwise well going to have a problem
after watching a black picture for 5 hours*/
static uint64_t *yHistogram= NULL;
int black=0, white=255; // blackest black and whitest white in the picture
#ifdef TIMEING
long long T0, T1, memcpyTime=0, vertTime=0, horizTime=0, sumTime, diffTime=0;
sumTime= rdtsc();
#endif
if(!yHistogram)
{
int i;
yHistogram= (uint64_t*)malloc(8*256);
for(i=0; i<256; i++) yHistogram[i]= width*height/64*15/256;
}
if(!isColor)
{
uint64_t sum= 0;
int i;
static int framenum= -1;
uint64_t maxClipped;
uint64_t clipped;
double scale;
framenum++;
if(framenum == 1) yHistogram[0]= width*height/64*15/256;
for(i=0; i<256; i++)
{
sum+= yHistogram[i];
// printf("%d ", yHistogram[i]);
}
// printf("\n\n");
/* we allways get a completly black picture first */
maxClipped= (uint64_t)(sum * maxClippedThreshold);
clipped= sum;
for(black=255; black>0; black--)
{
if(clipped < maxClipped) break;
clipped-= yHistogram[black];
}
clipped= sum;
for(white=0; white<256; white++)
{
if(clipped < maxClipped) break;
clipped-= yHistogram[white];
}
// we cant handle negative correctures
packedYOffset= MAX(black - minAllowedY, 0);
packedYOffset|= packedYOffset<<32;
packedYOffset|= packedYOffset<<16;
packedYOffset|= packedYOffset<<8;
scale= (double)(maxAllowedY - minAllowedY) / (double)(white-black);
packedYScale= (uint16_t)(scale*256.0 + 0.5);
packedYScale|= packedYScale<<32;
packedYScale|= packedYScale<<16;
}
else
{
packedYScale= 0x0100010001000100LL;
packedYOffset= 0;
}
for(x=0; x<width; x+=BLOCK_SIZE)
blockCopy(dst + x, dstStride, src + x, srcStride, 8, mode & LEVEL_FIX);
for(y=0; y<height; y+=BLOCK_SIZE)
{
//1% speedup if these are here instead of the inner loop
uint8_t *srcBlock= &(src[y*srcStride]);
uint8_t *dstBlock= &(dst[y*dstStride]);
uint8_t *vertSrcBlock= &(srcBlock[srcStride*3]); // Blocks are 10x8 -> *3 to start
uint8_t *vertBlock= &(dstBlock[dstStride*3]);
// finish 1 block before the next otherwise well might have a problem
// with the L1 Cache of the P4 ... or only a few blocks at a time or soemthing
for(x=0; x<width; x+=BLOCK_SIZE)
const int stride= dstStride;
1885
1886
1887
1888
1889
1890
1891
1892
1893
1894
1895
1896
1897
1898
1899
1900
1901
1902
1903
1904
1905
int QP= isColor ?
QPs[(y>>3)*QPStride + (x>>3)]:
(QPs[(y>>4)*QPStride + (x>>4)] * (packedYScale &0xFFFF))>>8;
#ifdef HAVE_MMX
asm volatile(
"movd %0, %%mm7 \n\t"
"packuswb %%mm7, %%mm7 \n\t" // 0, 0, 0, QP, 0, 0, 0, QP
"packuswb %%mm7, %%mm7 \n\t" // 0,QP, 0, QP, 0,QP, 0, QP
"packuswb %%mm7, %%mm7 \n\t" // QP,..., QP
"movq %%mm7, pQPb \n\t"
: : "r" (QP)
);
#endif
if(y + 12 < height)
{
#ifdef MORE_TIMEING
T0= rdtsc();
#endif
prefetchnta(vertSrcBlock + (((x>>3)&3) + 2)*srcStride + 32);
prefetchnta(vertSrcBlock + (((x>>3)&3) + 6)*srcStride + 32);
prefetcht0(vertBlock + (((x>>3)&3) + 2)*dstStride + 32);
prefetcht0(vertBlock + (((x>>3)&3) + 6)*dstStride + 32);
#elif defined(HAVE_3DNOW)
//FIXME check if this is faster on an 3dnow chip or if its faster without the prefetch or ...
/* prefetch(vertSrcBlock + (((x>>3)&3) + 2)*srcStride + 32);
prefetch(vertSrcBlock + (((x>>3)&3) + 6)*srcStride + 32);
prefetchw(vertBlock + (((x>>3)&3) + 2)*dstStride + 32);
prefetchw(vertBlock + (((x>>3)&3) + 6)*dstStride + 32);
*/
#endif
if(!isColor) yHistogram[ srcBlock[0] ]++;
blockCopy(vertBlock + dstStride*2, dstStride,
vertSrcBlock + srcStride*2, srcStride, 8, mode & LEVEL_FIX);
#ifdef MORE_TIMEING
T1= rdtsc();
memcpyTime+= T1-T0;
T0=T1;
#endif
if(mode & RK_FILTER)
vertRKFilter(vertBlock, stride, QP);
else if(mode & X1_FILTER)
vertX1Filter(vertBlock, stride, QP);
else
{
if( isVertDC(vertBlock, stride))
{
if(isVertMinMaxOk(vertBlock, stride, QP))
doVertLowPass(vertBlock, stride, QP);
}
else
doVertDefFilter(vertBlock, stride, QP);
}
}
#ifdef MORE_TIMEING
T1= rdtsc();
vertTime+= T1-T0;
T0=T1;
#endif
}
else
blockCopy(vertBlock + dstStride*1, dstStride,
vertSrcBlock + srcStride*1, srcStride, 4, mode & LEVEL_FIX);
if(x - 8 >= 0 && x<width)
{
#ifdef MORE_TIMEING
T0= rdtsc();
#endif
if( isHorizDCAndCopy2Temp(dstBlock-4, stride))
{
if(isHorizMinMaxOk(tempBlock, TEMP_STRIDE, QP))
doHorizLowPassAndCopyBack(dstBlock-4, stride, QP);
}
else
doHorizDefFilterAndCopyBack(dstBlock-4, stride, QP);
}
#ifdef MORE_TIMEING
T1= rdtsc();
horizTime+= T1-T0;
T0=T1;
#endif
dering(dstBlock - 9 - stride, stride, QP);
}
else if(y!=0)
dering(dstBlock - stride*9 + width-9, stride, QP);
//FIXME dering filter will not be applied to last block (bottom right)
dstBlock+=8;
srcBlock+=8;
vertBlock+=8;
vertSrcBlock+=8;
}
}
#ifdef HAVE_3DNOW
asm volatile("femms");
#elif defined (HAVE_MMX)