フルスクリーン時デバイスロストの処理

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
Libra

フルスクリーン時デバイスロストの処理

#1

投稿記事 by Libra » 15年前

DirectXで画像を出すプログラムを作成しています。
フルスクリーンでウィンドウを出した際、
背景色が表示されず、そこから、ウィンドウモードへ移項した場合、
ゴミのようなものが表示されてしまいます。

フルスクリーン時に、背景色を表示させるにはどうしたらよいでしょうか?
WNDCLASSによるウィンドウの生成の設定が悪いのか、
D3DPRESENT_PARAMETERSの設定が悪いのか、
原因のあたりが付かない状態です。



・フルスクリーンとウィンドウの切り替え
F9キーを押すことで、モードの切り替えを行えます。
ウィンドウモード時はで最大化ボタンを押すことでも切り替わります。
起動の際、フルスクリーンで行うと、おかしな挙動をしたため、ウィンドウモードで
ウィンドウを作成してから、すぐフルスクリーンに切り替えるということをやっています。

参考にしたWebサイト:ウィンドウとフルスクリーンの切り替え
http://www36.atwiki.jp/directx/pages/15.html


開発環境:VisualStudio2008
言語:C++、C
DirectX:9

御津凪

Re:フルスクリーン時の背景色表示

#2

投稿記事 by 御津凪 » 15年前

中身は見ていませんが、フルスクリーンとウィンドウの切り替えを行うと、(DirectX9 までは)デバイスロストが発生します。
このため、それまでに読み込んだテクスチャ・リソース類は全て(D3DPOOL_DEFAULT で生成されたものが)無効になります。
ですので、それらのテクスチャはスクリーンの切り替えを行った後、(Release で解放してから)再度作り直す必要があります。

Libra

Re:フルスクリーン時の背景色表示

#3

投稿記事 by Libra » 15年前

書籍にて、D3DPOOL_MANAGEDで生成されたものは、
「オブジェクトのメモリに関する部分を全てDirect3D側に
任せてしまうというフラグ」
とあったので、デバイスロストのみの処理を行っています。
書籍名:マスタリングDirectXプログラミング

自分のソースでは、GraphicManager.cpp:Clear_DrawScreenメソッドと、
Screen_Flipメソッドの2か所にデバイスロストの処理を入れています。
(2箇所なのは、まだ試験的なものです)

デバイスロスト時の処理
int GraphicManager::Screen_Flip( void )
{
	HRESULT hr ;
	
	lpD3DDev->EndScene( ) ;
	hr = lpD3DDev->Present( NULL , NULL , NULL , NULL ) ;

	if( FAILED( hr ) )
	{
		while( FAILED( hr = lpD3DDev->TestCooperativeLevel( ) ) )
		{
			switch( hr ){
			case D3DERR_DEVICELOST:
				Sleep( 100 ) ;
				break;
			case D3DERR_DEVICENOTRESET:
				lpD3DDev->Reset( &d3dpp ) ;
				break;
			default:
				break;
			}
		}
	}
	
	if( hr == S_OK )
	{
		return SUCCEED ;
	}
	else{
		return FAILURE ;
	}

}
一応ソースを最新版をアップしておきます。
(画像表示メソッド追加版)
画像位置を動かした状態で、フルスクリーンを行うと、
表示した画像が消えずに残っている様です・・・。

御津凪

Re:フルスクリーン時の背景色表示

#4

投稿記事 by 御津凪 » 15年前

とりあえず、切り替え後に Reset が正しく呼びだされていることも確認して、かつ成功しているかチェックしておいてください。

表示が切り替える前の状態のまま固まっていたり、あるいはごみのようなものが出ているということは正しくリセットされていないことを示しています。

異常が発生している時、メインループは正常に回っているかどうかも確認してください。

こちらでは動作チェックはできない環境にいるいるため、正確な答えではないかもしれません。

Libra

Re:フルスクリーン時の背景色表示

#5

投稿記事 by Libra » 15年前

