トップページ > 過去ログ > 記事閲覧
SetDrawBrightの問題なのでしょうか
名前:Aquid 日時: 2009/07/08 19:03

#include "DxLib.h" struct _resource{ int Sprite[2]; int GaugeCorner[2][4]; int GaugeJoint[2]; int GaugeLine[2][2]; int GaugeCornerGlow[4]; int GaugeBar,GaugeBarGlow[3]; }Resource; //ゲージ void DrawGauge(int,int,int,int,int,int,int,bool); // プログラムは WinMain から始まります int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow ){ ChangeWindowMode(TRUE); if( DxLib_Init() == -1 ){ MessageBox(NULL,"DirectXの初期化に失敗。\n","Error",MB_OK); return -1 ; // エラーが起きたら直ちに終了 } //読み出し Resource.Sprite[0]=LoadGraph("sprite_ship.bmp"); //ゲージパーツ読み込み Resource.GaugeCorner[0][0]=DerivationGraph(124+0,64+0,4,4,Resource.Sprite[0]); Resource.GaugeCorner[0][1]=DerivationGraph(124+8,64+0,4,4,Resource.Sprite[0]); Resource.GaugeCorner[0][2]=DerivationGraph(124+0,64+8,4,4,Resource.Sprite[0]); Resource.GaugeCorner[0][3]=DerivationGraph(124+8,64+8,4,4,Resource.Sprite[0]); Resource.GaugeCorner[1][0]=DerivationGraph(120+ 0,80+ 0,12,12,Resource.Sprite[0]); Resource.GaugeCorner[1][1]=DerivationGraph(120+12,80+ 0,12,12,Resource.Sprite[0]); Resource.GaugeCorner[1][2]=DerivationGraph(120+ 0,80+12,12,12,Resource.Sprite[0]); Resource.GaugeCorner[1][3]=DerivationGraph(120+12,80+12,12,12,Resource.Sprite[0]); Resource.GaugeCornerGlow[0]=DerivationGraph(172+ 0,76+ 0,12,12,Resource.Sprite[0]); Resource.GaugeCornerGlow[1]=DerivationGraph(172+ 8,76+ 0,12,12,Resource.Sprite[0]); Resource.GaugeCornerGlow[2]=DerivationGraph(172+ 0,76+12,12,12,Resource.Sprite[0]); Resource.GaugeCornerGlow[3]=DerivationGraph(172+ 8,76+12,12,12,Resource.Sprite[0]); Resource.GaugeJoint[0]=DerivationGraph(164,76+0,8,24,Resource.Sprite[0]); Resource.GaugeJoint[1]=DerivationGraph(148,72+0,16,32,Resource.Sprite[0]); Resource.GaugeLine[0][0]=DerivationGraph(140+ 0,64+ 0,4,8,Resource.Sprite[0]); Resource.GaugeLine[0][1]=DerivationGraph(140+ 4,64+ 0,4,8,Resource.Sprite[0]); Resource.GaugeLine[1][0]=DerivationGraph(140+ 0,72+ 0,4,8,Resource.Sprite[0]); Resource.GaugeLine[1][1]=DerivationGraph(140+ 4,72+ 0,4,8,Resource.Sprite[0]); Resource.GaugeBar=DerivationGraph(152,64,12,4,Resource.Sprite[0]); Resource.GaugeBarGlow[0]=DerivationGraph(172 ,64,12,12,Resource.Sprite[0]); Resource.GaugeBarGlow[1]=DerivationGraph(172- 4,64, 4,12,Resource.Sprite[0]); Resource.GaugeBarGlow[2]=DerivationGraph(172+12,64, 4,12,Resource.Sprite[0]); //メインループ while(ProcessMessage() == 0){ SetDrawScreen(DX_SCREEN_BACK); ClearDrawScreen(); for(int i=0;i<6;i++) DrawGauge(320,0 +i*24,20,i+1,100,0,127,true); ScreenFlip(); clsDx(); }; //DxLibを破棄 DxLib_End(); //でもって終了! return 0 ; } /******************************************************************************* void DrawGauge(int,int,int,int,int,GAUGE_POSITION,RGBTABLE,int,bool) ゲージの描画(テスト版のため上とは宣言が違います) *******************************************************************************/ void DrawGauge(int X,int Y,int Size,int Separate,int UseVal,int Position,int Param,bool White){ LONGLONG timer=GetNowHiPerformanceCount(); printfDx("[分割数:%d]",Separate); //ゲージ分割時の分割距離を指定 const int INTERVAL=2; int Mirror =(Position&0x01)>0; int Reverse=(Position&0x02)>0; //ベース設定 SetDrawBright(255,255,255); SetDrawBlendMode(DX_BLENDMODE_ADD,Param); //アイコン枠位置の指定(ついでにバーの基本描画位置も決定) int IconX=X,BarX=X; if(Mirror) IconX+=Size*Separate+(Separate-1)*INTERVAL -1; else BarX+=24 -1; //まずはアイコン枠を if(!Mirror){ DrawGraph(IconX,Y ,Resource.GaugeCorner[0][0],TRUE); DrawGraph(IconX,Y+20,Resource.GaugeCorner[0][2],TRUE); //リバースフラグを用いて反転描画 DrawExtendGraph(IconX+20,Y+24*(Reverse),IconX+20+8,Y+24*(1-Reverse),Resource.GaugeJoint[0],TRUE); }else{ DrawGraph(IconX+20,Y ,Resource.GaugeCorner[0][1],TRUE); DrawGraph(IconX+20,Y+20,Resource.GaugeCorner[0][3],TRUE); //リバースフラグを用いて反転描画 DrawExtendGraph(IconX+4,Y+24*(Reverse),IconX+4-8,Y+24*(1-Reverse),Resource.GaugeJoint[0],TRUE); } //枠部分は繰り返しじゃよ for(int i=0;i<Separate;i++){ //位置決定 int PosX1=BarX+i*(Size+INTERVAL),PosY=Y+(1-Reverse)*24-4, PosX2=PosX1+Size; //コーナー描画分の差分算出 bool CornerDraw[2]={true,true}; PosX1+=4; PosX2-=4; if((Mirror)&&(i==Separate-1)){ //反転で且つ最後の部分ならちょっと細工 PosX2-=1; CornerDraw[1]=false; }else if((!Mirror)&&(i==0)){ //反転でなく且つ最初の部分なら同じく細工 PosX1+=1; CornerDraw[0]=false; } //左側は一応描画 if(CornerDraw[0]){ DrawGraph(PosX1-4,Y+(1-Reverse)*20 ,Resource.GaugeCorner[0][(1-Reverse)*2],TRUE); DrawGraph(PosX1-4,Y+(1-Reverse)*20+(Reverse*2-1)*8,Resource.GaugeCorner[0][ Reverse *2],TRUE); } //右側は一応描画 if(CornerDraw[1]){ DrawGraph(PosX2,Y+(1-Reverse)*20 ,Resource.GaugeCorner[0][1+(1-Reverse)*2],TRUE); DrawGraph(PosX2,Y+(1-Reverse)*20+(Reverse*2-1)*8,Resource.GaugeCorner[0][1+ Reverse *2],TRUE); } //バー描画! DrawExtendGraph(PosX1,PosY,PosX2,PosY+8,Resource.GaugeLine[0][Reverse],TRUE); } //アイコン枠発色 SetDrawBright(0,255,0); if(!Mirror){ DrawGraph(IconX-4,Y-4 ,Resource.GaugeCorner[1][0],TRUE); DrawGraph(IconX-4,Y-4+20,Resource.GaugeCorner[1][2],TRUE); //リバースフラグを用いて反転描画(複雑だな) DrawExtendGraph(IconX-4+20,Y+24*(Reverse)+4*(Reverse*2-1) ,IconX+4+20+8,Y+24*(1-Reverse)-4*(Reverse*2-1),Resource.GaugeJoint[1],TRUE); }else{ DrawGraph(IconX-4+20,Y-4 ,Resource.GaugeCorner[1][1],TRUE); DrawGraph(IconX-4+20,Y-4+20,Resource.GaugeCorner[1][3],TRUE); //リバースフラグを用いて反転描画 DrawExtendGraph(IconX+4+4,Y+24*(Reverse)+4*(Reverse*2-1) ,IconX-4+4-8,Y+24*(1-Reverse)-4*(Reverse*2-1),Resource.GaugeJoint[1],TRUE); } //枠発行部分 for(int i=0;i<Separate;i++){ //位置決定 int PosX1=BarX+i*(Size+INTERVAL),PosY=Y+(1-Reverse)*24-4, PosX2=PosX1+Size; //コーナー描画分の差分算出 bool CornerDraw[2]={true,true}; PosX1+=4; PosX2-=4; if((Mirror)&&(i==Separate-1)){ //反転で且つ最後の部分ならちょっと細工 PosX2-=1; CornerDraw[1]=false; }else if((!Mirror)&&(i==0)){ //反転でなく且つ最初の部分なら同じく細工 PosX1+=1; CornerDraw[0]=false; } //左側は一応描画 if(CornerDraw[0]){ DrawGraph(PosX1-4-4,Y-4+(1-Reverse)*20 ,Resource.GaugeCornerGlow[(1-Reverse)*2],TRUE); DrawGraph(PosX1-4-4,Y-4+(1-Reverse)*20+(Reverse*2-1)*8,Resource.GaugeCorner [1][ Reverse *2],TRUE); } //右側は一応描画 if(CornerDraw[1]){ DrawGraph(PosX2-4,Y-4+(1-Reverse)*20 ,Resource.GaugeCornerGlow[1+(1-Reverse)*2],TRUE); DrawGraph(PosX2-4,Y-4+(1-Reverse)*20+(Reverse*2-1)*8,Resource.GaugeCorner [1][1+ Reverse *2],TRUE); } //バー描画! DrawExtendGraph(PosX1,PosY,PosX2,PosY+8,Resource.GaugeLine[1][Reverse],TRUE); } //バー本体は実数とか制御がむずいのは使いませんえん! if(White)SetDrawBright(255,255,255); for(int i=0;i<Separate;i++){ //反転制御用(Mirrorフラグを見て0オリジンのカウントダウンにする) int j=i; if(Mirror)j=Separate-i-1; //中身が存在するの? if(j*Size>=UseVal)continue; //大きすぎることは命にかかわるぞ… int ContSize=UseVal-j*Size; if(ContSize>Size)ContSize=Size; //位置決定 int PosX1=BarX+i*(Size+INTERVAL),PosY=Y+4+(1-Reverse)*12, PosX2=PosX1+Size; //吸着位置 if(!Mirror) PosX2=PosX1+ContSize; else PosX1=PosX2-ContSize; //ここは単純描画 DrawExtendGraph(PosX1,PosY,PosX2,PosY+4,Resource.GaugeBar,TRUE); } //バー発行 SetDrawBright(0,255,0); for(int i=0;i<Separate;i++){ //反転制御用(Mirrorフラグを見て0オリジンのカウントダウンにする) int j=i; if(Mirror)j=Separate-i-1; //中身が存在するの? if(j*Size>=UseVal)continue; //大きすぎることは命にかかわるぞ… int ContSize=UseVal-j*Size; if(ContSize>Size)ContSize=Size; //位置決定 int PosX1=BarX+i*(Size+INTERVAL),PosY=Y+4+(1-Reverse)*12, PosX2=PosX1+Size; //吸着位置 if(!Mirror) PosX2=PosX1+ContSize; else PosX1=PosX2-ContSize; //ここは単純描画 DrawExtendGraph(PosX1,PosY-4,PosX2,PosY+4+4,Resource.GaugeBarGlow[0],TRUE); //左右の発行はまれによくある DrawGraph(PosX1-4,PosY-4,Resource.GaugeBarGlow[1],TRUE); DrawGraph(PosX2 ,PosY-4,Resource.GaugeBarGlow[2],TRUE); } //戻し忘れ SetDrawBright(255,255,255); printfDx("%dマイクロ秒\n",GetNowHiPerformanceCount()-timer); timer=GetNowHiPerformanceCount(); } ※使用する画像は以下のURL ttp://www.aquafactory.x0.com/dxlib/sprite_ship.bmp 上記のソースを実行すると、分割数3の物が処理に異常な時間を取られているのですが、私のソースの書き方が悪いのか、DXライブラリ側の問題なのかどちらなのでしょうか? 分割数3の時のSetDrawBright(0,255,0)の直後のDrawGraphの時間を調べてみると、ここだけでこちらの環境で200マイクロ秒近く消費しており(他の部分はこんなに消費することがない。)SetDrawBrightの問題なのかなとは思ってはいるのですが…

