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