フルスクリーン切り替え時、Clearメソッドが失敗しているようです。
HRESULT hr ;

	hr = lpD3DDev->Clear( 0, NULL , ( D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER ) , D3DCOLOR_XRGB( bg_color.r , bg_color.g , bg_color.b ) , 1.0f , 0 ) ;
	if( hr != S_OK )
	{
		goto JUMP;
	}
	if( FAILED( lpD3DDev->BeginScene( ) ) )
	{
		return FAILURE ;	
	}

	if( FAILED( hr ) )
	{
		JUMP://Clearメソッド失敗したとき飛ぶよ
		while( FAILED( hr = lpD3DDev->TestCooperativeLevel( ) ) )
		{
			switch( hr ){
			case D3DERR_DEVICELOST:
				Sleep( 100 ) ;
				break;
			case D3DERR_DEVICENOTRESET:
				hr = lpD3DDev->Reset( &d3dpp ) ;
				break;
			default:
				hr = hr ;
				break;
			}
		}
	}
このようにgoto文で処理を飛ばしてみたのですが、
ループ内に処理が移行していかないようです。
画面には背景色、画像は表示されず、マウスポインタだけが表示されました。

次に、Clearが失敗したら、Resetの前まで飛ばすようにしてみたのですが、
画面には同じく背景色、画像は表示されず、マウスポインタだけが表示されました。




タイトルを「フルスクリーン時デバイスロストの処理」に変更しました。

御津凪

Re:フルスクリーン時デバイスロストの処理

#6

投稿記事 by 御津凪 » 15年前

動作チェックしてみました。

まず、
// Z バッファの自動作成
    d3dpp.EnableAutoDepthStencil = 1;
    d3dpp.AutoDepthStencilFormat = D3DFMT_D16 ;
これを起動時の初期化で行っているようですが、リセット時にはこの処理を行っていません。
つまり、ウインドウモードとフルスクリーンモードで設定を分けている各 D3DPRESENT_PARAMETERS 構造体の、
d3dppWnd.EnableAutoDepthStencil = FALSE ;
    d3dppWnd.AutoDepthStencilFormat = D3DFMT_A1R5G5B5 ;
がそのまま使用されることになり、深度バッファのないバックバッファが作成される状態となります。

Clear 関数が失敗しているのは、その存在しない深度バッファをクリアしようとしている(D3DCLEAR_ZBUFFER フラグが指定されている)ためです。

また、深度ステンシルバッファのフォーマットは、下記の形式しか使えません。
D3DFMT_D24S8
D3DFMT_D24X8
D3DFMT_D16
D3DFMT_D32F_LOCKABLE
ので、 D3DFMT_A1R5G5B5 をセットしておくのは不適切です。

因みに、DirectX などの HRESULT を返す関数で、その値に応じた名前と説明を返してくれる便利な関数が <dxerr.h> にあります。
DXTRACE_ERR マクロを使うとデバッグ出力に出してくれるので便利です。
例えば、
DXTRACE_ERR("[自由なメッセージ]", hr);
とすると、( hr が D3DERR_DEVICELOST の場合だと)
ファイルパス(行): [自由なメッセージ] hr=D3DERR_DEVICELOST (0x88760868)
のようにデバッグ出力に出してくれます。

Libra

Re:フルスクリーン時デバイスロストの処理

#7

投稿記事 by Libra » 15年前

回答ありがとうございます。

"とりあえず"動くソースが出来ました。(処理は後でまとめます)

わからなかった部分は、TestCooperativeLevelメソッドが
失敗しない点です。
書籍のサンプルソースには記述されていますが、
機能しないなら、抜いてもいいのではないかと思っています。

