Add a new libtheora_info example program.
[theora.git] / lib / x86 / x86enquant.c
1 /********************************************************************
2  *                                                                  *
3  * THIS FILE IS PART OF THE OggTheora SOFTWARE CODEC SOURCE CODE.   *
4  * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS     *
5  * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
6  * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING.       *
7  *                                                                  *
8  * THE Theora SOURCE CODE IS COPYRIGHT (C) 2002-2009                *
9  * by the Xiph.Org Foundation and contributors http://www.xiph.org/ *
10  *                                                                  *
11  ********************************************************************
12
13   function:
14     last mod: $Id: mmxstate.c 17247 2010-05-28 05:35:32Z tterribe $
15
16  ********************************************************************/
17
18 #include "x86enc.h"
19
20 #if defined(OC_X86_ASM)
21
22
23
24 /*The default enquant table is not quite suitable for SIMD purposes.
25   First, the m and l parameters need to be separated so that an entire row full
26    of m's or l's can be loaded at a time.
27   Second, x86 SIMD has no element-wise arithmetic right-shift, so we have to
28    emulate one with a multiply.
29   Therefore we translate the shift count into a scale factor.*/
30 void oc_enc_enquant_table_init_x86(void *_enquant,
31  const ogg_uint16_t _dequant[64]){
32   ogg_int16_t *m;
33   ogg_int16_t *l;
34   int          zzi;
35   m=(ogg_int16_t *)_enquant;
36   l=m+64;
37   for(zzi=0;zzi<64;zzi++){
38     oc_iquant q;
39     oc_iquant_init(&q,_dequant[zzi]);
40     m[zzi]=q.m;
41     /*q.l must be at least 2 for this to work; fortunately, once all the scale
42        factors are baked in, the minimum quantizer is much larger than that.*/
43     l[zzi]=1<<16-q.l;
44   }
45 }
46
47 void oc_enc_enquant_table_fixup_x86(void *_enquant[3][3][2],int _nqis){
48   int pli;
49   int qii;
50   int qti;
51   for(pli=0;pli<3;pli++)for(qii=1;qii<_nqis;qii++)for(qti=0;qti<2;qti++){
52     ((ogg_int16_t *)_enquant[pli][qii][qti])[0]=
53      ((ogg_int16_t *)_enquant[pli][0][qti])[0];
54     ((ogg_int16_t *)_enquant[pli][qii][qti])[64]=
55      ((ogg_int16_t *)_enquant[pli][0][qti])[64];
56   }
57 }
58
59 /*Convert DCT coefficients in %[dct] from natural order into zig-zag scan order
60    and store them in %[qdct].
61   The index of each output element in the original 64-element array should wind
62    up in the following 8x8 matrix (the letters indicate the order we compute
63    each 4-tuple below):
64     A  0  1  8 16   9  2  3 10 B
65     C 17 24 32 25  18 11  4  5 D
66     E 12 19 26 33  40 48 41 34 I
67     H 27 20 13  6   7 14 21 28 G
68     K 35 42 49 56  57 50 43 36 J
69     F 29 22 15 23  30 37 44 51 M
70     P 58 59 52 45  38 31 39 46 L
71     N 53 60 61 54  47 55 62 63 O
72   The order of the coefficients within each tuple is reversed in the comments
73    below to reflect the usual MSB to LSB notation.*/
74 #define OC_ZIG_ZAG_MMXEXT \
75   "movq 0x00(%[dct]),%%mm0\n\t"  /*mm0=03 02 01 00*/ \
76   "movq 0x08(%[dct]),%%mm1\n\t"  /*mm1=07 06 05 04*/ \
77   "movq 0x10(%[dct]),%%mm2\n\t"  /*mm2=11 10 09 08*/ \
78   "movq 0x20(%[dct]),%%mm3\n\t"  /*mm3=19 18 17 16*/ \
79   "movq 0x30(%[dct]),%%mm4\n\t"  /*mm4=27 26 25 24*/ \
80   "movq 0x40(%[dct]),%%mm5\n\t"  /*mm5=35 34 33 32*/ \
81   "movq %%mm2,%%mm7\n\t"         /*mm7=11 10 09 08*/ \
82   "punpcklwd %%mm3,%%mm2\n\t"    /*mm2=17 09 16 08*/ \
83   "movq %%mm0,%%mm6\n\t"         /*mm6=03 02 01 00*/ \
84   "punpckldq %%mm2,%%mm0\n\t"    /*mm0=16 08 01 00 *A*/ \
85   "movq %%mm0,0x00(%[qdct])\n\t" \
86   "movq 0x18(%[dct]),%%mm0\n\t"  /*mm0=15 14 13 12*/ \
87   "punpckhdq %%mm6,%%mm6\n\t"    /*mm6=03 02 03 02*/ \
88   "psrlq $16,%%mm7\n\t"          /*mm7=.. 11 10 09*/ \
89   "punpckldq %%mm7,%%mm6\n\t"    /*mm6=10 09 03 02*/ \
90   "punpckhwd %%mm7,%%mm3\n\t"    /*mm3=.. 19 11 18*/ \
91   "pshufw $0xD2,%%mm6,%%mm6\n\t" /*mm6=10 03 02 09 *B*/ \
92   "movq %%mm6,0x08(%[qdct])\n\t" \
93   "psrlq $48,%%mm2\n\t"          /*mm2=.. .. .. 17*/ \
94   "movq %%mm1,%%mm6\n\t"         /*mm6=07 06 05 04*/ \
95   "punpcklwd %%mm5,%%mm2\n\t"    /*mm2=33 .. 32 17*/ \
96   "movq %%mm3,%%mm7\n\t"         /*mm7=.. 19 11 18*/ \
97   "punpckldq %%mm1,%%mm3\n\t"    /*mm3=05 04 11 18 *C*/ \
98   "por %%mm2,%%mm7\n\t"          /*mm7=33 19 ?? ??*/ \
99   "punpcklwd %%mm4,%%mm2\n\t"    /*mm2=25 32 24 17 *D**/ \
100   "movq %%mm2,0x10(%[qdct])\n\t" \
101   "movq %%mm3,0x18(%[qdct])\n\t" \
102   "movq 0x28(%[dct]),%%mm2\n\t"  /*mm2=23 22 21 20*/ \
103   "movq 0x38(%[dct]),%%mm1\n\t"  /*mm1=31 30 29 28*/ \
104   "pshufw $0x9C,%%mm0,%%mm3\n\t" /*mm3=14 13 15 12*/ \
105   "punpckhdq %%mm7,%%mm7\n\t"    /*mm7=33 19 33 19*/ \
106   "punpckhwd %%mm3,%%mm6\n\t"    /*mm6=14 07 13 06*/ \
107   "punpckldq %%mm0,%%mm0\n\t"    /*mm0=13 12 13 12*/ \
108   "punpcklwd %%mm1,%%mm3\n\t"    /*mm3=29 15 28 12*/ \
109   "punpckhwd %%mm4,%%mm0\n\t"    /*mm0=27 13 26 12*/ \
110   "pshufw $0xB4,%%mm3,%%mm3\n\t" /*mm3=15 29 28 12*/ \
111   "psrlq $48,%%mm4\n\t"          /*mm4=.. .. .. 27*/ \
112   "punpcklwd %%mm7,%%mm0\n\t"    /*mm0=33 26 19 12 *E*/ \
113   "punpcklwd %%mm1,%%mm4\n\t"    /*mm4=29 .. 28 27*/ \
114   "punpckhwd %%mm2,%%mm3\n\t"    /*mm3=23 15 22 29 *F*/ \
115   "movq %%mm0,0x20(%[qdct])\n\t" \
116   "movq %%mm3,0x50(%[qdct])\n\t" \
117   "movq 0x60(%[dct]),%%mm3\n\t"  /*mm3=51 50 49 48*/ \
118   "movq 0x70(%[dct]),%%mm7\n\t"  /*mm7=59 58 57 56*/ \
119   "movq 0x50(%[dct]),%%mm0\n\t"  /*mm0=43 42 41 40*/ \
120   "punpcklwd %%mm4,%%mm2\n\t"    /*mm2=28 21 27 20*/ \
121   "psrlq $32,%%mm5\n\t"          /*mm5=.. .. 35 34*/ \
122   "movq %%mm2,%%mm4\n\t"         /*mm4=28 21 27 20*/ \
123   "punpckldq %%mm6,%%mm2\n\t"    /*mm2=13 06 27 20*/ \
124   "punpckhdq %%mm4,%%mm6\n\t"    /*mm6=28 21 14 07 *G*/ \
125   "movq %%mm3,%%mm4\n\t"         /*mm4=51 50 49 48*/ \
126   "pshufw $0xB1,%%mm2,%%mm2\n\t" /*mm2=06 13 20 27 *H*/ \
127   "movq %%mm2,0x30(%[qdct])\n\t" \
128   "movq %%mm6,0x38(%[qdct])\n\t" \
129   "movq 0x48(%[dct]),%%mm2\n\t"  /*mm2=39 38 37 36*/ \
130   "punpcklwd %%mm5,%%mm4\n\t"    /*mm4=35 49 34 48*/ \
131   "movq 0x58(%[dct]),%%mm5\n\t"  /*mm5=47 46 45 44*/ \
132   "punpckldq %%mm7,%%mm6\n\t"    /*mm6=57 56 14 07*/ \
133   "psrlq $32,%%mm3\n\t"          /*mm3=.. .. 51 50*/ \
134   "punpckhwd %%mm0,%%mm6\n\t"    /*mm6=43 57 42 56*/ \
135   "punpcklwd %%mm4,%%mm0\n\t"    /*mm0=34 41 48 40 *I*/ \
136   "pshufw $0x4E,%%mm6,%%mm6\n\t" /*mm6=42 56 43 57*/ \
137   "movq %%mm0,0x28(%[qdct])\n\t" \
138   "punpcklwd %%mm2,%%mm3\n\t"    /*mm3=37 51 36 50*/ \
139   "punpckhwd %%mm6,%%mm4\n\t"    /*mm4=42 35 56 49*/ \
140   "punpcklwd %%mm3,%%mm6\n\t"    /*mm6=36 43 50 57 *J*/ \
141   "pshufw $0x4E,%%mm4,%%mm4\n\t" /*mm4=56 49 42 35 *K*/ \
142   "movq %%mm4,0x40(%[qdct])\n\t" \
143   "movq %%mm6,0x48(%[qdct])\n\t" \
144   "movq 0x68(%[dct]),%%mm6\n\t"  /*mm6=55 54 53 52*/ \
145   "movq 0x78(%[dct]),%%mm0\n\t"  /*mm0=63 62 61 60*/ \
146   "psrlq $32,%%mm1\n\t"          /*mm1=.. .. 31 30*/ \
147   "pshufw $0xD8,%%mm5,%%mm5\n\t" /*mm5=47 45 46 44*/ \
148   "pshufw $0x0B,%%mm3,%%mm3\n\t" /*mm3=50 50 51 37*/ \
149   "punpcklwd %%mm5,%%mm1\n\t"    /*mm1=46 31 44 30*/ \
150   "pshufw $0xC9,%%mm6,%%mm6\n\t" /*mm6=55 52 54 53*/ \
151   "punpckhwd %%mm1,%%mm2\n\t"    /*mm2=46 39 31 38 *L*/ \
152   "punpcklwd %%mm3,%%mm1\n\t"    /*mm1=51 44 37 30 *M*/ \
153   "movq %%mm2,0x68(%[qdct])\n\t" \
154   "movq %%mm1,0x58(%[qdct])\n\t" \
155   "punpckhwd %%mm6,%%mm5\n\t"    /*mm5=55 47 52 45*/ \
156   "punpckldq %%mm0,%%mm6\n\t"    /*mm6=61 60 54 53*/ \
157   "pshufw $0x10,%%mm5,%%mm4\n\t" /*mm4=45 52 45 45*/ \
158   "pshufw $0x78,%%mm6,%%mm6\n\t" /*mm6=53 60 61 54 *N*/ \
159   "punpckhdq %%mm0,%%mm5\n\t"    /*mm5=63 62 55 47 *O*/ \
160   "punpckhdq %%mm4,%%mm7\n\t"    /*mm7=45 52 59 58 *P*/ \
161   "movq %%mm6,0x70(%[qdct])\n\t" \
162   "movq %%mm5,0x78(%[qdct])\n\t" \
163   "movq %%mm7,0x60(%[qdct])\n\t" \
164
165 int oc_enc_quantize_sse2(ogg_int16_t _qdct[64],const ogg_int16_t _dct[64],
166  const ogg_uint16_t _dequant[64],const void *_enquant){
167   ptrdiff_t r;
168   __asm__ __volatile__(
169     /*Put the input in zig-zag order.*/
170     OC_ZIG_ZAG_MMXEXT
171     "xor %[r],%[r]\n\t"
172     /*Loop through two rows at a time.*/
173     ".p2align 4\n\t"
174     "0:\n\t"
175     /*Load the first two rows of the data and the quant matrices.*/
176     "movdqa 0x00(%[qdct],%[r]),%%xmm0\n\t"
177     "movdqa 0x10(%[qdct],%[r]),%%xmm1\n\t"
178     "movdqa 0x00(%[dq],%[r]),%%xmm2\n\t"
179     "movdqa 0x10(%[dq],%[r]),%%xmm3\n\t"
180     "movdqa 0x00(%[q],%[r]),%%xmm4\n\t"
181     "movdqa 0x10(%[q],%[r]),%%xmm5\n\t"
182     /*Double the input and propagate its sign to the rounding factor.
183       Using SSSE3's psignw would help here, but we need the mask later anyway.*/
184     "movdqa %%xmm0,%%xmm6\n\t"
185     "psraw $15,%%xmm0\n\t"
186     "movdqa %%xmm1,%%xmm7\n\t"
187     "paddw %%xmm6,%%xmm6\n\t"
188     "psraw $15,%%xmm1\n\t"
189     "paddw %%xmm7,%%xmm7\n\t"
190     "paddw %%xmm0,%%xmm2\n\t"
191     "paddw %%xmm1,%%xmm3\n\t"
192     "pxor %%xmm0,%%xmm2\n\t"
193     "pxor %%xmm1,%%xmm3\n\t"
194     /*Add the rounding factor and perform the first multiply.*/
195     "paddw %%xmm2,%%xmm6\n\t"
196     "paddw %%xmm3,%%xmm7\n\t"
197     "pmulhw %%xmm6,%%xmm4\n\t"
198     "pmulhw %%xmm7,%%xmm5\n\t"
199     "movdqa 0x80(%[q],%[r]),%%xmm2\n\t"
200     "movdqa 0x90(%[q],%[r]),%%xmm3\n\t"
201     "paddw %%xmm4,%%xmm6\n\t"
202     "paddw %%xmm5,%%xmm7\n\t"
203     /*Emulate an element-wise right-shift via a second multiply.*/
204     "pmulhw %%xmm2,%%xmm6\n\t"
205     "pmulhw %%xmm3,%%xmm7\n\t"
206     "add $32,%[r]\n\t"
207     "cmp $96,%[r]\n\t"
208     /*Correct for the sign.*/
209     "psubw %%xmm0,%%xmm6\n\t"
210     "psubw %%xmm1,%%xmm7\n\t"
211     /*Save the result.*/
212     "movdqa %%xmm6,-0x20(%[qdct],%[r])\n\t"
213     "movdqa %%xmm7,-0x10(%[qdct],%[r])\n\t"
214     "jle 0b\n\t"
215     /*Now find the location of the last non-zero value.*/
216     "movdqa 0x50(%[qdct]),%%xmm5\n\t"
217     "movdqa 0x40(%[qdct]),%%xmm4\n\t"
218     "packsswb %%xmm7,%%xmm6\n\t"
219     "packsswb %%xmm5,%%xmm4\n\t"
220     "pxor %%xmm0,%%xmm0\n\t"
221     "mov $-1,%k[dq]\n\t"
222     "pcmpeqb %%xmm0,%%xmm6\n\t"
223     "pcmpeqb %%xmm0,%%xmm4\n\t"
224     "pmovmskb %%xmm6,%k[q]\n\t"
225     "pmovmskb %%xmm4,%k[r]\n\t"
226     "shl $16,%k[q]\n\t"
227     "or %k[r],%k[q]\n\t"
228     "mov $32,%[r]\n\t"
229     /*We have to use xor here instead of not in order to set the flags.*/
230     "xor %k[dq],%k[q]\n\t"
231     "jnz 1f\n\t"
232     "movdqa 0x30(%[qdct]),%%xmm7\n\t"
233     "movdqa 0x20(%[qdct]),%%xmm6\n\t"
234     "movdqa 0x10(%[qdct]),%%xmm5\n\t"
235     "movdqa 0x00(%[qdct]),%%xmm4\n\t"
236     "packsswb %%xmm7,%%xmm6\n\t"
237     "packsswb %%xmm5,%%xmm4\n\t"
238     "pcmpeqb %%xmm0,%%xmm6\n\t"
239     "pcmpeqb %%xmm0,%%xmm4\n\t"
240     "pmovmskb %%xmm6,%k[q]\n\t"
241     "pmovmskb %%xmm4,%k[r]\n\t"
242     "shl $16,%k[q]\n\t"
243     "or %k[r],%k[q]\n\t"
244     "xor %[r],%[r]\n\t"
245     "not %k[q]\n\t"
246     "or $1,%k[q]\n\t"
247     "1:\n\t"
248     "bsr %k[q],%k[q]\n\t"
249     "add %k[q],%k[r]\n\t"
250     :[r]"=&a"(r),[q]"+r"(_enquant),[dq]"+r"(_dequant)
251     :[dct]"r"(_dct),[qdct]"r"(_qdct)
252     :"cc","memory"
253   );
254   return (int)r;
255 }
256
257 #endif