1 /*
2    Copyright (c) 2003 Andreas Robinson, All rights reserved.
3 
4    This library is free software; you can redistribute it and/or
5    modify it under the terms of the GNU Lesser General Public
6    License as published by the Free Software Foundation; either
7    version 2 of the License, or (at your option) any later version.
8 */
9 
10 #include <config.h>
11 
12 #include <direct/messages.h>
13 
14 #include <gfx/convert.h>
15 
16 #include "unichrome.h"
17 #include "uc_accel.h"
18 #include "uc_fifo.h"
19 #include "mmio.h"
20 
21 #define UC_ACCEL_BEGIN()                        \
22     UcDriverData *ucdrv = (UcDriverData*) drv;  \
23     UcDeviceData *ucdev = (UcDeviceData*) dev;  \
24     struct uc_fifo *fifo = ucdrv->fifo;         \
25     /*printf("entering %s\n", __PRETTY_FUNCTION__)*/
26 
27 #define UC_ACCEL_END()                                      \
28     UC_FIFO_CHECK(fifo);                                    \
29     /*printf("leaving %s\n", __PRETTY_FUNCTION__)*/
30 
31 // Private functions ---------------------------------------------------------
32 
33 /** Wait until a new command can be set up. */
34 
uc_waitcmd(UcDriverData * ucdrv,UcDeviceData * ucdev)35 static inline void uc_waitcmd(UcDriverData* ucdrv, UcDeviceData* ucdev)
36 {
37     int loop = 0;
38 
39     if (!ucdev->must_wait)
40         return;
41 
42     //printf("waitcmd ");
43 
44     while (VIA_IN(ucdrv->hwregs, VIA_REG_STATUS) & VIA_CMD_RGTR_BUSY) {
45         if (++loop > MAXLOOP) {
46             D_ERROR("DirectFB/VIA: Timeout waiting for idle command regulator!\n");
47             break;
48         }
49     }
50 
51     //printf("waited for %d (0x%x) cycles.\n", loop, loop);
52 
53     ucdev->cmd_waitcycles += loop;
54     ucdev->must_wait = 0;
55 }
56 
57 /** Send commands to 2D/3D engine. */
58 
uc_emit_commands(void * drv,void * dev)59 void uc_emit_commands(void* drv, void* dev)
60 {
61     UC_ACCEL_BEGIN()
62 
63     uc_waitcmd(ucdrv, ucdev);
64 
65     UC_FIFO_FLUSH(fifo);
66 
67     ucdev->must_wait = 1;
68 }
69 
uc_flush_texture_cache(void * drv,void * dev)70 void uc_flush_texture_cache(void* drv, void* dev)
71 {
72     UC_ACCEL_BEGIN()
73 
74     (void) ucdev;
75 
76     UC_FIFO_PREPARE(fifo, 4);
77 
78     UC_FIFO_ADD_HDR(fifo, (HC_ParaType_Tex << 16) | (HC_SubType_TexGeneral << 24));
79     UC_FIFO_ADD_3D(fifo, HC_SubA_HTXSMD, HC_HTXCHCLR_MASK);
80     UC_FIFO_ADD_3D(fifo, HC_SubA_HTXSMD, 0);
81 
82     UC_FIFO_CHECK(fifo);
83 }
84 
85 /**
86  * Draw a horizontal or vertical line.
87  *
88  * @param fifo          command FIFO
89  *
90  * @param x             start x position
91  * @param y             start y position
92  * @param len           length
93  * @param hv            if zero: draw from left to right
94  *                      if nonzero: draw from top to bottom.
95  *
96  * @note This is actually a 1-pixel high or wide rectangular color fill.
97  */
98 
uc_draw_hv_line(struct uc_fifo * fifo,int x,int y,int len,int hv,int rop)99 static inline void uc_draw_hv_line(struct uc_fifo* fifo,
100                                    int x, int y, int len, int hv, int rop)
101 {
102     UC_FIFO_ADD_2D(fifo, VIA_REG_DSTPOS, ((RS16(y) << 16) | RS16(x)));
103     UC_FIFO_ADD_2D(fifo, VIA_REG_DIMENSION, len << (hv ? 16 : 0));
104     UC_FIFO_ADD_2D(fifo, VIA_REG_GECMD, VIA_GEC_BLT | VIA_GEC_FIXCOLOR_PAT
105         | rop | VIA_GEC_CLIP_ENABLE);
106 }
107 
108 // DirectFB interfacing functions --------------------------------------------
109 
110 // Functions using the 2D engine ---
111 
uc_fill_rectangle(void * drv,void * dev,DFBRectangle * r)112 bool uc_fill_rectangle(void* drv, void* dev, DFBRectangle* r)
113 {
114     UC_ACCEL_BEGIN()
115 
116     //printf("%s: r = {%d, %d, %d, %d}, c = 0x%08x\n", __PRETTY_FUNCTION__,
117     //  r->x, r->y, r->w, r->h, ucdev->color);
118 
119     if (r->w == 0 || r->h == 0) return true;
120 
121     UC_FIFO_PREPARE(fifo, 8);
122 
123     UC_FIFO_ADD_HDR(fifo, HC_ParaType_NotTex << 16);
124 
125     UC_FIFO_ADD_2D(fifo, VIA_REG_DSTPOS, ((RS16(r->y) << 16) | RS16(r->x)));
126     UC_FIFO_ADD_2D(fifo, VIA_REG_DIMENSION,
127         (((RS16(r->h - 1)) << 16) | RS16((r->w - 1))));
128     UC_FIFO_ADD_2D(fifo, VIA_REG_GECMD, VIA_GEC_BLT | VIA_GEC_FIXCOLOR_PAT
129         | ucdev->draw_rop2d | VIA_GEC_CLIP_ENABLE);
130 
131     UC_ACCEL_END();
132     return true;
133 }
134 
uc_draw_rectangle(void * drv,void * dev,DFBRectangle * r)135 bool uc_draw_rectangle(void* drv, void* dev, DFBRectangle* r)
136 {
137     UC_ACCEL_BEGIN()
138 
139     //printf("%s: r = {%d, %d, %d, %d}, c = 0x%08x\n", __PRETTY_FUNCTION__,
140     //  r->x, r->y, r->w, r->h, ucdev->color);
141 
142     int rop = ucdev->draw_rop2d;
143 
144     // Draw lines, in this order: top, bottom, left, right
145 
146     UC_FIFO_PREPARE(fifo, 26);
147 
148     UC_FIFO_ADD_HDR(fifo, HC_ParaType_NotTex << 16);
149 
150     uc_draw_hv_line(fifo, r->x, r->y, r->w - 1, 0, rop);
151     uc_draw_hv_line(fifo, r->x, r->y + r->h - 1, r->w - 1, 0, rop);
152     uc_draw_hv_line(fifo, r->x, r->y, r->h - 1, 1, rop);
153     uc_draw_hv_line(fifo, r->x + r->w - 1, r->y, r->h - 1, 1, rop);
154 
155     UC_ACCEL_END();
156     return true;
157 }
158 
uc_draw_line(void * drv,void * dev,DFBRegion * line)159 bool uc_draw_line(void* drv, void* dev, DFBRegion* line)
160 {
161     UC_ACCEL_BEGIN()
162 
163     //printf("%s: l = (%d, %d) - (%d, %d), c = 0x%08x\n", __PRETTY_FUNCTION__,
164     //  line->x1, line->y1, line->x2, line->y2, ucdev->color);
165 
166     int cmd;
167     int dx, dy, tmp, error;
168 
169     error = 1;
170 
171     cmd = VIA_GEC_LINE | VIA_GEC_FIXCOLOR_PAT | ucdev->draw_rop2d
172         | VIA_GEC_CLIP_ENABLE;
173 
174     dx = line->x2 - line->x1;
175     if (dx < 0)
176     {
177         dx = -dx;
178         cmd |= VIA_GEC_DECX;        // line will be drawn from right
179         error = 0;
180     }
181 
182     dy = line->y2 - line->y1;
183     if (dy < 0)
184     {
185         dy = -dy;
186         cmd |= VIA_GEC_DECY;        // line will be drawn from bottom
187     }
188 
189     if (dy > dx)
190     {
191         tmp  = dy;
192         dy = dx;
193         dx = tmp;                   // Swap 'dx' and 'dy'
194         cmd |= VIA_GEC_Y_MAJOR;     // Y major line
195     }
196 
197     UC_FIFO_PREPARE(fifo, 12);
198 
199     UC_FIFO_ADD_HDR(fifo, HC_ParaType_NotTex << 16);
200 
201     UC_FIFO_ADD_2D(fifo, VIA_REG_LINE_K1K2,
202         ((((dy << 1) & 0x3fff) << 16)| (((dy - dx) << 1) & 0x3fff)));
203     UC_FIFO_ADD_2D(fifo, VIA_REG_LINE_XY,
204         ((RS16(line->y1) << 16) | RS16(line->x1)));
205     UC_FIFO_ADD_2D(fifo, VIA_REG_DIMENSION, dx);
206     UC_FIFO_ADD_2D(fifo, VIA_REG_LINE_ERROR,
207         (((dy << 1) - dx - error) & 0x3fff));
208     UC_FIFO_ADD_2D(fifo, VIA_REG_GECMD, cmd);
209 
210     UC_ACCEL_END();
211     return true;
212 }
213 
uc_blit(void * drv,void * dev,DFBRectangle * rect,int dx,int dy)214 bool uc_blit(void* drv, void* dev, DFBRectangle* rect, int dx, int dy)
215 {
216     UC_ACCEL_BEGIN()
217 
218     //printf("%s: r = (%d, %d, %d, %d) -> (%d, %d)\n", __PRETTY_FUNCTION__,
219     //  rect->x, rect->y, rect->h, rect->w, dx, dy);
220 
221     int cmd = VIA_GEC_BLT | VIA_ROP_S | VIA_GEC_CLIP_ENABLE;
222 
223     int sx = rect->x;
224     int sy = rect->y;
225     int w = rect->w;
226     int h = rect->h;
227 
228     if (!w || !h) return true;
229 
230     (void) ucdev; // Kill 'unused variable' compiler warning.
231 
232     if (sx < dx) {
233         cmd |= VIA_GEC_DECX;
234         sx += w - 1;
235         dx += w - 1;
236     }
237 
238     if (sy < dy) {
239         cmd |= VIA_GEC_DECY;
240         sy += h - 1;
241         dy += h - 1;
242     }
243 
244     UC_FIFO_PREPARE(fifo, 10);
245 
246     UC_FIFO_ADD_HDR(fifo, HC_ParaType_NotTex << 16);
247 
248     UC_FIFO_ADD_2D(fifo, VIA_REG_SRCPOS, (RS16(sy) << 16) | RS16(sx));
249     UC_FIFO_ADD_2D(fifo, VIA_REG_DSTPOS, (RS16(dy) << 16) | RS16(dx));
250     UC_FIFO_ADD_2D(fifo, VIA_REG_DIMENSION, (RS16(h - 1) << 16) | RS16(w - 1));
251     UC_FIFO_ADD_2D(fifo, VIA_REG_GECMD, cmd);
252 
253     UC_ACCEL_END();
254     return true;
255 }
256 
257 // Functions using the 3D engine ---
258 
uc_fill_rectangle_3d(void * drv,void * dev,DFBRectangle * r)259 bool uc_fill_rectangle_3d(void* drv, void* dev, DFBRectangle* r)
260 {
261     UC_ACCEL_BEGIN()
262 
263     //printf("%s: r = {%d, %d, %d, %d}, c = 0x%08x\n", __PRETTY_FUNCTION__,
264     //  r->x, r->y, r->w, r->h, ucdev->color3d);
265 
266     int cmdB = HC_ACMD_HCmdB | HC_HVPMSK_X | HC_HVPMSK_Y | HC_HVPMSK_Cd;
267     int cmdA = HC_ACMD_HCmdA | HC_HPMType_Tri | HC_HVCycle_AFP |
268         HC_HVCycle_AA | HC_HVCycle_BB | HC_HVCycle_NewC | HC_HShading_FlatC;
269     int cmdA_End = cmdA | HC_HPLEND_MASK | HC_HPMValidN_MASK | HC_HE3Fire_MASK;
270 
271     if (r->w == 0 || r->h == 0) return true;
272 
273     UC_FIFO_PREPARE(fifo, 18);
274 
275     UC_FIFO_ADD_HDR(fifo, HC_ParaType_CmdVdata << 16);
276     UC_FIFO_ADD(fifo, cmdB);
277     UC_FIFO_ADD(fifo, cmdA);
278 
279     UC_FIFO_ADD_XYC(fifo, r->x, r->y, 0);
280     UC_FIFO_ADD_XYC(fifo, r->x + r->w, r->y + r->h, 0);
281     UC_FIFO_ADD_XYC(fifo, r->x + r->w, r->y, ucdev->color3d);
282     UC_FIFO_ADD_XYC(fifo, r->x, r->y + r->h, ucdev->color3d);
283 
284     UC_FIFO_ADD(fifo, cmdA_End);
285 
286     UC_FIFO_PAD_EVEN(fifo);
287 
288     UC_ACCEL_END();
289     return true;
290 }
291 
uc_draw_rectangle_3d(void * drv,void * dev,DFBRectangle * r)292 bool uc_draw_rectangle_3d(void* drv, void* dev, DFBRectangle* r)
293 {
294     UC_ACCEL_BEGIN()
295 
296     int cmdB = HC_ACMD_HCmdB | HC_HVPMSK_X | HC_HVPMSK_Y | HC_HVPMSK_Cd;
297     int cmdA = HC_ACMD_HCmdA | HC_HPMType_Line | HC_HVCycle_AFP | HC_HShading_FlatA;
298     int cmdA_End = cmdA | HC_HPLEND_MASK | HC_HPMValidN_MASK | HC_HE3Fire_MASK;
299 
300     UC_FIFO_PREPARE(fifo, 20);
301 
302     UC_FIFO_ADD_HDR(fifo, HC_ParaType_CmdVdata << 16);
303     UC_FIFO_ADD(fifo, cmdB);
304     UC_FIFO_ADD(fifo, cmdA);
305 
306     UC_FIFO_ADD_XYC(fifo, r->x, r->y, ucdev->color3d);
307     UC_FIFO_ADD_XYC(fifo, r->x + r->w - 1, r->y, ucdev->color3d);
308     UC_FIFO_ADD_XYC(fifo, r->x + r->w - 1, r->y + r->h - 1, ucdev->color3d);
309     UC_FIFO_ADD_XYC(fifo, r->x, r->y + r->h - 1, ucdev->color3d);
310     UC_FIFO_ADD_XYC(fifo, r->x, r->y, ucdev->color3d);
311 
312     UC_FIFO_ADD(fifo, cmdA_End);
313 
314     UC_ACCEL_END();
315     return true;
316 }
317 
uc_draw_line_3d(void * drv,void * dev,DFBRegion * line)318 bool uc_draw_line_3d(void* drv, void* dev, DFBRegion* line)
319 {
320     UC_ACCEL_BEGIN()
321 
322     int cmdB = HC_ACMD_HCmdB | HC_HVPMSK_X | HC_HVPMSK_Y | HC_HVPMSK_Cd;
323     int cmdA = HC_ACMD_HCmdA | HC_HPMType_Line | HC_HVCycle_Full | HC_HShading_FlatA;
324     int cmdA_End = cmdA | HC_HPLEND_MASK | HC_HPMValidN_MASK | HC_HE3Fire_MASK;
325 
326     UC_FIFO_PREPARE(fifo, 12);
327 
328     UC_FIFO_ADD_HDR(fifo, HC_ParaType_CmdVdata << 16);
329     UC_FIFO_ADD(fifo, cmdB);
330     UC_FIFO_ADD(fifo, cmdA);
331 
332     UC_FIFO_ADD_XYC(fifo, line->x1, line->y1, ucdev->color3d);
333     UC_FIFO_ADD_XYC(fifo, line->x2, line->y2, 0);
334 
335     UC_FIFO_ADD(fifo, cmdA_End);
336 
337     UC_FIFO_PAD_EVEN(fifo);
338 
339     UC_ACCEL_END();
340     return true;
341 }
342 
uc_fill_triangle(void * drv,void * dev,DFBTriangle * tri)343 bool uc_fill_triangle(void* drv, void* dev, DFBTriangle* tri)
344 {
345     UC_ACCEL_BEGIN()
346 
347     int cmdB = HC_ACMD_HCmdB | HC_HVPMSK_X | HC_HVPMSK_Y | HC_HVPMSK_Cd;
348     int cmdA = HC_ACMD_HCmdA | HC_HPMType_Tri | HC_HVCycle_Full | HC_HShading_FlatA;
349     int cmdA_End = cmdA | HC_HPLEND_MASK | HC_HPMValidN_MASK | HC_HE3Fire_MASK;
350 
351     UC_FIFO_PREPARE(fifo, 14);
352 
353     UC_FIFO_ADD_HDR(fifo, HC_ParaType_CmdVdata << 16);
354     UC_FIFO_ADD(fifo, cmdB);
355     UC_FIFO_ADD(fifo, cmdA);
356 
357     UC_FIFO_ADD_XYC(fifo, tri->x1, tri->y1, ucdev->color3d);
358     UC_FIFO_ADD_XYC(fifo, tri->x2, tri->y2, 0);
359     UC_FIFO_ADD_XYC(fifo, tri->x3, tri->y3, 0);
360 
361     UC_FIFO_ADD(fifo, cmdA_End);
362 
363     UC_ACCEL_END();
364     return true;
365 }
366 
uc_blit_3d(void * drv,void * dev,DFBRectangle * rect,int dx,int dy)367 bool uc_blit_3d(void* drv, void* dev,
368                 DFBRectangle* rect, int dx, int dy)
369 {
370     // TODO: Write separate blit function to save some overhead.
371 
372     // Hmm, I don't think we can save anything beyond a few CPU cycles. -- dok
373 
374     DFBRectangle dest = {dx, dy, rect->w, rect->h};
375     return uc_stretch_blit(drv, dev, rect, &dest);
376 }
377 
uc_stretch_blit(void * drv,void * dev,DFBRectangle * sr,DFBRectangle * dr)378 bool uc_stretch_blit(void* drv, void* dev,
379                      DFBRectangle* sr, DFBRectangle* dr)
380 {
381     UC_ACCEL_BEGIN()
382 
383     float w = ucdev->hwtex.l2w;
384     float h = ucdev->hwtex.l2h;
385 
386     float dy = dr->y;
387 
388     float s1 = (sr->x        ) / w;
389     float t1 = (sr->y        ) / h;
390     float s2 = (sr->x + sr->w) / w;
391     float t2 = (sr->y + sr->h) / h;
392 
393     int cmdB = HC_ACMD_HCmdB | HC_HVPMSK_X | HC_HVPMSK_Y | HC_HVPMSK_W |
394                HC_HVPMSK_Cd  | HC_HVPMSK_S | HC_HVPMSK_T;
395 
396     int cmdA = HC_ACMD_HCmdA | HC_HPMType_Tri | HC_HShading_FlatC |
397                HC_HVCycle_AFP | HC_HVCycle_AA | HC_HVCycle_BB | HC_HVCycle_NewC;
398 
399     int cmdA_End = cmdA | HC_HPLEND_MASK | HC_HPMValidN_MASK | HC_HE3Fire_MASK;
400 
401     if (ucdev->bflags & DSBLIT_DEINTERLACE) {
402          t1 *= 0.5f;
403          t2 *= 0.5f;
404 
405          if (ucdev->field)
406              dy += 0.5f;
407          else
408              dy -= 0.5f;
409     }
410 
411     UC_FIFO_PREPARE(fifo, 30);
412 
413     UC_FIFO_ADD_HDR(fifo, HC_ParaType_CmdVdata << 16);
414     UC_FIFO_ADD(fifo, cmdB);
415     UC_FIFO_ADD(fifo, cmdA);
416 
417     UC_FIFO_ADD_XYWCST(fifo, dr->x+dr->w, dy,       1, 0,              s2, t1);
418     UC_FIFO_ADD_XYWCST(fifo, dr->x,       dy+dr->h, 1, 0,              s1, t2);
419     UC_FIFO_ADD_XYWCST(fifo, dr->x,       dy,       1, ucdev->color3d, s1, t1);
420     UC_FIFO_ADD_XYWCST(fifo, dr->x+dr->w, dy+dr->h, 1, ucdev->color3d, s2, t2);
421 
422     UC_FIFO_ADD(fifo, cmdA_End);
423 
424     UC_FIFO_PAD_EVEN(fifo);
425 
426     UC_ACCEL_END();
427 
428     return true;
429 }
430 
431 #define DFBCOLOR_TO_ARGB(c)   PIXEL_ARGB( (c).a, (c).r, (c).g, (c).b )
432 
uc_texture_triangles(void * drv,void * dev,DFBVertex * vertices,int num,DFBTriangleFormation formation)433 bool uc_texture_triangles( void *drv, void *dev,
434                            DFBVertex *vertices, int num,
435                            DFBTriangleFormation formation )
436 {
437      UC_ACCEL_BEGIN()
438 
439      int i;
440 
441      int cmdB = HC_ACMD_HCmdB |
442                 HC_HVPMSK_X   | HC_HVPMSK_Y | HC_HVPMSK_Z | HC_HVPMSK_W |
443                 HC_HVPMSK_Cd  | HC_HVPMSK_S | HC_HVPMSK_T;
444 
445      int cmdA = HC_ACMD_HCmdA | HC_HPMType_Tri | HC_HShading_Gouraud |
446                 HC_HVCycle_Full;
447 
448      int cmdA_End = cmdA | HC_HPLEND_MASK | HC_HPMValidN_MASK | HC_HE3Fire_MASK;
449 
450 
451      switch (formation) {
452           case DTTF_LIST:
453                cmdA |= HC_HVCycle_NewA | HC_HVCycle_NewB | HC_HVCycle_NewC;
454                break;
455           case DTTF_STRIP:
456                cmdA |= HC_HVCycle_AB | HC_HVCycle_BC | HC_HVCycle_NewC;
457                break;
458           case DTTF_FAN:
459                cmdA |= HC_HVCycle_AA | HC_HVCycle_BC | HC_HVCycle_NewC;
460                break;
461           default:
462                D_ONCE( "unknown triangle formation" );
463                return false;
464      }
465 
466      UC_FIFO_PREPARE(fifo, 6 + num * 7);
467 
468      UC_FIFO_ADD_HDR(fifo, HC_ParaType_CmdVdata << 16);
469      UC_FIFO_ADD(fifo, cmdB);
470      UC_FIFO_ADD(fifo, cmdA);
471 
472      for (i=0; i<num; i++) {
473           UC_FIFO_ADD_XYZWCST(fifo,
474                               vertices[i].x, vertices[i].y,
475                               vertices[i].z, vertices[i].w, ucdev->color3d,
476                               vertices[i].s, vertices[i].t);
477      }
478 
479      UC_FIFO_ADD(fifo, cmdA_End);
480 
481      UC_FIFO_PAD_EVEN(fifo);
482 
483      UC_ACCEL_END();
484 
485      return true;
486 }
487 
488     // Blit profiling
489 
490     //struct timeval tv_start, tv_stop;
491     //gettimeofday(&tv_start, NULL);
492 
493     // Run test here
494 
495     //gettimeofday(&tv_stop, NULL);
496 
497     //tv_stop.tv_sec -= tv_start.tv_sec;
498     //tv_stop.tv_usec -= tv_start.tv_usec;
499     //if (tv_stop.tv_usec < 0) {
500     //  tv_stop.tv_sec--;
501     //  tv_stop.tv_usec += 1000000;
502     //}
503 
504     //printf("elapsed time: %d us\n", tv_stop.tv_usec);
505