DirectX9でプログラムを組んでいるのですが、ウインドウモードだとfpsが48前後に落ちてしまいます。
フルスクリーンモードだと60前後で安定します。
以前はウインドウモードでも60fps前後に安定してできたのですが、事情があって最初から作り直していて、今回は48fpsにまで落ちてしまいました。
いちおう以前のプログラムと違う部分を探して直してみたりといったことをしているのですが、全く見つけることが出来ないので、どのあたりを変更すればいいのか知っている方がいればご教授ください。
ちなみに以前のプログラムではスプライトの加算合成が何故か出来なかったり、DirextX9を触るのが初めてで色々と汚いプログラムになってしまったため、今回最初から組みなおしています。
(今回はスプライトの加算合成には成功しましたが、前回と何が違うのかは結局わかりませんでした)
DirectX9でウインドウモードだとfpsが落ちる
Re: DirectX9でウインドウモードだとfpsが落ちる
えーと、D3DPRESENT_PARAMETERS変数のパラメータを弄っていたところ、一応fps60で安定したんですが、理由が全くわからない状態です。
D3DPRESENT_PARAMETERS d3dpp;
と変数を宣言し、パラメータを設定していく中で、
今までは
d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_DEFAULT;
としていて、これだと48fps前後になってしまいました。
d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;
に変えてみたところ、今度は超高速になってしまいました。
しかし、なんとなく
d3dpp.PresentationInterval = 1;
にしたら、何故か60fpsで安定してしまいました……。
できたのはいいんですが、理由が分からないし、別のPC上では正常に動いていない可能性もあるので、この現象について説明できる方はお願いします。
D3DPRESENT_PARAMETERS d3dpp;
と変数を宣言し、パラメータを設定していく中で、
今までは
d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_DEFAULT;
としていて、これだと48fps前後になってしまいました。
d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;
に変えてみたところ、今度は超高速になってしまいました。
しかし、なんとなく
d3dpp.PresentationInterval = 1;
にしたら、何故か60fpsで安定してしまいました……。
できたのはいいんですが、理由が分からないし、別のPC上では正常に動いていない可能性もあるので、この現象について説明できる方はお願いします。
Re: DirectX9でウインドウモードだとfpsが落ちる
どこまで垂直同期について理解されているかわからないので、詳し目に書きます。
まず、ディスプレイに画像などを表示するとき、Present関数(SwapBuffer関数)などを利用すると思います。
しかし、ディスプレイの表示を更新(リフレッシュ)するのにはあるタイミングがあり、それ以外の時に更新しようとするといわゆる「テアリング」の問題が起こってしまうため、
むやみやたらにすぐに更新を行うわけにはいきません。
これを回避するためにはそのタイミングに同期して更新を行う必要があります。この同期のことを垂直同期といいます。
そして本題に戻ると、D3DPRESENT_PARAMETERSはこの垂直同期の設定を指定するための構造体です。
PresentationIntervalの値の意味はmsdnを参照すればわかる通り、先ほどのリフレッシュのタイミングを何回分待って更新するかを指定するものです。
つまり、そこに1(=D3DPRESENT_INTERVAL_ONE)を指定するということは、垂直同期のタイミングごとに更新を行うということであり、
ディスプレイの更新頻度(リフレッシュレート)と同じだけのfpsとなります。(多くのディスプレイは60fpsが標準なので、おそらくプログラムの方も約60fpsになるはずです)
また、そこにD3DPRESENT_INTERVAL_IMMEDIATE、つまり0を指定するということは、垂直同期を待たないということであり、Present関数と同時に更新を開始します。
(その代り、先ほどのテアリングが発生する可能性があります)
ここで、今回話をややこしくしているのがD3DPRESENT_INTERVAL_DEFAULTで、msdnの注意書きにも書いてある通り、
基本的には1を指定したときと同様なのですが、こちらの方があまり厳密ではなく、60fpsとなるとは限らないようです。
(もう少し詳しく書くと、timeBeginPeriod関数によってタイマー精度を向上させているのがONEで、その関数を使用しないのがDEFAULTでの挙動です。)
まず、ディスプレイに画像などを表示するとき、Present関数(SwapBuffer関数)などを利用すると思います。
しかし、ディスプレイの表示を更新(リフレッシュ)するのにはあるタイミングがあり、それ以外の時に更新しようとするといわゆる「テアリング」の問題が起こってしまうため、
むやみやたらにすぐに更新を行うわけにはいきません。
これを回避するためにはそのタイミングに同期して更新を行う必要があります。この同期のことを垂直同期といいます。
そして本題に戻ると、D3DPRESENT_PARAMETERSはこの垂直同期の設定を指定するための構造体です。
PresentationIntervalの値の意味はmsdnを参照すればわかる通り、先ほどのリフレッシュのタイミングを何回分待って更新するかを指定するものです。
つまり、そこに1(=D3DPRESENT_INTERVAL_ONE)を指定するということは、垂直同期のタイミングごとに更新を行うということであり、
ディスプレイの更新頻度(リフレッシュレート)と同じだけのfpsとなります。(多くのディスプレイは60fpsが標準なので、おそらくプログラムの方も約60fpsになるはずです)
また、そこにD3DPRESENT_INTERVAL_IMMEDIATE、つまり0を指定するということは、垂直同期を待たないということであり、Present関数と同時に更新を開始します。
(その代り、先ほどのテアリングが発生する可能性があります)
ここで、今回話をややこしくしているのがD3DPRESENT_INTERVAL_DEFAULTで、msdnの注意書きにも書いてある通り、
基本的には1を指定したときと同様なのですが、こちらの方があまり厳密ではなく、60fpsとなるとは限らないようです。
(もう少し詳しく書くと、timeBeginPeriod関数によってタイマー精度を向上させているのがONEで、その関数を使用しないのがDEFAULTでの挙動です。)
Re: DirectX9でウインドウモードだとfpsが落ちる
なるほど、ありがとうございます!
>>つまり、そこに1(=D3DPRESENT_INTERVAL_ONE)を指定するということは、垂直同期のタイミングごとに更新を行うということであり、
ディスプレイの更新頻度(リフレッシュレート)と同じだけのfpsとなります。(多くのディスプレイは60fpsが標準なので、おそらくプログラムの方も約60fpsになるはずです)
ということですが、これはつまり現在(=1を指定している状態)のままでは、ディスプレイの設定によっては60fpsではなくなってしまう場合もあるということですよね?
つまり、基本は1を指定しておき、それでfpsがおかしくなってしまったケースの為に設定で変えられるようにすればゲーム側の実装としてはOKということになりますでしょうか。
>>つまり、そこに1(=D3DPRESENT_INTERVAL_ONE)を指定するということは、垂直同期のタイミングごとに更新を行うということであり、
ディスプレイの更新頻度(リフレッシュレート)と同じだけのfpsとなります。(多くのディスプレイは60fpsが標準なので、おそらくプログラムの方も約60fpsになるはずです)
ということですが、これはつまり現在(=1を指定している状態)のままでは、ディスプレイの設定によっては60fpsではなくなってしまう場合もあるということですよね?
つまり、基本は1を指定しておき、それでfpsがおかしくなってしまったケースの為に設定で変えられるようにすればゲーム側の実装としてはOKということになりますでしょうか。
Re: DirectX9でウインドウモードだとfpsが落ちる
はい、ディスプレイの設定によっては120fpsや30fpsにもなりうるということです。(まあ、あまりそういうことは多く起きないでしょうけど、ないとは言い切れませんね)
ですので、必ず約60fpsにしたいということであればIMMIDIATEを指定して、Sleep関数などを使って自前でfpsを管理する必要があるでしょう。
ですので、必ず約60fpsにしたいということであればIMMIDIATEを指定して、Sleep関数などを使って自前でfpsを管理する必要があるでしょう。
Re: DirectX9でウインドウモードだとfpsが落ちる
モニタのリフレッシュレートとは異なるフレームレートを実現する上でもテアリングを許容する場合とテアリングを許容しない場合があると思います。
テアリングを許容しない場合、VSYNC待機によってゲーム内の更新処理が間に合わないフレームが発生する可能性があります。
その場合は、その次のフレームの描画処理を省略して追い付かせます。
いわゆる変動フレームレートと呼ばれる手法です。
テアリングを許容する場合は、特定の経過時間ごとにフレームを進めるだけで済みます。
と言いたいところですがゲーム内の処理の負荷によって、更新が間に合わないケースもあります。
なので、変動フレームレートは常に考慮する必要があります。
最近はモニタのリフレッシュレートを変動させるハードウェアの仕組みも現れました。
ですが、変動フレームレートを考慮したプログラムであれば新たに対策することはありません。
過去に何度も話題になっているので「FPS制御」のキーワードで過去ログを検索してみてください。
具体的な対策方法やサンプルコードもあります。
テアリングを許容しない場合、VSYNC待機によってゲーム内の更新処理が間に合わないフレームが発生する可能性があります。
その場合は、その次のフレームの描画処理を省略して追い付かせます。
いわゆる変動フレームレートと呼ばれる手法です。
テアリングを許容する場合は、特定の経過時間ごとにフレームを進めるだけで済みます。
と言いたいところですがゲーム内の処理の負荷によって、更新が間に合わないケースもあります。
なので、変動フレームレートは常に考慮する必要があります。
最近はモニタのリフレッシュレートを変動させるハードウェアの仕組みも現れました。
ですが、変動フレームレートを考慮したプログラムであれば新たに対策することはありません。
過去に何度も話題になっているので「FPS制御」のキーワードで過去ログを検索してみてください。
具体的な対策方法やサンプルコードもあります。
Re: DirectX9でウインドウモードだとfpsが落ちる
お二方とも、ありがとうございました!
fpsについての理解を深めることが出来ました。早速組み込んでみたいと思います。
fpsについての理解を深めることが出来ました。早速組み込んでみたいと思います。