Software support for the new TMU
[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 "rpipe.h"
31
32 #include "spam.h"
33
34 #define RPIPE_FRAMEQ_SIZE 4 /* < must be a power of 2 */
35 #define RPIPE_FRAMEQ_MASK (RPIPE_FRAMEQ_SIZE-1)
36
37 static struct rpipe_frame *queue[RPIPE_FRAMEQ_SIZE];
38 static unsigned int produce;
39 static unsigned int consume;
40 static unsigned int level;
41 static int cts;
42
43 struct rpipe_frame *bh_frame;
44 static int run_wave_bottom_half;
45 static int run_swap_bottom_half;
46
47 static unsigned int frames;
48 static unsigned int fps;
49 static unsigned int spam_counter;
50 int spam_enabled;
51
52 static unsigned short texbufferA[512*512];
53 static unsigned short texbufferB[512*512];
54 static unsigned short *tex_frontbuffer;
55 static unsigned short *tex_backbuffer;
56
57 static struct tmu_vertex scale_tex_vertices[TMU_MESH_MAXSIZE][TMU_MESH_MAXSIZE];
58
59 #define SPAM_W          75
60 #define SPAM_H          75
61 #define SPAM_X          545
62 #define SPAM_Y          30
63 #define SPAM_CHROMAKEY  0x001f
64
65 static struct tmu_vertex spam_vertices[TMU_MESH_MAXSIZE][TMU_MESH_MAXSIZE];
66
67 void rpipe_init()
68 {
69         produce = 0;
70         consume = 0;
71         level = 0;
72         cts = 1;
73
74         frames = 0;
75         fps = 0;
76         spam_counter = 0;
77         spam_enabled = 1;
78
79         run_wave_bottom_half = 0;
80         run_swap_bottom_half = 0;
81
82         scale_tex_vertices[0][0].x = 0;
83         scale_tex_vertices[0][0].y = 0;
84         scale_tex_vertices[0][1].x = renderer_texsize << TMU_FIXEDPOINT_SHIFT;
85         scale_tex_vertices[0][1].y = 0;
86         scale_tex_vertices[1][0].x = 0;
87         scale_tex_vertices[1][0].y = renderer_texsize << TMU_FIXEDPOINT_SHIFT;
88         scale_tex_vertices[1][1].x = renderer_texsize << TMU_FIXEDPOINT_SHIFT;
89         scale_tex_vertices[1][1].y = renderer_texsize << TMU_FIXEDPOINT_SHIFT;
90
91         spam_vertices[0][0].x = 0;
92         spam_vertices[0][0].y = 0;
93         spam_vertices[0][1].x = SPAM_W << TMU_FIXEDPOINT_SHIFT;
94         spam_vertices[0][1].y = 0;
95         spam_vertices[1][0].x = 0;
96         spam_vertices[1][0].y = SPAM_H << TMU_FIXEDPOINT_SHIFT;
97         spam_vertices[1][1].x = SPAM_W << TMU_FIXEDPOINT_SHIFT;
98         spam_vertices[1][1].y = SPAM_H << TMU_FIXEDPOINT_SHIFT;
99
100         tex_frontbuffer = texbufferA;
101         tex_backbuffer = texbufferB;
102         
103         printf("RPI: rendering pipeline ready\n");
104 }
105
106 static struct tmu_td tmu_task1;
107 static struct tmu_td tmu_task2;
108
109 static void rpipe_tmu_warpdone(struct tmu_td *td)
110 {
111         bh_frame = (struct rpipe_frame *)td->user;
112         run_wave_bottom_half = 1;
113 }
114
115 static void rpipe_start(struct rpipe_frame *frame)
116 {
117         tmu_task1.flags = 0;
118         tmu_task1.hmeshlast = renderer_hmeshlast;
119         tmu_task1.vmeshlast = renderer_hmeshlast;
120         tmu_task1.brightness = frame->brightness;
121         tmu_task1.chromakey = 0;
122         tmu_task1.vertices = &frame->vertices[0][0];
123         tmu_task1.texfbuf = tex_frontbuffer;
124         tmu_task1.texhres = renderer_texsize;
125         tmu_task1.texvres = renderer_texsize;
126         tmu_task1.texhmask = TMU_MASK_FULL;
127         tmu_task1.texvmask = TMU_MASK_FULL;
128         tmu_task1.dstfbuf = tex_backbuffer;
129         tmu_task1.dsthres = renderer_texsize;
130         tmu_task1.dstvres = renderer_texsize;
131         tmu_task1.dsthoffset = 0;
132         tmu_task1.dstvoffset = 0;
133         tmu_task1.dstsquarew = renderer_texsize/renderer_hmeshlast;
134         tmu_task1.dstsquareh = renderer_texsize/renderer_vmeshlast;
135
136         tmu_task1.callback = rpipe_tmu_warpdone;
137         tmu_task1.user = frame;
138         tmu_submit_task(&tmu_task1);
139 }
140
141 int rpipe_input(struct rpipe_frame *frame)
142 {
143         if(level >= RPIPE_FRAMEQ_SIZE) {
144                 printf("RPI: taskq overflow\n");
145                 return 0;
146         }
147
148         queue[produce] = frame;
149         produce = (produce + 1) & RPIPE_FRAMEQ_MASK;
150         level++;
151
152         if(cts) {
153                 rpipe_start(frame);
154                 cts = 0;
155         }
156         return 1;
157 }
158
159 /* TODO: implement missing wave modes */
160
161 static int wave_mode_0(struct wave_vertex *vertices)
162 {
163         return 0;
164 }
165
166 static int wave_mode_1(struct wave_vertex *vertices)
167 {
168         return 0;
169 }
170
171 static int wave_mode_2(struct wave_vertex *vertices)
172 {
173         return 0;
174 }
175
176 static int wave_mode_3(struct wave_vertex *vertices)
177 {
178         return 0;
179 }
180
181 static int wave_mode_4(struct wave_vertex *vertices)
182 {
183         return 0;
184 }
185
186 static int wave_mode_5(struct wave_vertex *vertices)
187 {
188         int nvertices;
189         int i;
190         float s1, s2;
191         float x0, y0;
192         float cos_rot, sin_rot;
193
194         nvertices = 128-64;
195
196         cos_rot = cosf(bh_frame->time*0.3f);
197         sin_rot = sinf(bh_frame->time*0.3f);
198
199         for(i=0;i<nvertices;i++) {
200                 s1 = bh_frame->samples[8*i     ]/32768.0;
201                 s2 = bh_frame->samples[8*i+64+1]/32768.0;
202                 x0 = 2.0*s1*s2;
203                 y0 = s1*s1 - s2*s2;
204
205                 vertices[i].x = (float)vga_hres*((x0*cos_rot - y0*sin_rot)*bh_frame->wave_scale*0.5 + bh_frame->wave_x);
206                 vertices[i].y = (float)vga_vres*((x0*sin_rot + y0*cos_rot)*bh_frame->wave_scale*0.5 + bh_frame->wave_y);
207         }
208
209         return nvertices;
210 }
211
212 static int wave_mode_6(struct wave_vertex *vertices)
213 {
214         return 0;
215 }
216
217 static int wave_mode_7(struct wave_vertex *vertices)
218 {
219         return 0;
220 }
221
222 static void rpipe_draw_waves()
223 {
224         struct wave_params params;
225         struct wave_vertex vertices[256];
226         int nvertices;
227
228         /*
229          * We assume that the VGA back buffer is not in any cache
230          * (such a cached copy would be incoherent because the TMU
231          * has just written it, straight to SDRAM).
232          */
233
234         params.wave_mode = bh_frame->wave_mode;
235         params.wave_additive = bh_frame->wave_additive;
236         params.wave_dots = bh_frame->wave_usedots;
237         params.wave_maximize_color = bh_frame->wave_maximize_color;
238         params.wave_thick = bh_frame->wave_thick;
239         
240         params.wave_r = bh_frame->wave_r;
241         params.wave_g = bh_frame->wave_g;
242         params.wave_b = bh_frame->wave_b;
243         params.wave_a = bh_frame->wave_a;
244         
245         params.treb = bh_frame->treb;
246
247         switch(bh_frame->wave_mode) {
248                 case 0:
249                         nvertices = wave_mode_0(vertices);
250                         break;
251                 case 1:
252                         nvertices = wave_mode_1(vertices);
253                         break;
254                 case 2:
255                         nvertices = wave_mode_2(vertices);
256                         break;
257                 case 3:
258                         nvertices = wave_mode_3(vertices);
259                         break;
260                 case 4:
261                         nvertices = wave_mode_4(vertices);
262                         break;
263                 case 5:
264                         nvertices = wave_mode_5(vertices);
265                         break;
266                 case 6:
267                         nvertices = wave_mode_6(vertices);
268                         break;
269                 case 7:
270                         nvertices = wave_mode_7(vertices);
271                         break;
272                 default:
273                         nvertices = 0;
274                         break;
275         }
276
277         wave_draw(tex_backbuffer, vga_hres, vga_vres, &params, vertices, nvertices);
278 }
279
280 static void rpipe_tmu_copydone(struct tmu_td *td)
281 {
282         run_swap_bottom_half = 1;
283 }
284
285 static void rpipe_wave_bottom_half()
286 {
287         rpipe_draw_waves();
288         flush_bridge_cache();
289
290         tmu_task2.flags = 0;
291         tmu_task2.hmeshlast = 1;
292         tmu_task2.vmeshlast = 1;
293         tmu_task2.brightness = TMU_BRIGHTNESS_MAX;
294         tmu_task2.chromakey = 0;
295         tmu_task2.vertices = &scale_tex_vertices[0][0];
296         tmu_task2.texfbuf = tex_backbuffer;
297         tmu_task2.texhres = renderer_texsize;
298         tmu_task2.texvres = renderer_texsize;
299         tmu_task2.texhmask = TMU_MASK_FULL;
300         tmu_task2.texvmask = TMU_MASK_FULL;
301         tmu_task2.dstfbuf = vga_backbuffer;
302         tmu_task2.dsthres = vga_hres;
303         tmu_task2.dstvres = vga_vres;
304         tmu_task2.dsthoffset = 0;
305         tmu_task2.dstvoffset = 0;
306         tmu_task2.dstsquarew = vga_hres;
307         tmu_task2.dstsquareh = vga_vres;
308         if(spam_enabled)
309                 tmu_task2.callback = NULL;
310         else
311                 tmu_task2.callback = rpipe_tmu_copydone;
312         tmu_task2.user = NULL;
313         
314         tmu_submit_task(&tmu_task2);
315
316         if(spam_enabled) {
317                 tmu_task1.flags = 0;
318                 tmu_task1.hmeshlast = 1;
319                 tmu_task1.vmeshlast = 1;
320                 tmu_task1.brightness = TMU_BRIGHTNESS_MAX;
321                 tmu_task1.chromakey = SPAM_CHROMAKEY;
322                 tmu_task1.vertices = &spam_vertices[0][0];
323                 tmu_task1.texfbuf = (unsigned short *)spam_raw;
324                 tmu_task1.texhres = SPAM_W;
325                 tmu_task1.texvres = SPAM_H;
326                 tmu_task1.texhmask = TMU_MASK_FULL;
327                 tmu_task1.texvmask = TMU_MASK_FULL;
328                 tmu_task1.dstfbuf = vga_backbuffer;
329                 tmu_task1.dsthres = vga_hres;
330                 tmu_task1.dstvres = vga_vres;
331                 tmu_task1.dsthoffset = SPAM_X;
332                 tmu_task1.dstvoffset = SPAM_Y;
333                 tmu_task1.dstsquarew = SPAM_W;
334                 tmu_task1.dstsquareh = SPAM_H;
335                 tmu_task1.callback = rpipe_tmu_copydone;
336                 tmu_task1.user = NULL;
337                 tmu_submit_task(&tmu_task1);
338         }
339 }
340
341 void rpipe_swap_bottom_half()
342 {
343         unsigned short *b;
344         unsigned int oldmask;
345         
346         /* Swap texture buffers */
347         b = tex_backbuffer;
348         tex_backbuffer = tex_frontbuffer;
349         tex_frontbuffer = b;
350
351         /* Update display */
352         vga_swap_buffers();
353
354         /* Update statistics */
355         oldmask = irq_getmask();
356         irq_setmask(oldmask & ~(IRQ_TIMER0));
357         frames++;
358         irq_setmask(oldmask);
359
360         /* Ready to process the next frame ! */
361         queue[consume]->callback(queue[consume]);
362         consume = (consume + 1) & RPIPE_FRAMEQ_MASK;
363         level--;
364         if(level > 0)
365                 rpipe_start(queue[consume]);
366         else
367                 cts = 1;
368 }
369
370 void rpipe_service()
371 {
372         if(run_wave_bottom_half) {
373                 cpustats_enter();
374                 rpipe_wave_bottom_half();
375                 run_wave_bottom_half = 0;
376                 cpustats_leave();
377         }
378
379         if(run_swap_bottom_half) {
380                 cpustats_enter();
381                 rpipe_swap_bottom_half();
382                 run_swap_bottom_half = 0;
383                 cpustats_leave();
384         }
385 }
386
387 void rpipe_tick()
388 {
389         fps = frames;
390         frames = 0;
391 }
392
393 int rpipe_fps()
394 {
395         return fps;
396 }