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

Reorganization..
author Shinji KONO <kono@ie.u-ryukyu.ac.jp>
date Mon, 12 Oct 2009 09:39:35 +0900
parents
children ab866bc8a624
comparison
equal deleted inserted replaced
506:1d4a8a86f26b 507:735f76483bb2
1 // #define DEBUG
2 #include "error.h"
3 #include "CreateSpan.h"
4 #include "viewer_types.h"
5
6 // DMA channel
7 static const int SPAN_PACK_LOAD = 5;
8 static const int SPAN_PACK_STORE = 6;
9 static const int POLYGON_PACK_LOAD = 7;
10 static const int TILE_ALLOCATE = 8;
11 static const int TILE_LOAD = 9;
12 static const int TILE_STORE = 10;
13
14 typedef struct g {
15 SpanPackPtr spack ;
16 SpanPackPtr send_spack ;
17 int prev_index;
18 } G, *Gptr;
19
20 SchedDefineTask(CreateSpan);
21
22 static float
23 calc(float f1, float f2,int i, float base)
24 {
25 float ans;
26 ans = f1/f2*i + base;
27 return ans;
28 }
29
30
31 /**
32 * TrianglePack から、vMin, vMid, vMax を求める
33 *
34 * @param [triPack] TrianglePack
35 * @param [vMin] [vMid] [vMax]
36 */
37 static void
38 make_vertex(TrianglePack *triPack,
39 VertexPackPtr *vMin, VertexPackPtr *vMid, VertexPackPtr *vMax)
40 {
41 if (triPack->ver1.y <= triPack->ver2.y) {
42 if (triPack->ver2.y <= triPack->ver3.y) {
43 *vMin = &triPack->ver1;
44 *vMid = &triPack->ver2;
45 *vMax = &triPack->ver3;
46 } else if (triPack->ver3.y <= triPack->ver1.y) {
47 *vMin = &triPack->ver3;
48 *vMid = &triPack->ver1;
49 *vMax = &triPack->ver2;
50 } else {
51 *vMin = &triPack->ver1;
52 *vMid = &triPack->ver3;
53 *vMax = &triPack->ver2;
54 }
55 } else {
56 if (triPack->ver1.y <= triPack->ver3.y) {
57 *vMin = &triPack->ver2;
58 *vMid = &triPack->ver1;
59 *vMax = &triPack->ver3;
60 } else if (triPack->ver3.y <= triPack->ver2.y) {
61 *vMin = &triPack->ver3;
62 *vMid = &triPack->ver2;
63 *vMax = &triPack->ver1;
64 } else {
65 *vMin = &triPack->ver2;
66 *vMid = &triPack->ver3;
67 *vMax = &triPack->ver1;
68 }
69 }
70 }
71
72 static void
73 make_vMid10(VertexPack *v, VertexPack *vMin,
74 VertexPack *vMid, VertexPack *vMax)
75 {
76 //int d, d1;
77 float d;
78 int d1;
79
80 d = vMax->y - vMin->y;
81 d1 = (int)(vMid->y - vMin->y);
82
83 v->tex_x = calc(vMax->tex_x - vMin->tex_x, d, d1, vMin->tex_x);
84 v->tex_y = calc(vMax->tex_y - vMin->tex_y, d, d1, vMin->tex_y);
85 v->x = calc(vMax->x - vMin->x, d, d1, vMin->x);
86 v->y = vMid->y;
87 v->z = calc(vMax->z - vMin->z, d, d1, vMin->z);
88 }
89
90 /**
91 * 与えられた scale から、実際に使うテクスチャの Tapestry を選択する
92 *
93 * テクスチャは、オリジナルのサイズから、可能なかぎり 1/2 で縮小していき、
94 * 下の図の様に連続した領域に入れられる
95 *
96 * Tapestry (1)
97 * +---+---+---+---+
98 * | 0 | 1 | 2 | 3 |
99 * +---+---+---+---+
100 * | 4 | 5 | 6 | 7 | (2)
101 * +---+---+---+---+ +---+---+
102 * | 8 | 9 | 10| 11| | 16| 17| (3)
103 * +---+---+---+---+ +---+---+ +---+
104 * | 12| 13| 14| 15| | 18| 19| | 20|
105 * +---+---+---+---+ +---+---+ +---|
106 *
107 * (1) (2) (3)
108 * +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
109 * | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | * | * | * | 14| 15| 16| 17| 18| 19| 20|
110 * +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
111 *
112 * scale の値から、各 Tapestry の先頭アドレスを返す
113 *
114 * @param[in] tw Width of texture
115 * @param[in] th Height of texture
116 * @param[in] scale テクスチャの縮小率 (= 2^n)
117 * @param[in] addr_top テクスチャの先頭アドレス (上の図での (1)
118 * @return scale に対応する Tapestry のアドレス (上の図での (1) or (2) or(3)
119 */
120 static uint32*
121 getTapestry(int tw, int th, int scale, uint32 *addr_top)
122 {
123 int index = 0;
124
125 for (int s = 1; s < scale; s <<= 1) {
126 index += tw*th;
127 tw >>= 1; /* tw /= 2 */
128 th >>= 1;
129 }
130
131 return addr_top + index;
132 }
133
134
135 /**
136 * span の width,height と texture の width,height を比べて
137 * span を描画する際に使う texture の比率を求める
138 *
139 * @param[in] width Width of span
140 * @param[in] height Height of span
141 * @param[in] tex_width Width of 1/1 texture that span use
142 * @param[in] tex_height Height of 1/1 texture that span use
143 * @param[in] scale_max この Span で使う texture の最大縮小率
144 * 計算結果が scale_max 以上になるのを防ぐ
145 * @return 描画に使う texture の比率
146 * width と height は 1/scale の画像を使う
147 *
148 */
149 static int
150 getScale(int width, int height, int tex_width, int tex_height, int scale_max)
151 {
152 int base, tex_base;
153 int scale = 1;
154
155 /**
156 * width と height で、長い方を基準に、
157 * texture の scale を決める
158 */
159 if (width > height) {
160 base = width;
161 tex_base = tex_width;
162 } else {
163 base = height;
164 tex_base = tex_height;
165 }
166
167 if (tex_base > base) {
168 int t_scale = tex_base/base;
169 while (t_scale >>= 1) {
170 scale <<= 1;
171 }
172 }
173
174 return (scale > scale_max) ? scale_max : scale;
175 //return scale_max;
176 }
177
178 /**
179 * x軸に水平な辺を持つ三角形ポリゴンから、
180 * Span を抜き出す
181 *
182 * @param[in] spackList triangle から生成された span を格納する List
183 * @param[in] charge_y_top 担当する y の範囲開始地点
184 * @param[in] charge_y_end 担当する y の範囲終了地点
185 * @param[in] tex_addr triangle が参照するテクスチャの先頭アドレス
186 * @param[in] tex_width テクスチャの width
187 * @param[in] tex_height テクスチャの height
188 * @param[in] tex_scale_max テクスチャの最大縮小率 (2^n)
189 * @param[in] vMin triangle の座標
190 * @param[in] vMid triangle の座標。triangle を二つに分けて出来た新しい座標
191 * @param[in] vMid10 triangle の座標
192 * @param[in] length_y 分割する前の Triangle の y の長さ
193 * @param[in] tex_y_len 分割する前の Triangle に貼られている Texture の
194 * 長さの割合 (0 ... 1)
195 */
196
197 static void
198 half_triangle(SchedTask *smanager, Gptr g, SpanPackPtr *spackList,
199 int charge_y_top, int charge_y_end,
200 TriangleTexInfoPtr tex_info,
201 VertexPack *vMin,VertexPack *vMid,VertexPack *vMid10,
202 int length_y, float tex_y_len)
203 {
204 float tmp_z,tmp_tex1, tmp_tex2 ,tmp_tey1,tmp_tey2;
205 float tmp_xpos,tmp_end,tmp_zpos;
206 float start_z, end_z;
207 float start_tex_x, end_tex_x, start_tex_y, end_tex_y;
208 int x, y, length;
209
210 #if 1
211 // これじゃないと
212 // テクスチャの貼りに微妙に隙間が。謎だ
213 int start_y = (int)vMid->y;
214 int end_y = (int)vMin->y;
215 #else
216 float start_y = vMid->y;
217 float end_y = vMin->y;
218 #endif
219 float div_y = start_y - end_y;
220 int k = 0;
221 int l = 1;
222
223 SpanPackPtr tmp_spack;
224
225 /**
226 * 三角形ポリゴンをx軸に水平に二つに分けようとして
227 * ある一辺がすでに水平だった場合、つまり
228 *
229 * |\
230 * | \
231 * | \
232 * -----
233 *
234 *
235 * 上のようなポリゴンだった場合は、本来なら上の部分の三角形にだけ
236 * half_triangle の処理をするべきだが、現在の処理だと
237 * この half_triangle に「上の部分の三角形」と、
238 * 「『下の部分の三角形と判断してしまった』直線」が来てしまう。
239 * 直線の部分が来ると、calc() で 0 除算とかで、値不定で暴走するので
240 * 現在はこれで代用。
241 * half_triangle 呼ぶ前にこれを判断できれば良いかもしれない。
242 * てかこんなんでいいのかよ。。。
243 */
244 #if 1
245 if ((int)div_y == 0) {
246 return;
247 }
248 #else
249 if (vMid10->x == vMin->x && vMid10->y == vMin->y) {
250 return;
251 }
252 #endif
253
254 if (div_y < 0) {
255 div_y = -div_y;
256 k = 1;
257 l = -1;
258 }
259
260 for (int i = k; i < (int)div_y+1; i++) {
261 y = (int)vMin->y + i*l;
262 #if 1
263
264 /**
265 * 担当 y 範囲内
266 */
267 if (charge_y_top <= y && y <= charge_y_end) {
268 // 1..8 を index0, 9..16 を index1 にするために y を -1
269 int index = (y-1) / split_screen_h;
270
271 /**
272 * 違う SpanPack を扱う場合、
273 * 現在の SpanPack をメインメモリに送り、
274 * 新しい SpanPack を取ってくる
275 */
276 if (index != g->prev_index) {
277 tmp_spack = g->spack;
278 g->spack = g->send_spack;
279 g->send_spack = tmp_spack;
280
281 smanager->dma_wait(SPAN_PACK_STORE);
282 smanager->dma_store(g->send_spack, (uint32)spackList[g->prev_index],
283 sizeof(SpanPack), SPAN_PACK_STORE);
284
285 smanager->dma_load(g->spack, (uint32)spackList[index],
286 sizeof(SpanPack), SPAN_PACK_LOAD);
287 g->prev_index = index;
288 smanager->dma_wait(SPAN_PACK_LOAD);
289 }
290
291 /**
292 * 書き込む SpanPack が満杯だったら
293 * メインメモリで allocate した領域 (next) を持ってきて
294 * 現在の spack->next につなぎ、next を次の spack とする。
295 */
296 if (g->spack->info.size >= MAX_SIZE_SPAN) {
297 SpanPackPtr next;
298
299 __debug_spe("CreateSpan mainMem_alloc 0x%x\n", (unsigned int)sizeof(SpanPack));
300 smanager->mainMem_alloc(0, sizeof(SpanPack));
301 smanager->mainMem_wait();
302 next = (SpanPackPtr)smanager->mainMem_get(0);
303 __debug_spe("CreateSpan mainMem_allocated 0x%x\n", (unsigned int)next);
304
305 g->spack->next = next; // この部分は TaskManager でやる
306
307 tmp_spack = g->spack;
308 g->spack = g->send_spack;
309 g->send_spack = tmp_spack;
310
311 smanager->dma_wait(SPAN_PACK_STORE);
312 smanager->dma_store(g->send_spack, (uint32)spackList[index],
313 sizeof(SpanPack), SPAN_PACK_STORE);
314
315 spackList[index] = next;
316
317 smanager->dma_load(g->spack, (uint32)spackList[index],
318 sizeof(SpanPack), SPAN_PACK_LOAD);
319 smanager->dma_wait(SPAN_PACK_LOAD);
320 g->spack->init((index+1)*split_screen_h);
321 }
322 } else {
323 /**
324 * 担当範囲外だったら無視
325 */
326 continue;
327 }
328
329 tmp_xpos = calc(vMid10->x - vMin->x ,div_y, i, vMin->x);
330 tmp_end = calc(vMid->x - vMin->x ,div_y, i, vMin->x);
331 tmp_z = calc(vMid10->z - vMin->z ,div_y, i, vMin->z);
332 tmp_zpos = calc(vMid->z - vMin->z ,div_y, i, vMin->z);
333
334 length = (tmp_xpos > tmp_end)
335 ? (int)tmp_xpos - (int)tmp_end : (int)tmp_end - (int)tmp_xpos;
336 if (length == 0) {
337 continue;
338 }
339
340 tmp_tex1 =((i/(div_y)) * vMid10->tex_x) +
341 ( ((div_y - i)/(div_y)) * vMin->tex_x);
342 tmp_tex2 =( (i/(div_y)) * vMid->tex_x) +
343 ( ((div_y - i)/(div_y)) * vMin->tex_x);
344
345 tmp_tey1 =( (i/(div_y)) * vMid10->tex_y) +
346 ( ((div_y - i)/(div_y)) * vMin->tex_y);
347 tmp_tey2 =( (i/(div_y)) * vMid->tex_y) +
348 ( ((div_y - i)/(div_y)) * vMin->tex_y);
349
350 if (tmp_xpos > tmp_end) {
351 x = (int)tmp_end;
352 length = (int)(tmp_xpos)-(int)(tmp_end)+1;
353 start_z = tmp_zpos;
354 end_z = tmp_z;
355 start_tex_x = tmp_tex2;
356 end_tex_x = tmp_tex1;
357 start_tex_y = tmp_tey2;
358 end_tex_y = tmp_tey1;
359 } else {
360 x = (int)tmp_xpos;
361 length = (int)(tmp_end)-(int)(tmp_xpos)+1;
362 start_z = tmp_z;
363 end_z = tmp_zpos;
364 start_tex_x = tmp_tex1;
365 end_tex_x = tmp_tex2;
366 start_tex_y = tmp_tey1;
367 end_tex_y = tmp_tey2;
368 }
369
370 smanager->dma_wait(SPAN_PACK_LOAD);
371
372 Span *span = &g->spack->span[g->spack->info.size++];
373
374 span->x = x;
375 span->y = y;
376 span->length_x = length;
377 span->start_z = start_z;
378 span->end_z = end_z;
379 span->tex_x1 = start_tex_x;
380 span->tex_x2 = end_tex_x;
381 span->tex_y1 = start_tex_y;
382 span->tex_y2 = end_tex_y;
383
384
385 float tex_x_len = span->tex_x2 - span->tex_x1;
386
387 /**
388 * tex_x_len, tex_y_len を掛ける理由は
389 * Changelog の 2008-12-16 を参照
390 */
391 int scale = getScale(span->length_x, length_y,
392 (int)(span->tex_width*tex_x_len),
393 (int)(span->tex_height*tex_y_len),
394 tex_info->scale_max);
395 //scale = tex_info->scale_max;
396
397 uint32 *tapestry = getTapestry(tex_info->width,
398 tex_info->height, scale,
399 tex_info->addr);
400 span->tex_addr = tapestry;
401 span->tex_width = tex_info->width/scale;
402 span->tex_height = tex_info->height/scale;
403 }
404 #else
405
406 /**
407 * ここに SIMD 化した記述をしようとして断念
408 */
409
410 #endif
411
412 }
413
414
415 static int
416 run(SchedTask *smanager, void *rbuf, void *wbuf)
417 {
418 __debug_spe("CreateSpan\n");
419 Gptr g = (Gptr)smanager->allocate(sizeof(G));
420 g->prev_index = 0;
421
422 PolygonPack *pp = (PolygonPack*)smanager->get_input(0);
423 PolygonPack *next_pp =
424 (PolygonPack*)smanager->allocate(sizeof(PolygonPack));
425 PolygonPack *free_pp = next_pp;
426 PolygonPack *tmp_pp;
427
428 TrianglePackPtr triPack;
429 VertexPackPtr vMin, vMid, vMax;
430 VertexPackPtr vMid10
431 = (VertexPackPtr)smanager->allocate(sizeof(VertexPack));
432
433 SpanPackPtr *spackList = (SpanPackPtr*)smanager->get_input(1);
434 g->spack = (SpanPackPtr)smanager->get_input(2);
435 g->send_spack = (SpanPackPtr)smanager->allocate(sizeof(SpanPack));
436 g->prev_index = (int)smanager->get_param(0);
437
438 // spack と send_spack は swap しながら DMA を繰り返すので
439 // 自分で allocate した send_spack を覚えてないといけない
440 SpanPackPtr free_spack = g->send_spack;
441
442 int charge_y_top = smanager->get_param(1);
443 int charge_y_end = smanager->get_param(2);
444
445 do {
446 __debug_spe("CreateSpan allocated 0x%x\n",(uint32)next_pp);
447
448 if (pp->next != NULL) {
449 smanager->dma_load(next_pp, (uint32)pp->next,
450 sizeof(PolygonPack), POLYGON_PACK_LOAD);
451 } else {
452 next_pp = NULL;
453 }
454
455 for (int i = 0; i < pp->info.size; i++) {
456 triPack = &pp->tri[i];
457
458 TriangleTexInfoPtr tri_tex_info = &triPack->tex_info;
459
460 make_vertex(triPack, &vMin, &vMid, &vMax);
461 make_vMid10(vMid10, vMin, vMid, vMax);
462
463 /**
464 * ポリゴンを、x軸に水平に分割して二つの三角形を作り、
465 * それぞれから Span を求める
466 *
467 * vMax
468 * |\
469 * | \
470 * | \
471 * | \
472 * vMid10 ------ vMid
473 * | /
474 * | /
475 * | /
476 * |/
477 * vMin
478 *
479 * (vMax, vMid, vMin) という triangle を
480 * (vMax, vMid, vMid10) (vMin, vMid, vMid10) という
481 * 二つの Triangle に分けている
482 */
483 half_triangle(smanager, g, spackList, charge_y_top, charge_y_end,
484 tri_tex_info, vMin, vMid, vMid10,
485 (int)(vMax->y - vMin->y), vMax->tex_y - vMin->tex_y);
486 half_triangle(smanager, g, spackList, charge_y_top, charge_y_end,
487 tri_tex_info, vMax, vMid, vMid10,
488 (int)(vMax->y - vMin->y), vMax->tex_y - vMin->tex_y);
489 }
490
491 smanager->dma_wait(POLYGON_PACK_LOAD);
492
493 tmp_pp = pp;
494 pp = next_pp;
495 next_pp = tmp_pp;
496 } while (pp);
497
498 smanager->dma_wait(SPAN_PACK_STORE);
499 smanager->dma_store(g->spack, (uint32)spackList[g->prev_index],
500 sizeof(SpanPack), SPAN_PACK_STORE);
501 smanager->dma_wait(SPAN_PACK_STORE);
502 __debug_spe("CreateSpan spack_stored 0x%x\n",(uint32)spackList[g->prev_index]);
503
504 // smanager で allocate したのだから free も smanager でやるべき
505 free(free_pp);
506 free(free_spack);
507 free(vMid10);
508 free(g);
509
510 return 0;
511 }