comparison Renderer/Engine/spe/DrawSpan.cc @ 507:735f76483bb2

Reorganization..
author Shinji KONO <kono@ie.u-ryukyu.ac.jp>
date Mon, 12 Oct 2009 09:39:35 +0900
parents
children 20166ecb1a78
comparison
equal deleted inserted replaced
506:1d4a8a86f26b 507:735f76483bb2
1 // #define DEBUG
2 #include "error.h"
3
4 #include <stdlib.h>
5 #include <string.h>
6 #include <spu_intrinsics.h>
7 #include "DrawSpan.h"
8 #include "polygon_pack.h"
9 #include "texture.h"
10 #include "viewer_types.h"
11 #include "Func.h"
12 #include "global_alloc.h"
13
14 SchedDefineTask(DrawSpan);
15 SchedDefineTask1(DrawSpanEnd,draw_span_end);
16
17 #define TEX_LOAD1 0
18 #define TEX_LOAD2 1
19 #define SPAN_PACK_LOAD 2
20 #define FB_STORE 3
21
22 static int
23 draw_span_end(SchedTask *s, void *rbuf, void *wbuf)
24 {
25 Gptr g = (Gptr)s->get_param(0);
26 s->dma_wait(FB_STORE);
27 free((void*)((int)g->linebuf*g->doneWrite));
28 free(g);
29 return 0;
30 }
31
32
33 inline vector float
34 spu_re_nrm(vector float a)
35 {
36 vector float unit = (vector float){1.0, 1.0, 1.0, 1.0};
37 vector float approximation;
38
39 approximation = spu_re(a);
40 return spu_madd(spu_nmsub(approximation, a, unit),
41 approximation, approximation);
42 }
43
44
45 #if 0
46 static vector signed int
47 getLocalPositionVec(vector signed int d, signed int offset)
48 {
49 return spu_and(d, spu_splats(offset-1));
50 }
51
52 static vector signed int
53 getLocalXVec(vector signed int x)
54 {
55 return getLocalPositionVec(x, split_screen_w);
56 }
57 #endif
58
59
60 /**
61 * テクスチャは、TEXTURE_SPLIT_PIXEL^2 のブロックに分割する
62 *
63 * +---+---+---+---+---+---+
64 * | 0 | 1 | 2 | 3 | 4 | 5 |
65 * +---+---+---+---+---+---+
66 * | | | | | |11 |
67 * +---+---+---+---+---+---+
68 * | | | | | |17 |
69 * +---+---+---+---+---+---+
70 * | | | | | |23 |
71 * +---+---+---+---+---+---+
72 * | | | | | |29 |
73 * +---+---+---+---+---+---+
74 * | | | | | |35 |
75 * +---+---+---+---+---+---+
76 *
77 * 一辺を TEXTURE_SPLIT とする
78 * 各ブロックの数字がブロックIDとなる。
79 */
80
81 /**
82 * テクスチャの座標から、
83 * テクスチャのどのブロックかを求める
84 *
85 * @param[in] tx X coordinates of texture
86 * @param[in] tx Y coordinates of texture
87 * @param[in] twidth Width of texture
88 * @return block ID
89 */
90 static int
91 getTexBlock(int tx, int ty, int twidth)
92 {
93 int blockX, blockY;
94
95 blockX = tx / TEXTURE_SPLIT_PIXEL;
96 blockY = ty / TEXTURE_SPLIT_PIXEL;
97
98 return blockX + (twidth/TEXTURE_SPLIT_PIXEL)*blockY;
99 }
100
101 /**
102 * block ID と、テクスチャの TOP address から
103 * (tx,ty) で使われるテクスチャの Tile addres を求める
104 *
105 * @param[in] tx X coordinates of texture
106 * @param[in] tx Y coordinates of texture
107 * @param[in] tw Width of texture
108 * @param[in] tex_addr_top (tx,ty) で使うテクスチャの先頭address
109 * @return block ID
110 */
111 static memaddr
112 getTile(int tx, int ty, int tw, memaddr tex_addr_top)
113 {
114 int block = getTexBlock(tx, ty, tw);
115 return tex_addr_top + block*TEXTURE_BLOCK_SIZE * sizeof(uint32);
116 }
117
118 /**
119 * FrameBuffer に書き込む rgb の領域初期化
120 *
121 * @param width Width of Buffer
122 * @param height Height of Buffer
123 * @param rgb Initial value of RGB at Buffer
124 * @return Buffer
125 */
126 static int*
127 linebuf_init(SchedTask *smanager, int width, int height, int rgb)
128 {
129 int *buf = (int*)smanager->allocate(sizeof(int)*width*height);
130
131 for (int i = 0; i < width*height; i++) {
132 buf[i] = rgb;
133 }
134
135 return buf;
136 }
137
138 /**
139 * Z-Buffer の初期化
140 *
141 * @param width Width of Z-Buffer
142 * @param height Height of Z-Buffer
143 * @return Z-Buffer
144 */
145 static float*
146 zRow_init(SchedTask *smanager, int width, int height)
147 {
148 float *buf = (float*)smanager->allocate(sizeof(float)*width*height);
149 float def = 65535.0f;
150
151 vector float init = spu_splats(0.0f);
152 vector float defi = spu_splats(def);
153
154 for (int i = 0; i < width*height; i += 4) {
155 vector float *out = (vector float *)&buf[i];
156
157 *out = spu_add(init, defi);
158 }
159
160 return buf;
161 }
162
163
164 static uint32
165 get_rgb(int tx, int ty, TilePtr tile)
166 {
167 uint32 *data = (uint32 *)tile->data;
168 return data[(TEXTURE_SPLIT_PIXEL)*ty+tx];
169 }
170
171 #if 0
172 /**
173 * DrawSpan の再起動 (DrawSpanRenew 生成)
174 *
175 * @param[in] spack 現在処理している SpanPack
176 * @param[in] cur_span_x span->length_x != 1 の時の Span の処理で
177 * どこまで進んでいるか
178 */
179 void
180 DrawSpan::reboot(SpanPackPtr spack, int cur_span_x)
181 {
182 DrawSpanArgPtr args =
183 (DrawSpanArgPtr)smanager->allocate(sizeof(DrawSpanArg));
184 TaskPtr renew_task = smanager->create_task(TASK_DRAW_SPAN2);
185
186 // 数が多いので構造体で渡す
187 args->display = smanager->get_param(0);
188 args->screen_width = smanager->get_param(1);
189 args->rangex_start = smanager->get_param(2);
190 args->rangex_end = smanager->get_param(3);
191 args->rangey = smanager->get_param(4);
192 renew_task->add_param((int)args);
193
194 /**
195 * SpanPack は続きから開始するので、
196 * 現在の状態をコピーしておく。
197 * spack は rbuf から取得してる可能性があり
198 * rbuf はシステムが自動的に free() するため
199 * アドレスだけ渡すのはNG
200 */
201 SpanPackPtr curr = (SpanPackPtr)smanager->allocate(sizeof(SpanPack));
202 memcpy(curr, spack, sizeof(SpanPack));
203 renew_task->add_param((int)curr);
204 renew_task->add_param(cur_span_x);
205
206 // linebuf と zRow も引き継がせる
207 renew_task->add_param((int)linebuf);
208 renew_task->add_param((int)zRow);
209
210 /**
211 * 再起動したタスクを待つ
212 */
213 smanager->wait_task(renew_task);
214
215 // next_spack は free() するので wait する
216 smanager->dma_wait(SPAN_PACK_LOAD);
217 }
218 #endif
219
220 static void
221 writebuffer(SchedTask *smanager, Gptr g, unsigned int display,
222 int buf_width, int height, int screen_width)
223 {
224 for (int i = 0; i < height; i++) {
225 smanager->dma_store(&g->linebuf[i*buf_width],
226 display + (sizeof(int)*screen_width*i),
227 sizeof(int)*buf_width, FB_STORE);
228 }
229
230 g->doneWrite = 1;
231 }
232
233 /**
234 * zRow と Linebuf を更新する
235 *
236 * @param zpos 更新する pixel のZ座標
237 * @param rangex このタスクが処理する描画領域の x の長さ
238 * @param x pixel の、描画領域内での x 座標
239 * @param y 〃 の、y 座標
240 * @param tex_x pixel が使用するテクスチャの、Tile (8x8) 内での x 座標
241 * @param tex_y 〃 の y 座標
242 * @param tex_addr テクスチャのアドレス(MainMemory)
243 */
244 static void
245 updateBuffer(Gptr g, float zpos, int rangex, int x, int y,
246 int tex_x, int tex_y, TilePtr tile)
247 {
248 int rgb = get_rgb(tex_x, tex_y, tile);
249
250 g->zRow[x + (rangex*y)] = zpos;
251 g->linebuf[x + (rangex*y)] = rgb;
252 }
253
254 /**
255 * 長さが 1 の Span の描画 (要するに 1 pixel)
256 *
257 * @param span Span
258 * @param startx 描画開始範囲
259 * @param endx 描画終了範囲
260 */
261
262 static int
263 drawDot1(SchedTask *smanager, Gptr g, SpanPtr span, int startx, int endx, int wait_tag)
264 {
265 int rangex = endx - startx + 1;
266
267 /* span->x に対応する Texture の座標 (tex_xpos, tex_ypos) */
268 int tex_xpos, tex_ypos;
269
270 // span の始点に対応する Texture の座標 (tex1, tey1)
271 float tex = span->tex_x1;
272 float tey = span->tex_y1;
273
274 // span の始点に対応する z 座標
275 float zpos = span->start_z;
276
277 /* Tile 内での座標 */
278 int localx = getLocalX(span->x-1);
279 int localy = getLocalY(span->y-1);
280
281 /**
282 * (tex_xpos, tex_ypos) の、Tile 内(上の図参照)での座標と
283 * そのブロックのアドレス(MainMemory)
284 */
285 int tex_localx;
286 int tex_localy;
287 memaddr tex_addr;
288
289 if (span->x < startx || endx < span->x) {
290 return -1;
291 }
292
293 tex_xpos = (int)((span->tex_width-1) * tex);
294 tex_ypos = (int)((span->tex_height-1) * tey);
295
296 if (zpos < g->zRow[localx + (rangex*localy)]) {
297 tex_addr = getTile(tex_xpos, tex_ypos,
298 span->tex_width, (memaddr)span->tex_addr);
299 tex_localx = tex_xpos % TEXTURE_SPLIT_PIXEL;
300 tex_localy = tex_ypos % TEXTURE_SPLIT_PIXEL;
301
302 TilePtr tile = smanager->get_segment(tex_addr,g->tileList);
303 smanager->wait_segment(tile);
304
305 updateBuffer(g, zpos, rangex, localx, localy,
306 tex_localx, tex_localy, tile);
307 }
308
309 return -1;
310 }
311
312
313 /**
314 * 長さが 1 より大きい Span の描画
315 *
316 * 本来の目的として、この関数(drawLine1) では
317 * : 既に SPE 上に Tile のある pixel だけ描画
318 * : それ以外は、ここで予め DMA load しておき、
319 * : drawLine2 で一気に描画する
320 * ってものだったんだけど、どうも上手く行かなかったので
321 * 今は drawLine1 で load -> wait -> rendering を全部やってます
322 * (rendering といっても、rendering buffer に書き込むだけで
323 * まだ main memory (frame buffer) に dma store してるわけではない)
324 *
325 * @param span Span
326 * @param startx 描画開始範囲
327 * @param endx 描画終了範囲
328 * @return 「span のどの位置まで rendering が終わったか」の x 座標
329 */
330 static int
331 drawLine1(SchedTask *smanager, Gptr g, SpanPtr span, int startx, int endx, int wait_tag)
332 {
333 int x = span->x;
334 int rangex = endx - startx + 1;
335 int x_len = span->length_x;
336
337 int js = (x < startx) ? startx - x : 0;
338 int je = (x + x_len > endx) ? endx - x : x_len;
339
340 /* span->x に対応する Texture の座標 (tex_xpos, tex_ypos) */
341 int tex_xpos, tex_ypos;
342
343 // span の始点に対応する座標 (tex1, tey1)
344 float tex1 = span->tex_x1;
345 float tey1 = span->tex_y1;
346
347 // span の終点に対応する座標 (tex2, tey2)
348 float tex2 = span->tex_x2;
349 float tey2 = span->tex_y2;
350
351 // span の始点、終点に対応する z 座標
352 float zpos1 = span->start_z;
353 float zpos2 = span->end_z;
354
355 // Tile 内での座標
356 int localx, localy = getLocalY(span->y-1);
357
358 int ret = je+1;
359
360 //for (int j = js; j <= je; j++) {
361 for (int j = je; j >= js; j--) {
362 float tex_x, tex_y, tex_z;
363
364 localx = getLocalX(x-1+j);
365
366 tex_z = zpos1*(x_len-1-j)/(x_len-1) + zpos2*j/(x_len-1);
367
368 tex_x = tex1*(x_len-1-j)/(x_len-1) + tex2*j/(x_len-1);
369 tex_y = tey1*(x_len-1-j)/(x_len-1) + tey2*j/(x_len-1);
370 if (tex_x > 1) tex_x = 1;
371 if (tex_x < 0) tex_x = 0;
372 if (tex_y > 1) tex_y = 1;
373 if (tex_y < 0) tex_y = 0;
374 tex_xpos = (int)((span->tex_width-1) * tex_x);
375 tex_ypos = (int)((span->tex_height-1) * tex_y);
376
377 if (tex_z < g->zRow[localx + (rangex*localy)]) {
378 // (tex_xpos, tex_ypos) の、Tile 内(上の図参照)での座標と
379 // そのブロックのアドレス(MainMemory)
380 memaddr tex_addr;
381 int tex_localx;
382 int tex_localy;
383
384 tex_addr = getTile(tex_xpos, tex_ypos,
385 span->tex_width, (memaddr)span->tex_addr);
386 tex_localx = tex_xpos % TEXTURE_SPLIT_PIXEL;
387 tex_localy = tex_ypos % TEXTURE_SPLIT_PIXEL;
388
389 TilePtr tile = smanager->get_segment(tex_addr,g->tileList);
390 smanager->wait_segment(tile);
391
392 updateBuffer(g, tex_z, rangex, localx, localy,
393 tex_localx, tex_localy, tile);
394 }
395 }
396
397 return ret;
398 }
399
400 #if 1
401 void
402 fix_relocation(char **addr,int count)
403 {
404 unsigned int pc;
405 unsigned int label;
406 __asm__ __volatile__(
407 " brsl %0,____LLLL\n"
408 "____LLLL:"
409 " ila %1,____LLLL"
410 : "=r" (pc), "=r" (label));
411 int offset = pc-label;
412 int i;
413 for(i=0;i<count;i++) {
414 addr[i] += offset;
415 }
416 }
417 #endif
418
419 static int
420 run(SchedTask *smanager, void *rbuf, void *wbuf)
421 {
422 __debug_spe("DrawSpan\n");
423 Gptr g = (Gptr)smanager->allocate(sizeof(G));
424
425 SpanPackPtr spack = (SpanPackPtr)smanager->get_input(0);
426 SpanPackPtr next_spack = (SpanPackPtr)smanager->allocate(sizeof(SpanPack));
427 SpanPackPtr free_spack = next_spack; // next_spack の free() 用
428 Span *span;
429
430 Span nop_span;
431 nop_span.length_x = 1;
432
433 // int (*drawFunc1[2])(SchedTask *, Gptr, SpanPtr, int, int, int) = {
434 // &drawDot1, &drawLine1
435 // };
436 // fix_relocation((void**)drawFunc1,2);
437
438 uint32 display = smanager->get_param(0);
439 int screen_width = smanager->get_param(1);
440 int rangex_start = smanager->get_param(2);
441 int rangex_end = smanager->get_param(3);
442
443 // このタスクが担当する x の範囲
444 int rangex = rangex_end - rangex_start + 1;
445
446 // y の範囲
447 int rangey = smanager->get_param(4);
448
449 g->tileList = (TileListPtr)smanager->global_get(GLOBAL_TILE_LIST);
450
451 g->zRow = zRow_init(smanager, rangex, rangey);
452 //linebuf = linebuf_init(rangex, rangey, 0x00ffffff);
453 g->linebuf = linebuf_init(smanager, rangex, rangey, 0);
454
455 g->doneWrite = 0;
456
457 int tl_tag[2] = {TEX_LOAD1, TEX_LOAD2};
458 int tl_tag_flg1 = 0;
459 int tl_tag_flg2 = 1;
460
461 do {
462 /**
463 * SpanPack->next が存在する場合、
464 * 現在の SpanPack を処理してる間に
465 * 次の SpanPack の DMA 転送を行う
466 */
467 if (spack->next != NULL) {
468 smanager->dma_load(next_spack, (memaddr)spack->next,
469 sizeof(SpanPack), SPAN_PACK_LOAD);
470 } else {
471 next_spack = NULL;
472 }
473
474 SpanPtr resume_span = &nop_span;
475 int resume_span_x = 0;
476
477 for (int t = 0; t < spack->info.size; t++) {
478 SpanPtr next_span;
479 int next_span_x;
480
481 span = &spack->span[t];
482
483 /**
484 * span の長さによって、drawLine か drawDot を選択している
485 */
486 if (span->length_x != 1) {
487 next_span_x
488 = drawLine1( smanager, g,
489 span, rangex_start, rangex_end, tl_tag[tl_tag_flg1]);
490 } else {
491 next_span_x
492 = drawDot1( smanager, g,
493 span, rangex_start, rangex_end, tl_tag[tl_tag_flg1]);
494 }
495 next_span = span;
496
497 resume_span = next_span;
498 resume_span_x = next_span_x;
499
500 //smanager->dma_wait(tl_tag[tl_tag_flg1]);
501
502 tl_tag_flg1 ^= 1;
503 tl_tag_flg2 ^= 1;
504 }
505
506 // 現在 drawLine2、drawDot2 は機能してないので
507 //(this->*drawFunc2[(resume_span->length_x != 1)])(
508 //resume_span, rangex_start, rangex_end, resume_span_x,
509 //tl_tag[tl_tag_flg1]);
510
511 smanager->dma_wait(SPAN_PACK_LOAD);
512
513 SpanPackPtr tmp_spack = spack;
514 spack = next_spack;
515 next_spack = tmp_spack;
516 } while (spack);
517
518 writebuffer(smanager, g, display, rangex, rangey, screen_width);
519
520 // linebuf は、writebuffer() の dma_store を wait する
521 // DrawSpan::~DrawSpan() 内で free する。
522 //free(linebuf);
523 free(g->zRow);
524
525 //FINISH:
526 /**
527 * goto FINISH; の時は reboot なので
528 * linebuf, zRow は free() しない
529 */
530
531 free(free_spack);
532
533 TaskPtr nextTask = smanager->create_task(TASK_DRAW_SPAN_END);
534 nextTask->add_param((int)g);
535 smanager->wait_task(nextTask);
536
537 return 0;
538 }