57a3d48f817e394437ea4c9ceed794015706a542
[mw/milkymist.git] / software / demo / eval.c
1 /*
2  * Milkymist VJ SoC (Software)
3  * Copyright (C) 2007, 2008, 2009, 2010 Sebastien Bourdeauducq
4  *
5  * This program is free software: you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation, version 3 of the License.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
16  */
17
18 #include <stdio.h>
19 #include <string.h>
20 #include <hw/pfpu.h>
21 #include <hw/tmu.h>
22
23 #include <hal/pfpu.h>
24
25 #include "ast.h"
26 #include "compiler.h"
27 #include "scheduler.h"
28 #include "eval.h"
29
30 //#define EVAL_DEBUG
31
32 /****************************************************************/
33 /* PER-FRAME VARIABLES                                          */
34 /****************************************************************/
35
36 static const char pfv_names[EVAL_PFV_COUNT][IDENTIFIER_SIZE] = {
37         "cx",
38         "cy",
39         "rot",
40         "dx",
41         "dy",
42         "zoom",
43         "decay",
44         "wave_mode",
45         "wave_scale",
46         "wave_additive",
47         "wave_usedots",
48         "bMaximizeWaveColor",
49         "wave_thick",
50         "wave_x",
51         "wave_y",
52         "wave_r",
53         "wave_g",
54         "wave_b",
55         "wave_a",
56         
57         "ob_size",
58         "ob_r",
59         "ob_g",
60         "ob_b",
61         "ob_a",
62         "ib_size",
63         "ib_r",
64         "ib_g",
65         "ib_b",
66         "ib_a",
67
68         "nMotionVectorsX",
69         "nMotionVectorsY",
70         "mv_dx",
71         "mv_dy",
72         "mv_l",
73         "mv_r",
74         "mv_g",
75         "mv_b",
76         "mv_a",
77         
78         "bTexWrap",
79
80         "time",
81         "bass",
82         "mid",
83         "treb",
84         "bass_att",
85         "mid_att",
86         "treb_att"
87 };
88
89 static int pfv_from_name(const char *name)
90 {
91         int i;
92         for(i=0;i<EVAL_PFV_COUNT;i++)
93                 if(strcmp(pfv_names[i], name) == 0) return i;
94         if(strcmp(name, "fDecay") == 0) return pfv_decay;
95         if(strcmp(name, "nWaveMode") == 0) return pfv_wave_mode;
96         if(strcmp(name, "fWaveScale") == 0) return pfv_wave_scale;
97         if(strcmp(name, "bAdditiveWaves") == 0) return pfv_wave_additive;
98         if(strcmp(name, "bWaveDots") == 0) return pfv_wave_usedots;
99         if(strcmp(name, "bWaveThick") == 0) return pfv_wave_thick;
100         if(strcmp(name, "fWaveAlpha") == 0) return pfv_wave_a;
101         return -1;
102 }
103
104 static void load_defaults(struct eval_state *sc)
105 {
106         int i;
107
108         for(i=0;i<EVAL_PFV_COUNT;i++)
109                 sc->pfv_initial[i] = 0.0;
110         sc->pfv_initial[pfv_zoom] = 1.0;
111         sc->pfv_initial[pfv_decay] = 1.0;
112         sc->pfv_initial[pfv_wave_mode] = 1.0;
113         sc->pfv_initial[pfv_wave_scale] = 1.0;
114         sc->pfv_initial[pfv_wave_r] = 1.0;
115         sc->pfv_initial[pfv_wave_g] = 1.0;
116         sc->pfv_initial[pfv_wave_b] = 1.0;
117         sc->pfv_initial[pfv_wave_a] = 1.0;
118
119         sc->pfv_initial[pfv_mv_x] = 16.0;
120         sc->pfv_initial[pfv_mv_y] = 12.0;
121         sc->pfv_initial[pfv_mv_dx] = 0.02;
122         sc->pfv_initial[pfv_mv_dy] = 0.02;
123         sc->pfv_initial[pfv_mv_l] = 1.0;
124 }
125
126 static void generate_initial(struct eval_state *sc, struct preset *ast)
127 {
128         struct preset_line *line;
129
130         load_defaults(sc);
131
132         line = ast->lines;
133         while(line != NULL) {
134                 if(!line->iseq) {
135                         int pfv;
136
137                         pfv = pfv_from_name(line->label);
138                         if(pfv >= 0)
139                                 sc->pfv_initial[pfv] = line->contents.parameter;
140                 }
141                 line = line->next;
142         }
143 }
144
145 void eval_reset_pfv(struct eval_state *sc)
146 {
147         int i;
148         for(i=0;i<PFPU_REG_COUNT;i++)
149                 sc->perframe_regs_current[i] = sc->perframe_regs_init[i];
150 }
151
152 int eval_reinit_pfv(struct eval_state *sc, int pfv)
153 {
154         int r;
155
156         r = sc->pfv_allocation[pfv];
157         if(r < 0) return 0;
158         sc->perframe_regs_current[r] = sc->perframe_regs_init[r];
159         return 1;
160 }
161
162 void eval_reinit_all_pfv(struct eval_state *sc)
163 {
164         eval_reinit_pfv(sc, pfv_cx);
165         eval_reinit_pfv(sc, pfv_cy);
166         eval_reinit_pfv(sc, pfv_rot);
167         eval_reinit_pfv(sc, pfv_dx);
168         eval_reinit_pfv(sc, pfv_dy);
169         eval_reinit_pfv(sc, pfv_zoom);
170         eval_reinit_pfv(sc, pfv_decay);
171         
172         eval_reinit_pfv(sc, pfv_wave_mode);
173         eval_reinit_pfv(sc, pfv_wave_scale);
174         eval_reinit_pfv(sc, pfv_wave_additive);
175         eval_reinit_pfv(sc, pfv_wave_usedots);
176         eval_reinit_pfv(sc, pfv_wave_maximize_color);
177         eval_reinit_pfv(sc, pfv_wave_thick);
178         
179         eval_reinit_pfv(sc, pfv_wave_x);
180         eval_reinit_pfv(sc, pfv_wave_y);
181         eval_reinit_pfv(sc, pfv_wave_r);
182         eval_reinit_pfv(sc, pfv_wave_g);
183         eval_reinit_pfv(sc, pfv_wave_b);
184         eval_reinit_pfv(sc, pfv_wave_a);
185
186         eval_reinit_pfv(sc, pfv_ob_size);
187         eval_reinit_pfv(sc, pfv_ob_r);
188         eval_reinit_pfv(sc, pfv_ob_g);
189         eval_reinit_pfv(sc, pfv_ob_b);
190         eval_reinit_pfv(sc, pfv_ob_a);
191
192         eval_reinit_pfv(sc, pfv_ib_size);
193         eval_reinit_pfv(sc, pfv_ib_r);
194         eval_reinit_pfv(sc, pfv_ib_g);
195         eval_reinit_pfv(sc, pfv_ib_b);
196         eval_reinit_pfv(sc, pfv_ib_a);
197
198         eval_reinit_pfv(sc, pfv_mv_x);
199         eval_reinit_pfv(sc, pfv_mv_y);
200         eval_reinit_pfv(sc, pfv_mv_dx);
201         eval_reinit_pfv(sc, pfv_mv_dy);
202         eval_reinit_pfv(sc, pfv_mv_l);
203         eval_reinit_pfv(sc, pfv_mv_r);
204         eval_reinit_pfv(sc, pfv_mv_g);
205         eval_reinit_pfv(sc, pfv_mv_b);
206         eval_reinit_pfv(sc, pfv_mv_a);
207         
208         eval_reinit_pfv(sc, pfv_tex_wrap);
209 }
210
211 static int generate_perframe(struct eval_state *sc, struct preset *ast)
212 {
213         struct compiler_state compiler;
214         struct compiler_initial initials[PFPU_REG_COUNT];
215         int i;
216         struct scheduler_state scheduler;
217         struct preset_line *line;
218
219         compiler_init(&compiler);
220
221         /* Add equations from MilkDrop */
222         line = ast->lines;
223         while(line != NULL) {
224                 if(line->iseq && (strncmp(line->label, "per_frame_", 10) == 0)) {
225                         struct preset_equation *equation;
226
227                         equation = line->contents.equations;
228                         while(equation != NULL) {
229                                 if(!compiler_compile_equation(&compiler, equation->target, equation->topnode)) return 0;
230                                 equation = equation->next;
231                         }
232                 }
233                 line = line->next;
234         }
235
236         /* Generate initial register content */
237         for(i=0;i<PFPU_REG_COUNT;i++)
238                 initials[i].name[0] = 0;
239         for(i=0;i<EVAL_PFV_COUNT;i++) {
240                 strcpy(initials[i].name, pfv_names[i]);
241                 initials[i].x = sc->pfv_initial[i];
242         }
243         compiler_get_initial_regs(&compiler, initials, sc->perframe_regs_init);
244         eval_reset_pfv(sc);
245
246         /* Find out which variables we must read from the PFPU */
247         for(i=0;i<EVAL_PFV_COUNT;i++) {
248                 int j;
249
250                 for(j=0;j<PFPU_REG_COUNT;j++)
251                         if(
252                                 compiler.terminals[j].valid
253                                 && !compiler.terminals[j].isconst
254                                 && (strcmp(compiler.terminals[j].id.name, pfv_names[i]) == 0)
255                         ) break;
256                 if(j < PFPU_REG_COUNT)
257                         sc->pfv_allocation[i] = j;
258                 else
259                         sc->pfv_allocation[i] = -1;
260         }
261
262         #ifdef EVAL_DEBUG
263         printf("======== Per-frame virtual program ========\n");
264         print_vprogram(&compiler);
265         printf("======== Per-frame static register allocation ========\n");
266         print_terminals(&compiler);
267         printf("======== Per-frame variables from PFPU ========\n");
268         for(i=0;i<EVAL_PFV_COUNT;i++)
269                 if(sc->pfv_allocation[i] != -1)
270                         printf("R%03d - %s\n", sc->pfv_allocation[i], pfv_names[i]);
271         #endif
272
273         /* Schedule instructions */
274         scheduler_init(&scheduler);
275         scheduler_dont_touch(&scheduler, compiler.terminals);
276         scheduler_schedule(&scheduler, compiler.prog, compiler.prog_length);
277         /* patch the program to make a dummy DMA at the end (otherwise PFPU never finishes) */
278         scheduler.last_exit++;
279         if(scheduler.last_exit == PFPU_PROGSIZE) return 0;
280         scheduler.prog[scheduler.last_exit].i.opcode = PFPU_OPCODE_VECTOUT;
281
282         #ifdef EVAL_DEBUG
283         printf("======== Per-frame HW program ========\n");
284         print_program(&scheduler);
285         #endif
286
287         sc->perframe_prog_length = scheduler.last_exit+1;
288         for(i=0;i<=scheduler.last_exit;i++)
289                 sc->perframe_prog[i].w = scheduler.prog[i].w;
290         for(;i<PFPU_PROGSIZE;i++)
291                 sc->perframe_prog[i].w = 0;
292
293         return 1;
294 }
295
296 static unsigned int dummy[2];
297
298 void eval_pfv_fill_td(struct eval_state *sc, struct pfpu_td *td, pfpu_callback callback, void *user)
299 {
300         td->output = &dummy[0];
301         td->hmeshlast = 0;
302         td->vmeshlast = 0;
303         td->program = sc->perframe_prog;
304         td->progsize = sc->perframe_prog_length;
305         td->registers = sc->perframe_regs_current;
306         td->update = 1;
307         td->invalidate = 0; /* < we don't care if our dummy variable has coherency problems */
308         td->callback = callback;
309         td->user = user;
310 }
311
312 float eval_read_pfv(struct eval_state *sc, int pfv)
313 {
314         if(sc->pfv_allocation[pfv] < 0)
315                 return sc->pfv_initial[pfv];
316         else
317                 return sc->perframe_regs_current[sc->pfv_allocation[pfv]];
318 }
319
320 void eval_write_pfv(struct eval_state *sc, int pfv, float x)
321 {
322         if(sc->pfv_allocation[pfv] >= 0)
323                 sc->perframe_regs_current[sc->pfv_allocation[pfv]] = x;
324 }
325
326 /****************************************************************/
327 /* PER-VERTEX VARIABLES                                         */
328 /****************************************************************/
329
330 static int generate_pervertex(struct eval_state *sc, struct preset *ast)
331 {
332         int i;
333         struct scheduler_state scheduler;
334         vpfpu_instruction vprog[PFPU_PROGSIZE];
335         unsigned int vlen;
336         
337         sc->pvv_allocation[pvv_hmeshsize] = 3;
338         sc->pvv_allocation[pvv_vmeshsize] = 4;
339         sc->pvv_allocation[pvv_hres] = 5;
340         sc->pvv_allocation[pvv_vres] = 6;
341         sc->pvv_allocation[pvv_cx] = 7;
342         sc->pvv_allocation[pvv_cy] = 8;
343         sc->pvv_allocation[pvv_rot] = 9;
344         sc->pvv_allocation[pvv_dx] = 10;
345         sc->pvv_allocation[pvv_dy] = 11;
346         sc->pvv_allocation[pvv_zoom] = 12;
347
348         for(i=0;i<PFPU_REG_COUNT;i++)
349                 sc->pervertex_regs[i] = 0.0f;
350         sc->pervertex_regs[3] = 1.0f/(float)sc->hmeshlast;
351         sc->pervertex_regs[4] = 1.0f/(float)sc->vmeshlast;
352         sc->pervertex_regs[5] = (float)(sc->hres << TMU_FIXEDPOINT_SHIFT);
353         sc->pervertex_regs[6] = (float)(sc->vres << TMU_FIXEDPOINT_SHIFT);
354         sc->pervertex_regs[13] = PFPU_TRIG_CONV;
355
356         vlen = 0;
357         
358 #define ADD_ISN(_opcode, _opa, _opb, _dest) do { \
359                 vprog[vlen].opcode = _opcode; \
360                 vprog[vlen].opa = _opa; \
361                 vprog[vlen].opb = _opb; \
362                 vprog[vlen].dest = _dest; \
363                 vlen++; \
364         } while(0)
365 #define BR(x) (x)                       /* bound register */
366 #define FR(x) (PFPU_REG_COUNT+(x))      /* free register */
367
368         /* Compute current coordinates as floating point in range 0..1 */
369         ADD_ISN(PFPU_OPCODE_I2F,        BR(  0), BR(  0), FR(  0)); /* FR00: current X index in float */
370         ADD_ISN(PFPU_OPCODE_I2F,        BR(  1), BR(  0), FR(  1)); /* FR01: current Y index in float */
371         ADD_ISN(PFPU_OPCODE_FMUL,       FR(  0), BR(  3), FR(  2)); /* FR02: current X coord (0..1) */
372         ADD_ISN(PFPU_OPCODE_FMUL,       FR(  1), BR(  4), FR(  3)); /* FR03: current Y coord (0..1) */
373
374         /* Zoom */
375         ADD_ISN(PFPU_OPCODE_FSUB,       FR(  2), BR(  7), FR(  4)); /* FR04: x-cx */
376         ADD_ISN(PFPU_OPCODE_FSUB,       FR(  3), BR(  8), FR(  5)); /* FR05: y-cy */
377         ADD_ISN(PFPU_OPCODE_FMUL,       FR(  4), BR( 12), FR(  6)); /* FR06: zoom*(x-cx) */
378         ADD_ISN(PFPU_OPCODE_FMUL,       FR(  5), BR( 12), FR(  7)); /* FR07: zoom*(y-cy) */
379         ADD_ISN(PFPU_OPCODE_FADD,       FR(  6), BR(  7), FR(  8)); /* FR08: final zoomed X: zoom*(x-cx)+cx */
380         ADD_ISN(PFPU_OPCODE_FADD,       FR(  7), BR(  8), FR(  9)); /* FR09: final zoomed Y: zoom*(y-cy)+cy */
381         
382         /* Rotation */
383         ADD_ISN(PFPU_OPCODE_FMUL,       BR( 13), BR(  9), FR( 80)); /* FR80: rot*conv */
384         ADD_ISN(PFPU_OPCODE_F2I,        FR( 80), BR(  0), FR( 81)); /* FR81: int(rot*conv) */
385         ADD_ISN(PFPU_OPCODE_COS,        FR( 81), BR(  0), FR( 10)); /* FR10: cos(rot*conv) */
386         ADD_ISN(PFPU_OPCODE_SIN,        FR( 81), BR(  0), FR( 11)); /* FR11: sin(rot*conv) */
387         ADD_ISN(PFPU_OPCODE_FSUB,       FR(  8), BR(  7), FR( 12)); /* FR12: u=x-cx */
388         ADD_ISN(PFPU_OPCODE_FSUB,       FR(  9), BR(  8), FR( 13)); /* FR13: v=y-cy */
389         ADD_ISN(PFPU_OPCODE_FMUL,       FR( 12), FR( 10), FR( 14)); /* FR14: u*cos */
390         ADD_ISN(PFPU_OPCODE_FMUL,       FR( 12), FR( 11), FR( 15)); /* FR15: u*sin */
391         ADD_ISN(PFPU_OPCODE_FMUL,       FR( 13), FR( 10), FR( 16)); /* FR16: v*cos */
392         ADD_ISN(PFPU_OPCODE_FMUL,       FR( 13), FR( 11), FR( 17)); /* FR17: v*sin */
393         ADD_ISN(PFPU_OPCODE_FSUB,       FR( 14), FR( 17), FR( 18)); /* FR18: u*cos - v*sin */
394         ADD_ISN(PFPU_OPCODE_FADD,       FR( 15), FR( 16), FR( 19)); /* FR19: u*sin + v*cos */
395         ADD_ISN(PFPU_OPCODE_FADD,       FR( 18), BR(  7), FR( 30)); /* FR30: final rotated X: ...+cx */
396         ADD_ISN(PFPU_OPCODE_FADD,       FR( 19), BR(  8), FR( 31)); /* FR31: final rotated Y: ...+cy */
397         
398         /* Displacement */
399         ADD_ISN(PFPU_OPCODE_FADD,       FR( 30), BR( 10), FR( 20)); /* FR20: X */
400         ADD_ISN(PFPU_OPCODE_FADD,       FR( 31), BR( 11), FR( 21)); /* FR21: Y */
401
402         /* Convert to screen coordinates and generate vertex */
403         ADD_ISN(PFPU_OPCODE_FMUL,       FR( 20), BR(  5), FR( 22)); /* FR22: X screen float */
404         ADD_ISN(PFPU_OPCODE_FMUL,       FR( 21), BR(  6), FR( 23)); /* FR23: Y screen float */
405         ADD_ISN(PFPU_OPCODE_F2I,        FR( 22), BR(  0), FR( 24)); /* FR26: X screen integer */
406         ADD_ISN(PFPU_OPCODE_F2I,        FR( 23), BR(  0), FR( 25)); /* FR27: Y screen integer */
407         ADD_ISN(PFPU_OPCODE_VECTOUT,    FR( 24), FR( 25), BR(  0)); /* put out vector */
408
409 #undef BR
410 #undef FR
411 #undef ADD_ISN
412
413         /* Schedule */
414         scheduler_init(&scheduler);
415         for(i=0;i<EVAL_PVV_COUNT;i++)
416                 scheduler.dont_touch[sc->pvv_allocation[i]] = 1;
417         scheduler.dont_touch[13] = 1; /* PFPU_TRIG_CONV */
418
419         scheduler_schedule(&scheduler, vprog, vlen);
420
421         #ifdef EVAL_DEBUG
422         printf("======== Per-vertex HW program ========\n");
423         print_program(&scheduler);
424         #endif
425
426         sc->pervertex_prog_length = scheduler.last_exit+1;
427         for(i=0;i<=scheduler.last_exit;i++)
428                 sc->pervertex_prog[i].w = scheduler.prog[i].w;
429         for(;i<PFPU_PROGSIZE;i++)
430                 sc->pervertex_prog[i].w = 0;
431
432         return 1;
433 }
434
435 void eval_pfv_to_pvv(struct eval_state *sc)
436 {
437         sc->pervertex_regs[sc->pvv_allocation[pvv_cx]] = eval_read_pfv(sc, pfv_cx);
438         sc->pervertex_regs[sc->pvv_allocation[pvv_cy]] = eval_read_pfv(sc, pfv_cy);
439         sc->pervertex_regs[sc->pvv_allocation[pvv_rot]] = -eval_read_pfv(sc, pfv_rot);
440         sc->pervertex_regs[sc->pvv_allocation[pvv_dx]] = -eval_read_pfv(sc, pfv_dx);
441         sc->pervertex_regs[sc->pvv_allocation[pvv_dy]] = -eval_read_pfv(sc, pfv_dy);
442         sc->pervertex_regs[sc->pvv_allocation[pvv_zoom]] = 1.0/eval_read_pfv(sc, pfv_zoom);
443 }
444
445 void eval_pvv_fill_td(struct eval_state *sc, struct pfpu_td *td, struct tmu_vertex *vertices, pfpu_callback callback, void *user)
446 {
447         td->output = (unsigned int *)vertices;
448         td->hmeshlast = sc->hmeshlast;
449         td->vmeshlast = sc->vmeshlast;
450         td->program = sc->pervertex_prog;
451         td->progsize = sc->pervertex_prog_length;
452         td->registers = sc->pervertex_regs;
453         td->update = 0; /* < no transfer of data in per-vertex equations between frames */
454         td->invalidate = 1;
455         td->callback = callback;
456         td->user = user;
457 }
458
459 /****************************************************************/
460 /* GENERAL                                                      */
461 /****************************************************************/
462
463 void eval_init(struct eval_state *sc,
464         unsigned int hmeshlast, unsigned int vmeshlast,
465         unsigned int hres, unsigned int vres)
466 {
467         sc->hmeshlast = hmeshlast;
468         sc->vmeshlast = vmeshlast;
469         sc->hres = hres;
470         sc->vres = vres;
471 }
472
473 int eval_load_preset(struct eval_state *sc, struct preset *ast)
474 {
475         generate_initial(sc, ast);
476         if(!generate_perframe(sc, ast)) return 0;
477         if(!generate_pervertex(sc, ast)) return 0;
478         return 1;
479 }