Make the SATD functions return the signed DC value instead of abs(dc).
[theora.git] / lib / x86_vc / mmxencfrag.c
1 /********************************************************************\r
2  *                                                                  *\r
3  * THIS FILE IS PART OF THE OggTheora SOFTWARE CODEC SOURCE CODE.   *\r
4  * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS     *\r
5  * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *\r
6  * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING.       *\r
7  *                                                                  *\r
8  * THE Theora SOURCE CODE IS COPYRIGHT (C) 2002-2009                *\r
9  * by the Xiph.Org Foundation http://www.xiph.org/                  *\r
10  *                                                                  *\r
11  ********************************************************************\r
12 \r
13   function:\r
14   last mod: $Id: dsp_mmx.c 14579 2008-03-12 06:42:40Z xiphmont $\r
15 \r
16  ********************************************************************/\r
17 #include <stddef.h>\r
18 #include "x86enc.h"\r
19 \r
20 #if defined(OC_X86_ASM)\r
21 \r
22 unsigned oc_enc_frag_sad_mmxext(const unsigned char *_src,\r
23  const unsigned char *_ref,int _ystride){\r
24   ptrdiff_t ret;\r
25   __asm{\r
26 #define SRC esi\r
27 #define REF edx\r
28 #define YSTRIDE ecx\r
29 #define YSTRIDE3 edi\r
30     mov YSTRIDE,_ystride\r
31     mov SRC,_src\r
32     mov REF,_ref\r
33     /*Load the first 4 rows of each block.*/\r
34     movq mm0,[SRC]\r
35     movq mm1,[REF]\r
36     movq mm2,[SRC][YSTRIDE]\r
37     movq mm3,[REF][YSTRIDE]\r
38     lea YSTRIDE3,[YSTRIDE+YSTRIDE*2]\r
39     movq mm4,[SRC+YSTRIDE*2]\r
40     movq mm5,[REF+YSTRIDE*2]\r
41     movq mm6,[SRC+YSTRIDE3]\r
42     movq mm7,[REF+YSTRIDE3]\r
43     /*Compute their SADs and add them in mm0*/\r
44     psadbw mm0,mm1\r
45     psadbw mm2,mm3\r
46     lea SRC,[SRC+YSTRIDE*4]\r
47     paddw mm0,mm2\r
48     lea REF,[REF+YSTRIDE*4]\r
49     /*Load the next 3 rows as registers become available.*/\r
50     movq mm2,[SRC]\r
51     movq mm3,[REF]\r
52     psadbw mm4,mm5\r
53     psadbw mm6,mm7\r
54     paddw mm0,mm4\r
55     movq mm5,[REF+YSTRIDE]\r
56     movq mm4,[SRC+YSTRIDE]\r
57     paddw mm0,mm6\r
58     movq mm7,[REF+YSTRIDE*2]\r
59     movq mm6,[SRC+YSTRIDE*2]\r
60     /*Start adding their SADs to mm0*/\r
61     psadbw mm2,mm3\r
62     psadbw mm4,mm5\r
63     paddw mm0,mm2\r
64     psadbw mm6,mm7\r
65     /*Load last row as registers become available.*/\r
66     movq mm2,[SRC+YSTRIDE3]\r
67     movq mm3,[REF+YSTRIDE3]\r
68     /*And finish adding up their SADs.*/\r
69     paddw mm0,mm4\r
70     psadbw mm2,mm3\r
71     paddw mm0,mm6\r
72     paddw mm0,mm2\r
73     movd [ret],mm0\r
74 #undef SRC\r
75 #undef REF\r
76 #undef YSTRIDE\r
77 #undef YSTRIDE3\r
78   }\r
79   return (unsigned)ret;\r
80 }\r
81 \r
82 unsigned oc_enc_frag_sad_thresh_mmxext(const unsigned char *_src,\r
83  const unsigned char *_ref,int _ystride,unsigned _thresh){\r
84   /*Early termination is for suckers.*/\r
85   return oc_enc_frag_sad_mmxext(_src,_ref,_ystride);\r
86 }\r
87 \r
88 #define OC_SAD2_LOOP __asm{ \\r
89   /*We want to compute (mm0+mm1>>1) on unsigned bytes without overflow, but \\r
90      pavgb computes (mm0+mm1+1>>1). \\r
91    The latter is exactly 1 too large when the low bit of two corresponding \\r
92     bytes is only set in one of them. \\r
93    Therefore we pxor the operands, pand to mask out the low bits, and psubb to \\r
94     correct the output of pavgb.*/ \\r
95   __asm  movq mm6,mm0 \\r
96   __asm  lea REF1,[REF1+YSTRIDE*2] \\r
97   __asm  pxor mm0,mm1 \\r
98   __asm  pavgb mm6,mm1 \\r
99   __asm  lea REF2,[REF2+YSTRIDE*2] \\r
100   __asm  movq mm1,mm2 \\r
101   __asm  pand mm0,mm7 \\r
102   __asm  pavgb mm2,mm3 \\r
103   __asm  pxor mm1,mm3 \\r
104   __asm  movq mm3,[REF2+YSTRIDE] \\r
105   __asm  psubb mm6,mm0 \\r
106   __asm  movq mm0,[REF1] \\r
107   __asm  pand mm1,mm7 \\r
108   __asm  psadbw mm4,mm6 \\r
109   __asm  movd mm6,RET \\r
110   __asm  psubb mm2,mm1 \\r
111   __asm  movq mm1,[REF2] \\r
112   __asm  lea SRC,[SRC+YSTRIDE*2] \\r
113   __asm  psadbw mm5,mm2 \\r
114   __asm  movq mm2,[REF1+YSTRIDE] \\r
115   __asm  paddw mm5,mm4 \\r
116   __asm  movq mm4,[SRC] \\r
117   __asm  paddw mm6,mm5 \\r
118   __asm  movq mm5,[SRC+YSTRIDE] \\r
119   __asm  movd RET,mm6 \\r
120 }\r
121 \r
122 /*Same as above, but does not pre-load the next two rows.*/\r
123 #define OC_SAD2_TAIL __asm{ \\r
124   __asm  movq mm6,mm0 \\r
125   __asm  pavgb mm0,mm1 \\r
126   __asm  pxor mm6,mm1 \\r
127   __asm  movq mm1,mm2 \\r
128   __asm  pand mm6,mm7 \\r
129   __asm  pavgb mm2,mm3 \\r
130   __asm  pxor mm1,mm3 \\r
131   __asm  psubb mm0,mm6 \\r
132   __asm  pand mm1,mm7 \\r
133   __asm  psadbw mm4,mm0 \\r
134   __asm  psubb mm2,mm1 \\r
135   __asm  movd mm6,RET \\r
136   __asm  psadbw mm5,mm2 \\r
137   __asm  paddw mm5,mm4 \\r
138   __asm  paddw mm6,mm5 \\r
139   __asm  movd RET,mm6 \\r
140 }\r
141 \r
142 unsigned oc_enc_frag_sad2_thresh_mmxext(const unsigned char *_src,\r
143  const unsigned char *_ref1,const unsigned char *_ref2,int _ystride,\r
144  unsigned _thresh){\r
145   ptrdiff_t ret;\r
146   __asm{\r
147 #define REF1 ecx\r
148 #define REF2 edi\r
149 #define YSTRIDE esi\r
150 #define SRC edx\r
151 #define RET eax\r
152     mov YSTRIDE,_ystride\r
153     mov SRC,_src\r
154     mov REF1,_ref1\r
155     mov REF2,_ref2\r
156     movq mm0,[REF1]\r
157     movq mm1,[REF2]\r
158     movq mm2,[REF1+YSTRIDE]\r
159     movq mm3,[REF2+YSTRIDE]\r
160     xor RET,RET\r
161     movq mm4,[SRC]\r
162     pxor mm7,mm7\r
163     pcmpeqb mm6,mm6\r
164     movq mm5,[SRC+YSTRIDE]\r
165     psubb mm7,mm6\r
166     OC_SAD2_LOOP\r
167     OC_SAD2_LOOP\r
168     OC_SAD2_LOOP\r
169     OC_SAD2_TAIL\r
170     mov [ret],RET\r
171 #undef REF1\r
172 #undef REF2\r
173 #undef YSTRIDE\r
174 #undef SRC\r
175 #undef RET\r
176   }\r
177   return (unsigned)ret;\r
178 }\r
179 \r
180 /*Load an 8x4 array of pixel values from %[src] and %[ref] and compute their\r
181   16-bit difference in mm0...mm7.*/\r
182 #define OC_LOAD_SUB_8x4(_off) __asm{ \\r
183   __asm  movd mm0,[_off+SRC] \\r
184   __asm  movd mm4,[_off+REF] \\r
185   __asm  movd mm1,[_off+SRC+SRC_YSTRIDE] \\r
186   __asm  lea SRC,[SRC+SRC_YSTRIDE*2] \\r
187   __asm  movd mm5,[_off+REF+REF_YSTRIDE] \\r
188   __asm  lea REF,[REF+REF_YSTRIDE*2] \\r
189   __asm  movd mm2,[_off+SRC] \\r
190   __asm  movd mm7,[_off+REF] \\r
191   __asm  movd mm3,[_off+SRC+SRC_YSTRIDE] \\r
192   __asm  movd mm6,[_off+REF+REF_YSTRIDE] \\r
193   __asm  punpcklbw mm0,mm4 \\r
194   __asm  lea SRC,[SRC+SRC_YSTRIDE*2] \\r
195   __asm  punpcklbw mm4,mm4 \\r
196   __asm  lea REF,[REF+REF_YSTRIDE*2] \\r
197   __asm  psubw mm0,mm4 \\r
198   __asm  movd mm4,[_off+SRC] \\r
199   __asm  movq [_off*2+BUF],mm0 \\r
200   __asm  movd mm0,[_off+REF] \\r
201   __asm  punpcklbw mm1,mm5 \\r
202   __asm  punpcklbw mm5,mm5 \\r
203   __asm  psubw mm1,mm5 \\r
204   __asm  movd mm5,[_off+SRC+SRC_YSTRIDE] \\r
205   __asm  punpcklbw mm2,mm7 \\r
206   __asm  punpcklbw mm7,mm7 \\r
207   __asm  psubw mm2,mm7 \\r
208   __asm  movd mm7,[_off+REF+REF_YSTRIDE] \\r
209   __asm  punpcklbw mm3,mm6 \\r
210   __asm  lea SRC,[SRC+SRC_YSTRIDE*2] \\r
211   __asm  punpcklbw mm6,mm6 \\r
212   __asm  psubw mm3,mm6 \\r
213   __asm  movd mm6,[_off+SRC] \\r
214   __asm  punpcklbw mm4,mm0 \\r
215   __asm  lea REF,[REF+REF_YSTRIDE*2] \\r
216   __asm  punpcklbw mm0,mm0 \\r
217   __asm  lea SRC,[SRC+SRC_YSTRIDE*2] \\r
218   __asm  psubw mm4,mm0 \\r
219   __asm  movd mm0,[_off+REF] \\r
220   __asm  punpcklbw mm5,mm7 \\r
221   __asm  neg SRC_YSTRIDE \\r
222   __asm  punpcklbw mm7,mm7 \\r
223   __asm  psubw mm5,mm7 \\r
224   __asm  movd mm7,[_off+SRC+SRC_YSTRIDE] \\r
225   __asm  punpcklbw mm6,mm0 \\r
226   __asm  lea REF,[REF+REF_YSTRIDE*2] \\r
227   __asm  punpcklbw mm0,mm0 \\r
228   __asm  neg REF_YSTRIDE \\r
229   __asm  psubw mm6,mm0 \\r
230   __asm  movd mm0,[_off+REF+REF_YSTRIDE] \\r
231   __asm  lea SRC,[SRC+SRC_YSTRIDE*8] \\r
232   __asm  punpcklbw mm7,mm0 \\r
233   __asm  neg SRC_YSTRIDE \\r
234   __asm  punpcklbw mm0,mm0 \\r
235   __asm  lea REF,[REF+REF_YSTRIDE*8] \\r
236   __asm  psubw mm7,mm0 \\r
237   __asm  neg REF_YSTRIDE \\r
238   __asm  movq mm0,[_off*2+BUF] \\r
239 }\r
240 \r
241 /*Load an 8x4 array of pixel values from %[src] into %%mm0...%%mm7.*/\r
242 #define OC_LOAD_8x4(_off) __asm{ \\r
243   __asm  movd mm0,[_off+SRC] \\r
244   __asm  movd mm1,[_off+SRC+YSTRIDE] \\r
245   __asm  movd mm2,[_off+SRC+YSTRIDE*2] \\r
246   __asm  pxor mm7,mm7 \\r
247   __asm  movd mm3,[_off+SRC+YSTRIDE3] \\r
248   __asm  punpcklbw mm0,mm7 \\r
249   __asm  movd mm4,[_off+SRC4] \\r
250   __asm  punpcklbw mm1,mm7 \\r
251   __asm  movd mm5,[_off+SRC4+YSTRIDE] \\r
252   __asm  punpcklbw mm2,mm7 \\r
253   __asm  movd mm6,[_off+SRC4+YSTRIDE*2] \\r
254   __asm  punpcklbw mm3,mm7 \\r
255   __asm  movd mm7,[_off+SRC4+YSTRIDE3] \\r
256   __asm  punpcklbw mm4,mm4 \\r
257   __asm  punpcklbw mm5,mm5 \\r
258   __asm  psrlw mm4,8 \\r
259   __asm  psrlw mm5,8 \\r
260   __asm  punpcklbw mm6,mm6 \\r
261   __asm  punpcklbw mm7,mm7 \\r
262   __asm  psrlw mm6,8 \\r
263   __asm  psrlw mm7,8 \\r
264 }\r
265 \r
266 /*Performs the first two stages of an 8-point 1-D Hadamard transform.\r
267   The transform is performed in place, except that outputs 0-3 are swapped with\r
268    outputs 4-7.\r
269   Outputs 2, 3, 6, and 7 from the second stage are negated (which allows us to\r
270    perform this stage in place with no temporary registers).*/\r
271 #define OC_HADAMARD_AB_8x4 __asm{ \\r
272   /*Stage A: \\r
273     Outputs 0-3 are swapped with 4-7 here.*/ \\r
274   __asm  paddw mm5,mm1 \\r
275   __asm  paddw mm6,mm2 \\r
276   __asm  paddw mm1,mm1 \\r
277   __asm  paddw mm2,mm2 \\r
278   __asm  psubw mm1,mm5 \\r
279   __asm  psubw mm2,mm6 \\r
280   __asm  paddw mm7,mm3 \\r
281   __asm  paddw mm4,mm0 \\r
282   __asm  paddw mm3,mm3 \\r
283   __asm  paddw mm0,mm0 \\r
284   __asm  psubw mm3,mm7 \\r
285   __asm  psubw mm0,mm4 \\r
286    /*Stage B:*/ \\r
287   __asm  paddw mm0,mm2 \\r
288   __asm  paddw mm1,mm3 \\r
289   __asm  paddw mm4,mm6 \\r
290   __asm  paddw mm5,mm7 \\r
291   __asm  paddw mm2,mm2 \\r
292   __asm  paddw mm3,mm3 \\r
293   __asm  paddw mm6,mm6 \\r
294   __asm  paddw mm7,mm7 \\r
295   __asm  psubw mm2,mm0 \\r
296   __asm  psubw mm3,mm1 \\r
297   __asm  psubw mm6,mm4 \\r
298   __asm  psubw mm7,mm5 \\r
299 }\r
300 \r
301 /*Performs the last stage of an 8-point 1-D Hadamard transform in place.\r
302   Outputs 1, 3, 5, and 7 are negated (which allows us to perform this stage in\r
303    place with no temporary registers).*/\r
304 #define OC_HADAMARD_C_8x4 __asm{ \\r
305   /*Stage C:*/ \\r
306   __asm  paddw mm0,mm1 \\r
307   __asm  paddw mm2,mm3 \\r
308   __asm  paddw mm4,mm5 \\r
309   __asm  paddw mm6,mm7 \\r
310   __asm  paddw mm1,mm1 \\r
311   __asm  paddw mm3,mm3 \\r
312   __asm  paddw mm5,mm5 \\r
313   __asm  paddw mm7,mm7 \\r
314   __asm  psubw mm1,mm0 \\r
315   __asm  psubw mm3,mm2 \\r
316   __asm  psubw mm5,mm4 \\r
317   __asm  psubw mm7,mm6 \\r
318 }\r
319 \r
320 /*Performs an 8-point 1-D Hadamard transform.\r
321   The transform is performed in place, except that outputs 0-3 are swapped with\r
322    outputs 4-7.\r
323   Outputs 1, 2, 5 and 6 are negated (which allows us to perform the transform\r
324    in place with no temporary registers).*/\r
325 #define OC_HADAMARD_8x4 __asm{ \\r
326   OC_HADAMARD_AB_8x4 \\r
327   OC_HADAMARD_C_8x4 \\r
328 }\r
329 \r
330 /*Performs the first part of the final stage of the Hadamard transform and\r
331    summing of absolute values.\r
332   At the end of this part, mm1 will contain the DC coefficient of the\r
333    transform.*/\r
334 #define OC_HADAMARD_C_ABS_ACCUM_A_8x4(_r6,_r7) __asm{ \\r
335   /*We use the fact that \\r
336       (abs(a+b)+abs(a-b))/2=max(abs(a),abs(b)) \\r
337      to merge the final butterfly with the abs and the first stage of \\r
338      accumulation. \\r
339     Thus we can avoid using pabsw, which is not available until SSSE3. \\r
340     Emulating pabsw takes 3 instructions, so the straightforward MMXEXT \\r
341      implementation would be (3+3)*8+7=55 instructions (+4 for spilling \\r
342      registers). \\r
343     Even with pabsw, it would be (3+1)*8+7=39 instructions (with no spills). \\r
344     This implementation is only 26 (+4 for spilling registers).*/ \\r
345   __asm  movq [_r7+BUF],mm7 \\r
346   __asm  movq [_r6+BUF],mm6 \\r
347   /*mm7={0x7FFF}x4 \\r
348     mm0=max(abs(mm0),abs(mm1))-0x7FFF*/ \\r
349   __asm  pcmpeqb mm7,mm7 \\r
350   __asm  movq mm6,mm0 \\r
351   __asm  psrlw mm7,1 \\r
352   __asm  paddw mm6,mm1 \\r
353   __asm  pmaxsw mm0,mm1 \\r
354   __asm  paddsw mm6,mm7 \\r
355   __asm  psubw mm0,mm6 \\r
356   /*mm2=max(abs(mm2),abs(mm3))-0x7FFF \\r
357     mm4=max(abs(mm4),abs(mm5))-0x7FFF*/ \\r
358   __asm  movq mm6,mm2 \\r
359   __asm  movq mm1,mm4 \\r
360   __asm  pmaxsw mm2,mm3 \\r
361   __asm  pmaxsw mm4,mm5 \\r
362   __asm  paddw mm6,mm3 \\r
363   __asm  paddw mm1,mm5 \\r
364   __asm  movq mm3,[_r7+BUF] \\r
365 }\r
366 \r
367 /*Performs the second part of the final stage of the Hadamard transform and\r
368    summing of absolute values.*/\r
369 #define OC_HADAMARD_C_ABS_ACCUM_B_8x4(_r6,_r7) __asm{ \\r
370   __asm  paddsw mm6,mm7 \\r
371   __asm  movq mm5,[_r6+BUF] \\r
372   __asm  paddsw mm1,mm7 \\r
373   __asm  psubw mm2,mm6 \\r
374   __asm  psubw mm4,mm1 \\r
375   /*mm7={1}x4 (needed for the horizontal add that follows) \\r
376     mm0+=mm2+mm4+max(abs(mm3),abs(mm5))-0x7FFF*/ \\r
377   __asm  movq mm6,mm3 \\r
378   __asm  pmaxsw mm3,mm5 \\r
379   __asm  paddw mm0,mm2 \\r
380   __asm  paddw mm6,mm5 \\r
381   __asm  paddw mm0,mm4 \\r
382   __asm  paddsw mm6,mm7 \\r
383   __asm  paddw mm0,mm3 \\r
384   __asm  psrlw mm7,14 \\r
385   __asm  psubw mm0,mm6 \\r
386 }\r
387 \r
388 /*Performs the last stage of an 8-point 1-D Hadamard transform, takes the\r
389    absolute value of each component, and accumulates everything into mm0.\r
390   This is the only portion of SATD which requires MMXEXT (we could use plain\r
391    MMX, but it takes 4 instructions and an extra register to work around the\r
392    lack of a pmaxsw, which is a pretty serious penalty).*/\r
393 #define OC_HADAMARD_C_ABS_ACCUM_8x4(_r6,_r7) __asm{ \\r
394   OC_HADAMARD_C_ABS_ACCUM_A_8x4(_r6,_r7) \\r
395   OC_HADAMARD_C_ABS_ACCUM_B_8x4(_r6,_r7) \\r
396 }\r
397 \r
398 /*Performs an 8-point 1-D Hadamard transform, takes the absolute value of each\r
399    component, and accumulates everything into mm0.\r
400   Note that mm0 will have an extra 4 added to each column, and that after\r
401    removing this value, the remainder will be half the conventional value.*/\r
402 #define OC_HADAMARD_ABS_ACCUM_8x4(_r6,_r7) __asm{ \\r
403   OC_HADAMARD_AB_8x4 \\r
404   OC_HADAMARD_C_ABS_ACCUM_8x4(_r6,_r7) \\r
405 }\r
406 \r
407 /*Performs two 4x4 transposes (mostly) in place.\r
408   On input, {mm0,mm1,mm2,mm3} contains rows {e,f,g,h}, and {mm4,mm5,mm6,mm7}\r
409    contains rows {a,b,c,d}.\r
410   On output, {0x40,0x50,0x60,0x70}+_off+BUF contains {e,f,g,h}^T, and\r
411    {mm4,mm5,mm6,mm7} contains the transposed rows {a,b,c,d}^T.*/\r
412 #define OC_TRANSPOSE_4x4x2(_off) __asm{ \\r
413   /*First 4x4 transpose:*/ \\r
414   __asm  movq [0x10+_off+BUF],mm5 \\r
415   /*mm0 = e3 e2 e1 e0 \\r
416     mm1 = f3 f2 f1 f0 \\r
417     mm2 = g3 g2 g1 g0 \\r
418     mm3 = h3 h2 h1 h0*/ \\r
419   __asm  movq mm5,mm2 \\r
420   __asm  punpcklwd mm2,mm3 \\r
421   __asm  punpckhwd mm5,mm3 \\r
422   __asm  movq mm3,mm0 \\r
423   __asm  punpcklwd mm0,mm1 \\r
424   __asm  punpckhwd mm3,mm1 \\r
425   /*mm0 = f1 e1 f0 e0 \\r
426     mm3 = f3 e3 f2 e2 \\r
427     mm2 = h1 g1 h0 g0 \\r
428     mm5 = h3 g3 h2 g2*/ \\r
429   __asm  movq mm1,mm0 \\r
430   __asm  punpckldq mm0,mm2 \\r
431   __asm  punpckhdq mm1,mm2 \\r
432   __asm  movq mm2,mm3 \\r
433   __asm  punpckhdq mm3,mm5 \\r
434   __asm  movq [0x40+_off+BUF],mm0 \\r
435   __asm  punpckldq mm2,mm5 \\r
436   /*mm0 = h0 g0 f0 e0 \\r
437     mm1 = h1 g1 f1 e1 \\r
438     mm2 = h2 g2 f2 e2 \\r
439     mm3 = h3 g3 f3 e3*/ \\r
440   __asm  movq mm5,[0x10+_off+BUF] \\r
441   /*Second 4x4 transpose:*/ \\r
442   /*mm4 = a3 a2 a1 a0 \\r
443     mm5 = b3 b2 b1 b0 \\r
444     mm6 = c3 c2 c1 c0 \\r
445     mm7 = d3 d2 d1 d0*/ \\r
446   __asm  movq mm0,mm6 \\r
447   __asm  punpcklwd mm6,mm7 \\r
448   __asm  movq [0x50+_off+BUF],mm1 \\r
449   __asm  punpckhwd mm0,mm7 \\r
450   __asm  movq mm7,mm4 \\r
451   __asm  punpcklwd mm4,mm5 \\r
452   __asm  movq [0x60+_off+BUF],mm2 \\r
453   __asm  punpckhwd mm7,mm5 \\r
454   /*mm4 = b1 a1 b0 a0 \\r
455     mm7 = b3 a3 b2 a2 \\r
456     mm6 = d1 c1 d0 c0 \\r
457     mm0 = d3 c3 d2 c2*/ \\r
458   __asm  movq mm5,mm4 \\r
459   __asm  punpckldq mm4,mm6 \\r
460   __asm  movq [0x70+_off+BUF],mm3 \\r
461   __asm  punpckhdq mm5,mm6 \\r
462   __asm  movq mm6,mm7 \\r
463   __asm  punpckhdq mm7,mm0 \\r
464   __asm  punpckldq mm6,mm0 \\r
465   /*mm4 = d0 c0 b0 a0 \\r
466     mm5 = d1 c1 b1 a1 \\r
467     mm6 = d2 c2 b2 a2 \\r
468     mm7 = d3 c3 b3 a3*/ \\r
469 }\r
470 \r
471 static unsigned oc_int_frag_satd_mmxext(int *_dc,\r
472  const unsigned char *_src,int _src_ystride,\r
473  const unsigned char *_ref,int _ref_ystride){\r
474   OC_ALIGN8(ogg_int16_t buf[64]);\r
475   ogg_int16_t *bufp;\r
476   unsigned     ret;\r
477   unsigned     ret2;\r
478   int          dc;\r
479   bufp=buf;\r
480   __asm{\r
481 #define SRC esi\r
482 #define REF eax\r
483 #define SRC_YSTRIDE ecx\r
484 #define REF_YSTRIDE edx\r
485 #define BUF edi\r
486 #define RET edx\r
487 #define RET2 ecx\r
488 #define DC eax\r
489 #define DC_WORD ax\r
490     mov SRC,_src\r
491     mov SRC_YSTRIDE,_src_ystride\r
492     mov REF,_ref\r
493     mov REF_YSTRIDE,_ref_ystride\r
494     mov BUF,bufp\r
495     OC_LOAD_SUB_8x4(0x00)\r
496     OC_HADAMARD_8x4\r
497     OC_TRANSPOSE_4x4x2(0x00)\r
498     /*Finish swapping out this 8x4 block to make room for the next one.\r
499       mm0...mm3 have been swapped out already.*/\r
500     movq [0x00+BUF],mm4\r
501     movq [0x10+BUF],mm5\r
502     movq [0x20+BUF],mm6\r
503     movq [0x30+BUF],mm7\r
504     OC_LOAD_SUB_8x4(0x04)\r
505     OC_HADAMARD_8x4\r
506     OC_TRANSPOSE_4x4x2(0x08)\r
507     /*Here the first 4x4 block of output from the last transpose is the second\r
508        4x4 block of input for the next transform.\r
509       We have cleverly arranged that it already be in the appropriate place, so\r
510        we only have to do half the loads.*/\r
511     movq mm1,[0x10+BUF]\r
512     movq mm2,[0x20+BUF]\r
513     movq mm3,[0x30+BUF]\r
514     movq mm0,[0x00+BUF]\r
515     /*We split out the stages here so we can save the DC coefficient in the\r
516        middle.*/\r
517     OC_HADAMARD_AB_8x4\r
518     OC_HADAMARD_C_ABS_ACCUM_A_8x4(0x28,0x38)\r
519     movd DC,mm1\r
520     OC_HADAMARD_C_ABS_ACCUM_B_8x4(0x28,0x38)\r
521     /*Up to this point, everything fit in 16 bits (8 input + 1 for the\r
522        difference + 2*3 for the two 8-point 1-D Hadamards - 1 for the abs - 1\r
523        for the factor of two we dropped + 3 for the vertical accumulation).\r
524       Now we finally have to promote things to dwords.\r
525       We break this part out of OC_HADAMARD_ABS_ACCUM_8x4 to hide the long\r
526        latency of pmaddwd by starting the next series of loads now.*/\r
527     pmaddwd mm0,mm7\r
528     movq mm1,[0x50+BUF]\r
529     movq mm5,[0x58+BUF]\r
530     movq mm4,mm0\r
531     movq mm2,[0x60+BUF]\r
532     punpckhdq mm0,mm0\r
533     movq mm6,[0x68+BUF]\r
534     paddd mm4,mm0\r
535     movq mm3,[0x70+BUF]\r
536     movd RET2,mm4\r
537     movq mm7,[0x78+BUF]\r
538     movq mm0,[0x40+BUF]\r
539     movq mm4,[0x48+BUF]\r
540     OC_HADAMARD_ABS_ACCUM_8x4(0x68,0x78)\r
541     pmaddwd mm0,mm7\r
542     /*Subtract abs(dc) from 2*ret2.*/\r
543     movsx DC,DC_WORD\r
544     cdq\r
545     lea RET2,[RET+RET2*2]\r
546     movq mm4,mm0\r
547     punpckhdq mm0,mm0\r
548     xor RET,DC\r
549     paddd mm4,mm0\r
550     /*The sums produced by OC_HADAMARD_ABS_ACCUM_8x4 each have an extra 4\r
551        added to them, a factor of two removed, and the DC value included;\r
552        correct the final sum here.*/\r
553     sub RET2,RET\r
554     movd RET,mm4\r
555     lea RET,[RET2+RET*2-64]\r
556     mov ret,RET\r
557     mov dc,DC\r
558 #undef SRC\r
559 #undef REF\r
560 #undef SRC_YSTRIDE\r
561 #undef REF_YSTRIDE\r
562 #undef BUF\r
563 #undef RET\r
564 #undef RET2\r
565 #undef DC\r
566 #undef DC_WORD\r
567   }\r
568   *_dc=dc;\r
569   return ret;\r
570 }\r
571 \r
572 unsigned oc_enc_frag_satd_mmxext(int *_dc,const unsigned char *_src,\r
573  const unsigned char *_ref,int _ystride){\r
574   return oc_int_frag_satd_mmxext(_dc,_src,_ystride,_ref,_ystride);\r
575 }\r
576 \r
577 \r
578 /*Our internal implementation of frag_copy2 takes an extra stride parameter so\r
579    we can share code with oc_enc_frag_satd2_mmxext().*/\r
580 static void oc_int_frag_copy2_mmxext(unsigned char *_dst,int _dst_ystride,\r
581  const unsigned char *_src1,const unsigned char *_src2,int _src_ystride){\r
582   __asm{\r
583     /*Load the first 3 rows.*/\r
584 #define DST_YSTRIDE edi\r
585 #define SRC_YSTRIDE esi\r
586 #define DST eax\r
587 #define SRC1 edx\r
588 #define SRC2 ecx\r
589     mov DST_YSTRIDE,_dst_ystride\r
590     mov SRC_YSTRIDE,_src_ystride\r
591     mov DST,_dst\r
592     mov SRC1,_src1\r
593     mov SRC2,_src2\r
594     movq mm0,[SRC1]\r
595     movq mm1,[SRC2]\r
596     movq mm2,[SRC1+SRC_YSTRIDE]\r
597     lea SRC1,[SRC1+SRC_YSTRIDE*2]\r
598     movq mm3,[SRC2+SRC_YSTRIDE]\r
599     lea SRC2,[SRC2+SRC_YSTRIDE*2]\r
600     pxor mm7,mm7\r
601     movq mm4,[SRC1]\r
602     pcmpeqb mm6,mm6\r
603     movq mm5,[SRC2]\r
604     /*mm7={1}x8.*/\r
605     psubb mm7,mm6\r
606     /*Start averaging mm0 and mm1 into mm6.*/\r
607     movq mm6,mm0\r
608     pxor mm0,mm1\r
609     pavgb mm6,mm1\r
610     /*mm1 is free, start averaging mm3 into mm2 using mm1.*/\r
611     movq mm1,mm2\r
612     pand mm0,mm7\r
613     pavgb mm2,mm3\r
614     pxor mm1,mm3\r
615     /*mm3 is free.*/\r
616     psubb mm6,mm0\r
617     /*mm0 is free, start loading the next row.*/\r
618     movq mm0,[SRC1+SRC_YSTRIDE]\r
619     /*Start averaging mm5 and mm4 using mm3.*/\r
620     movq mm3,mm4\r
621     /*mm6 [row 0] is done; write it out.*/\r
622     movq [DST],mm6\r
623     pand mm1,mm7\r
624     pavgb mm4,mm5\r
625     psubb mm2,mm1\r
626     /*mm1 is free, continue loading the next row.*/\r
627     movq mm1,[SRC2+SRC_YSTRIDE]\r
628     pxor mm3,mm5\r
629     lea SRC1,[SRC1+SRC_YSTRIDE*2]\r
630     /*mm2 [row 1] is done; write it out.*/\r
631     movq [DST+DST_YSTRIDE],mm2\r
632     pand mm3,mm7\r
633     /*Start loading the next row.*/\r
634     movq mm2,[SRC1]\r
635     lea DST,[DST+DST_YSTRIDE*2]\r
636     psubb mm4,mm3\r
637     lea SRC2,[SRC2+SRC_YSTRIDE*2]\r
638     /*mm4 [row 2] is done; write it out.*/\r
639     movq [DST],mm4\r
640     /*Continue loading the next row.*/\r
641     movq mm3,[SRC2]\r
642     /*Start averaging mm0 and mm1 into mm6.*/\r
643     movq mm6,mm0\r
644     pxor mm0,mm1\r
645     /*Start loading the next row.*/\r
646     movq mm4,[SRC1+SRC_YSTRIDE]\r
647     pavgb mm6,mm1\r
648     /*mm1 is free; start averaging mm3 into mm2 using mm1.*/\r
649     movq mm1,mm2\r
650     pand mm0,mm7\r
651     /*Continue loading the next row.*/\r
652     movq mm5,[SRC2+SRC_YSTRIDE]\r
653     pavgb mm2,mm3\r
654     lea SRC1,[SRC1+SRC_YSTRIDE*2]\r
655     pxor mm1,mm3\r
656     /*mm3 is free.*/\r
657     psubb mm6,mm0\r
658     /*mm0 is free, start loading the next row.*/\r
659     movq mm0,[SRC1]\r
660     /*Start averaging mm5 into mm4 using mm3.*/\r
661     movq mm3,mm4\r
662     /*mm6 [row 3] is done; write it out.*/\r
663     movq [DST+DST_YSTRIDE],mm6\r
664     pand mm1,mm7\r
665     lea SRC2,[SRC2+SRC_YSTRIDE*2]\r
666     pavgb mm4,mm5\r
667     lea DST,[DST+DST_YSTRIDE*2]\r
668     psubb mm2,mm1\r
669     /*mm1 is free; continue loading the next row.*/\r
670     movq mm1,[SRC2]\r
671     pxor mm3,mm5\r
672     /*mm2 [row 4] is done; write it out.*/\r
673     movq [DST],mm2\r
674     pand mm3,mm7\r
675     /*Start loading the next row.*/\r
676     movq mm2,[SRC1+SRC_YSTRIDE]\r
677     psubb mm4,mm3\r
678     /*Start averaging mm0 and mm1 into mm6.*/\r
679     movq mm6,mm0\r
680     /*Continue loading the next row.*/\r
681     movq mm3,[SRC2+SRC_YSTRIDE]\r
682     /*mm4 [row 5] is done; write it out.*/\r
683     movq [DST+DST_YSTRIDE],mm4\r
684     pxor mm0,mm1\r
685     pavgb mm6,mm1\r
686     /*mm4 is free; start averaging mm3 into mm2 using mm4.*/\r
687     movq mm4,mm2\r
688     pand mm0,mm7\r
689     pavgb mm2,mm3\r
690     pxor mm4,mm3\r
691     lea DST,[DST+DST_YSTRIDE*2]\r
692     psubb mm6,mm0\r
693     pand mm4,mm7\r
694     /*mm6 [row 6] is done, write it out.*/\r
695     movq [DST],mm6\r
696     psubb mm2,mm4\r
697     /*mm2 [row 7] is done, write it out.*/\r
698     movq [DST+DST_YSTRIDE],mm2\r
699 #undef SRC1\r
700 #undef SRC2\r
701 #undef SRC_YSTRIDE\r
702 #undef DST_YSTRIDE\r
703 #undef DST\r
704   }\r
705 }\r
706 \r
707 unsigned oc_enc_frag_satd2_mmxext(int *_dc,const unsigned char *_src,\r
708  const unsigned char *_ref1,const unsigned char *_ref2,int _ystride){\r
709   OC_ALIGN8(unsigned char ref[64]);\r
710   oc_int_frag_copy2_mmxext(ref,8,_ref1,_ref2,_ystride);\r
711   return oc_int_frag_satd_mmxext(_dc,_src,_ystride,ref,8);\r
712 }\r
713 \r
714 unsigned oc_enc_frag_intra_satd_mmxext(int *_dc,const unsigned char *_src,\r
715  int _ystride){\r
716   OC_ALIGN8(ogg_int16_t buf[64]);\r
717   ogg_int16_t *bufp;\r
718   unsigned     ret1;\r
719   unsigned     ret2;\r
720   int          dc;\r
721   bufp=buf;\r
722   __asm{\r
723 #define SRC eax\r
724 #define SRC4 esi\r
725 #define BUF edi\r
726 #define YSTRIDE edx\r
727 #define YSTRIDE3 ecx\r
728 #define RET eax\r
729 #define RET2 ecx\r
730 #define DC edx\r
731 #define DC_WORD dx\r
732     mov SRC,_src\r
733     mov BUF,bufp\r
734     mov YSTRIDE,_ystride\r
735     /* src4 = src+4*ystride */\r
736     lea SRC4,[SRC+YSTRIDE*4]\r
737     /* ystride3 = 3*ystride */\r
738     lea YSTRIDE3,[YSTRIDE+YSTRIDE*2]\r
739     OC_LOAD_8x4(0x00)\r
740     OC_HADAMARD_8x4\r
741     OC_TRANSPOSE_4x4x2(0x00)\r
742     /*Finish swapping out this 8x4 block to make room for the next one.\r
743       mm0...mm3 have been swapped out already.*/\r
744     movq [0x00+BUF],mm4\r
745     movq [0x10+BUF],mm5\r
746     movq [0x20+BUF],mm6\r
747     movq [0x30+BUF],mm7\r
748     OC_LOAD_8x4(0x04)\r
749     OC_HADAMARD_8x4\r
750     OC_TRANSPOSE_4x4x2(0x08)\r
751     /*Here the first 4x4 block of output from the last transpose is the second\r
752       4x4 block of input for the next transform.\r
753       We have cleverly arranged that it already be in the appropriate place, so\r
754       we only have to do half the loads.*/\r
755     movq mm1,[0x10+BUF]\r
756     movq mm2,[0x20+BUF]\r
757     movq mm3,[0x30+BUF]\r
758     movq mm0,[0x00+BUF]\r
759     /*We split out the stages here so we can save the DC coefficient in the\r
760       middle.*/\r
761     OC_HADAMARD_AB_8x4\r
762     OC_HADAMARD_C_ABS_ACCUM_A_8x4(0x28,0x38)\r
763     movd DC,mm1\r
764     OC_HADAMARD_C_ABS_ACCUM_B_8x4(0x28,0x38)\r
765     /*Up to this point, everything fit in 16 bits (8 input + 1 for the\r
766       difference + 2*3 for the two 8-point 1-D Hadamards - 1 for the abs - 1\r
767       for the factor of two we dropped + 3 for the vertical accumulation).\r
768       Now we finally have to promote things to dwords.\r
769       We break this part out of OC_HADAMARD_ABS_ACCUM_8x4 to hide the long\r
770       latency of pmaddwd by starting the next series of loads now.*/\r
771     pmaddwd mm0,mm7\r
772     movq mm1,[0x50+BUF]\r
773     movq mm5,[0x58+BUF]\r
774     movq mm2,[0x60+BUF]\r
775     movq mm4,mm0\r
776     movq mm6,[0x68+BUF]\r
777     punpckhdq mm0,mm0\r
778     movq mm3,[0x70+BUF]\r
779     paddd mm4,mm0\r
780     movq mm7,[0x78+BUF]\r
781     movd RET,mm4\r
782     movq mm0,[0x40+BUF]\r
783     movq mm4,[0x48+BUF]\r
784     OC_HADAMARD_ABS_ACCUM_8x4(0x68,0x78)\r
785     pmaddwd mm0,mm7\r
786     /*We assume that the DC coefficient is always positive (which is true,\r
787     because the input to the INTRA transform was not a difference).*/\r
788     movzx DC,DC_WORD\r
789     add RET,RET\r
790     sub RET,DC\r
791     movq mm4,mm0\r
792     punpckhdq mm0,mm0\r
793     paddd mm4,mm0\r
794     movd RET2,mm4\r
795     lea RET,[-64+RET+RET2*2]\r
796     mov [dc],DC\r
797     mov [ret1],RET\r
798 #undef SRC\r
799 #undef SRC4\r
800 #undef BUF\r
801 #undef YSTRIDE\r
802 #undef YSTRIDE3\r
803 #undef RET\r
804 #undef RET2\r
805 #undef DC\r
806 #undef DC_WORD\r
807   }\r
808   *_dc=dc;\r
809   return ret1;\r
810 }\r
811 \r
812 void oc_enc_frag_sub_mmx(ogg_int16_t _residue[64],\r
813  const unsigned char *_src, const unsigned char *_ref,int _ystride){\r
814   int i;\r
815   __asm  pxor mm7,mm7\r
816   for(i=4;i-->0;){\r
817     __asm{\r
818 #define SRC edx\r
819 #define YSTRIDE esi\r
820 #define RESIDUE eax\r
821 #define REF ecx\r
822       mov YSTRIDE,_ystride\r
823       mov RESIDUE,_residue\r
824       mov SRC,_src\r
825       mov REF,_ref\r
826       /*mm0=[src]*/\r
827       movq mm0,[SRC]\r
828       /*mm1=[ref]*/\r
829       movq mm1,[REF]\r
830       /*mm4=[src+ystride]*/\r
831       movq mm4,[SRC+YSTRIDE]\r
832       /*mm5=[ref+ystride]*/\r
833       movq mm5,[REF+YSTRIDE]\r
834       /*Compute [src]-[ref].*/\r
835       movq mm2,mm0\r
836       punpcklbw mm0,mm7\r
837       movq mm3,mm1\r
838       punpckhbw mm2,mm7\r
839       punpcklbw mm1,mm7\r
840       punpckhbw mm3,mm7\r
841       psubw mm0,mm1\r
842       psubw mm2,mm3\r
843       /*Compute [src+ystride]-[ref+ystride].*/\r
844       movq mm1,mm4\r
845       punpcklbw mm4,mm7\r
846       movq mm3,mm5\r
847       punpckhbw mm1,mm7\r
848       lea SRC,[SRC+YSTRIDE*2]\r
849       punpcklbw mm5,mm7\r
850       lea REF,[REF+YSTRIDE*2]\r
851       punpckhbw mm3,mm7\r
852       psubw mm4,mm5\r
853       psubw mm1,mm3\r
854       /*Write the answer out.*/\r
855       movq [RESIDUE+0x00],mm0\r
856       movq [RESIDUE+0x08],mm2\r
857       movq [RESIDUE+0x10],mm4\r
858       movq [RESIDUE+0x18],mm1\r
859       lea RESIDUE,[RESIDUE+0x20]\r
860       mov _residue,RESIDUE\r
861       mov _src,SRC\r
862       mov _ref,REF\r
863 #undef SRC\r
864 #undef YSTRIDE\r
865 #undef RESIDUE\r
866 #undef REF\r
867     }\r
868   }\r
869 }\r
870 \r
871 void oc_enc_frag_sub_128_mmx(ogg_int16_t _residue[64],\r
872  const unsigned char *_src,int _ystride){\r
873    __asm{\r
874 #define YSTRIDE edx\r
875 #define YSTRIDE3 edi\r
876 #define RESIDUE ecx\r
877 #define SRC eax\r
878     mov YSTRIDE,_ystride\r
879     mov RESIDUE,_residue\r
880     mov SRC,_src\r
881     /*mm0=[src]*/\r
882     movq mm0,[SRC]\r
883     /*mm1=[src+ystride]*/\r
884     movq mm1,[SRC+YSTRIDE]\r
885     /*mm6={-1}x4*/\r
886     pcmpeqw mm6,mm6\r
887     /*mm2=[src+2*ystride]*/\r
888     movq mm2,[SRC+YSTRIDE*2]\r
889     /*[ystride3]=3*[ystride]*/\r
890     lea YSTRIDE3,[YSTRIDE+YSTRIDE*2]\r
891     /*mm6={1}x4*/\r
892     psllw mm6,15\r
893     /*mm3=[src+3*ystride]*/\r
894     movq mm3,[SRC+YSTRIDE3]\r
895     /*mm6={128}x4*/\r
896     psrlw mm6,8\r
897     /*mm7=0*/ \r
898     pxor mm7,mm7\r
899     /*[src]=[src]+4*[ystride]*/\r
900     lea SRC,[SRC+YSTRIDE*4]\r
901     /*Compute [src]-128 and [src+ystride]-128*/\r
902     movq mm4,mm0\r
903     punpcklbw mm0,mm7\r
904     movq mm5,mm1\r
905     punpckhbw mm4,mm7\r
906     psubw mm0,mm6\r
907     punpcklbw mm1,mm7\r
908     psubw mm4,mm6\r
909     punpckhbw mm5,mm7\r
910     psubw mm1,mm6\r
911     psubw mm5,mm6\r
912     /*Write the answer out.*/\r
913     movq [RESIDUE+0x00],mm0\r
914     movq [RESIDUE+0x08],mm4\r
915     movq [RESIDUE+0x10],mm1\r
916     movq [RESIDUE+0x18],mm5\r
917     /*mm0=[src+4*ystride]*/\r
918     movq mm0,[SRC]\r
919     /*mm1=[src+5*ystride]*/\r
920     movq mm1,[SRC+YSTRIDE]\r
921     /*Compute [src+2*ystride]-128 and [src+3*ystride]-128*/\r
922     movq mm4,mm2\r
923     punpcklbw mm2,mm7\r
924     movq mm5,mm3\r
925     punpckhbw mm4,mm7\r
926     psubw mm2,mm6\r
927     punpcklbw mm3,mm7\r
928     psubw mm4,mm6\r
929     punpckhbw mm5,mm7\r
930     psubw mm3,mm6\r
931     psubw mm5,mm6\r
932     /*Write the answer out.*/\r
933     movq [RESIDUE+0x20],mm2\r
934     movq [RESIDUE+0x28],mm4\r
935     movq [RESIDUE+0x30],mm3\r
936     movq [RESIDUE+0x38],mm5\r
937     /*Compute [src+6*ystride]-128 and [src+7*ystride]-128*/\r
938     movq mm2,[SRC+YSTRIDE*2]\r
939     movq mm3,[SRC+YSTRIDE3]\r
940     movq mm4,mm0\r
941     punpcklbw mm0,mm7\r
942     movq mm5,mm1\r
943     punpckhbw mm4,mm7\r
944     psubw mm0,mm6\r
945     punpcklbw mm1,mm7\r
946     psubw mm4,mm6\r
947     punpckhbw mm5,mm7\r
948     psubw mm1,mm6\r
949     psubw mm5,mm6\r
950     /*Write the answer out.*/\r
951     movq [RESIDUE+0x40],mm0\r
952     movq [RESIDUE+0x48],mm4\r
953     movq [RESIDUE+0x50],mm1\r
954     movq [RESIDUE+0x58],mm5\r
955     /*Compute [src+6*ystride]-128 and [src+7*ystride]-128*/\r
956     movq mm4,mm2\r
957     punpcklbw mm2,mm7\r
958     movq mm5,mm3\r
959     punpckhbw mm4,mm7\r
960     psubw mm2,mm6\r
961     punpcklbw mm3,mm7\r
962     psubw mm4,mm6\r
963     punpckhbw mm5,mm7\r
964     psubw mm3,mm6\r
965     psubw mm5,mm6\r
966     /*Write the answer out.*/\r
967     movq [RESIDUE+0x60],mm2\r
968     movq [RESIDUE+0x68],mm4\r
969     movq [RESIDUE+0x70],mm3\r
970     movq [RESIDUE+0x78],mm5\r
971 #undef YSTRIDE\r
972 #undef YSTRIDE3\r
973 #undef RESIDUE\r
974 #undef SRC\r
975   }\r
976 }\r
977 \r
978 void oc_enc_frag_copy2_mmxext(unsigned char *_dst,\r
979  const unsigned char *_src1,const unsigned char *_src2,int _ystride){\r
980   oc_int_frag_copy2_mmxext(_dst,_ystride,_src1,_src2,_ystride);\r
981 }\r
982 \r
983 #endif\r