HRESULT hr ;

	hr = lpD3DDev->Clear( 0, NULL , ( D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER ) , D3DCOLOR_XRGB( bg_color.r , bg_color.g , bg_color.b ) , 1.0f , 0 ) ;
	if( hr != S_OK )
	{
		DXTRACE_ERR( "[Clearメソッドを失敗]" , hr ) ;
		goto JUMP;
	}
	if( FAILED( lpD3DDev->BeginScene( ) ) )
	{
		return FAILURE ;
	
	}

	if( FAILED( hr ) )
	{	
		while( FAILED( hr = lpD3DDev->TestCooperativeLevel( ) ) )
		{
			DXTRACE_ERR( "[TestCooperativeLevelメソッドがFAILED]" , hr ) ;

			switch( hr ){
			case D3DERR_DEVICELOST:
				Sleep( 100 ) ;
				break;
			case D3DERR_DEVICENOTRESET:
				JUMP://Clearで飛ぶよ				
				DXTRACE_ERR( "[自由なメッセージだわ]" , hr ) ;
				hr = lpD3DDev->Reset( &d3dpp ) ;
				d3dpp.EnableAutoDepthStencil = TRUE ;
				d3dpp.AutoDepthStencilFormat = D3DFMT_D24S8 ;
				break;
			default:
				hr = hr ;
				break;
			}
		}
		DXTRACE_ERR( "[自由なメッセージなの]" , hr ) ;
		hr = lpD3DDev->Clear( 0, NULL , ( D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER ) , D3DCOLOR_XRGB( bg_color.r , bg_color.g , bg_color.b ) , 1.0f , 0 ) ;
		if( hr != S_OK )
		{
			DXTRACE_ERR( "[Clearメソッドを失敗だッ]" , hr ) ;
			goto JUMP;//Reset処理へ移動
		}
		if( FAILED( lpD3DDev->BeginScene( ) ) )
		{
			return FAILURE ;
		
		}
	}
	DXTRACE_ERR( "[自由なメッセージかしら], hr ) ;



>>深度ステンシルバッファのフォーマットは、下記の形式しか使えません。

参考書やサンプルソースの例を元に作っているため、
自分の仕様に合わせたくても、パラメーターの説明を読んでも
わからない部分が多いので、なかなか上手くいきません・・・。
基本これにしておけば大丈夫!というパラメーターも、
自分の仕様にすると合わないのですね orz;


>>DXTRACE_ERR マクロを使うとデバッグ出力に出してくれるので便利です。

これは非常に役立ちました。
<dxerr.h>はWindows.hで定義されているものがあるので、
Windows.hより後に記述しないと使えないというのと、
#pragma comment(lib, "dxerr.lib")を付けないと使えないという2点を
知らなかったため、サンプルソースで記述されていても抜いて使っていました。
フルスクリーンでデバックするときは、ブレークポイントを用いて
値を確認することが出来なかったため、困っていました。

御津凪

Re:フルスクリーン時デバイスロストの処理

#8

投稿記事 by 御津凪 » 15年前

> わからなかった部分は、TestCooperativeLevelメソッドが
> 失敗しない点です。
> 書籍のサンプルソースには記述されていますが、
> 機能しないなら、抜いてもいいのではないかと思っています。

TestCooperativeLevel メソッドが行っているのは、平たく言えばデバイスが消失(ロスト)しているか、
あるいはその状態から復帰可能かどうかをチェックするものです。

Clear メソッドが前のコードで失敗しているのは D3DERR_INVALIDCALL 、
つまり「関数の呼び出しが無効である」というだけで、デバイスが消失しているわけではありません。

ではなぜ Clear メソッドが D3DERR_INVALIDCALL を返すのかというと、
深度バッファが作成されずに Reset 関数を呼び出したために深度バッファが無くなり、
Clear メソッドで指定している D3DCLEAR_ZBUFFER フラグにより、 Clear メソッドが深度バッファをクリアしようとしても
深度バッファが存在しないため、エラーとなって D3DERR_INVALIDCALL を返した、というわけです。


あと、それとは別ですが、

#pragma comment(lib, "dxerr.lib")

というマクロは環境依存であることを忘れないでください。
できれば VC++ のプロジェクト設定のリンカオプションで指定することをお勧めします。
(VC++ でのみ扱うコードならばそのまま使用しても支障はありません)

そして、 DXTRACE_ERR を付け忘れたところでエラーが出た場合でも、
エラー値さえ分かればエラーの種別を容易に判別する方法があります。
DirectX SDK には DirectX Error Lookup というエラー値からエラー名と説明を知ることができる
ユーティリティツールが付属しています。
(スタートメニュー内にあります)

ただし、説明文は英語ですけどね。

Libra

Re:フルスクリーン時デバイスロストの処理

#9

投稿記事 by Libra » 15年前

やっとバグの取り除きに成功しました。
解決した、ということで変更したソースも添付しておきます。
御津凪さん、アドバイスありがとうございました!

仕様:
F9でフルスクリーン、ウィンドウ切り替え
ウィンドウモードの時、最大化ボタンを押すとフルスクリーン化


>>TestCooperativeLevel メソッドが行っているのは、平たく言えばデバイスが消失(ロスト)しているか、
あるいはその状態から復帰可能かどうかをチェックするものです。

D3DPRESENT_PARAMETERSの変数の値を修正したところ、期待通りの動作をしました。


>>DirectX SDK には DirectX Error Lookup というエラー値からエラー名と説明を知ることができる
>>ユーティリティツールが付属しています。
>>(スタートメニュー内にあります)

これも知りませんでした。
大変勉強になります。m(_ _)m
フルスクリーン状態でもprintf代わりに
DXTRACE_ERRを使えるようになったので、
デバッグ速度がかなり向上しました。



>>あと、それとは別ですが、

>>#pragma comment(lib, "dxerr.lib")

>>というマクロは環境依存であることを忘れないでください。
>>できれば VC++ のプロジェクト設定のリンカオプションで指定することをお勧めします。
>>(VC++ でのみ扱うコードならばそのまま使用しても支障はありません)

この部分だけわかりませんでした。
一応、今はVCのみで作成していますが、(ExpressEditionでした)
後々のため、教えていただけないでしょうか(^^;)
VCの使い方の話になってしまって申し訳ないです・・・。


VCはブレークポイント、コメントアウト、ブックマークくらいの
機能しか使えてないです・・・。

御津凪

Re:フルスクリーン時デバイスロストの処理

#10

投稿記事 by 御津凪 » 15年前

簡単に説明します。

#pragma comment(lib, "dxerr.lib")

これは、リンカ時に渡すライブラリファイルを指定するマクロです(プラグマ命令と言います)。

このプラグマ命令は、他の用途でも使用され(#pragma message("コンパイル中に表示するメッセージ") など)、
その機能はコンパイラや処理系(BCC や GCC などのこと)によって、大体同じではありますが、書き方が違います。
詳しくは "#pragma" でググるなどして調べるといいでしょう。

なので、書いているプログラムコードが移植目的(別のコンパイラでコンパイルするなど)であれば書くのを避けるべきです。

逆にいえば、 VC++ だけで使用するコードならば、使用しても問題ではありません。

なお、DirectX 関連の書籍では、大抵 Visual Studio でのライブラリファイルの追加方法などが載っていますので参考にするといいでしょう。

プロジェクトのプロパティから、
リンカ - 入力 のページにある「追加の依存ファイル」が、ライブラリファイルを指定する場所です。
ここにリンクするライブラリファイル名を追加することで、
#pragma comment(lib, "リンクするライブラリファイル名")
と同じ効果になります。

Libra

Re:フルスクリーン時デバイスロストの処理

#11

投稿記事 by Libra » 15年前

回答ありがとうございます。

「リンカオプション 設定」etc等で色々検索かけたのですが、
見つからなかったので・・・。

>>なお、DirectX 関連の書籍では、大抵 Visual Studio でのライブラリファイルの追加方法などが載っていますので参考にするといいでしょう。

友人から借りた本にはVisualStudioに関する記載はなかったです・・・。残念。

#pragmaに関しては、調べて勉強します。

御津凪

Re:フルスクリーン時デバイスロストの処理

#12

投稿記事 by 御津凪 » 15年前

近くに書店があれば、書籍を探してみると良いですよ。
DirectX 9 関連の書籍はたくさんありますが、それぞれ初期化部分や描画の仕方等に定型的なコードはあれど、
説明のしかたが色々なので、理解を得やすいものがあるかもしれませんよ。
(大規模な所じゃないと余り沢山並んでないかもしれませんが)

さすがにおまじないと称して説明をしないのはあまり参考にならないですが…。

あと、 VisualStudio 関連の書籍もあるので、興味があったら見てみるといいでしょう。

閉鎖

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