Mercurial > hg > Members > kono > Cerium
diff 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 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Renderer/Engine/spe/DrawSpan.cc Mon Oct 12 09:39:35 2009 +0900 @@ -0,0 +1,538 @@ +// #define DEBUG +#include "error.h" + +#include <stdlib.h> +#include <string.h> +#include <spu_intrinsics.h> +#include "DrawSpan.h" +#include "polygon_pack.h" +#include "texture.h" +#include "viewer_types.h" +#include "Func.h" +#include "global_alloc.h" + +SchedDefineTask(DrawSpan); +SchedDefineTask1(DrawSpanEnd,draw_span_end); + +#define TEX_LOAD1 0 +#define TEX_LOAD2 1 +#define SPAN_PACK_LOAD 2 +#define FB_STORE 3 + +static int +draw_span_end(SchedTask *s, void *rbuf, void *wbuf) +{ + Gptr g = (Gptr)s->get_param(0); + s->dma_wait(FB_STORE); + free((void*)((int)g->linebuf*g->doneWrite)); + free(g); + return 0; +} + + +inline vector float +spu_re_nrm(vector float a) +{ + vector float unit = (vector float){1.0, 1.0, 1.0, 1.0}; + vector float approximation; + + approximation = spu_re(a); + return spu_madd(spu_nmsub(approximation, a, unit), + approximation, approximation); +} + + +#if 0 +static vector signed int +getLocalPositionVec(vector signed int d, signed int offset) +{ + return spu_and(d, spu_splats(offset-1)); +} + +static vector signed int +getLocalXVec(vector signed int x) +{ + return getLocalPositionVec(x, split_screen_w); +} +#endif + + +/** + * テクスチャは、TEXTURE_SPLIT_PIXEL^2 のブロックに分割する + * + * +---+---+---+---+---+---+ + * | 0 | 1 | 2 | 3 | 4 | 5 | + * +---+---+---+---+---+---+ + * | | | | | |11 | + * +---+---+---+---+---+---+ + * | | | | | |17 | + * +---+---+---+---+---+---+ + * | | | | | |23 | + * +---+---+---+---+---+---+ + * | | | | | |29 | + * +---+---+---+---+---+---+ + * | | | | | |35 | + * +---+---+---+---+---+---+ + * + * 一辺を TEXTURE_SPLIT とする + * 各ブロックの数字がブロックIDとなる。 + */ + +/** + * テクスチャの座標から、 + * テクスチャのどのブロックかを求める + * + * @param[in] tx X coordinates of texture + * @param[in] tx Y coordinates of texture + * @param[in] twidth Width of texture + * @return block ID + */ +static int +getTexBlock(int tx, int ty, int twidth) +{ + int blockX, blockY; + + blockX = tx / TEXTURE_SPLIT_PIXEL; + blockY = ty / TEXTURE_SPLIT_PIXEL; + + return blockX + (twidth/TEXTURE_SPLIT_PIXEL)*blockY; +} + +/** + * block ID と、テクスチャの TOP address から + * (tx,ty) で使われるテクスチャの Tile addres を求める + * + * @param[in] tx X coordinates of texture + * @param[in] tx Y coordinates of texture + * @param[in] tw Width of texture + * @param[in] tex_addr_top (tx,ty) で使うテクスチャの先頭address + * @return block ID + */ +static memaddr +getTile(int tx, int ty, int tw, memaddr tex_addr_top) +{ + int block = getTexBlock(tx, ty, tw); + return tex_addr_top + block*TEXTURE_BLOCK_SIZE * sizeof(uint32); +} + +/** + * FrameBuffer に書き込む rgb の領域初期化 + * + * @param width Width of Buffer + * @param height Height of Buffer + * @param rgb Initial value of RGB at Buffer + * @return Buffer + */ +static int* +linebuf_init(SchedTask *smanager, int width, int height, int rgb) +{ + int *buf = (int*)smanager->allocate(sizeof(int)*width*height); + + for (int i = 0; i < width*height; i++) { + buf[i] = rgb; + } + + return buf; +} + +/** + * Z-Buffer の初期化 + * + * @param width Width of Z-Buffer + * @param height Height of Z-Buffer + * @return Z-Buffer + */ +static float* +zRow_init(SchedTask *smanager, int width, int height) +{ + float *buf = (float*)smanager->allocate(sizeof(float)*width*height); + float def = 65535.0f; + + vector float init = spu_splats(0.0f); + vector float defi = spu_splats(def); + + for (int i = 0; i < width*height; i += 4) { + vector float *out = (vector float *)&buf[i]; + + *out = spu_add(init, defi); + } + + return buf; +} + + +static uint32 +get_rgb(int tx, int ty, TilePtr tile) +{ + uint32 *data = (uint32 *)tile->data; + return data[(TEXTURE_SPLIT_PIXEL)*ty+tx]; +} + +#if 0 +/** + * DrawSpan の再起動 (DrawSpanRenew 生成) + * + * @param[in] spack 現在処理している SpanPack + * @param[in] cur_span_x span->length_x != 1 の時の Span の処理で + * どこまで進んでいるか + */ +void +DrawSpan::reboot(SpanPackPtr spack, int cur_span_x) +{ + DrawSpanArgPtr args = + (DrawSpanArgPtr)smanager->allocate(sizeof(DrawSpanArg)); + TaskPtr renew_task = smanager->create_task(TASK_DRAW_SPAN2); + + // 数が多いので構造体で渡す + args->display = smanager->get_param(0); + args->screen_width = smanager->get_param(1); + args->rangex_start = smanager->get_param(2); + args->rangex_end = smanager->get_param(3); + args->rangey = smanager->get_param(4); + renew_task->add_param((int)args); + + /** + * SpanPack は続きから開始するので、 + * 現在の状態をコピーしておく。 + * spack は rbuf から取得してる可能性があり + * rbuf はシステムが自動的に free() するため + * アドレスだけ渡すのはNG + */ + SpanPackPtr curr = (SpanPackPtr)smanager->allocate(sizeof(SpanPack)); + memcpy(curr, spack, sizeof(SpanPack)); + renew_task->add_param((int)curr); + renew_task->add_param(cur_span_x); + + // linebuf と zRow も引き継がせる + renew_task->add_param((int)linebuf); + renew_task->add_param((int)zRow); + + /** + * 再起動したタスクを待つ + */ + smanager->wait_task(renew_task); + + // next_spack は free() するので wait する + smanager->dma_wait(SPAN_PACK_LOAD); +} +#endif + +static void +writebuffer(SchedTask *smanager, Gptr g, unsigned int display, + int buf_width, int height, int screen_width) +{ + for (int i = 0; i < height; i++) { + smanager->dma_store(&g->linebuf[i*buf_width], + display + (sizeof(int)*screen_width*i), + sizeof(int)*buf_width, FB_STORE); + } + + g->doneWrite = 1; +} + +/** + * zRow と Linebuf を更新する + * + * @param zpos 更新する pixel のZ座標 + * @param rangex このタスクが処理する描画領域の x の長さ + * @param x pixel の、描画領域内での x 座標 + * @param y 〃 の、y 座標 + * @param tex_x pixel が使用するテクスチャの、Tile (8x8) 内での x 座標 + * @param tex_y 〃 の y 座標 + * @param tex_addr テクスチャのアドレス(MainMemory) + */ +static void +updateBuffer(Gptr g, float zpos, int rangex, int x, int y, + int tex_x, int tex_y, TilePtr tile) +{ + int rgb = get_rgb(tex_x, tex_y, tile); + + g->zRow[x + (rangex*y)] = zpos; + g->linebuf[x + (rangex*y)] = rgb; +} + +/** + * 長さが 1 の Span の描画 (要するに 1 pixel) + * + * @param span Span + * @param startx 描画開始範囲 + * @param endx 描画終了範囲 + */ + +static int +drawDot1(SchedTask *smanager, Gptr g, SpanPtr span, int startx, int endx, int wait_tag) +{ + int rangex = endx - startx + 1; + + /* span->x に対応する Texture の座標 (tex_xpos, tex_ypos) */ + int tex_xpos, tex_ypos; + + // span の始点に対応する Texture の座標 (tex1, tey1) + float tex = span->tex_x1; + float tey = span->tex_y1; + + // span の始点に対応する z 座標 + float zpos = span->start_z; + + /* Tile 内での座標 */ + int localx = getLocalX(span->x-1); + int localy = getLocalY(span->y-1); + + /** + * (tex_xpos, tex_ypos) の、Tile 内(上の図参照)での座標と + * そのブロックのアドレス(MainMemory) + */ + int tex_localx; + int tex_localy; + memaddr tex_addr; + + if (span->x < startx || endx < span->x) { + return -1; + } + + tex_xpos = (int)((span->tex_width-1) * tex); + tex_ypos = (int)((span->tex_height-1) * tey); + + if (zpos < g->zRow[localx + (rangex*localy)]) { + tex_addr = getTile(tex_xpos, tex_ypos, + span->tex_width, (memaddr)span->tex_addr); + tex_localx = tex_xpos % TEXTURE_SPLIT_PIXEL; + tex_localy = tex_ypos % TEXTURE_SPLIT_PIXEL; + + TilePtr tile = smanager->get_segment(tex_addr,g->tileList); + smanager->wait_segment(tile); + + updateBuffer(g, zpos, rangex, localx, localy, + tex_localx, tex_localy, tile); + } + + return -1; +} + + +/** + * 長さが 1 より大きい Span の描画 + * + * 本来の目的として、この関数(drawLine1) では + * : 既に SPE 上に Tile のある pixel だけ描画 + * : それ以外は、ここで予め DMA load しておき、 + * : drawLine2 で一気に描画する + * ってものだったんだけど、どうも上手く行かなかったので + * 今は drawLine1 で load -> wait -> rendering を全部やってます + * (rendering といっても、rendering buffer に書き込むだけで + * まだ main memory (frame buffer) に dma store してるわけではない) + * + * @param span Span + * @param startx 描画開始範囲 + * @param endx 描画終了範囲 + * @return 「span のどの位置まで rendering が終わったか」の x 座標 + */ +static int +drawLine1(SchedTask *smanager, Gptr g, SpanPtr span, int startx, int endx, int wait_tag) +{ + int x = span->x; + int rangex = endx - startx + 1; + int x_len = span->length_x; + + int js = (x < startx) ? startx - x : 0; + int je = (x + x_len > endx) ? endx - x : x_len; + + /* span->x に対応する Texture の座標 (tex_xpos, tex_ypos) */ + int tex_xpos, tex_ypos; + + // span の始点に対応する座標 (tex1, tey1) + float tex1 = span->tex_x1; + float tey1 = span->tex_y1; + + // span の終点に対応する座標 (tex2, tey2) + float tex2 = span->tex_x2; + float tey2 = span->tex_y2; + + // span の始点、終点に対応する z 座標 + float zpos1 = span->start_z; + float zpos2 = span->end_z; + + // Tile 内での座標 + int localx, localy = getLocalY(span->y-1); + + int ret = je+1; + + //for (int j = js; j <= je; j++) { + for (int j = je; j >= js; j--) { + float tex_x, tex_y, tex_z; + + localx = getLocalX(x-1+j); + + tex_z = zpos1*(x_len-1-j)/(x_len-1) + zpos2*j/(x_len-1); + + tex_x = tex1*(x_len-1-j)/(x_len-1) + tex2*j/(x_len-1); + tex_y = tey1*(x_len-1-j)/(x_len-1) + tey2*j/(x_len-1); + if (tex_x > 1) tex_x = 1; + if (tex_x < 0) tex_x = 0; + if (tex_y > 1) tex_y = 1; + if (tex_y < 0) tex_y = 0; + tex_xpos = (int)((span->tex_width-1) * tex_x); + tex_ypos = (int)((span->tex_height-1) * tex_y); + + if (tex_z < g->zRow[localx + (rangex*localy)]) { + // (tex_xpos, tex_ypos) の、Tile 内(上の図参照)での座標と + // そのブロックのアドレス(MainMemory) + memaddr tex_addr; + int tex_localx; + int tex_localy; + + tex_addr = getTile(tex_xpos, tex_ypos, + span->tex_width, (memaddr)span->tex_addr); + tex_localx = tex_xpos % TEXTURE_SPLIT_PIXEL; + tex_localy = tex_ypos % TEXTURE_SPLIT_PIXEL; + + TilePtr tile = smanager->get_segment(tex_addr,g->tileList); + smanager->wait_segment(tile); + + updateBuffer(g, tex_z, rangex, localx, localy, + tex_localx, tex_localy, tile); + } + } + + return ret; +} + +#if 1 +void +fix_relocation(char **addr,int count) +{ + unsigned int pc; + unsigned int label; + __asm__ __volatile__( +" brsl %0,____LLLL\n" +"____LLLL:" +" ila %1,____LLLL" + : "=r" (pc), "=r" (label)); + int offset = pc-label; + int i; + for(i=0;i<count;i++) { + addr[i] += offset; + } +} +#endif + +static int +run(SchedTask *smanager, void *rbuf, void *wbuf) +{ + __debug_spe("DrawSpan\n"); + Gptr g = (Gptr)smanager->allocate(sizeof(G)); + + SpanPackPtr spack = (SpanPackPtr)smanager->get_input(0); + SpanPackPtr next_spack = (SpanPackPtr)smanager->allocate(sizeof(SpanPack)); + SpanPackPtr free_spack = next_spack; // next_spack の free() 用 + Span *span; + + Span nop_span; + nop_span.length_x = 1; + +// int (*drawFunc1[2])(SchedTask *, Gptr, SpanPtr, int, int, int) = { +// &drawDot1, &drawLine1 +// }; +// fix_relocation((void**)drawFunc1,2); + + uint32 display = smanager->get_param(0); + int screen_width = smanager->get_param(1); + int rangex_start = smanager->get_param(2); + int rangex_end = smanager->get_param(3); + + // このタスクが担当する x の範囲 + int rangex = rangex_end - rangex_start + 1; + + // y の範囲 + int rangey = smanager->get_param(4); + + g->tileList = (TileListPtr)smanager->global_get(GLOBAL_TILE_LIST); + + g->zRow = zRow_init(smanager, rangex, rangey); + //linebuf = linebuf_init(rangex, rangey, 0x00ffffff); + g->linebuf = linebuf_init(smanager, rangex, rangey, 0); + + g->doneWrite = 0; + + int tl_tag[2] = {TEX_LOAD1, TEX_LOAD2}; + int tl_tag_flg1 = 0; + int tl_tag_flg2 = 1; + + do { + /** + * SpanPack->next が存在する場合、 + * 現在の SpanPack を処理してる間に + * 次の SpanPack の DMA 転送を行う + */ + if (spack->next != NULL) { + smanager->dma_load(next_spack, (memaddr)spack->next, + sizeof(SpanPack), SPAN_PACK_LOAD); + } else { + next_spack = NULL; + } + + SpanPtr resume_span = &nop_span; + int resume_span_x = 0; + + for (int t = 0; t < spack->info.size; t++) { + SpanPtr next_span; + int next_span_x; + + span = &spack->span[t]; + + /** + * span の長さによって、drawLine か drawDot を選択している + */ + if (span->length_x != 1) { + next_span_x + = drawLine1( smanager, g, + span, rangex_start, rangex_end, tl_tag[tl_tag_flg1]); + } else { + next_span_x + = drawDot1( smanager, g, + span, rangex_start, rangex_end, tl_tag[tl_tag_flg1]); + } + next_span = span; + + resume_span = next_span; + resume_span_x = next_span_x; + + //smanager->dma_wait(tl_tag[tl_tag_flg1]); + + tl_tag_flg1 ^= 1; + tl_tag_flg2 ^= 1; + } + + // 現在 drawLine2、drawDot2 は機能してないので + //(this->*drawFunc2[(resume_span->length_x != 1)])( + //resume_span, rangex_start, rangex_end, resume_span_x, + //tl_tag[tl_tag_flg1]); + + smanager->dma_wait(SPAN_PACK_LOAD); + + SpanPackPtr tmp_spack = spack; + spack = next_spack; + next_spack = tmp_spack; + } while (spack); + + writebuffer(smanager, g, display, rangex, rangey, screen_width); + + // linebuf は、writebuffer() の dma_store を wait する + // DrawSpan::~DrawSpan() 内で free する。 + //free(linebuf); + free(g->zRow); + +//FINISH: + /** + * goto FINISH; の時は reboot なので + * linebuf, zRow は free() しない + */ + + free(free_spack); + + TaskPtr nextTask = smanager->create_task(TASK_DRAW_SPAN_END); + nextTask->add_param((int)g); + smanager->wait_task(nextTask); + + return 0; +}