2 using System.Collections.Generic;
3 using System.Diagnostics;
8 public class デバイスリソース : IDisposable
10 public SharpDX.Size2F 設計画面サイズdpx = new SharpDX.Size2F( 1920f, 1080f ); // 設計サイズ。
11 public SharpDX.Size2F 物理画面サイズpx = new SharpDX.Size2F( 0, 0 ); // (0, 0) は、サイズ依存リソース無効の印。
12 public IntPtr ウィンドウハンドル = IntPtr.Zero;
13 public float 視野角deg { get; set; } = 45f;
14 public SharpDX.Matrix ビュー変換行列
18 var カメラの位置 = new SharpDX.Vector3( 0f, 0f, ( -2f * this.dz( this.設計画面サイズdpx.Height, this.視野角deg ) ) );
19 var カメラの注視点 = new SharpDX.Vector3( 0f, 0f, 0f );
20 var カメラの上方向 = new SharpDX.Vector3( 0f, 1f, 0f );
21 var mat = SharpDX.Matrix.LookAtLH( カメラの位置, カメラの注視点, カメラの上方向 );
22 mat.Transpose(); // 転置
26 public SharpDX.Matrix 射影変換行列
30 float dz = this.dz( this.設計画面サイズdpx.Height, this.視野角deg );
31 var mat = SharpDX.Matrix.PerspectiveFovLH(
32 SharpDX.MathUtil.DegreesToRadians( 視野角deg ),
33 設計画面サイズdpx.Width / 設計画面サイズdpx.Height, // アスペクト比
36 mat.Transpose(); // 転置
40 public SharpDX.MediaFoundation.DXGIDeviceManager DXGIDeviceManager => ( this.bs_DXGIDeviceManager );
41 public SharpDX.DXGI.SwapChain SwapChain => ( this.bs_SwapChain );
42 public SharpDX.Direct3D11.RenderTargetView D3DRenderTargetView => ( this.bs_D3DRenderTargetView );
43 public SharpDX.Mathematics.Interop.RawViewportF[] D3DViewPort => ( this.bs_D3DViewPort );
44 public SharpDX.Direct3D11.Texture2D D3DDepthStencil => ( this.bs_D3DDepthStencil );
45 public SharpDX.Direct3D11.DepthStencilView D3DDepthStencilView => ( this.bs_D3DDepthStencilView );
46 public SharpDX.Direct3D11.DepthStencilState D3DDepthStencilState => ( this.bs_D3DDepthStencilState );
47 public SharpDX.Direct3D11.DeviceDebug D3DDeviceDebug => ( this.bs_D3DDeviceDebug );
48 public SharpDX.Direct2D1.Factory2 D2DFactory2 => ( this.bs_D2DFactory2 );
49 public SharpDX.DirectWrite.Factory DWriteFactory => ( this.bs_DWriteFactory );
50 public SharpDX.WIC.ImagingFactory2 WicImagingFactory2 => ( this.bs_WicImagingFactory2 );
51 public SharpDX.Direct2D1.Device1 D2DDevice1 => ( this.bs_D2DDevice1 );
52 public SharpDX.Direct2D1.DeviceContext1 D2DContext1 => ( this.bs_D2DContext1 );
53 public SharpDX.Direct2D1.Bitmap1 D2DRenderTargetBitmap => ( this.bs_D2DRenderTargetBitmap );
55 public float 拡大率DPXtoPX横方向 => ( this.物理画面サイズpx.Width / this.設計画面サイズdpx.Width );
56 public float 拡大率DPXtoPX縦方向 => ( this.物理画面サイズpx.Height / this.設計画面サイズdpx.Height );
57 public float 拡大率PXtoDPX横方向 => ( 1f / this.拡大率DPXtoPX横方向 );
58 public float 拡大率PXtoDPX縦方向 => ( 1f / this.拡大率DPXtoPX縦方向 );
59 public SharpDX.Matrix3x2 拡大行列DPXtoPX => SharpDX.Matrix3x2.Scaling( this.拡大率DPXtoPX横方向, this.拡大率DPXtoPX縦方向 );
60 public SharpDX.Matrix3x2 拡大行列PXtoDPX => SharpDX.Matrix3x2.Scaling( this.拡大率PXtoDPX横方向, this.拡大率PXtoDPX縦方向 );
62 public void すべてのリソースを作成する( System.Drawing.Size バックバッファサイズpx, IntPtr ウィンドウハンドル )
66 FDK.Log.BeginInfo( $"{FDK.Utilities.現在のメソッド名}" );
68 this.物理画面サイズpx = new SharpDX.Size2F( バックバッファサイズpx.Width, バックバッファサイズpx.Height );
69 this.ウィンドウハンドル = ウィンドウハンドル;
75 FDK.Log.EndInfo( $"{FDK.Utilities.現在のメソッド名}" );
78 protected void すべてのリソースを作成する()
82 FDK.Log.BeginInfo( $"{FDK.Utilities.現在のメソッド名}" );
84 // これらが呼び出し前に設定されていること。
85 Debug.Assert( ( 0f < this.物理画面サイズpx.Width ) && ( 0f < this.物理画面サイズpx.Height ) );
86 Debug.Assert( IntPtr.Zero != this.ウィンドウハンドル );
88 #region " D2DFactory2 を作成する。"
91 var デバッグレベル = SharpDX.Direct2D1.DebugLevel.None;
93 // プロジェクトがデバッグビルドに含まれている場合は、Direct2D デバッグレイヤーを SDK レイヤーを介して有効にする。
94 デバッグレベル = SharpDX.Direct2D1.DebugLevel.Information;
96 this.bs_D2DFactory2 = new SharpDX.Direct2D1.Factory2( SharpDX.Direct2D1.FactoryType.SingleThreaded, デバッグレベル );
100 #region " DWriteFactory を作成する。"
102 this.bs_DWriteFactory = new SharpDX.DirectWrite.Factory( SharpDX.DirectWrite.FactoryType.Shared );
105 #region " WicImagingFactory2 を作成する。"
107 this.bs_WicImagingFactory2 = new SharpDX.WIC.ImagingFactory2();
111 var d3dDevice = (SharpDX.Direct3D11.Device) null;
113 #region " DXGIDeviceManager を作成する。"
115 this.bs_DXGIDeviceManager = new SharpDX.MediaFoundation.DXGIDeviceManager();
118 #region " D3Dデバイス、スワップチェーンを作成する。"
121 var swapChainDesc = new SharpDX.DXGI.SwapChainDescription() {
123 ModeDescription = new SharpDX.DXGI.ModeDescription() {
124 Width = (int) this.物理画面サイズpx.Width,
125 Height = (int) this.物理画面サイズpx.Height,
126 RefreshRate = new SharpDX.DXGI.Rational( 60, 1 ),
127 Format = SharpDX.DXGI.Format.B8G8R8A8_UNorm, // D2D をサポートするなら B8G8R8A8 を使う必要がある。
128 Scaling = SharpDX.DXGI.DisplayModeScaling.Stretched,
129 ScanlineOrdering = SharpDX.DXGI.DisplayModeScanlineOrder.Progressive,
132 OutputHandle = ウィンドウハンドル,
133 SampleDescription = new SharpDX.DXGI.SampleDescription( 1, 0 ),
134 SwapEffect = SharpDX.DXGI.SwapEffect.Discard,
135 Usage = SharpDX.DXGI.Usage.RenderTargetOutput,
136 Flags = SharpDX.DXGI.SwapChainFlags.AllowModeSwitch,
139 var featureLevels = new SharpDX.Direct3D.FeatureLevel[] {
140 SharpDX.Direct3D.FeatureLevel.Level_11_0,
141 SharpDX.Direct3D.FeatureLevel.Level_10_1,
142 SharpDX.Direct3D.FeatureLevel.Level_10_0,
144 var creationFlags = SharpDX.Direct3D11.DeviceCreationFlags.BgraSupport; // D2Dをサポートするなら BgraSupport フラグが必須。
146 // D3D11 Debugメッセージは、プロジェクトプロパティで「ネイティブコードのデバッグを有効にする」を ON にしないと表示されないので注意。
147 creationFlags |= SharpDX.Direct3D11.DeviceCreationFlags.Debug;
149 // デバイスとスワップチェーンを作成する。
150 SharpDX.Direct3D11.Device.CreateWithSwapChain(
151 SharpDX.Direct3D.DriverType.Hardware,
156 out this.bs_SwapChain );
158 FDK.Log.Info( "D3Dデバイスとスワップチェーンを生成しました。" );
159 FDK.Log.Info( $"機能レベル: {d3dDevice.FeatureLevel.ToString()}" );
167 #region " デバイスからデバッグオブジェクトを取得する。"
169 this.bs_D3DDeviceDebug = d3dDevice.QueryInterfaceOrNull<SharpDX.Direct3D11.DeviceDebug>();
172 #region " D3DDevice が ID3D11VideoDevice を実装してないならエラー。(Win8以降のPCでは実装されているはず。) "
174 using( var videoDevice = d3dDevice.QueryInterfaceOrNull<SharpDX.Direct3D11.VideoDevice>() )
176 if( null == videoDevice )
177 throw new FDKException( "Direct3D11デバイスが、ID3D11VideoDevice をサポートしていません。" );
181 #region " マルチスレッドモードを ON に設定する。DXVAを使う場合は必須。"
183 using( var multithread = d3dDevice.QueryInterfaceOrNull<SharpDX.Direct3D.DeviceMultithread>() )
185 if( null == multithread )
186 throw new FDKException( "Direct3D11デバイスが、ID3D10Multithread をサポートしていません。" );
188 multithread.SetMultithreadProtected( true );
192 #region " DXGIデバイスマネージャに D3Dデバイスを登録する。"
194 this.DXGIDeviceManager.ResetDevice( d3dDevice );
197 #region " すべての Windows イベントを無視する。具体的には PrintScreen と Alt+Enter 。"
199 using( var factory = this.bs_SwapChain.GetParent<SharpDX.DXGI.Factory>() )
201 factory.MakeWindowAssociation( ウィンドウハンドル, SharpDX.DXGI.WindowAssociationFlags.IgnoreAll );
207 this.サイズに依存するリソースを作成する();
211 FDK.Log.EndInfo( $"{FDK.Utilities.現在のメソッド名}" );
214 public void すべてのリソースを解放する()
218 FDK.Log.BeginInfo( $"{FDK.Utilities.現在のメソッド名}" );
221 this.bs_SwapChain?.SetFullscreenState( fullscreen: false, targetRef: null ); // スワップチェインをウインドウモードにする。
222 this.サイズに依存するリソースを解放する();
224 FDK.Utilities.解放する( ref this.bs_SwapChain );
225 FDK.Utilities.解放する( ref this.bs_DXGIDeviceManager );
228 FDK.Utilities.解放する( ref this.bs_WicImagingFactory2 );
229 FDK.Utilities.解放する( ref this.bs_DWriteFactory );
230 FDK.Utilities.解放する( ref this.bs_D2DFactory2 );
232 this.bs_D3DDeviceDebug?.ReportLiveDeviceObjects( SharpDX.Direct3D11.ReportingLevel.Detail );
233 FDK.Utilities.解放する( ref this.bs_D3DDeviceDebug );
237 FDK.Log.EndInfo( $"{FDK.Utilities.現在のメソッド名}" );
240 public void Dispose()
242 this.すべてのリソースを解放する();
244 public void サイズに依存するリソースを作成する()
248 FDK.Log.BeginInfo( $"{FDK.Utilities.現在のメソッド名}" );
250 #region " スワップチェーンのサイズを変更する。"
252 Debug.Assert( null != this.SwapChain ); // スワップチェーンは(デバイスとともに)すでに生成されていること。
254 this.SwapChain.ResizeBuffers(
256 width: (int) this.物理画面サイズpx.Width,
257 height: (int) this.物理画面サイズpx.Height,
258 newFormat: SharpDX.DXGI.Format.B8G8R8A8_UNorm,
259 swapChainFlags: SharpDX.DXGI.SwapChainFlags.AllowModeSwitch );
263 // バックバッファを使って、D3D / D2D 関連のリソースを作成する。
264 using( var backBuffer = SharpDX.Direct3D11.Texture2D.FromSwapChain<SharpDX.Direct3D11.Texture2D>( this.bs_SwapChain, 0 ) )
266 var d3dDevice = (SharpDX.Direct3D11.Device) null;
267 using( var d3dLock = new FDK.同期.AutoD3DDeviceLock( this.DXGIDeviceManager, out d3dDevice ) )
271 #region " レンダーターゲットビューを作成する。"
273 this.bs_D3DRenderTargetView = new SharpDX.Direct3D11.RenderTargetView( d3dDevice, backBuffer );
276 #region " 深度ステンシルテクスチャを作成する。"
278 var descDepth = backBuffer.Description;
279 //descDepth.Width = backBuffer.Description.Width; → backBuffer に同じ
280 //descDepth.Height = backBuffer.Description.Height; → 同上
281 descDepth.MipLevels = 1; // ミップマップレベル数
282 descDepth.ArraySize = 1; // 配列サイズ
283 descDepth.Format = SharpDX.DXGI.Format.D32_Float; // フォーマット(深度のみ)
284 descDepth.Usage = SharpDX.Direct3D11.ResourceUsage.Default; // デフォルト使用法
285 descDepth.BindFlags = SharpDX.Direct3D11.BindFlags.DepthStencil; // 深度ステンシル
286 descDepth.CpuAccessFlags = SharpDX.Direct3D11.CpuAccessFlags.None; // CPUからはアクセスしない
287 descDepth.OptionFlags = SharpDX.Direct3D11.ResourceOptionFlags.None; // その他の設定なし
288 this.bs_D3DDepthStencil = new SharpDX.Direct3D11.Texture2D( d3dDevice, descDepth );
291 #region " 深度ステンシルビューを作成する。"
293 var descDSV = new SharpDX.Direct3D11.DepthStencilViewDescription() {
294 Format = descDepth.Format,
295 Dimension = SharpDX.Direct3D11.DepthStencilViewDimension.Texture2D,
296 Flags = SharpDX.Direct3D11.DepthStencilViewFlags.None,
297 Texture2D = new SharpDX.Direct3D11.DepthStencilViewDescription.Texture2DResource() {
301 this.bs_D3DDepthStencilView = new SharpDX.Direct3D11.DepthStencilView( d3dDevice, this.bs_D3DDepthStencil, descDSV );
304 #region " 深度ステンシルステートを作成する。"
306 var DepthSencil = new SharpDX.Direct3D11.DepthStencilStateDescription() {
307 IsDepthEnabled = true, // 深度テストあり
308 DepthWriteMask = SharpDX.Direct3D11.DepthWriteMask.All, // 書き込む
309 DepthComparison = SharpDX.Direct3D11.Comparison.Less, // 手前の物体を描画
310 IsStencilEnabled = false, // ステンシルテストなし。
311 StencilReadMask = 0, // ステンシル読み込みマスク。
312 StencilWriteMask = 0, // ステンシル書き込みマスク。
314 // 面が表を向いている場合のステンシル・テストの設定
315 FrontFace = new SharpDX.Direct3D11.DepthStencilOperationDescription() {
316 FailOperation = SharpDX.Direct3D11.StencilOperation.Keep, // 維持
317 DepthFailOperation = SharpDX.Direct3D11.StencilOperation.Keep, // 維持
318 PassOperation = SharpDX.Direct3D11.StencilOperation.Keep, // 維持
319 Comparison = SharpDX.Direct3D11.Comparison.Never, // 常に失敗
322 // 面が裏を向いている場合のステンシル・テストの設定
323 BackFace = new SharpDX.Direct3D11.DepthStencilOperationDescription() {
324 FailOperation = SharpDX.Direct3D11.StencilOperation.Keep, // 維持
325 DepthFailOperation = SharpDX.Direct3D11.StencilOperation.Keep, // 維持
326 PassOperation = SharpDX.Direct3D11.StencilOperation.Keep, // 維持
327 Comparison = SharpDX.Direct3D11.Comparison.Always, // 常に成功
330 this.bs_D3DDepthStencilState = new SharpDX.Direct3D11.DepthStencilState( d3dDevice, DepthSencil );
333 #region " ビューポートを作成する。"
335 this.bs_D3DViewPort[ 0 ] = new SharpDX.Mathematics.Interop.RawViewportF() {
338 Width = (float) backBuffer.Description.Width, // 物理画面単位[px]
339 Height = (float) backBuffer.Description.Height, // 物理画面単位[px]
345 #region " 全テクスチャで共有するリソースを作成する。"
347 FDK.メディア.テクスチャ.全インスタンスで共有するリソースを作成する( this );
352 using( var backsurface = SharpDX.DXGI.Surface.FromSwapChain( this.bs_SwapChain, 0 ) )
354 #region " D2DDevice を作成する。"
356 using( var dxgiDevice = d3dDevice.QueryInterfaceOrNull<SharpDX.DXGI.Device>() )
358 if( null == dxgiDevice )
359 throw new FDKException( "Direct3D11デバイスが、IDXGIDevice3 をサポートしていません。" );
361 this.bs_D2DDevice1 = new SharpDX.Direct2D1.Device1( this.D2DFactory2, dxgiDevice );
365 #region " D2Dの既定のデバイスコンテキストを作成する。"
367 this.bs_D2DContext1 = new SharpDX.Direct2D1.DeviceContext1( this.D2DDevice1, SharpDX.Direct2D1.DeviceContextOptions.None );
369 // 現在のディスプレイDPI を取得し、D2DContext に設定する。
370 this.D2DContext1.DotsPerInch = this.D2DFactory2.DesktopDpi;
373 #region " D2Dの既定のレンダーターゲットビットマップを作成する。"
375 var dpi = this.D2DContext1.DotsPerInch;
377 // DXGIスワップチェーンのバックバッファとデータを共有するD2Dターゲットビットマップを作成する。ビューではなく共有リソース。
378 this.bs_D2DRenderTargetBitmap = new SharpDX.Direct2D1.Bitmap1(
379 this.D2DContext1, // このコンテキストを通じて、
380 backsurface, // バックバッファとデータを共有する。
381 new SharpDX.Direct2D1.BitmapProperties1(
382 new SharpDX.Direct2D1.PixelFormat( backsurface.Description.Format, SharpDX.Direct2D1.AlphaMode.Premultiplied ),
385 SharpDX.Direct2D1.BitmapOptions.Target | SharpDX.Direct2D1.BitmapOptions.CannotDraw ) );
387 // ここでもうD2Dのレンダーターゲットとして登録しておく。
388 this.D2DContext1.Target = this.bs_D2DRenderTargetBitmap;
391 #region " テキストのアンチエイリアシングを設定する。"
393 // Grayscale が、すべての Windows ストアアプリで推奨される。らしい。
394 this.D2DContext1.TextAntialiasMode = SharpDX.Direct2D1.TextAntialiasMode.Grayscale;
403 FDK.Log.EndInfo( $"{FDK.Utilities.現在のメソッド名}" );
406 public void サイズに依存するリソースを解放する()
410 FDK.Log.BeginInfo( $"{FDK.Utilities.現在のメソッド名}" );
413 if( null != this.bs_D2DContext1 )
414 this.bs_D2DContext1.Target = null;
415 FDK.Utilities.解放する( ref this.bs_D2DRenderTargetBitmap );
416 FDK.Utilities.解放する( ref this.bs_D2DContext1 );
417 FDK.Utilities.解放する( ref this.bs_D2DDevice1 );
420 var d3dDevice = (SharpDX.Direct3D11.Device) null;
421 using( var d3dLock = new FDK.同期.AutoD3DDeviceLock( this.DXGIDeviceManager, out d3dDevice ) )
423 using( var d3dContext = d3dDevice.ImmediateContext )
425 d3dContext.ClearState();
426 d3dContext.OutputMerger.ResetTargets();
428 FDK.メディア.テクスチャ.全インスタンスで共有するリソースを解放する();
430 FDK.Utilities.解放する( ref this.bs_D3DDepthStencilState );
431 FDK.Utilities.解放する( ref this.bs_D3DDepthStencilView );
432 FDK.Utilities.解放する( ref this.bs_D3DDepthStencil );
433 FDK.Utilities.解放する( ref this.bs_D3DRenderTargetView );
434 //FDK.Utilities.解放する( ref this.bs_SwapChain ); → スワップチェーンは解放しない(これの生成・解放はデバイスとセットで行う)。
436 // (0,0)は、サイズ依存リソース無効の印。
437 this.物理画面サイズpx = new SharpDX.Size2F( 0, 0 );
442 FDK.Log.EndInfo( $"{FDK.Utilities.現在のメソッド名}" );
445 public void D3Dデバイスが消失していれば再構築する( out bool 異常状態なのでアプリを終了せよ )
447 異常状態なのでアプリを終了せよ = false;
450 var d3dDevice = (SharpDX.Direct3D11.Device) null;
451 using( var d3dLock = new FDK.同期.AutoD3DDeviceLock( this.DXGIDeviceManager, out d3dDevice ) )
454 削除理由 = d3dDevice.DeviceRemovedReason;
458 return; // デバイスは消失していない。
461 new { Code = SharpDX.DXGI.ResultCode.DeviceHung.Code, Info = SharpDX.DXGI.ResultCode.DeviceHung.ApiCode, Rebuild = true },
462 new { Code = SharpDX.DXGI.ResultCode.DeviceReset.Code, Info = SharpDX.DXGI.ResultCode.DeviceReset.ApiCode, Rebuild = true },
463 new { Code = SharpDX.DXGI.ResultCode.DeviceRemoved.Code, Info = SharpDX.DXGI.ResultCode.DeviceRemoved.ApiCode, Rebuild = false },
464 new { Code = SharpDX.DXGI.ResultCode.DriverInternalError.Code, Info = SharpDX.DXGI.ResultCode.DriverInternalError.ApiCode, Rebuild = false },
465 new { Code = SharpDX.DXGI.ResultCode.InvalidCall.Code, Info = SharpDX.DXGI.ResultCode.InvalidCall.ApiCode, Rebuild = false },
466 }.First( ( エラー ) => エラー.Code == 削除理由.Code ); // 見つからないなら System.InvalidOperationException 。
468 Trace.WriteLine( $"D3Dデバイスが消失しました: {エラー詳細.Info}" );
472 this.すべてのリソースを解放する();
473 this.すべてのリソースを作成する();
477 異常状態なのでアプリを終了せよ = true;
480 public void D2DContextの設定をリセットする( SharpDX.Direct2D1.DeviceContext1 context1 )
482 context1.Transform = SharpDX.Matrix3x2.Identity;
483 context1.PrimitiveBlend = SharpDX.Direct2D1.PrimitiveBlend.SourceOver;
486 private float dz( float 高さdpx, float 視野角deg )
488 return (float) ( 高さdpx / ( 4.0 * Math.Tan( SharpDX.MathUtil.DegreesToRadians( 視野角deg / 2.0f ) ) ) );
493 private SharpDX.Direct2D1.Factory2 bs_D2DFactory2 = null;
494 private SharpDX.DirectWrite.Factory bs_DWriteFactory = null;
495 private SharpDX.WIC.ImagingFactory2 bs_WicImagingFactory2 = null;
496 private SharpDX.MediaFoundation.DXGIDeviceManager bs_DXGIDeviceManager = null;
497 private SharpDX.DXGI.SwapChain bs_SwapChain = null;
498 private SharpDX.Mathematics.Interop.RawViewportF[] bs_D3DViewPort = new SharpDX.Mathematics.Interop.RawViewportF[ 1 ];
499 private SharpDX.Direct3D11.DepthStencilState bs_D3DDepthStencilState = null;
500 private SharpDX.Direct3D11.RenderTargetView bs_D3DRenderTargetView = null;
501 private SharpDX.Direct3D11.Texture2D bs_D3DDepthStencil = null;
502 private SharpDX.Direct3D11.DepthStencilView bs_D3DDepthStencilView = null;
503 private SharpDX.Direct3D11.DeviceDebug bs_D3DDeviceDebug = null;
504 private SharpDX.Direct2D1.Device1 bs_D2DDevice1 = null;
505 private SharpDX.Direct2D1.DeviceContext1 bs_D2DContext1 = null;
506 private SharpDX.Direct2D1.Bitmap1 bs_D2DRenderTargetBitmap = null;