1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292
|
// -*- c++ -*-
/////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2001 Tom Barry. All rights reserved.
/////////////////////////////////////////////////////////////////////////////
//
// This file is subject to the terms of the GNU General Public License as
// published by the Free Software Foundation. A copy of this license is
// included with this software distribution in the file COPYING. If you
// do not have a copy, you may obtain a copy by writing to the Free
// Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
//
// This software is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details
//
/////////////////////////////////////////////////////////////////////////////
#include "x86-64_macros.inc"
void FUNCT_NAME(TDeinterlaceInfo* pInfo)
{
int64_t i;
bool InfoIsOdd = (pInfo->PictureHistory[0]->Flags & PICTURE_INTERLACED_ODD) ? 1 : 0;
// in tight loop some vars are accessed faster in local storage
int64_t YMask = 0x00ff00ff00ff00ffull; // to keep only luma
int64_t UVMask = 0xff00ff00ff00ff00ull; // to keep only chroma
int64_t ShiftMask = 0xfefffefffefffeffull; // to avoid shifting chroma to luma
int64_t QW256 = 0x0100010001000100ull; // 4 256's
// Set up our two parms that are actually evaluated for each pixel
i=GreedyMaxComb;
int64_t MaxComb = i << 56 | i << 48 | i << 40 | i << 32 | i << 24 | i << 16 | i << 8 | i;
i = GreedyMotionThreshold; // scale to range of 0-257
int64_t MotionThreshold = i << 48 | i << 32 | i << 16 | i | UVMask;
i = GreedyMotionSense; // scale to range of 0-257
int64_t MotionSense = i << 48 | i << 32 | i << 16 | i;
int Line;
long LoopCtr;
unsigned int Pitch = pInfo->InputPitch;
unsigned char* L1; // ptr to Line1, of 3
unsigned char* L2; // ptr to Line2, the weave line
unsigned char* L3; // ptr to Line3
unsigned char* L2P; // ptr to prev Line2
unsigned char* Dest = pInfo->Overlay;
int64_t QW256B;
int64_t LastAvg=0; //interp value from left qword
i = 0xffffffff - 256;
QW256B = i << 48 | i << 32 | i << 16 | i; // save a couple instr on PMINSW instruct.
// copy first even line no matter what, and the first odd line if we're
// processing an EVEN field. (note diff from other deint rtns.)
if(InfoIsOdd) {
L1 = pInfo->PictureHistory[1]->pData;
L2 = pInfo->PictureHistory[0]->pData;
L3 = L1 + Pitch;
L2P = pInfo->PictureHistory[2]->pData;
// copy first even line
pInfo->pMemcpy(Dest, L1, pInfo->LineLength);
Dest += pInfo->OverlayPitch;
} else {
L1 = pInfo->PictureHistory[1]->pData;
L2 = pInfo->PictureHistory[0]->pData + Pitch;
L3 = L1 + Pitch;
L2P = pInfo->PictureHistory[2]->pData + Pitch;
// copy first even line
pInfo->pMemcpy(Dest, pInfo->PictureHistory[0]->pData, pInfo->LineLength);
Dest += pInfo->OverlayPitch;
// then first odd line
pInfo->pMemcpy(Dest, L1, pInfo->LineLength);
Dest += pInfo->OverlayPitch;
}
long oldbx;
for (Line = 0; Line < (pInfo->FieldHeight - 1); ++Line) {
LoopCtr = pInfo->LineLength / 8 - 1; // there are LineLength / 8 qwords per line but do 1 less, adj at end of loop
// For ease of reading, the comments below assume that we're operating on an odd
// field (i.e., that InfoIsOdd is true). Assume the obvious for even lines..
__asm__ __volatile__
(
// save ebx (-fPIC)
MOVX " %%" XBX ", %[oldbx]\n\t"
MOVX " %[L1], %%" XAX "\n\t"
LEAX " 8(%%" XAX "), %%" XBX "\n\t" // next qword needed by DJR
MOVX " %[L3], %%" XCX "\n\t"
SUBX " %%" XAX ", %%" XCX "\n\t" // carry L3 addr as an offset
MOVX " %[L2P], %%" XDX "\n\t"
MOVX " %[L2], %%" XSI "\n\t"
MOVX " %[Dest], %%" XDI "\n\t" // DL1 if Odd or DL2 if Even
".align 8\n\t"
"1:\n\t"
"movq (%%" XSI "), %%mm0\n\t" // L2 - the newest weave pixel value
"movq (%%" XAX "), %%mm1\n\t" // L1 - the top pixel
"movq (%%" XDX "), %%mm2\n\t" // L2P - the prev weave pixel
"movq (%%" XAX ", %%" XCX "), %%mm3\n\t" // L3, next odd row
"movq %%mm1, %%mm6\n\t" // L1 - get simple single pixel interp
// pavgb mm6, mm3 // use macro below
V_PAVGB ("%%mm6", "%%mm3", "%%mm4", "%[ShiftMask]")
// DJR - Diagonal Jaggie Reduction
// In the event that we are going to use an average (Bob) pixel we do not want a jagged
// stair step effect. To combat this we avg in the 2 horizontally adjacen pixels into the
// interpolated Bob mix. This will do horizontal smoothing for only the Bob'd pixels.
"movq %[LastAvg], %%mm4\n\t" // the bob value from prev qword in row
"movq %%mm6, %[LastAvg]\n\t" // save for next pass
"psrlq $48, %%mm4\n\t" // right justify 1 pixel
"movq %%mm6, %%mm7\n\t" // copy of simple bob pixel
"psllq $16, %%mm7\n\t" // left justify 3 pixels
"por %%mm7, %%mm4\n\t" // and combine
"movq (%%" XBX "), %%mm5\n\t" // next horiz qword from L1
// pavgb mm5, qword ptr[ebx+ecx] // next horiz qword from L3, use macro below
V_PAVGB ("%%mm5", "(%%" XBX ",%%" XCX ")", "%%mm7", "%[ShiftMask]")
"psllq $48, %%mm5\n\t" // left just 1 pixel
"movq %%mm6, %%mm7\n\t" // another copy of simple bob pixel
"psrlq $16, %%mm7\n\t" // right just 3 pixels
"por %%mm7, %%mm5\n\t" // combine
// pavgb mm4, mm5 // avg of forward and prev by 1 pixel, use macro
V_PAVGB ("%%mm4", "%%mm5", "%%mm5", "%[ShiftMask]") // mm5 gets modified if MMX
// pavgb mm6, mm4 // avg of center and surround interp vals, use macro
V_PAVGB ("%%mm6", "%%mm4", "%%mm7", "%[ShiftMask]")
// Don't do any more averaging than needed for mmx. It hurts performance and causes rounding errors.
#ifndef IS_MMX
// pavgb mm4, mm6 // 1/4 center, 3/4 adjacent
V_PAVGB ("%%mm4", "%%mm6", "%%mm7", "%[ShiftMask]")
// pavgb mm6, mm4 // 3/8 center, 5/8 adjacent
V_PAVGB ("%%mm6", "%%mm4", "%%mm7", "%[ShiftMask]")
#endif
// get abs value of possible L2 comb
"movq %%mm6, %%mm4\n\t" // work copy of interp val
"movq %%mm2, %%mm7\n\t" // L2
"psubusb %%mm4, %%mm7\n\t" // L2 - avg
"movq %%mm4, %%mm5\n\t" // avg
"psubusb %%mm2, %%mm5\n\t" // avg - L2
"por %%mm7, %%mm5\n\t" // abs(avg-L2)
// get abs value of possible L2P comb
"movq %%mm0, %%mm7\n\t" // L2P
"psubusb %%mm4, %%mm7\n\t" // L2P - avg
"psubusb %%mm0, %%mm4\n\t" // avg - L2P
"por %%mm7, %%mm4\n\t" // abs(avg-L2P)
// use L2 or L2P depending upon which makes smaller comb
"psubusb %%mm5, %%mm4\n\t" // see if it goes to zero
"psubusb %%mm5, %%mm5\n\t" // 0
"pcmpeqb %%mm5, %%mm4\n\t" // if (mm4=0) then FF else 0
"pcmpeqb %%mm4, %%mm5\n\t" // opposite of mm4
// if Comb(L2P) <= Comb(L2) then mm4=ff, mm5=0 else mm4=0, mm5 = 55
"pand %%mm2, %%mm5\n\t" // use L2 if mm5 == ff, else 0
"pand %%mm0, %%mm4\n\t" // use L2P if mm4 = ff, else 0
"por %%mm5, %%mm4\n\t" // may the best win
// Inventory: at this point we have the following values:
// mm0 = L2P (or L2)
// mm1 = L1
// mm2 = L2 (or L2P)
// mm3 = L3
// mm4 = the best of L2,L2P weave pixel, base upon comb
// mm6 = the avg interpolated value, if we need to use it
// Let's measure movement, as how much the weave pixel has changed
"movq %%mm2, %%mm7\n\t"
"psubusb %%mm0, %%mm2\n\t"
"psubusb %%mm7, %%mm0\n\t"
"por %%mm2, %%mm0\n\t" // abs value of change, used later
// Now lets clip our chosen value to be not outside of the range
// of the high/low range L1-L3 by more than MaxComb.
// This allows some comb but limits the damages and also allows more
// detail than a boring oversmoothed clip.
"movq %%mm1, %%mm2\n\t" // copy L1
// pmaxub mm2, mm3 // use macro
V_PMAXUB ("%%mm2", "%%mm3") // now = Max(L1,L3)
"movq %%mm1, %%mm5\n\t" // copy L1
// pminub mm5, mm3 // now = Min(L1,L3), use macro
V_PMINUB ("%%mm5", "%%mm3", "%%mm7")
// allow the value to be above the high or below the low by amt of MaxComb
"psubusb %[MaxComb], %%mm5\n\t" // lower min by diff
"paddusb %[MaxComb], %%mm2\n\t" // increase max by diff
// pmaxub mm4, mm5 // now = Max(best,Min(L1,L3) use macro
V_PMAXUB ("%%mm4", "%%mm5")
// pminub mm4, mm2 // now = Min( Max(best, Min(L1,L3), L2 )=L2 clipped
V_PMINUB ("%%mm4", "%%mm2", "%%mm7")
// Blend weave pixel with bob pixel, depending on motion val in mm0
"psubusb %[MotionThreshold], %%mm0\n\t"// test Threshold, clear chroma change >>>??
"pmullw %[MotionSense], %%mm0\n\t" // mul by user factor, keep low 16 bits
"movq %[QW256], %%mm7\n\t"
#ifdef IS_SSE
"pminsw %%mm7, %%mm0\n\t" // max = 256
#else
"paddusw %[QW256B], %%mm0\n\t" // add, may sat at fff..
"psubusw %[QW256B], %%mm0\n\t" // now = Min(L1,256)
#endif
"psubusw %%mm0, %%mm7\n\t" // so the 2 sum to 256, weighted avg
"movq %%mm4, %%mm2\n\t" // save weave chroma info before trashing
"pand %[YMask], %%mm4\n\t" // keep only luma from calc'd value
"pmullw %%mm7, %%mm4\n\t" // use more weave for less motion
"pand %[YMask], %%mm6\n\t" // keep only luma from calc'd value
"pmullw %%mm0, %%mm6\n\t" // use more bob for large motion
"paddusw %%mm6, %%mm4\n\t" // combine
"psrlw $8, %%mm4\n\t" // div by 256 to get weighted avg
// chroma comes from weave pixel
"pand %[UVMask], %%mm2\n\t" // keep chroma
"por %%mm4, %%mm2\n\t" // and combine
V_MOVNTQ ("(%%" XDI ")", "%%mm2") // move in our clipped best, use macro
// bump ptrs and loop
LEAX " 8(%%" XAX "), %%" XAX "\n\t"
LEAX " 8(%%" XBX "), %%" XBX "\n\t"
LEAX " 8(%%" XDX "), %%" XDX "\n\t"
LEAX " 8(%%" XDI "), %%" XDI "\n\t"
LEAX " 8(%%" XSI "), %%" XSI "\n\t"
DECX " %[LoopCtr]\n\t"
"jg 1b\n\t" // loop if not to last line
// note P-III default assumes backward branches taken
"jl 1f\n\t" // done
MOVX " %%" XAX ", %%" XBX "\n\t" // sharpness lookahead 1 byte only, be wrong on 1
"jmp 1b\n\t"
"1:\n\t"
MOVX " %[oldbx], %%" XBX "\n\t"
: /* no outputs */
: [LastAvg] "m"(LastAvg),
[L1] "m"(L1),
[L3] "m"(L3),
[L2P] "m"(L2P),
[L2] "m"(L2),
[Dest] "m"(Dest),
[ShiftMask] "m"(ShiftMask),
[MaxComb] "m"(MaxComb),
[MotionThreshold] "m"(MotionThreshold),
[MotionSense] "m"(MotionSense),
[QW256B] "m"(QW256B),
[YMask] "m"(YMask),
[UVMask] "m"(UVMask),
[LoopCtr] "m"(LoopCtr),
[QW256] "m"(QW256),
[oldbx] "m"(oldbx)
: XAX, XCX, XDX, XSI, XDI,
#ifdef ARCH_386
"st", "st(1)", "st(2)", "st(3)", "st(4)", "st(5)", "st(6)", "st(7)",
#endif
#ifdef __MMX__
"mm0", "mm1", "mm2", "mm3", "mm4", "mm5", "mm6", "mm7",
#endif
"memory", "cc"
);
Dest += pInfo->OverlayPitch;
pInfo->pMemcpy(Dest, L3, pInfo->LineLength);
Dest += pInfo->OverlayPitch;
L1 += Pitch;
L2 += Pitch;
L3 += Pitch;
L2P += Pitch;
}
if (InfoIsOdd) {
pInfo->pMemcpy(Dest, L2, pInfo->LineLength);
}
// clear out the MMX registers ready for doing floating point again
#ifdef ARCH_386
__asm__ __volatile__ ("emms\n\t");
#endif
}
|