全画面表示の処理方式を変えてみたり

(外部リンクがあるようなので修正&加筆しました)
またこんなに空いてしまった。いけませんね、ようやく尿管結石がようやく出たというのに。
分析して貰ったら96%シュウ酸って凄くね!って医者に言われました。


そんなこんなで、ちょっと前にお話ししたフルスクリーン(ソフトウェアスケーリング)絡みのネタをつらつらと。
正確に言うと「ソフトウェアで補間をかけて拡大する方法」になるのですが、前回「Windows7でDirectDrawとかオーバーレイ表示すると補間利かなくなっちゃった」という記事を書いてから改善されるかと期待していたのですが、どうも一向に改善されませんので、どうやらドライバの話ではなく「OSの仕様」ということで落ち着きそうです。
この一向に整理されない液晶アスペクト比地獄の中では、なかなか痛い出費(仕様変更)です。トホホ。
Windows7で補間して拡大する方法は、実用的なところではVMRかDirect3Dぐらい見つけられませんでした。(CPUとWin32APIでは60FPSに耐えられません故)
VMRはよくわからんので素直にDirect3Dを使う事にしました。

Direct3Dを使う

Direct3Dを使用する方法では、テクスチャにゲーム画面を書き込んで、バックバッファにテクスチャ補間で引き延ばしてレンダリング、等倍転送で画面に反映する形になります。
うちはグラフィック処理全てCPU処理なのでこんなかんじ。

step1
[ゲーム画面(CPU)]→(転送)→[テクスチャ(VRAM)]→(ポリゴン描画:アスペクト比スケーリング)→[バックバッファ]→
step2
[バックバッファ]→(等倍転送)→[フロントバッファ:表示画面]

等倍転送というところが肝です。でないと二重スケーリングですごく画像がぼけるので注意。


さて、記事にはフルスクリーンと有りますが、ソフトウェアスケーリングが出来ると可変ウインドウ設計も可能になります。
なので、ついでに可変ウインドウ時の処理も実装しておきましょう。
上司に隠れて320x240で小さく遊んだり、ブラウジングしながら遊んだり、マルチディスプレイ対応も簡単に対応できるのはなかなか美味しいと思いますので。

可変ウインドウにおける処理

DirectDrawだとBltで転送先サイズを変えるだけでよかったのですが、Direct3Dではバックバッファにレンダリングする関係上、引き延ばせる限界がバックバッファサイズの制限を受けます。
つまり、ウインドウサイズによってバックバッファのサイズを変える必要が有るわけですが、ウインドウのリサイズ時に生成し直すというのは処理的にレスポンス低下を招くことと、実際のハードウェア事情(連続変更すると不安定&クラッシュする場合がある)もあって良い方法では無さそうです。
よって、これを回避するには「液晶表示サイズ(デスクトップのサイズ)のサイズのバックバッファを用意しておく」方法が良いと思われます。
1920x1200の環境なら、1920x1200のバックバッファを持ったウインドウモードで起動させるって事を行います。
これなら画面一杯に引き延ばしてもドットバイドットの恩恵も受けられます。(ドットバイドット以外の解像度だと拡大補間に液晶補間が重なってすごくぼける)


ただし、この場合は画面表示(反映)の方法がかなり特殊になります。
まずレンダリング前に可変ウインドウの表示領域を取得し、そのサイズにポリゴンレンダリングさせます。
この時、バックバッファにレンダリングされたものはウインドウサイズ分ですから、バックバッファの他の部分は真っ黒ですんで、必要なウインドウサイズ分だけを抜き取って画面に等倍で反映させる必要があります。

ウインドウサイズ:640x400とすると

step1
[ゲーム画面(CPU)]→(転送)→[テクスチャ(VRAM)]→(ポリゴン描画:640,400サイズに引き延ばし)→[バックバッファ]→
step2
[バックバッファ]→(転送元範囲指定640,400:等倍転送)→[フロントバッファ:表示画面]

Direct3DのPresentでは転送元、転送先領域がちゃんと指定できるのでごにょごにょしてあげましょう。
でも、大抵のミドルウェアやライブラリはウインドウサイズがバックバッファ固定だったりするので、実現できないケースも多そうな気もします。
尚、上のコードではポリゴン描画部分がアスペクト比スケーリングになってないのであしからず。(書くと複雑なんで…)

液晶サイズよりウインドウサイズが大きくなった場合

さて、バックバッファを画面サイズ分確保しましたが、ウインドウアプリケーションなのでそれ以上のサイズになることもあります。
かといってバックバッファはこれ以上拡張するのは機種依存を考えると危ないので、ここは仕方ないのでウインドウ(フロントバッファ)に等倍転送するところを、拡大転送して茶を濁しましょう。
こうなることはかなり希なケースで、しかもその状態でプレイしないでしょうから補間が利かなくても問題ないでしょう。
ただし、必ず発生するケースなので例外処理だけはやっておきましょう。


最後に、マルチディスプレイ環境対策ですが、プライマリディスプレイの解像度で初期化しておけば大丈夫な気もします。
全ディスプレイの解像度をサーチして最も大きいものを使用する方法が良いのかどうかは、まだサンプルが足りないので保留で。それを行うと危険なケースが出てくるかも知れませんので。