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