Page: 1 |

Re: SetDrawBrightの問題なのでしょうか ( No.1 )
名前:管理人 日時:2009/07/12 19:29

ご報告頂いた現象はDXライブラリ側が原因です。 細かい話を抜きにすれば SetDrawBright が原因と言えます。 ただ、厳密な意味での原因が何なのかは私もわかりませんでした。 描画処理を全てライブラリ内で行えるDXライブラリのソフトウエアレンダリングモードでは 描画負荷が分割数と比例して上昇していたので Aquidさんのプログラムが原因ではないということは 分るのですが、Direct3D を使用して描画する標準のモードでは、最終的な描画処理は Direct3D が行うので、分割数3の時に中で何か処理効率上都合の悪いことがあって 処理負荷が上がっているのかもしれません。 因みにDXライブラリは描画に Direct3D を使用している場合、DrawGraph や DrawExtendGraph を 呼んだ直後は描画処理は行われないようになっています。 何故かと言うと、Direct3D の描画の仕組みでは、Direct3D に対する一回の描画命令で一度に 沢山のポリゴンを描画できるようになっているので、DrawGraph 一回に付き Direct3D の描画命令を 一回実行すると処理速度的に勿体無いことになるからです。 なので、ScreenFlip や SetDrawScreen や SetDrawArea や SetDrawBlendGraph や SetDrawMode 等、 描画の条件や描画方式が変わる時や、それ以前に描画関数で使用していた画像とは異なる画像を 使用して描画関数が呼ばれたときなどに、それまでに呼ばれていた描画関数の描画処理を一度に 行うようになっています。 この描画方式が変わる条件の一つに SetDrawBright の設定が SetDrawBright( 255,255,255 ); と、 Red,Green,Blue 全てが 255 になっているか、そうではないかというのもありまして、 この条件結果が変わる場合も描画処理が発生します。 DrawGauge 関数では SetDrawBright の引数が 255,255,255 の場合と、そうではない場合が混在して いますので、設定変更による描画処理が何度か発生していることになります。 なので、255,255,255 の代わりに 254,254,254 とすると常に 「SetDrawBrightの引数が 255,255,255 ではない」状態が保たれることになりますので、 頻繁に SetDrawBright の設定を変更される場合はこうした方が速度的には有利になります。 試しに DrawGauge 内に記述されている SetDrawBright(255,255,255) を全て SetDrawBright(254,254,254) にしましたところ、CPUの負荷は半分になりました。 よろしければお試し下さい。m(_ _)m

Page: 1 |