FPSが60に届かない

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
wasawasa
記事: 94
登録日時: 11年前

FPSが60に届かない

#1

投稿記事 by wasawasa » 11年前

数値・文字列データと画像ファイルを加工したうえで取り込む画像データの二つを格納して初期化するATile_ini関数、FPSを60に調整するfps_wait関数、FPSを文字として表示するdraw_fps関数とこれら三つの関数をmain関数で呼ぶ記述を下記のように書いたところ、表示されるFPSが43~44と60にまで届きません。その後ATile_ini関数を調べたところ、画像ファイルを加工する記述である「FPS低下の原因1」とコメントを付けた行から「FPS低下の原因2」とコメントした行までをコメントアウトして実行したらFPSが59.5~60まで上昇しました。
記述を見て分かる通りATile_ini関数はループの中で何度も呼び出すようには書いておらず、重くなるとすれば一瞬だけだと思っていたのでこの実行結果が腑に落ちません。
最終的には画像ファイルを加工する処理を削除せずにFPSが60まで出るようにしたいのですが、一体何故この部分を実行するとFPSが上がってしまうのでしょうか?どなたかよろしくお願いします。

Data_Tile.cpp

コード:

#include "DxLib.h"
#include "stdio.h"
#define AutoTileMax 18//オートタイルの種類
#define AutopatMax 4//オートタイルのアニメ最大枚数
#define NomalTileMax 3//ノーマルタイルの種類
#define NomalTipsMax 264//1枚のノーマルタイルセットのタイルの最大数
#define TipsSqu 32//タイル1枚分画像の1辺の長さ

struct ATileData{
	int pics[4][48];//
	int pri;//
	int pat;//
	char name[32];//画像名
};

struct ATileData ATile[AutoTileMax];

void ATile_ini(){
    int file,i,j,k,n=0,m=0,ed=0;
	int l;//テスト用
    int text[32];
    char textc[32];
	int ATRule[48][4][2];
	int Pic[192];
	int maketipsc;//オートタイルチップを作成するスクリーン
	char FPass[] = "./Data/Pics/TileA/";
	char Exten[] = ".png";
	char pass[64];
	//-オートタイル格納用配列の読み込み-
	file = FileRead_open( "./Data/Txt/ATileRuleData.txt" ) ;
	if(file==NULL){printfDx("read error\n");return;}
	while(1){
        for(i=0;i<32;i++){
            text[i] = FileRead_getc(file);
            textc[i] = text[i];
            if(textc[i]=='/'){while(FileRead_getc(file)!='\n'){i=-1;continue;}}
            if(text[i]==',' || text[i]=='\n'){textc[i]='\0';break;}
            if(text[i]==EOF){ed=1;break;}
        }
		if(ed==1){FileRead_close(file);break;}
		ATRule[m/8][(m/2)%4][m%2] = atoi(textc);
        m++;
	}
	n=0;m=0;ed=0;
	//-オートタイルデータの読み込み-
    file = FileRead_open( "./Data/Txt/ATileData.txt" ) ;
    if(file==NULL){printfDx("read error\n");return;}
    while(1){
        for(i=0;i<32;i++){
            text[i] = FileRead_getc(file);
            textc[i] = text[i];
            if(textc[i]=='/'){while(FileRead_getc(file)!='\n'){i=-1;continue;}}
            if(text[i]==',' || text[i]=='\n'){textc[i]='\0';break;}
            if(text[i]==EOF){ed=1;break;}
        }
        if(ed==1){FileRead_close(file);break;}
        switch(m){
			case 0: for(i=0;i<32;i++){
				ATile[n].name[i] = textc[i];
					}
					break;
            case 1: ATile[n].pri = atoi(textc);break;
            case 2: ATile[n].pat = atoi(textc);break;
        }
        m++;
        if(m==3){m=0;n++;}
    }
	//画像データの読み込み
	for(i=0;i<AutoTileMax;i++){
		strcpy(pass,FPass);strcat(pass,ATile[i].name);strcat(pass,Exten);
		for(j=0;j<192;j++){
			Pic[j] = MakeGraph(16,16);
		}
		LoadDivGraph( pass , 48*ATile[i].pat , 6*ATile[i].pat , 8 , 16 , 16 , Pic ) ;
		for(k=0;k<4;k++){
			for(j=0;j<48;j++){
				ATile[i].pics[k][j] = MakeGraph(TipsSqu,TipsSqu);
			}
		}
		for(k=0;k<ATile[i].pat;k++){
			for(j=0;j<48;j++){
				maketipsc = MakeScreen( TipsSqu, TipsSqu, TRUE ) ;
				SetDrawScreen( maketipsc ) ;//FPS低下の原因1
				DrawGraph( 0, 0,Pic[ATRule[j][0][0]+6*ATRule[j][0][1]*ATile[i].pat],TRUE);
				DrawGraph(16, 0,Pic[ATRule[j][1][0]+6*ATRule[j][1][1]*ATile[i].pat],TRUE);
				DrawGraph( 0,16,Pic[ATRule[j][2][0]+6*ATRule[j][2][1]*ATile[i].pat],TRUE);
				DrawGraph(16,16,Pic[ATRule[j][3][0]+6*ATRule[j][3][1]*ATile[i].pat],TRUE);
				SetDrawScreen( DX_SCREEN_FRONT ) ;//FPS低下の原因2
				ATile[i].pics[k][j] = maketipsc;
			}
		}		
		memset(pass,0,sizeof(pass));
	}
}
main.h

コード:

#ifndef DEF_Main_H //二重include防止
#define DEF_Main_H

//-Data_Tile.cpp-
void ATile_ini();

