Mercurial > hg > Members > kono > Cerium
view Renderer/Engine/viewer.cc @ 986:ac437c3cf766 akira
double buffering of spanpack/polgonpack
not yet worked.
author | root@henri.cr.ie.u-ryukyu.ac.jp |
---|---|
date | Fri, 01 Oct 2010 03:42:25 +0900 |
parents | e40dd2384357 |
children | 0b6f8c82625a |
line wrap: on
line source
#include <SDL.h> #include "viewer.h" #include "viewer_types.h" #include "SceneGraph.h" #include "SceneGraphRoot.h" #include "scene_graph_pack.h" #include "sys.h" #include "Func.h" #include "error.h" #include "TaskManager.h" #include <wchar.h> #include "Pad.h" #include "Application.h" #include "lindaapi.h" static void post2runLoop(SchedTask *s,void *viewer,void *s1); static void post2runDraw(SchedTask *s,void *viewer,void *s1); static void post2speRendering(SchedTask *s,void *viewer,void *s1); static void post2speDraw(SchedTask *s,void *viewer,void *s1); static void post2runMoveDrawLoop(SchedTask *s,void *viewer,void *s1); /* measure for FPS (Frame Per Second) */ static int start_time; static int this_time; int frames; // static void post2speRunLoop(void *viewer); //static void post2runMove(void *viewer); //static void post2exchange_sgroot(void *viewer); //static void post2speRunLoop(void *viewer); //SceneGraphRootPtr sgroot_2; /* Data Pack sent to Other CPUs (ex. SPE) */ RederingData r[2]; int ppi, spi; /** * */ Viewer::Viewer(TaskManager *m, ViewerDevice *vd, int b, int w, int h, int _num) { spe_num = _num; manager = m; dev = vd; pixels = dev->video_init(manager, b, w, h); width = dev->width; height = dev->height; bpp = dev->bpp; } int Viewer::get_ticks(void) { int time; time = SDL_GetTicks(); return time; } bool Viewer::quit_check(void) { SDL_Event event; while(SDL_PollEvent(&event)) { if (event.type==SDL_QUIT) { return true; } } Uint8 *keys=SDL_GetKeyState(NULL); if (keys[SDLK_q] == SDL_PRESSED) { return true; } return false; } void Viewer::quit(void) { SDL_Quit(); } void Viewer::run_init(TaskManager *manager, Application *app) { this->manager = manager; if (spe_num == 0) spe_num = 1; sgroot = new SceneGraphRoot(this->width, this->height); sgroot->tmanager = manager; int light_num = 4; int size = sizeof(float)*4*light_num; //xyz+alfa(4) * light_num(4) int light_size = size / sizeof(float); light_xyz_stock = (float *)manager->allocate(size); light_xyz = (float *)manager->allocate(size); for (int i = 0; i < light_size ; i++) { light_xyz[i] = 0.0f; } for(int i = 0; i < spe_num; i++) { HTaskPtr data_load = manager->create_task(DataAllocate); data_load->set_param(0,(memaddr)3); // num of allocate block data_load->set_param(0,(memaddr)(sizeof(float)*4*light_num)); // 1st allocate size data_load->set_param(1,(memaddr)Light); // 1st id data_load->set_param(0,(memaddr)(light_num * sizeof(int))); // 2nd size data_load->set_param(1,(memaddr)LightSwitch); // 2nd id data_load->set_param(0,(memaddr)16); // 3rd size data_load->set_param(1,(memaddr)LightSysSwitch); // 3rd id data_load->set_cpu((CPU_TYPE)((int)SPE_0 + i)); data_load->spawn(); } light_switch = (int*)manager->allocate(size); for (int i = 0; i < light_num; i++) { light_switch[i] = 0; } size = 16; // LightSysSwitch は 4byte. 残り 12byte は DMA転送の為のパディング light_sysswitch = (int*)manager->allocate(size); for (unsigned int i = 0; i < size / sizeof(int); i++) { light_sysswitch[i] = 0; } start_time = get_ticks(); this_time = 0; frames = 0; MainLoop *mainloop = app->init(this, this->width, this->height); mainloop->mainLoop(); } HTaskPtr Viewer::initLoop() { HTaskPtr task_next; HTaskPtr task_tex; for(int i=0;i<2;i++) { r[i].ppack = (PolygonPack*)manager->allocate(sizeof(PolygonPack)); r[i].spackList_length = (this->height + split_screen_h - 1) / split_screen_h; r[i].spackList = (SpanPack*)manager->allocate(sizeof(SpanPack)*r[i].spackList_length); // printf("spackList %0lx height %d\n",(unsigned long)r[i].spackList, this->height); /** * SPU に送る address list は 16 バイト倍数でないといけない。 * spackList_length*sizeof(SpanPack*) が 16 バイト倍数になるような * length_align を求めている。はみ出した部分は使われない * (ex) spackList_length が 13 の場合 * spackList_length_align = 16; * 実際に送るデータは64バイトになるのでOK * 14,15,16 の部分は何も入らない。 */ r[i].spackList_length_align = (r[i].spackList_length + 3)&(~3); /* 各 SPU が持つ、SpanPack の address list */ r[i].spackList_ptr = (SpanPack**)manager->allocate(sizeof(SpanPack*)*r[i].spackList_length_align); for (int j = 0; i < r[i].spackList_length; i++) { r[i].spackList_ptr[j] = &r[i].spackList[j]; } for (int j = 1; j <= r[i].spackList_length; i++) { r[i].spackList[j-1].init(j*split_screen_h); } } task_next = manager->create_task(Dummy,0,0,0,0); // ここは、Iterator を用意するべきだよね for (int j = 0; j < spe_num; j++) { task_tex = manager->create_task(LoadTexture,0,0,0,0); task_tex->set_cpu((CPU_TYPE)((int)SPE_0 + j)); task_next->wait_for(task_tex); task_tex->spawn(); } return task_next; } void Viewer::getKey() { Pad *pad = sgroot->getController(); if (pad->right.isHold()) { keyPtr->right = HOLD; } else if (pad->right.isPush()) { keyPtr->right = PUSH; } else { keyPtr->right = NONE; } if (pad->left.isHold()) { keyPtr->left = HOLD; } else if (pad->left.isPush()) { keyPtr->left = PUSH; } else { keyPtr->left = NONE; } if (pad->up.isHold()) { keyPtr->up = HOLD; } else if (pad->up.isPush()) { keyPtr->up = PUSH; } else { keyPtr->up = NONE; } if (pad->down.isHold()) { keyPtr->down = HOLD; } else if (pad->down.isPush()) { keyPtr->down = PUSH; } else { keyPtr->down = NONE; } if (pad->circle.isHold()) { keyPtr->circle = HOLD; } else if (pad->circle.isPush()) { keyPtr->circle = PUSH; } else { keyPtr->circle = NONE; } } static void post2runMoveDrawLoop(SchedTask *m, void *viewer_, void *arg) { Viewer *viewer = (Viewer*)viewer_; // 同じ PPE 上なので sgroot(ポインタ) を set_param で送る。 //HTaskPtr send_key_task = viewer->manager->create_task(SendKey); //send_key_task->set_param((int)sgroot); // set input data -> viewer keyPtr viewer->getKey(); //HTaskPtr update_key = viewer->manager->create_task(UpdateKey,viewer->keyPtr, sizeof(key_stat),0,0); HTaskPtr update_key = viewer->manager->create_task(UpdateKey,0,0,0,0); update_key->add_inData(viewer->keyPtr, sizeof(key_stat)); //update_key->set_cpu(SPE_0); update_key->spawn(); /* TASK_MOVE は外から引数で取ってくるべき */ //HTaskPtr move_task = viewer->manager->create_task(viewer->app->move_taskid); // HTaskPtr move_task = viewer->manager->create_task(Move,0,0,0,0); //move_task->set_param(sgroot); //HTaskPtr draw_task = viewer->manager->create_task(Draw); /* rendering task test */ HTaskPtr draw_task = viewer->manager->create_task(Dummy,0,0,0,0); HTaskPtr draw_dummy = viewer->manager->create_task(Dummy,0,0,0,0); HTaskPtr switch_task = viewer->manager->create_task(Switch,0,0,0,0); viewer->draw_dummy = draw_dummy; switch_task->wait_for(draw_dummy); draw_task->set_post(post2speRendering, (void*)viewer, 0); // switch_task->wait_for(move_task); switch_task->wait_for(draw_task); // move_task->spawn(); draw_task->spawn(); switch_task->set_post(post2runMoveDrawLoop, (void*)viewer, 0); switch_task->spawn(); } void Viewer::mainLoop() { HTaskPtr task_next = initLoop(); task_next->set_post(&post2runLoop, (void *)this, 0); // set_post(function(this->run_loop()), NULL) task_next->spawn(); } void Viewer::run_loop(HTaskPtr task_next) { dev->clear_screen(); bool quit_flg; quit_flg = quit_check(); if (quit_flg == true) { this_time = get_ticks(); run_finish(); return; } dev->clean_pixels(); pixels = dev->flip_screen(pixels); /* ここでGameTaskの終了を待つTaskを生成しておく */ sgroot->wait_game_task = manager->create_task(Dummy,0,0,0,0); sgroot->updateControllerState(); sgroot->allExecute(width, height); light_xyz_stock = sgroot->getLightVector(); light_switch_stock = sgroot->getLightSwitch(); light_sysswitch_stock = sgroot->getLightSysSwitch(); //sgroot->checkRemove(); // ここから下は Rendering という関数にする rendering(task_next); } void Viewer::run_collision() { } void post2rendering(SchedTask *s, void *viewer_, void *arg) { Viewer *viewer = (Viewer *)viewer_; HTaskPtr task_next = viewer->manager->create_task(Dummy,0,0,0,0); viewer->rendering(task_next); } void Viewer::rendering(HTaskPtr task_next) { common_rendering(task_next, sgroot); // Barrier 同期 // run_draw() を呼ぶ post2runDraw task_next->set_post(post2runDraw, (void*)this, 0); // set_post(function(this->run_draw()), NULL) task_next->spawn(); // TASK_CREATE_SPAN が全て終わったら DUMMY_TASK が Viewer::run_draw() を呼ぶ } static void post2runLoop(SchedTask *s, void *viewer_, void *arg) { Viewer *viewer = (Viewer*)viewer_; HTaskPtr task_next = viewer->manager->create_task(Dummy,0,0,0,0); viewer->run_loop(task_next); psx_sync_n(); } static void post2runDraw(SchedTask *s, void *viewer_, void *arg) { Viewer *viewer = (Viewer*)viewer_; HTaskPtr task_next = viewer->manager->create_task(Dummy,0,0,0,0); viewer->run_draw(task_next); } void Viewer::run_draw(HTaskPtr task_next) // 引数に post2runLoop を入れるようにする { common_draw(task_next); task_next->set_post(post2runLoop, (void*)this, 0); // set_post(function(this->run_loop()), NULL) task_next->spawn(); // TASK_DRAW_SPAN が全て終わったら DUMMY_TASK が Viewer::run_loop() を呼ぶ frames++; } static void post2speRendering(SchedTask *s, void *viewer_, void *arg) { Viewer *viewer = (Viewer*)viewer_; HTaskPtr task_next = viewer->manager->create_task(Dummy,0,0,0,0); viewer->spe_rendering(task_next); } void Viewer::spe_rendering(HTaskPtr task_next) { common_rendering(task_next, sgroot); this->draw_dummy->wait_for(task_next); task_next->set_post(post2speDraw, (void*)this, 0); task_next->spawn(); } static void post2speDraw(SchedTask *s, void *viewer_, void *arg) { Viewer *viewer = (Viewer*)viewer_; HTaskPtr task_next = viewer->manager->create_task(Dummy,0,0,0,0); viewer->spe_draw(task_next); } void Viewer::spe_draw(HTaskPtr task_next) { common_draw(task_next); this->draw_dummy->wait_for(task_next); task_next->spawn(); this->draw_dummy->spawn(); frames++; } // 完全にMac仕様。。sg_matrix を allocate してやらないといけないよ。 float* copy_matrix(SceneGraphPtr sg, TaskManager *manager) { float *matrix = sg->matrix; float *real_matrix = sg->real_matrix; //変換行列は4x4 なんで、16。が二つで32.と言い訳を書いてみる。 float *sg_matrix = (float*)manager->allocate(sizeof(float)*32); for (int i = 0; i < 16; i++) { sg_matrix[i] = matrix[i]; sg_matrix[i+16] = real_matrix[i]; } return sg_matrix; } void print_matrix(float *matrix) { for (int i = 0; i < 32; i++) { printf("%f\n",matrix[i]); } } void add_matrix_list(SceneGraphPtr sg, TaskManager *manager, MatrixListInfo* info) { MatrixList *matrix_list = (MatrixList*)manager->allocate(sizeof(MatrixList)); #if SPE_CREATE_POLYGON_CHECK print_matrix(sg->sg_matrix); #endif matrix_list->matrix = copy_matrix(sg, manager);; matrix_list->next = NULL; if (info->last != NULL) { info->last->next = matrix_list; } info->last = matrix_list; info->list_length += 1; } void new_matrix_info(SceneGraphPtr sg, TaskManager *manager, MatrixListInfo* info) { MatrixListInfo *next = NULL; if (info->id == -1) { info->id = sg->sgid; info->list_length = 1; info->coord_pack = sg->coord_pack; info->coord_pack_size = sg->coord_pack_size; next = info; } else { MatrixListInfo* t; for (t = info; t->next != NULL; t = t->next) { } next = (MatrixListInfo*)manager->allocate(sizeof(MatrixListInfo)); next->id = sg->sgid; next->list_length = 1; next->coord_pack = sg->coord_pack; next->coord_pack_size = sg->coord_pack_size; next->next = NULL; t->next = next; } MatrixList *new_list = (MatrixList*)manager->allocate(sizeof(MatrixList)); new_list->matrix = copy_matrix(sg, manager); #if SPE_CREATE_POLYGON_CHECK print_matrix(sg->sg_matrix); #endif new_list->next = NULL; next->first = new_list; next->last = new_list; } void collect_matrix(SceneGraphPtr sg, MatrixListInfo *matrix_info, TaskManager *manager) { matrix_info->id = -1; matrix_info->list_length = 0; matrix_info->next = NULL; matrix_info->first = NULL; matrix_info->last = NULL; while (sg) { if (sg->flag_drawable) { int flag = 0; for (MatrixListInfo* t = matrix_info; t != NULL; t = t->next) { if (sg->sgid == t->id) { add_matrix_list(sg, manager, t); flag = 1; } } if (flag != 1) { new_matrix_info(sg, manager, matrix_info); } // search SceneGraph. でも、ただのリストがあったハズだから、あとでそれに直す。はず・・ if (sg->children != NULL) { sg = sg->children; } else if (sg->brother != NULL) { sg = sg->brother; } else { while (sg) { if (sg->brother != NULL) { sg = sg->brother; break; } else { if (sg->parent == NULL) { sg = NULL; break; } else { sg = sg->parent; } } } } } } } void check_matrix(MatrixListInfo *matrix_info,SceneGraphPtr sg) { for (MatrixListInfo* t = matrix_info; t != NULL; t = t->next) { for (MatrixList* u = t->first; u != NULL; u = u->next) { print_matrix(u->matrix); } } } void coord_allocate(int &cur_point, float *coord_pack, int spe_num, int alloc_size, HTaskPtr alloc_wait, TaskManager *manager) { for (int i = 0; i < spe_num; i++) { HTaskPtr data_alloc = manager->create_task(DataAllocate); //data_alloc->set_inData(0, &coord_pack[cur_point], alloc_size); data_alloc->set_param(0,(memaddr)alloc_size); data_alloc->set_param(1,(memaddr)SG_COORD); data_alloc->set_cpu((CPU_TYPE)((int)SPE_0 + i)); alloc_wait->wait_for(data_alloc); data_alloc->spawn(); } cur_point += alloc_size / sizeof(float); } void coord_free(int spe_num, TaskManager *manager, HTaskPtr alloc_wait) { for (int i = 0; i < spe_num; i++) { HTaskPtr data_free = manager->create_task(DataFree); data_free->set_param(0,(memaddr)SG_COORD); data_free->set_cpu((CPU_TYPE)((int)SPE_0 + i)); data_free->wait_for(alloc_wait); data_free->spawn(); } } void create_pp_task(SceneGraphPtr sg, TaskManager *manager, int spe_num, HTaskPtr task_next) { MatrixListInfo *matrix_info = (MatrixListInfo*)manager->allocate(sizeof(MatrixListInfo)); collect_matrix(sg, matrix_info, manager); //HTaskPtr phase_wait = manager->create_task(Dummy); for (MatrixListInfo* t = matrix_info; t != NULL; t = t->next) { printf("list_length %d \n", t->list_length); int alloc_size = 16*1024; if (t->coord_pack_size < alloc_size) { alloc_size = t->coord_pack_size; } int division_num = (t->coord_pack_size + alloc_size - 1) / alloc_size; int phase_num = (division_num + spe_num -1) / spe_num; int cur_point = 0; for (int i = 0; i < phase_num; i++) { HTaskPtr alloc_wait = manager->create_task(Dummy); coord_allocate(cur_point, t->coord_pack, spe_num, alloc_size, alloc_wait, manager); for (MatrixList* u = t->first; u != NULL; u = u->next) { //HTaskPtr free_wait = manager->create_task(Dummy); //phase_wait = manager->create_task(Dummy); } coord_free(spe_num, manager, alloc_wait); alloc_wait->spawn(); } } printf("-----------------------\n"); //return create_pp_wait; } void Viewer::common_rendering(HTaskPtr task_next, SceneGraphRoot *sgroot) { #if SPE_CREATE_POLYGON SceneGraphPtr sg = sgroot->getDrawSceneGraph(); create_pp_task(sg, manager, spe_num, task_next); #if SPE_CREATE_POLYGON_CHECK check_matrix(matrix_info,sg); #endif #else HTaskPtr task_create_pp = manager->create_task(CreatePolygonFromSceneGraph); HTaskPtr game_task = sgroot->wait_game_task; // SceneGraph(木構造) -> PolygonPack task_create_pp->set_param(0,(memaddr)sgroot->getDrawSceneGraph()); task_create_pp->set_param(1,(memaddr)r[ppi].ppack); /* GameTaskの終了を待ってからポリゴンを作る */ task_create_pp->wait_for(game_task); task_next->wait_for(task_create_pp); #endif int range_base = spe_num; // 切り上げのつもり int range = (r[spi].spackList_length + range_base - 1) / range_base; for (int i = 0; i < range_base; i++) { int index_start = range*i; int index_end = (index_start + range >= r[spi].spackList_length) ? r[spi].spackList_length : index_start + range; HTaskPtr task_create_sp = manager->create_task(CreateSpan); task_create_sp->set_param(0,index_start); /** * ex. screen_height が 480, spenum が 6 の場合、各SPEのy担当範囲 * [ 1.. 80] [ 81..160] [161..240] * [241..320] [321..400] [401..480] * * ex. screen_height が 1080, spenum が 5 の場合、 * [ 1..216] [217..432] [433..648] * [649..864] [865..1080] */ task_create_sp->set_param(1,index_start*split_screen_h + 1); task_create_sp->set_param(2,index_end*split_screen_h); task_create_sp->add_inData(r[ppi].ppack, sizeof(PolygonPack)); task_create_sp->add_inData(r[spi].spackList_ptr, sizeof(SpanPack*)*r[spi].spackList_length_align); task_create_sp->add_inData(&r[spi].spackList[index_start], sizeof(SpanPack)); task_next->wait_for(task_create_sp); task_create_sp->wait_for(task_create_pp); task_create_sp->set_cpu(SPE_ANY); task_create_sp->spawn(); } task_create_pp->spawn(); game_task->spawn(); } void Viewer::common_draw(HTaskPtr task_next) { //task_next = manager->create_task(Dummy); //task_next->set_post(post2runLoop, (void*)this); //Light info update int light_num = 4; int size = sizeof(float)*4*light_num; //xyz+alpha(4) * light_num(4) int light_size = size / sizeof(float); for (int i = 0; i < light_size; i++) { light_xyz[i] = light_xyz_stock[i]; } for (int i = 0; i < light_num; i++) { light_switch[i] = light_switch_stock[i]; } light_sysswitch[0] = light_sysswitch_stock; HTask *data_update_wait = 0; for (int i = 0; i < spe_num; i++) { data_update_wait = manager->create_task(DataUpdate); data_update_wait->set_param(0,3); data_update_wait->set_param(1,Light); // GlobalSet ID base data_update_wait->set_inData(0,light_xyz,size); // Light data_update_wait->set_inData(1,light_switch,light_num * sizeof(int)); // LightSwitch = Light+1 data_update_wait->set_inData(2,light_sysswitch,16); // LightSysSwitch = Light+2 data_update_wait->set_cpu((CPU_TYPE)(SPE_0+i)); data_update_wait->spawn(); } ppi ^= 1; r[ppi].ppack->clear(); for (int i = 0; i < r[spi].spackList_length; i++) { SpanPack *spack = &r[spi].spackList[i]; int startx = 1; int endx = split_screen_w; int starty = spack->info.y_top - split_screen_h + 1; //int endy = spack->info.y_top; int rangey = (starty + split_screen_h - 1 > this->height) ? this->height - starty + 1 : split_screen_h; #if 1 // mem_flag は spe 側で黒い部分を 0 で埋めるフラグ if(spack->info.size > 0 || mem_flag == 1) { int array_task_num = (this->width + split_screen_w - 1) / split_screen_w; HTaskPtr task_draw_array = manager->create_task_array(DrawSpan, array_task_num, 6, 1, rangey); Task *task_draw = 0; while (startx < this->width) { // Draw SpanPack task_draw = task_draw_array->next_task_array(DrawSpan,task_draw); task_draw->set_param(0,(memaddr)&pixels[(startx-1) + this->width*(starty-1)]); task_draw->set_param(1,this->width); task_draw->set_param(2,startx); task_draw->set_param(3,endx); task_draw->set_param(4,rangey); task_draw->set_param(5,spack->info.size); task_draw->set_inData(0,spack, sizeof(SpanPack)); for (int i = 0; i < rangey; i++) { task_draw->set_outData(i, &pixels[(startx-1) + this->width*(starty-1 + i) ], (endx-startx+1)*sizeof(int)); } startx += split_screen_w; endx += split_screen_w; if (endx > this->width) { endx = this->width; } } task_draw_array->spawn_task_array(task_draw->next()); task_draw_array->set_cpu(SPE_ANY); task_next->wait_for(task_draw_array); task_draw_array->spawn(); } else { memset(&pixels[(startx-1)+this->width*(starty-1)], 0, (this->width)*sizeof(int)*rangey); } #else HTaskPtr task_draw; while (startx < this->width) { if (spack->info.size > 0) { // Draw SpanPack task_draw = manager->create_task(DrawSpan); task_draw->set_param(0, (memaddr)&pixels[(startx-1) + this->width*(starty-1)]); task_draw->set_param(1,this->width); task_draw->set_param(2,startx); task_draw->set_param(3,endx); task_draw->set_param(4,rangey); task_draw->set_param(5,spack->info.size); task_draw->add_inData(spack, sizeof(SpanPack)); for (int i = 0; i < rangey; i++) { task_draw->add_outData( &pixels[(startx-1) + this->width*(starty-1 + i) ], (endx-startx+1)*sizeof(int)); } } else { // 7.7.3 SL1 Data Cache Range Set to Zero コマンド // を使って、DMAでclearするべき... ということは、 // それもSPEでやる方が良い? memset(&pixels[(startx-1)+this->width*(starty-1)], 0, (this->width)*sizeof(int)*rangey); break; } task_draw->set_cpu(SPE_ANY); task_next->wait_for(task_draw); task_draw->spawn(); startx += split_screen_w; endx += split_screen_w; if (endx > this->width) { endx = this->width; } } #endif } spi ^= 1; for (int i = 1; i <= r[spi].spackList_length; i++) { r[spi].spackList[i-1].reinit(i*split_screen_h); } if (profile) { if (frames % 50 == 49) { manager->show_profile(); this_time = get_ticks(); if (this_time != start_time) { printf("\n%f FPS\n", ((((float)frames)*1000.0)/(this_time-start_time))); start_time = this_time; frames = 0; } } } } void Viewer::run_finish() { dev->free_device(); if (this_time != start_time) { printf("%f FPS\n", (((float)frames)/(this_time-start_time))*1000.0); } if (profile) { manager->show_profile(); } delete sgroot; // delete sgroot_2; quit(); } /* end */