Changed strategy about ffmpeg fft usage. Using system ffmpeg rather than bundled...
[gsoc2010-fftw-neon:gsoc2010-fftw-neon.git] / dft / simd / nonportable / arm / neon-ffmpeg.c
1 #include "dft.h"
2
3 #include "ffmpeg/ffmpeg_fft.h"
4 #include "api/api.h"
5
6 /*
7  * Do not allow these files to improve runtimes vs. codelets (my intrinsics 
8  * implementation is now synonymous with codelets, will fix that later)
9  */
10 #if defined(FFTW_SINGLE) && defined(HAVE_NEON) && !defined(HAVE_NEON_INTRINSICS)
11
12 #ifndef _MATH_H
13 #include <math.h>
14 #endif
15 #ifndef _COMPLEX_H
16 #include <complex.h>
17 #endif
18
19 /*
20 // XXX: added apiplan pointer to plan structure so that sign could be dug out
21 // from kernel/ifftw.h
22 struct plan_s {
23      const plan_adt *adt;
24      apiplan *apiplan;
25      opcnt ops;
26      double pcost;
27      enum wakefulness wakefulness;
28      int could_prune_now_p;
29 };
30 typedef struct plan_s plan;
31 */
32
33 typedef struct {
34      solver super;
35 } S;
36
37 typedef struct {
38      plan_dft super;
39      INT n;     /* problem size */
40      INT m;    /* m = log2(n) */
41      R *w;      /* input */
42      R *W;      /* output */
43      int sign;
44      plan *p;
45      FFTContext *s;
46 } P;
47
48 static int _log2(unsigned int n) {
49         unsigned int m = 0;
50         for( m = 0; m < 32; m++ )
51                 if ( ((1<<m)^n) == 0 )
52                         break;
53         return ( m == 32 ) ? -1 : m;
54 }
55
56 static void apply(const plan *ego_, R *ri, R *ii, R *ro, R *io)
57 {
58      const P *ego = (const P *) ego_;
59      INT n = ego->n;
60      R *w = (R *)ego->w, *W = (R *) ego->W;
61
62      // FIXME: av_fft_calc gives the illusion of doing everything
63      // in-place, but it actually does not... annoyingly, it uses
64      // an internally malloc'd buffer that it does not expose to the
65      // outside world... a fix will be needed to correctly specify
66      // exactly where the output buffer starts.
67
68      av_fft_permute(ego->s,(FFTComplex *)(ego->w));
69      av_fft_calc(ego->s,(FFTComplex *)(ego->w));
70
71 }
72
73 static void awake(plan *ego_, enum wakefulness wakefulness)
74 {
75         (void) ego_; /* UNUSED */
76         (void) wakefulness; /* UNUSED */
77 }
78
79 static int applicable0(const problem *p_)
80 {
81      const problem_dft *p = (const problem_dft *) p_;
82      return (1
83              && p->sz->rnk == 1 /* 1d data */
84              && p->vecsz->rnk == 0 /* a single vector */
85              && _log2(p->sz->dims[0].n) != -1 /* power of two */
86              && p->io == &p->ro[1] /* contiguous memory */
87              && p->ii == &p->ri[1]
88              && p->sz->dims[0].is == 2
89              && p->sz->dims[0].os == 2
90              && p->ri != p->ro /* out-of-place */
91              && p->ii != p->io
92      );
93 }
94
95 static int applicable(const solver *ego, const problem *p_,
96                       const planner *plnr)
97 {
98      UNUSED(ego);
99      if (!applicable0(p_)) return 0;
100      return 1;
101 }
102
103 static void destroy(plan *ego_)
104 {
105      P *ego = (P *) ego_;
106      av_fft_end(ego->s);
107      X(plan_destroy_internal)(ego->p);
108 }
109
110 static void print(const plan *ego_, printer *p)
111 {
112      const P *ego = (const P *)ego_;
113      p->print(p, "(neon-ffmpeg-%D)",ego->n);
114 }
115
116 static plan *mkplan(const solver *ego, const problem *p_, planner *plnr)
117 {
118      const problem_dft *p = (const problem_dft *) p_;
119      FFTContext *s;
120      P *pln;
121      INT n, m;
122      plan *plan = 0;
123
124      static const plan_adt padt = {
125           X(dft_solve), awake, print, destroy
126      };
127
128      if (!applicable(ego, p_, plnr))
129           return NULL;
130
131      n = p->sz->dims[0].n;
132
133      plan = X(mkplan_f_d)(plnr,
134                           X(mkproblem_dft_d)(X(mktensor_1d)(2, 2, 2),
135                                              X(mktensor_1d)(1, 0, 0),
136                                              p->ri, p->ii,
137                                              p->ro, p->io),
138                           0, 0, 0);
139      if (!plan) goto nada;
140
141      pln = MKPLAN_DFT(P, &padt, apply);
142
143      pln->n = n;
144      pln->m = _log2(n);
145      pln->w = 0;
146      pln->W = 0;
147      pln->p = plan;
148
149      X(ops_add)(&plan->ops, &plan->ops, &pln->super.super.ops);
150
151      /* XXX: given that the armv7a cycle counter is not a part of the standard
152       * kernel, this algorithm will always be evaluated using FFTW_ESTIMATE.
153       * However, those numbers could easily be misleading, so the only
154       * real solution in that case is to just reduce the opcount by
155       * some factor. For now, it's just approximated.
156       */
157      const int factor = 10;
158      pln->super.super.ops.add += 2 * n * m / factor;
159      pln->super.super.ops.mul += 5 * n * n / factor;
160      pln->super.super.ops.other += n * m / factor;
161
162      /* XXX: we're required to dig out the 'sign' flag
163       * that indicates FFTW_FORWARD (-1) or FFTW_REVERSE(+1)
164       * since the fftw3 api carefully hides it in an
165       * apiplan structure. Also, re/im indices are
166       * reversed on the sign and will need to be
167       * repaired  (see api/execute-dft.c api/extract-reim.c).
168       */
169      apiplan *xplan = (apiplan *)(pln->super.super.super);
170
171      // ffmpeg encoding of sign / fft direction
172      // 1 == idft, 0 = dft
173      pln->sign = (xplan->sign == 1) ? 1 : 0;
174      pln->s = av_fft_init(m,pln->s);
175      if ( ! pln->s ) goto nada;
176
177      return &(pln->super.super);
178
179  nada:
180      X(plan_destroy_internal)(plan);
181      return NULL;
182 }
183
184 static solver *mksolver(void)
185 {
186      static const solver_adt sadt = { PROBLEM_DFT, mkplan, 0 };
187      S *slv = MKSOLVER(S, &sadt);
188      return &(slv->super);
189 }
190
191 void X(dft_neon_ffmpeg_register)(planner *p)
192 {
193      REGISTER_SOLVER(p, mksolver());
194 }
195
196 #endif