#endif
main.cpp

コード:

#include "DxLib.h"
#include <math.h>
#include "main.h"

//fps
#define FLAME 60

//fpsのカウンタ、60フレームに1回基準となる時刻を記録する変数
int fps_count,count0t;
//平均を計算するため60回の1周時間を記録
int f[FLAME];
//平均fps
double ave;

//FLAME fps になるようにfpsを計算・制御
void fps_wait(){
    int term,i,gnt;
    static int t=0;
    if(fps_count==0){//60フレームの1回目なら
        if(t==0)//完全に最初ならまたない
            term=0;
        else//前回記録した時間を元に計算
            term=count0t+1000-GetNowCount();
    }
    else    //待つべき時間=現在あるべき時刻-現在の時刻
        term = (int)(count0t+fps_count*(1000.0/FLAME))-GetNowCount();

    if(term>0)//待つべき時間だけ待つ
        Sleep(term);

    gnt=GetNowCount();

    if(fps_count==0)//60フレームに1度基準を作る
        count0t=gnt;
    f[fps_count]=gnt-t;//1周した時間を記録
    t=gnt;
    //平均計算
    if(fps_count==FLAME-1){
        ave=0;
        for(i=0;i<FLAME;i++)
            ave+=f[i];
        ave/=FLAME;
    }
    fps_count = (++fps_count)%FLAME ;
}

//x,yの位置にfpsを表示
void draw_fps(int x, int y){
    if(ave!=0){
        DrawFormatString(x, y,GetColor(255,255,255),"[%.1f]",1000/ave);
    }
    return;
}

int WINAPI WinMain(HINSTANCE,HINSTANCE,LPSTR,int){
        ChangeWindowMode(TRUE), DxLib_Init(), SetDrawScreen( DX_SCREEN_BACK ); //ウィンドウモード変更と初期化と裏画面設定

		ATile_ini();

        while( ScreenFlip()==0 && ProcessMessage()==0 && ClearDrawScreen()==0 ){
			draw_fps(0,0);
			fps_wait();
        }

        DxLib_End();    // DXライブラリ終了処理
        return 0;
}

アバター
みけCAT
記事: 6734
登録日時: 14年前
住所: 千葉県
連絡を取る:

Re: FPSが60に届かない

#2

投稿記事 by みけCAT » 11年前

「FPS低下の原因2」で、SetDrawScreen( DX_SCREEN_FRONT )ではなく
SetDrawScreen( DX_SCREEN_BACK )としたらどうなりますか?
また、この行はこの行を含む2重のfor文を抜けた直後に1回だけ実行すればいいのではないですか?
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

wasawasa
記事: 94
登録日時: 11年前

Re: FPSが60に届かない

#3

投稿記事 by wasawasa » 11年前

>SetDrawScreen( DX_SCREEN_BACK )としたらどうなりますか?
無事FPSが60まで届きました。FPSが低下していた原因はSetDrawScreen( DX_SCREEN_FRONT )だったのですね。ありがとうございます。
>また、この行はこの行を含む2重のfor文を抜けた直後に1回だけ実行すればいいのではないですか?
maketipscに何か画像を入れないとエラーが出るので・・・・・・と思っていたのですがmaketipsc = MakeScreen( TipsSqu, TipsSqu, TRUE ) ;を一文増やせばいいだけでした。次からそうしたいと思います。

後学のためにお聞きしたいのですが、今回のATile_ini関数はwhileの外で呼び出していたのにFPSが低下しました。
FPSの低下が発生する原因は、画像の読み込み等の低速の処理を何度も呼び出す事だと思っていたので、極端な話一度しか呼び出さない関数がいくら重くてもwhile内の処理には特別大きな支障はないと考えていました。
FPSの低下の原因には低速処理の連続した実行以外にどんなものがあるのでしょうか?教えていただければ幸いです。

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 15年前
住所: 東海地方
連絡を取る:

Re: FPSが60に届かない

#4

投稿記事 by softya(ソフト屋) » 11年前

> FPSの低下の原因には低速処理の連続した実行以外にどんなものがあるのでしょうか?教えていただければ幸いです。

外的要因だと個々の問題過ぎて列挙出来ないですね。GPUがしょぼいとか。
内的要因なら、CPUを使い過ぎかGPUの使いすぎ、今回のような初期化のミスです。
それとファイル読み出しをメインループ内で行うのは速度的にNGです。

気にしすぎても作れないので、色々作って経験を積んでくださいってのが結論かと思います。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

wasawasa
記事: 94
登録日時: 11年前

Re: FPSが60に届かない

#5

投稿記事 by wasawasa » 11年前

>softya(ソフト屋) さん
ありがとうございます。参考になりました。

アバター
みけCAT
記事: 6734
登録日時: 14年前
住所: 千葉県
連絡を取る:

Re: FPSが60に届かない

#6

投稿記事 by みけCAT » 11年前

wasawasa さんが書きました:後学のためにお聞きしたいのですが、今回のATile_ini関数はwhileの外で呼び出していたのにFPSが低下しました。
FPSの低下が発生する原因は、画像の読み込み等の低速の処理を何度も呼び出す事だと思っていたので、極端な話一度しか呼び出さない関数がいくら重くてもwhile内の処理には特別大きな支障はないと考えていました。
今回の問題は処理が重いことではなく、描画先が表画面になっている状態でScreenFlip関数を使用していたことです。
原因は私にはわかりませんが、DXライブラリで描画先が表画面である状態でScreenFlip関数を毎フレーム呼び出すと、
FPSが40程度になる、という現象はたびたび報告されているようです。
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

閉鎖

“C言語何でも質問掲示板” へ戻る