change includes to use new csr base address
[mw/milkymist.git] / software / demo / rpipe.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 <irq.h>
20 #include <system.h>
21 #include <math.h>
22 #include <hw/interrupts.h>
23
24 #include <hal/vga.h>
25 #include <hal/tmu.h>
26
27 #include "renderer.h"
28 #include "wave.h"
29 #include "cpustats.h"
30 #include "color.h"
31 #include "line.h"
32 #include "osd.h"
33 #include "rpipe.h"
34
35 #define RPIPE_FRAMEQ_SIZE 4 /* < must be a power of 2 */
36 #define RPIPE_FRAMEQ_MASK (RPIPE_FRAMEQ_SIZE-1)
37
38 static struct rpipe_frame *queue[RPIPE_FRAMEQ_SIZE];
39 static unsigned int produce;
40 static unsigned int consume;
41 static unsigned int level;
42 static int cts;
43
44 struct rpipe_frame *bh_frame;
45 static int run_wave_bottom_half;
46 static int run_swap_bottom_half;
47
48 static unsigned int frames;
49 static unsigned int fps;
50
51 static unsigned short texbufferA[512*512];
52 static unsigned short texbufferB[512*512];
53 static unsigned short *tex_frontbuffer;
54 static unsigned short *tex_backbuffer;
55
56 static struct tmu_vertex scale_tex_vertices[TMU_MESH_MAXSIZE][TMU_MESH_MAXSIZE] __attribute__((aligned(8)));
57
58 void rpipe_init()
59 {
60         produce = 0;
61         consume = 0;
62         level = 0;
63         cts = 1;
64
65         frames = 0;
66         fps = 0;
67
68         run_wave_bottom_half = 0;
69         run_swap_bottom_half = 0;
70
71         scale_tex_vertices[0][0].x = 0;
72         scale_tex_vertices[0][0].y = 0;
73         scale_tex_vertices[0][1].x = renderer_texsize << TMU_FIXEDPOINT_SHIFT;
74         scale_tex_vertices[0][1].y = 0;
75         scale_tex_vertices[1][0].x = 0;
76         scale_tex_vertices[1][0].y = renderer_texsize << TMU_FIXEDPOINT_SHIFT;
77         scale_tex_vertices[1][1].x = renderer_texsize << TMU_FIXEDPOINT_SHIFT;
78         scale_tex_vertices[1][1].y = renderer_texsize << TMU_FIXEDPOINT_SHIFT;
79
80         tex_frontbuffer = texbufferA;
81         tex_backbuffer = texbufferB;
82         
83         printf("RPI: rendering pipeline ready\n");
84 }
85
86 static struct tmu_td tmu_task1;
87 static struct tmu_td tmu_task2;
88 static struct tmu_td tmu_task3;
89
90 static void rpipe_tmu_warpdone(struct tmu_td *td)
91 {
92         bh_frame = (struct rpipe_frame *)td->user;
93         run_wave_bottom_half = 1;
94 }
95
96 static unsigned int get_tmu_wrap_mask(unsigned int x)
97 {
98         unsigned int s;
99
100         s = 1 << TMU_FIXEDPOINT_SHIFT;
101         return (x-1)*s+s-1;
102 }
103
104 static void rpipe_start(struct rpipe_frame *frame)
105 {
106         unsigned int mask;
107         
108         if(frame->tex_wrap)
109                 mask = get_tmu_wrap_mask(renderer_texsize);
110         else
111                 mask = TMU_MASK_FULL;
112
113         tmu_task1.flags = 0;
114         tmu_task1.hmeshlast = renderer_hmeshlast;
115         tmu_task1.vmeshlast = renderer_vmeshlast;
116         tmu_task1.brightness = frame->brightness;
117         tmu_task1.chromakey = 0;
118         tmu_task1.vertices = &frame->vertices[0][0];
119         tmu_task1.texfbuf = tex_frontbuffer;
120         tmu_task1.texhres = renderer_texsize;
121         tmu_task1.texvres = renderer_texsize;
122         tmu_task1.texhmask = mask;
123         tmu_task1.texvmask = mask;
124         tmu_task1.dstfbuf = tex_backbuffer;
125         tmu_task1.dsthres = renderer_texsize;
126         tmu_task1.dstvres = renderer_texsize;
127         tmu_task1.dsthoffset = 0;
128         tmu_task1.dstvoffset = 0;
129         tmu_task1.dstsquarew = renderer_texsize/renderer_hmeshlast;
130         tmu_task1.dstsquareh = renderer_texsize/renderer_vmeshlast;
131         tmu_task1.alpha = TMU_ALPHA_MAX;
132
133         tmu_task1.callback = rpipe_tmu_warpdone;
134         tmu_task1.user = frame;
135         tmu_submit_task(&tmu_task1);
136 }
137
138 int rpipe_input(struct rpipe_frame *frame)
139 {
140         if(level >= RPIPE_FRAMEQ_SIZE) {
141                 printf("RPI: taskq overflow\n");
142                 return 0;
143         }
144
145         queue[produce] = frame;
146         produce = (produce + 1) & RPIPE_FRAMEQ_MASK;
147         level++;
148
149         if(cts) {
150                 rpipe_start(frame);
151                 cts = 0;
152         }
153         return 1;
154 }
155
156 static void draw_dot(struct line_context *ctx, int x, int y, unsigned int l)
157 {
158         // TODO: make them round and nice looking
159         l >>= 1;
160         hline(ctx, y, x-l, x+l);
161 }
162
163 static void rpipe_draw_motion_vectors()
164 {
165         int x, y;
166         struct line_context ctx;
167         float offsetx;
168         float intervalx;
169         float offsety;
170         float intervaly;
171         int nx, ny;
172         int l;
173         int px, py;
174
175         if(bh_frame->mv_a == 0.0) return;
176         if(bh_frame->mv_x == 0.0) return;
177         if(bh_frame->mv_y == 0.0) return;
178         
179         l = bh_frame->mv_l;
180         if(l < 1) l = 1;
181         if(l > 10) l = 10;
182         
183         line_init_context(&ctx, tex_backbuffer, renderer_texsize, renderer_texsize);
184         ctx.color = float_to_rgb565(bh_frame->mv_r, bh_frame->mv_g, bh_frame->mv_b);
185         ctx.alpha = 64.0*bh_frame->mv_a;
186         ctx.thickness = l;
187
188         offsetx = bh_frame->mv_dx*(float)renderer_texsize;
189         intervalx = (float)renderer_texsize/bh_frame->mv_x;
190         offsety = bh_frame->mv_dy*renderer_texsize;
191         intervaly = (float)renderer_texsize/bh_frame->mv_y;
192
193         nx = bh_frame->mv_x+1.5;
194         ny = bh_frame->mv_y+1.5;
195         for(y=0;y<ny;y++)
196                 for (x=0;x<nx;x++) {
197                         px = offsetx+x*intervalx;
198                         if(px < 0) px = 0;
199                         if(px >= renderer_texsize) px = renderer_texsize-1;
200                         py = offsety+y*intervaly;
201                         if(py < 0) py = 0;
202                         if(py >= renderer_texsize) py = renderer_texsize-1;
203                         draw_dot(&ctx, px, py, l);
204                 }
205 }
206
207 static void border_rect(int x0, int y0, int x1, int y1, short int color, unsigned int alpha)
208 {
209         int y;
210         struct line_context ctx;
211
212         line_init_context(&ctx, tex_backbuffer, renderer_texsize, renderer_texsize);
213         ctx.color = color;
214         ctx.alpha = alpha;
215         for(y=y0;y<=y1;y++)
216                 hline(&ctx, y, x0, x1);
217 }
218
219 static void rpipe_draw_borders()
220 {
221         unsigned int of;
222         unsigned int iff;
223         unsigned int texof;
224         short int ob_color, ib_color;
225         unsigned int ob_alpha, ib_alpha;
226         int cmax;
227
228         of = renderer_texsize*bh_frame->ob_size*.5;
229         iff = renderer_texsize*bh_frame->ib_size*.5;
230
231         if(of > 30) of = 30;
232         if(iff > 30) iff = 30;
233         
234         texof = renderer_texsize-of;
235         cmax = renderer_texsize-1;
236
237         ob_alpha = 80.0*bh_frame->ob_a;
238         if((of != 0) && (ob_alpha != 0)) {
239                 ob_color = float_to_rgb565(bh_frame->ob_r, bh_frame->ob_g, bh_frame->ob_b);
240                 
241
242                 border_rect(0, 0, of, cmax, ob_color, ob_alpha);
243                 border_rect(of, 0, texof, of, ob_color, ob_alpha);
244                 border_rect(texof, 0, cmax, cmax, ob_color, ob_alpha);
245                 border_rect(of, texof, texof, cmax, ob_color, ob_alpha);
246         }
247
248         ib_alpha = 80.0*bh_frame->ib_a;
249         if((iff != 0) && (ib_alpha != 0)) {
250                 ib_color = float_to_rgb565(bh_frame->ib_r, bh_frame->ib_g, bh_frame->ib_b);
251
252                 border_rect(of, of, of+iff-1, texof-1, ib_color, ib_alpha);
253                 border_rect(of+iff, of, texof-iff-1, of+iff-1, ib_color, ib_alpha);
254                 border_rect(texof-iff, of, texof-1, texof-1, ib_color, ib_alpha);
255                 border_rect(of+iff, texof-iff, texof-iff-1, texof-1, ib_color, ib_alpha);
256         }
257 }
258
259 /* TODO: implement missing wave modes */
260
261 static int wave_mode_0(struct wave_vertex *vertices)
262 {
263         return 0;
264 }
265
266 static int wave_mode_1(struct wave_vertex *vertices)
267 {
268         return 0;
269 }
270
271 static int wave_mode_23(struct wave_vertex *vertices)
272 {
273         int nvertices;
274         int i;
275         float s1, s2;
276
277         nvertices = 128-32;
278
279         for(i=0;i<nvertices;i++) {
280                 s1 = bh_frame->samples[8*i     ]/32768.0;
281                 s2 = bh_frame->samples[8*i+32+1]/32768.0;
282                 
283                 vertices[i].x = (s1*bh_frame->wave_scale*0.5 + bh_frame->wave_x)*renderer_texsize;
284                 vertices[i].y = (s2*bh_frame->wave_scale*0.5 + bh_frame->wave_x)*renderer_texsize;
285         }
286         
287         return nvertices;
288 }
289
290 static int wave_mode_4(struct wave_vertex *vertices)
291 {
292         int nvertices;
293         float wave_x;
294         int i;
295         float dy_adj;
296         float s1, s2;
297         float scale;
298
299         nvertices = 128;
300
301         // TODO: rotate using wave_mystery
302         wave_x = bh_frame->wave_x*.75 + .125;
303         scale = 4.0*(float)renderer_texsize/505.0;
304
305         for(i=1;i<=nvertices;i++) {
306                 s1 = bh_frame->samples[8*i]/32768.0;
307                 s2 = bh_frame->samples[8*i-2]/32768.0;
308                 
309                 dy_adj = s1*20.0*bh_frame->wave_scale-s2*20.0*bh_frame->wave_scale;
310                 // nb: x and y reversed to simulate default rotation from wave_mystery
311                 vertices[i-1].y = s1*20.0*bh_frame->wave_scale+(float)renderer_texsize*bh_frame->wave_x;
312                 vertices[i-1].x = (i*scale)+dy_adj;
313         }
314
315         return nvertices;
316 }
317
318 static int wave_mode_5(struct wave_vertex *vertices)
319 {
320         int nvertices;
321         int i;
322         float s1, s2;
323         float x0, y0;
324         float cos_rot, sin_rot;
325
326         nvertices = 128-64;
327
328         cos_rot = cosf(bh_frame->time*0.3);
329         sin_rot = sinf(bh_frame->time*0.3);
330
331         for(i=0;i<nvertices;i++) {
332                 s1 = bh_frame->samples[8*i     ]/32768.0;
333                 s2 = bh_frame->samples[8*i+64+1]/32768.0;
334                 x0 = 2.0*s1*s2;
335                 y0 = s1*s1 - s2*s2;
336
337                 vertices[i].x = (float)renderer_texsize*((x0*cos_rot - y0*sin_rot)*bh_frame->wave_scale*0.5 + bh_frame->wave_x);
338                 vertices[i].y = (float)renderer_texsize*((x0*sin_rot + y0*cos_rot)*bh_frame->wave_scale*0.5 + bh_frame->wave_y);
339         }
340
341         return nvertices;
342 }
343
344 static int wave_mode_6(struct wave_vertex *vertices)
345 {
346         int nvertices;
347         int i;
348         float inc;
349         float offset;
350         float s;
351
352         nvertices = 128;
353
354         // TODO: rotate/scale by wave_mystery
355
356         inc = (float)renderer_texsize/(float)nvertices;
357         offset = (float)renderer_texsize*(1.0-bh_frame->wave_x);
358         for(i=0;i<nvertices;i++) {
359                 s = bh_frame->samples[8*i]/32768.0;
360                 // nb: x and y reversed to simulate default rotation from wave_mystery
361                 vertices[i].y = s*20.0*bh_frame->wave_scale+offset;
362                 vertices[i].x = i*inc;
363         }
364         
365         return nvertices;
366 }
367
368 static int wave_mode_7(struct wave_vertex *vertices)
369 {
370         return 0;
371 }
372
373 static int wave_mode_8(struct wave_vertex *vertices)
374 {
375         return 0;
376 }
377
378 static void rpipe_draw_waves()
379 {
380         struct wave_params params;
381         struct wave_vertex vertices[256];
382         int nvertices;
383
384         /*
385          * We assume that the VGA back buffer is not in any cache
386          * (such a cached copy would be incoherent because the TMU
387          * has just written it, straight to SDRAM).
388          */
389
390         params.wave_mode = bh_frame->wave_mode;
391         params.wave_additive = bh_frame->wave_additive;
392         params.wave_dots = bh_frame->wave_usedots;
393         params.wave_brighten = bh_frame->wave_brighten;
394         params.wave_thick = bh_frame->wave_thick;
395         
396         params.wave_r = bh_frame->wave_r;
397         params.wave_g = bh_frame->wave_g;
398         params.wave_b = bh_frame->wave_b;
399         params.wave_a = bh_frame->wave_a;
400         
401         params.treb = bh_frame->treb;
402
403         switch(bh_frame->wave_mode) {
404                 case 0:
405                         nvertices = wave_mode_0(vertices);
406                         break;
407                 case 1:
408                         nvertices = wave_mode_1(vertices);
409                         break;
410                 case 2:
411                 case 3:
412                         nvertices = wave_mode_23(vertices);
413                         break;
414                 case 4:
415                         nvertices = wave_mode_4(vertices);
416                         break;
417                 case 5:
418                         nvertices = wave_mode_5(vertices);
419                         break;
420                 case 6:
421                         nvertices = wave_mode_6(vertices);
422                         break;
423                 case 7:
424                         nvertices = wave_mode_7(vertices);
425                         break;
426                 case 8:
427                         nvertices = wave_mode_8(vertices);
428                         break;
429                 default:
430                         nvertices = 0;
431                         break;
432         }
433
434         wave_draw(tex_backbuffer, renderer_texsize, renderer_texsize, &params, vertices, nvertices);
435 }
436
437 static void rpipe_tmu_copydone(struct tmu_td *td)
438 {
439         run_swap_bottom_half = 1;
440 }
441
442 static struct tmu_vertex vecho_vertices[TMU_MESH_MAXSIZE][TMU_MESH_MAXSIZE] __attribute__((aligned(8)));
443
444 static void rpipe_compute_vecho_vertices()
445 {
446         int a, b;
447         
448         a = (32.0-32.0/bh_frame->vecho_zoom)*(float)renderer_texsize;
449         b = renderer_texsize*64 - a;
450         
451         if((bh_frame->vecho_orientation == 1) || (bh_frame->vecho_orientation == 3)) {
452                 vecho_vertices[0][0].x = b;
453                 vecho_vertices[0][1].x = a;
454                 vecho_vertices[1][0].x = b;
455                 vecho_vertices[1][1].x = a;
456         } else {
457                 vecho_vertices[0][0].x = a;
458                 vecho_vertices[0][1].x = b;
459                 vecho_vertices[1][0].x = a;
460                 vecho_vertices[1][1].x = b;
461         }
462         if((bh_frame->vecho_orientation == 2) || (bh_frame->vecho_orientation == 3)) {
463                 vecho_vertices[0][0].y = b;
464                 vecho_vertices[0][1].y = b;
465                 vecho_vertices[1][0].y = a;
466                 vecho_vertices[1][1].y = a;
467         } else {
468                 vecho_vertices[0][0].y = a;
469                 vecho_vertices[0][1].y = a;
470                 vecho_vertices[1][0].y = b;
471                 vecho_vertices[1][1].y = b;
472         }
473 }
474
475 static void rpipe_compose_screen()
476 {
477         int vecho_alpha;
478         int vecho_enabled;
479         int osd_enabled;
480
481         vecho_alpha = 64.0*bh_frame->vecho_alpha;
482         vecho_enabled = vecho_alpha > 0;
483         vecho_alpha--;
484         if(vecho_alpha > TMU_ALPHA_MAX)
485                 vecho_alpha = TMU_ALPHA_MAX;
486
487         osd_enabled = osd_fill_blit_td(&tmu_task1, rpipe_tmu_copydone, NULL);
488
489         /* 1. Draw texture */
490         tmu_task3.flags = 0;
491         tmu_task3.hmeshlast = 1;
492         tmu_task3.vmeshlast = 1;
493         tmu_task3.brightness = TMU_BRIGHTNESS_MAX;
494         tmu_task3.chromakey = 0;
495         tmu_task3.vertices = &scale_tex_vertices[0][0];
496         tmu_task3.texfbuf = tex_backbuffer;
497         tmu_task3.texhres = renderer_texsize;
498         tmu_task3.texvres = renderer_texsize;
499         tmu_task3.texhmask = TMU_MASK_FULL;
500         tmu_task3.texvmask = TMU_MASK_FULL;
501         tmu_task3.dstfbuf = vga_backbuffer;
502         tmu_task3.dsthres = vga_hres;
503         tmu_task3.dstvres = vga_vres;
504         tmu_task3.dsthoffset = 0;
505         tmu_task3.dstvoffset = 0;
506         tmu_task3.dstsquarew = vga_hres;
507         tmu_task3.dstsquareh = vga_vres;
508         tmu_task3.alpha = TMU_ALPHA_MAX;
509         if(osd_enabled || vecho_enabled)
510                 tmu_task3.callback = NULL;
511         else
512                 tmu_task3.callback = rpipe_tmu_copydone;
513         tmu_task3.user = NULL;
514         tmu_submit_task(&tmu_task3);
515
516         /* 2. Draw video echo */
517         if(vecho_enabled) {
518                 rpipe_compute_vecho_vertices();
519                 tmu_task2.flags = 0;
520                 tmu_task2.hmeshlast = 1;
521                 tmu_task2.vmeshlast = 1;
522                 tmu_task2.brightness = TMU_BRIGHTNESS_MAX;
523                 tmu_task2.chromakey = 0;
524                 tmu_task2.vertices = &vecho_vertices[0][0];
525                 tmu_task2.texfbuf = tex_backbuffer;
526                 tmu_task2.texhres = renderer_texsize;
527                 tmu_task2.texvres = renderer_texsize;
528                 tmu_task2.texhmask = TMU_MASK_FULL;
529                 tmu_task2.texvmask = TMU_MASK_FULL;
530                 tmu_task2.dstfbuf = vga_backbuffer;
531                 tmu_task2.dsthres = vga_hres;
532                 tmu_task2.dstvres = vga_vres;
533                 tmu_task2.dsthoffset = 0;
534                 tmu_task2.dstvoffset = 0;
535                 tmu_task2.dstsquarew = vga_hres;
536                 tmu_task2.dstsquareh = vga_vres;
537                 tmu_task2.alpha = vecho_alpha;
538                 if(osd_enabled)
539                         tmu_task2.callback = NULL;
540                 else
541                         tmu_task2.callback = rpipe_tmu_copydone;
542                 tmu_task2.user = NULL;
543                 tmu_submit_task(&tmu_task2);
544         }
545
546         /* 3. Draw OSD */
547         if(osd_enabled)
548                 tmu_submit_task(&tmu_task1);
549 }
550
551 static void rpipe_wave_bottom_half()
552 {
553         rpipe_draw_motion_vectors();
554         rpipe_draw_borders();
555         rpipe_draw_waves();
556         flush_bridge_cache();
557         rpipe_compose_screen();
558 }
559
560 void rpipe_swap_bottom_half()
561 {
562         unsigned short *b;
563         unsigned int oldmask;
564         
565         /* Swap texture buffers */
566         b = tex_backbuffer;
567         tex_backbuffer = tex_frontbuffer;
568         tex_frontbuffer = b;
569
570         /* Update display */
571         vga_swap_buffers();
572
573         /* Update statistics */
574         oldmask = irq_getmask();
575         irq_setmask(oldmask & ~(IRQ_TIMER0));
576         frames++;
577         irq_setmask(oldmask);
578
579         /* Ready to process the next frame ! */
580         queue[consume]->callback(queue[consume]);
581         consume = (consume + 1) & RPIPE_FRAMEQ_MASK;
582         level--;
583         if(level > 0)
584                 rpipe_start(queue[consume]);
585         else
586                 cts = 1;
587 }
588
589 void rpipe_service()
590 {
591         if(run_wave_bottom_half) {
592                 cpustats_enter();
593                 run_wave_bottom_half = 0;
594                 rpipe_wave_bottom_half();
595                 cpustats_leave();
596         }
597
598         if(run_swap_bottom_half) {
599                 cpustats_enter();
600                 run_swap_bottom_half = 0;
601                 rpipe_swap_bottom_half();
602                 cpustats_leave();
603         }
604 }
605
606 void rpipe_tick()
607 {
608         fps = frames;
609         frames = 0;
610 }
611
612 int rpipe_fps()
613 {
614         return fps;
615 }